diff --git a/.changeset/early-monkeys-learn.md b/.changeset/early-monkeys-learn.md new file mode 100644 index 0000000..89dda24 --- /dev/null +++ b/.changeset/early-monkeys-learn.md @@ -0,0 +1,5 @@ +--- +"paneforge": patch +--- + +feat: reactive minSize prop diff --git a/docs/src/content/examples/collapsible-panes.md b/docs/src/content/examples/collapsible-panes.md index a7d5b22..5c59ce8 100644 --- a/docs/src/content/examples/collapsible-panes.md +++ b/docs/src/content/examples/collapsible-panes.md @@ -32,21 +32,9 @@ Here's the high-level structure of the example above: {#if collapsed} - + {:else} - + {/if} + import { ReactiveSizeDemo } from '$lib/components/demos' + import ViewExampleCode from '$lib/components/view-example-code.svelte' + + + + + + +## Anatomy + +Here's the high-level structure of the example above: + +```svelte + + + + + Left + + Right + +``` diff --git a/docs/src/lib/components/demos/index.ts b/docs/src/lib/components/demos/index.ts index 1303ab5..64a5745 100644 --- a/docs/src/lib/components/demos/index.ts +++ b/docs/src/lib/components/demos/index.ts @@ -6,3 +6,4 @@ export { default as CollapsibleDemo } from "./collapsible-demo.svelte"; export { default as ConditionalDemo } from "./conditional-demo.svelte"; export { default as CookieDemo } from "./cookie-demo.svelte"; export { default as StorageDemo } from "./storage-demo.svelte"; +export { default as ReactiveSizeDemo } from "./reactive-size-demo.svelte"; diff --git a/docs/src/lib/components/demos/reactive-size-demo.svelte b/docs/src/lib/components/demos/reactive-size-demo.svelte new file mode 100644 index 0000000..32ebd5b --- /dev/null +++ b/docs/src/lib/components/demos/reactive-size-demo.svelte @@ -0,0 +1,32 @@ + + + +
+ Panel Min: {panelMin} + + + +
+ Left +
+
+ +
+ +
+
+ +
+ Right +
+
+
+
diff --git a/docs/src/routes/(docs)/docs/sink/+page.svelte b/docs/src/routes/(docs)/docs/sink/+page.svelte new file mode 100644 index 0000000..fd65b0d --- /dev/null +++ b/docs/src/routes/(docs)/docs/sink/+page.svelte @@ -0,0 +1,32 @@ + + + +
+ Panel Min: {panelMin} + + + +
+ Left +
+
+ +
+ +
+
+ +
+ Right +
+
+
+
diff --git a/packages/paneforge/package.json b/packages/paneforge/package.json index 1438515..0026861 100644 --- a/packages/paneforge/package.json +++ b/packages/paneforge/package.json @@ -36,7 +36,7 @@ }, "devDependencies": { "@sveltejs/kit": "^2.17.2", - "@sveltejs/package": "^2.3.0", + "@sveltejs/package": "^2.3.10", "@sveltejs/vite-plugin-svelte": "4.0.0", "@testing-library/dom": "^10.2.0", "@testing-library/jest-dom": "^6.4.6", @@ -46,7 +46,7 @@ "jsdom": "^24.0.0", "publint": "^0.1.9", "resize-observer-polyfill": "^1.5.1", - "svelte": "^5.20.1", + "svelte": "^5.20.2", "svelte-check": "^4.1.4", "tslib": "^2.4.1", "typescript": "^5.0.0", @@ -57,6 +57,7 @@ "types": "./dist/index.d.ts", "type": "module", "dependencies": { + "runed": "^0.23.4", "svelte-toolbelt": "^0.7.1" } } diff --git a/packages/paneforge/src/lib/components/pane-group.svelte b/packages/paneforge/src/lib/components/pane-group.svelte index d67b273..f28231e 100644 --- a/packages/paneforge/src/lib/components/pane-group.svelte +++ b/packages/paneforge/src/lib/components/pane-group.svelte @@ -33,7 +33,7 @@ export const getLayout = () => paneGroupState.layout; export const setLayout = paneGroupState.setLayout; - export const getId = () => paneGroupState.id.current; + export const getId = () => paneGroupState.opts.id.current; const mergedProps = $derived(mergeProps(restProps, paneGroupState.props)); diff --git a/packages/paneforge/src/lib/internal/helpers.ts b/packages/paneforge/src/lib/internal/helpers.ts index 4827a58..2862c18 100644 --- a/packages/paneforge/src/lib/internal/helpers.ts +++ b/packages/paneforge/src/lib/internal/helpers.ts @@ -1,4 +1,5 @@ -import type { Direction, DragState, PaneConstraints, PaneData, ResizeEvent } from "./types.js"; +import type { PaneState } from "$lib/paneforge.svelte.js"; +import type { Direction, DragState, PaneConstraints, ResizeEvent } from "./types.js"; import { calculateAriaValues } from "./utils/aria.js"; import { assert } from "./utils/assert.js"; import { areNumbersAlmostEqual } from "./utils/compare.js"; @@ -10,27 +11,26 @@ export function noop() {} export function updateResizeHandleAriaValues({ groupId, layout, - paneDataArray, + panesArray, }: { groupId: string; layout: number[]; - paneDataArray: PaneData[]; + panesArray: PaneState[]; }) { const resizeHandleElements = getResizeHandleElementsForGroup(groupId); - for (let index = 0; index < paneDataArray.length - 1; index++) { + for (let index = 0; index < panesArray.length - 1; index++) { const { valueMax, valueMin, valueNow } = calculateAriaValues({ layout, - panesArray: paneDataArray, + panesArray: panesArray, pivotIndices: [index, index + 1], }); const resizeHandleEl = resizeHandleElements[index]; if (isHTMLElement(resizeHandleEl)) { - const paneData = paneDataArray[index]; - - resizeHandleEl.setAttribute("aria-controls", paneData.id); + const paneData = panesArray[index]; + resizeHandleEl.setAttribute("aria-controls", paneData.opts.id.current); resizeHandleEl.setAttribute("aria-valuemax", `${Math.round(valueMax)}`); resizeHandleEl.setAttribute("aria-valuemin", `${Math.round(valueMin)}`); resizeHandleEl.setAttribute( @@ -73,13 +73,13 @@ export function getPivotIndices( return index != null ? [index, index + 1] : [-1, -1]; } -export function paneDataHelper(paneDataArray: PaneData[], paneData: PaneData, layout: number[]) { - const paneConstraintsArray = paneDataArray.map((paneData) => paneData.constraints); +export function paneDataHelper(panesArray: PaneState[], pane: PaneState, layout: number[]) { + const paneConstraintsArray = panesArray.map((paneData) => paneData.constraints); - const paneIndex = findPaneDataIndex(paneDataArray, paneData); + const paneIndex = findPaneDataIndex(panesArray, pane); const paneConstraints = paneConstraintsArray[paneIndex]; - const isLastPane = paneIndex === paneDataArray.length - 1; + const isLastPane = paneIndex === panesArray.length - 1; const pivotIndices = isLastPane ? [paneIndex - 1, paneIndex] : [paneIndex, paneIndex + 1]; const paneSize = layout[paneIndex]; @@ -91,30 +91,31 @@ export function paneDataHelper(paneDataArray: PaneData[], paneData: PaneData, la }; } -export function findPaneDataIndex(paneDataArray: readonly PaneData[], paneData: PaneData) { - return paneDataArray.findIndex((prevPaneData) => prevPaneData.id === paneData.id); +export function findPaneDataIndex(panesArray: readonly PaneState[], pane: PaneState) { + return panesArray.findIndex( + (prevPaneData) => prevPaneData.opts.id.current === pane.opts.id.current + ); } // Layout should be pre-converted into percentages export function callPaneCallbacks( - paneArray: PaneData[], + panesArray: PaneState[], layout: number[], paneIdToLastNotifiedSizeMap: Record ) { for (let index = 0; index < layout.length; index++) { const size = layout[index]; - const paneData = paneArray[index]; + const paneData = panesArray[index]; assert(paneData); - const { callbacks, constraints, id: paneId } = paneData; - const { collapsedSize = 0, collapsible } = constraints; + const { collapsedSize = 0, collapsible } = paneData.constraints; - const lastNotifiedSize = paneIdToLastNotifiedSizeMap[paneId]; + const lastNotifiedSize = paneIdToLastNotifiedSizeMap[paneData.opts.id.current]; // invert the logic from below if (!(lastNotifiedSize == null || size !== lastNotifiedSize)) continue; - paneIdToLastNotifiedSizeMap[paneId] = size; + paneIdToLastNotifiedSizeMap[paneData.opts.id.current] = size; - const { onCollapse, onExpand, onResize } = callbacks; + const { onCollapse, onExpand, onResize } = paneData.callbacks; onResize?.(size, lastNotifiedSize); @@ -138,16 +139,16 @@ export function callPaneCallbacks( } } -export function getUnsafeDefaultLayout({ paneDataArray }: { paneDataArray: PaneData[] }): number[] { - const layout = Array(paneDataArray.length); +export function getUnsafeDefaultLayout({ panesArray }: { panesArray: PaneState[] }): number[] { + const layout = Array(panesArray.length); - const paneConstraintsArray = paneDataArray.map((paneData) => paneData.constraints); + const paneConstraintsArray = panesArray.map((paneData) => paneData.constraints); let numPanesWithSizes = 0; let remainingSize = 100; // Distribute default sizes first - for (let index = 0; index < paneDataArray.length; index++) { + for (let index = 0; index < panesArray.length; index++) { const paneConstraints = paneConstraintsArray[index]; assert(paneConstraints); const { defaultSize } = paneConstraints; @@ -160,7 +161,7 @@ export function getUnsafeDefaultLayout({ paneDataArray }: { paneDataArray: PaneD } // Remaining size should be distributed evenly between panes without default sizes - for (let index = 0; index < paneDataArray.length; index++) { + for (let index = 0; index < panesArray.length; index++) { const paneConstraints = paneConstraintsArray[index]; assert(paneConstraints); const { defaultSize } = paneConstraints; @@ -169,7 +170,7 @@ export function getUnsafeDefaultLayout({ paneDataArray }: { paneDataArray: PaneD continue; } - const numRemainingPanes = paneDataArray.length - numPanesWithSizes; + const numRemainingPanes = panesArray.length - numPanesWithSizes; const size = remainingSize / numRemainingPanes; numPanesWithSizes++; @@ -373,14 +374,14 @@ export function getResizeEventCursorPosition(dir: Direction, e: ResizeEvent): nu export function getResizeHandlePaneIds( groupId: string, handleId: string, - panesArray: PaneData[] + panesArray: PaneState[] ): [idBefore: string | null, idAfter: string | null] { const handle = getResizeHandleElement(handleId); const handles = getResizeHandleElementsForGroup(groupId); const index = handle ? handles.indexOf(handle) : -1; - const idBefore: string | null = panesArray[index]?.id ?? null; - const idAfter: string | null = panesArray[index + 1]?.id ?? null; + const idBefore: string | null = panesArray[index]?.opts.id.current ?? null; + const idAfter: string | null = panesArray[index + 1]?.opts.id.current ?? null; return [idBefore, idAfter]; } diff --git a/packages/paneforge/src/lib/internal/utils/aria.ts b/packages/paneforge/src/lib/internal/utils/aria.ts index d17092b..797f329 100644 --- a/packages/paneforge/src/lib/internal/utils/aria.ts +++ b/packages/paneforge/src/lib/internal/utils/aria.ts @@ -1,4 +1,4 @@ -import type { PaneData } from "../types.js"; +import type { PaneState } from "$lib/paneforge.svelte.js"; /** * A utility function that calculates the `aria-valuemax`, `aria-valuemin`, @@ -10,7 +10,7 @@ export function calculateAriaValues({ pivotIndices, }: { layout: number[]; - panesArray: PaneData[]; + panesArray: PaneState[]; pivotIndices: number[]; }) { let currentMinSize = 0; @@ -22,7 +22,7 @@ export function calculateAriaValues({ // A pane's effective min/max sizes also need to account for other pane's sizes. for (let i = 0; i < panesArray.length; i++) { - const { constraints } = panesArray[i]; + const constraints = panesArray[i].constraints; const { maxSize = 100, minSize = 0 } = constraints; if (i === firstIndex) { diff --git a/packages/paneforge/src/lib/internal/utils/createContext.ts b/packages/paneforge/src/lib/internal/utils/createContext.ts deleted file mode 100644 index 5ad7202..0000000 --- a/packages/paneforge/src/lib/internal/utils/createContext.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { getContext as getSvelteContext, hasContext, setContext as setSvelteContext } from "svelte"; - -function setContext(key: symbol | string, value: T): T { - return setSvelteContext(key, value); -} - -function getContext(key: symbol | string, fallback?: T): T { - const trueKey = typeof key === "symbol" ? key : key; - const description = typeof key === "symbol" ? key.description : key; - - if (!hasContext(trueKey)) { - if (fallback === undefined) { - throw new Error( - `Missing context dependency: ${description} and no fallback was provided.` - ); - } - return fallback as T; - } - return getSvelteContext(key); -} - -function getSymbolDescription(providerComponentName: string | string[], contextName?: string) { - if (contextName !== undefined) return contextName; - if (typeof providerComponentName === "string" && contextName === undefined) { - return `${providerComponentName}Context`; - } else if (Array.isArray(providerComponentName) && contextName === undefined) { - return `${providerComponentName[0]}Context`; - } else { - if (contextName !== undefined) return contextName; - return `${providerComponentName}Context`; - } -} - -export function createContext( - providerComponentName: string | string[], - contextName?: string, - useSymbol = true -) { - const symbolDescription = getSymbolDescription(providerComponentName, contextName); - const symbol = Symbol(symbolDescription); - const key = symbolDescription; - - function getCtx( - fallback?: T - ): T extends null ? ContextValue | null : ContextValue { - const context = getContext(useSymbol ? symbol : key, fallback); - if (context === undefined) { - throw new Error( - `Context \`${symbolDescription}\` not found. Component must be used within ${ - Array.isArray(providerComponentName) - ? `one of the following components: ${providerComponentName.join(", ")}` - : `\`${providerComponentName}\`` - }` - ); - } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - if (context === null) return context as any; - return context; - } - - function setCtx(value: ContextValue): ContextValue { - if (useSymbol) { - return setContext(symbol, value); - } else { - return setContext(key, value); - } - } - - return [setCtx, getCtx] as const; -} diff --git a/packages/paneforge/src/lib/internal/utils/storage.ts b/packages/paneforge/src/lib/internal/utils/storage.ts index 6feb2a6..71eedc7 100644 --- a/packages/paneforge/src/lib/internal/utils/storage.ts +++ b/packages/paneforge/src/lib/internal/utils/storage.ts @@ -1,5 +1,5 @@ -import type { PaneData } from "../types.js"; import { LOCAL_STORAGE_DEBOUNCE_INTERVAL } from "../constants.js"; +import type { PaneState } from "$lib/paneforge.svelte.js"; export type PaneConfigState = { expandToSizes: { [paneId: string]: number }; @@ -45,15 +45,12 @@ function getPaneGroupKey(autoSaveId: string): string { * Returns a key to use for storing the pane state in local storage. * The key is based on the pane order and constraints. */ -function getPaneKey(panes: PaneData[]): string { +function getPaneKey(panes: PaneState[]): string { const sortedPaneIds = panes .map((pane) => { - const { constraints, id, idIsFromProps, order } = pane; - return idIsFromProps - ? id - : order - ? `${order}:${JSON.stringify(constraints)}` - : JSON.stringify(constraints); + return pane.opts.order.current + ? `${pane.opts.order.current}:${JSON.stringify(pane.constraints)}` + : JSON.stringify(pane.constraints); }) .sort() .join(","); @@ -88,11 +85,11 @@ function loadSerializedPaneGroupState( */ export function loadPaneGroupState( autoSaveId: string, - panes: PaneData[], + panesArray: PaneState[], storage: PaneGroupStorage ): PaneConfigState | null { const state = loadSerializedPaneGroupState(autoSaveId, storage) || {}; - const paneKey = getPaneKey(panes); + const paneKey = getPaneKey(panesArray); return state[paneKey] || null; } @@ -101,13 +98,13 @@ export function loadPaneGroupState( */ export function savePaneGroupState( autoSaveId: string, - panes: PaneData[], + panesArray: PaneState[], paneSizesBeforeCollapse: Map, sizes: number[], storage: PaneGroupStorage ): void { const paneGroupKey = getPaneGroupKey(autoSaveId); - const paneKey = getPaneKey(panes); + const paneKey = getPaneKey(panesArray); const state = loadSerializedPaneGroupState(autoSaveId, storage) || {}; state[paneKey] = { expandToSizes: Object.fromEntries(paneSizesBeforeCollapse.entries()), @@ -155,19 +152,19 @@ export function updateStorageValues({ autoSaveId, layout, storage, - paneDataArray, + panesArray, paneSizeBeforeCollapse, }: { autoSaveId: string; layout: number[]; storage: PaneGroupStorage; - paneDataArray: PaneData[]; + panesArray: PaneState[]; paneSizeBeforeCollapse: Map; }) { // If this pane has been configured to persist sizing // information, save sizes to local storage. - if (layout.length === 0 || layout.length !== paneDataArray.length) return; + if (layout.length === 0 || layout.length !== panesArray.length) return; let debouncedSave = debounceMap[autoSaveId]; @@ -179,8 +176,8 @@ export function updateStorageValues({ // Clone mutable data before passing to the debounced function, // else we run the risk of saving an incorrect combination of mutable and immutable values to state. - const clonedPaneDataArray = [...paneDataArray]; + const clonedPanesArray = [...panesArray]; const clonedPaneSizesBeforeCollapse = new Map(paneSizeBeforeCollapse); - debouncedSave(autoSaveId, clonedPaneDataArray, clonedPaneSizesBeforeCollapse, layout, storage); + debouncedSave(autoSaveId, clonedPanesArray, clonedPaneSizesBeforeCollapse, layout, storage); } diff --git a/packages/paneforge/src/lib/internal/utils/style.ts b/packages/paneforge/src/lib/internal/utils/style.ts index 16efef9..b507138 100644 --- a/packages/paneforge/src/lib/internal/utils/style.ts +++ b/packages/paneforge/src/lib/internal/utils/style.ts @@ -1,4 +1,5 @@ -import type { DragState, PaneData } from "../types.js"; +import type { PaneState } from "$lib/paneforge.svelte.js"; +import type { DragState } from "../types.js"; type CursorState = | "horizontal" @@ -71,14 +72,14 @@ export function computePaneFlexBoxStyle({ defaultSize, dragState, layout, - paneData, + panesArray, paneIndex, precision = 3, }: { defaultSize: number | undefined; layout: number[]; dragState: DragState | null; - paneData: PaneData[]; + panesArray: PaneState[]; paneIndex: number; precision?: number; }): Record { @@ -89,7 +90,7 @@ export function computePaneFlexBoxStyle({ // Initial render (before panes have registered themselves) // To support server rendering, fallback to default size flexGrow = defaultSize ?? "1"; - } else if (paneData.length === 1) { + } else if (panesArray.length === 1) { // Single pane group should always fill full width/height flexGrow = "1"; } else { diff --git a/packages/paneforge/src/lib/paneforge.svelte.ts b/packages/paneforge/src/lib/paneforge.svelte.ts index f67a020..670d0fa 100644 --- a/packages/paneforge/src/lib/paneforge.svelte.ts +++ b/packages/paneforge/src/lib/paneforge.svelte.ts @@ -6,7 +6,7 @@ import { useRefById, } from "svelte-toolbelt"; import { onMount, untrack } from "svelte"; -import { createContext } from "$lib/internal/utils/createContext.js"; +import { Context, watch } from "runed"; import { callPaneCallbacks, findPaneDataIndex, @@ -36,7 +36,6 @@ import { assert } from "$lib/internal/utils/assert.js"; import type { Direction, DragState, - PaneData, PaneOnCollapse, PaneOnExpand, PaneOnResize, @@ -50,6 +49,7 @@ import { loadPaneGroupState, updateStorageValues, } from "$lib/internal/utils/storage.js"; +import { on } from "svelte/events"; type PaneGroupStateProps = WithRefProps< ReadableBoxedValues<{ @@ -73,90 +73,67 @@ export const defaultStorage: PaneGroupStorage = { }; class PaneGroupState { - id: PaneGroupStateProps["id"]; - #ref: PaneGroupStateProps["ref"]; - #autoSaveId: PaneGroupStateProps["autoSaveId"]; - direction: PaneGroupStateProps["direction"]; - #keyboardResizeBy: PaneGroupStateProps["keyboardResizeBy"]; - #onLayout: PaneGroupStateProps["onLayout"]; - #storage: PaneGroupStateProps["storage"]; dragState = $state.raw(null); layout = $state.raw([]); - paneDataArray = $state.raw([]); - paneDataArrayChanged = $state(false); - + panesArray = $state.raw([]); + panesArrayChanged = $state(false); paneIdToLastNotifiedSizeMap = $state>({}); paneSizeBeforeCollapseMap = new Map(); prevDelta = $state(0); - constructor(props: PaneGroupStateProps) { - this.id = props.id; - this.#ref = props.ref; - this.#autoSaveId = props.autoSaveId; - this.direction = props.direction; - this.#keyboardResizeBy = props.keyboardResizeBy; - this.#onLayout = props.onLayout; - this.#storage = props.storage; - - useRefById({ - id: this.id, - ref: this.#ref, - }); - - $effect(() => { - const groupId = this.id.current; - const layout = this.layout; - const paneDataArray = this.paneDataArray; - - untrack(() => { - const unsub = updateResizeHandleAriaValues({ - groupId, - layout, - paneDataArray, - }); + constructor(readonly opts: PaneGroupStateProps) { + useRefById(opts); - return unsub; + watch([() => this.opts.id.current, () => this.layout, () => this.panesArray], () => { + return updateResizeHandleAriaValues({ + groupId: this.opts.id.current, + layout: this.layout, + panesArray: this.panesArray, }); }); $effect(() => { - untrack(() => { - const unsub = this.#setResizeHandlerEventListeners(); - return unsub; + return untrack(() => { + return this.#setResizeHandlerEventListeners(); }); }); - $effect(() => { - const autoSaveId = this.#autoSaveId.current; - const layout = this.layout; - const storage = this.#storage.current; - if (!autoSaveId) return; - - untrack(() => { + watch( + [ + () => this.opts.autoSaveId.current, + () => this.layout, + () => this.opts.storage.current, + ], + () => { + if (!this.opts.autoSaveId.current) return; updateStorageValues({ - autoSaveId, - layout, - storage, - paneDataArray: this.paneDataArray, + autoSaveId: this.opts.autoSaveId.current, + layout: this.layout, + storage: this.opts.storage.current, + panesArray: this.panesArray, paneSizeBeforeCollapse: this.paneSizeBeforeCollapseMap, }); - }); - }); - - $effect(() => { - const paneDataArrayChanged = this.paneDataArrayChanged; - if (!paneDataArrayChanged) return; - untrack(() => { - this.paneDataArrayChanged = false; - const autoSaveId = this.#autoSaveId.current; - const storage = this.#storage.current; + } + ); + + watch( + () => this.panesArrayChanged, + () => { + if (!this.panesArrayChanged) return; + this.panesArrayChanged = false; + // const autoSaveId = this.opts.autoSaveId.current; + // const storage = this.opts.storage.current; const prevLayout = this.layout; - const paneDataArray = this.paneDataArray; + // const paneDataArray = this.panesArray; let unsafeLayout: number[] | null = null; - if (autoSaveId) { - const state = loadPaneGroupState(autoSaveId, paneDataArray, storage); + if (this.opts.autoSaveId.current) { + const state = loadPaneGroupState( + this.opts.autoSaveId.current, + this.panesArray, + this.opts.storage.current + ); if (state) { this.paneSizeBeforeCollapseMap = new Map( Object.entries(state.expandToSizes) @@ -167,23 +144,23 @@ class PaneGroupState { if (unsafeLayout == null) { unsafeLayout = getUnsafeDefaultLayout({ - paneDataArray, + panesArray: this.panesArray, }); } const nextLayout = validatePaneGroupLayout({ layout: unsafeLayout, - paneConstraints: paneDataArray.map((paneData) => paneData.constraints), + paneConstraints: this.panesArray.map((paneData) => paneData.constraints), }); if (areArraysEqual(prevLayout, nextLayout)) return; this.layout = nextLayout; - this.#onLayout.current?.(nextLayout); + this.opts.onLayout.current?.(nextLayout); - callPaneCallbacks(paneDataArray, nextLayout, this.paneIdToLastNotifiedSizeMap); - }); - }); + callPaneCallbacks(this.panesArray, nextLayout, this.paneIdToLastNotifiedSizeMap); + } + ); } setLayout = (newLayout: number[]) => { @@ -194,13 +171,13 @@ class PaneGroupState { return (e: ResizeEvent) => { e.preventDefault(); - const direction = this.direction.current; + const direction = this.opts.direction.current; const dragState = this.dragState; - const groupId = this.id.current; - const keyboardResizeBy = this.#keyboardResizeBy.current; + const groupId = this.opts.id.current; + const keyboardResizeBy = this.opts.keyboardResizeBy.current; const prevLayout = this.layout; - const paneDataArray = this.paneDataArray; + const paneDataArray = this.panesArray; const { initialLayout } = dragState ?? {}; @@ -253,23 +230,23 @@ class PaneGroupState { } if (layoutChanged) { this.setLayout(nextLayout); - this.#onLayout.current?.(nextLayout); + this.opts.onLayout.current?.(nextLayout); callPaneCallbacks(paneDataArray, nextLayout, this.paneIdToLastNotifiedSizeMap); } }; }; - resizePane = (paneData: PaneData, unsafePaneSize: number) => { + resizePane = (paneState: PaneState, unsafePaneSize: number) => { const prevLayout = this.layout; - const paneDataArray = this.paneDataArray; + const panesArray = this.panesArray; - const paneConstraintsArr = paneDataArray.map((paneData) => paneData.constraints); + const paneConstraintsArr = panesArray.map((paneData) => paneData.constraints); - const { paneSize, pivotIndices } = paneDataHelper(paneDataArray, paneData, prevLayout); + const { paneSize, pivotIndices } = paneDataHelper(panesArray, paneState, prevLayout); assert(paneSize != null); - const isLastPane = findPaneDataIndex(paneDataArray, paneData) === paneDataArray.length - 1; + const isLastPane = findPaneDataIndex(panesArray, paneState) === panesArray.length - 1; const delta = isLastPane ? paneSize - unsafePaneSize : unsafePaneSize - paneSize; @@ -285,13 +262,13 @@ class PaneGroupState { this.setLayout(nextLayout); - this.#onLayout.current?.(nextLayout); + this.opts.onLayout.current?.(nextLayout); - callPaneCallbacks(paneDataArray, nextLayout, this.paneIdToLastNotifiedSizeMap); + callPaneCallbacks(panesArray, nextLayout, this.paneIdToLastNotifiedSizeMap); }; startDragging = (dragHandleId: string, e: ResizeEvent) => { - const direction = this.direction.current; + const direction = this.opts.direction.current; const layout = this.layout; const handleElement = getResizeHandleElement(dragHandleId); @@ -313,34 +290,23 @@ class PaneGroupState { this.dragState = null; }; - unregisterPane = (paneData: PaneData) => { - const paneDataArray = [...this.paneDataArray]; - const index = findPaneDataIndex(paneDataArray, paneData); - - if (index < 0) return; - paneDataArray.splice(index, 1); - this.paneDataArray = paneDataArray; - delete this.paneIdToLastNotifiedSizeMap[paneData.id]; - this.paneDataArrayChanged = true; - }; - - isPaneCollapsed = (paneData: PaneData) => { - const paneDataArray = this.paneDataArray; + isPaneCollapsed = (pane: PaneState) => { + const paneDataArray = this.panesArray; const layout = this.layout; const { collapsedSize = 0, collapsible, paneSize, - } = paneDataHelper(paneDataArray, paneData, layout); + } = paneDataHelper(paneDataArray, pane, layout); return collapsible === true && paneSize === collapsedSize; }; - expandPane = (paneData: PaneData) => { + expandPane = (pane: PaneState) => { const prevLayout = this.layout; - const paneDataArray = this.paneDataArray; + const paneDataArray = this.panesArray; - if (!paneData.constraints.collapsible) return; + if (!pane.constraints.collapsible) return; const paneConstraintsArray = paneDataArray.map((paneData) => paneData.constraints); const { @@ -348,14 +314,14 @@ class PaneGroupState { paneSize, minSize = 0, pivotIndices, - } = paneDataHelper(paneDataArray, paneData, prevLayout); + } = paneDataHelper(paneDataArray, pane, prevLayout); if (paneSize !== collapsedSize) return; // restore this pane to the size it was before it was collapsed, if possible. - const prevPaneSize = this.paneSizeBeforeCollapseMap.get(paneData.id); + const prevPaneSize = this.paneSizeBeforeCollapseMap.get(pane.opts.id.current); const baseSize = prevPaneSize != null && prevPaneSize >= minSize ? prevPaneSize : minSize; - const isLastPane = findPaneDataIndex(paneDataArray, paneData) === paneDataArray.length - 1; + const isLastPane = findPaneDataIndex(paneDataArray, pane) === paneDataArray.length - 1; const delta = isLastPane ? paneSize - baseSize : baseSize - paneSize; const nextLayout = adjustLayoutByDelta({ @@ -370,16 +336,16 @@ class PaneGroupState { this.setLayout(nextLayout); - this.#onLayout.current?.(nextLayout); + this.opts.onLayout.current?.(nextLayout); callPaneCallbacks(paneDataArray, nextLayout, this.paneIdToLastNotifiedSizeMap); }; - collapsePane = (paneData: PaneData) => { + collapsePane = (pane: PaneState) => { const prevLayout = this.layout; - const paneDataArray = this.paneDataArray; + const paneDataArray = this.panesArray; - if (!paneData.constraints.collapsible) return; + if (!pane.constraints.collapsible) return; const paneConstraintsArray = paneDataArray.map((paneData) => paneData.constraints); @@ -387,16 +353,16 @@ class PaneGroupState { collapsedSize = 0, paneSize, pivotIndices, - } = paneDataHelper(paneDataArray, paneData, prevLayout); + } = paneDataHelper(paneDataArray, pane, prevLayout); assert(paneSize != null); if (paneSize === collapsedSize) return; // Store the size before collapse, which is returned when `expand()` is called - this.paneSizeBeforeCollapseMap.set(paneData.id, paneSize); + this.paneSizeBeforeCollapseMap.set(pane.opts.id.current, paneSize); - const isLastPane = findPaneDataIndex(paneDataArray, paneData) === paneDataArray.length - 1; + const isLastPane = findPaneDataIndex(paneDataArray, pane) === paneDataArray.length - 1; const delta = isLastPane ? paneSize - collapsedSize : collapsedSize - paneSize; const nextLayout = adjustLayoutByDelta({ @@ -410,45 +376,44 @@ class PaneGroupState { if (areArraysEqual(prevLayout, nextLayout)) return; this.layout = nextLayout; - this.#onLayout.current?.(nextLayout); + this.opts.onLayout.current?.(nextLayout); callPaneCallbacks(paneDataArray, nextLayout, this.paneIdToLastNotifiedSizeMap); }; - getPaneSize = (paneData: PaneData) => { - const { paneSize } = paneDataHelper(this.paneDataArray, paneData, this.layout); - return paneSize; + getPaneSize = (pane: PaneState) => { + return paneDataHelper(this.panesArray, pane, this.layout).paneSize; }; - getPaneStyle = (paneData: PaneData, defaultSize: number | undefined) => { - const paneDataArray = this.paneDataArray; + getPaneStyle = (pane: PaneState, defaultSize: number | undefined) => { + const paneDataArray = this.panesArray; const layout = this.layout; const dragState = this.dragState; - const paneIndex = findPaneDataIndex(paneDataArray, paneData); + const paneIndex = findPaneDataIndex(paneDataArray, pane); return computePaneFlexBoxStyle({ defaultSize, dragState, layout, - paneData: paneDataArray, + panesArray: paneDataArray, paneIndex, }); }; - isPaneExpanded = (paneData: PaneData) => { + isPaneExpanded = (pane: PaneState) => { const { collapsedSize = 0, collapsible, paneSize, - } = paneDataHelper(this.paneDataArray, paneData, this.layout); + } = paneDataHelper(this.panesArray, pane, this.layout); return !collapsible || paneSize > collapsedSize; }; - registerPane = (paneData: PaneData) => { - const newPaneDataArray = [...this.paneDataArray, paneData]; + registerPane = (pane: PaneState) => { + const newPaneDataArray = [...this.panesArray, pane]; newPaneDataArray.sort((paneA, paneB) => { - const orderA = paneA.order; - const orderB = paneB.order; + const orderA = paneA.opts.order.current; + const orderB = paneB.opts.order.current; if (orderA == null && orderB == null) { return 0; @@ -460,14 +425,25 @@ class PaneGroupState { return orderA - orderB; } }); - this.paneDataArray = newPaneDataArray; - this.paneDataArrayChanged = true; + this.panesArray = newPaneDataArray; + this.panesArrayChanged = true; + + return () => { + const paneDataArray = [...this.panesArray]; + const index = findPaneDataIndex(this.panesArray, pane); + + if (index < 0) return; + paneDataArray.splice(index, 1); + this.panesArray = paneDataArray; + delete this.paneIdToLastNotifiedSizeMap[pane.opts.id.current]; + this.panesArrayChanged = true; + }; }; #setResizeHandlerEventListeners = () => { - const groupId = this.id.current; + const groupId = this.opts.id.current; const handles = getResizeHandleElementsForGroup(groupId); - const paneDataArray = this.paneDataArray; + const paneDataArray = this.panesArray; const unsubHandlers = handles.map((handle) => { const handleId = handle.getAttribute("data-pane-resizer-id"); @@ -481,8 +457,10 @@ class PaneGroupState { if (e.defaultPrevented || e.key !== "Enter") return; e.preventDefault(); - const paneDataArray = this.paneDataArray; - const index = paneDataArray.findIndex((paneData) => paneData.id === idBefore); + const paneDataArray = this.panesArray; + const index = paneDataArray.findIndex( + (paneData) => paneData.opts.id.current === idBefore + ); if (index < 0) return; @@ -525,27 +503,22 @@ class PaneGroupState { }; }; - props = $derived.by(() => ({ - id: this.id.current, - "data-pane-group": "", - "data-direction": this.direction.current, - "data-pane-group-id": this.id.current, - style: { - display: "flex", - flexDirection: this.direction.current === "horizontal" ? "row" : "column", - height: "100%", - overflow: "hidden", - width: "100%", - }, - })); - - createResizer = (props: PaneResizerStateProps) => { - return new PaneResizerState(props, this); - }; - - createPane = (props: PaneStateProps) => { - return new PaneState(props, this); - }; + props = $derived.by( + () => + ({ + id: this.opts.id.current, + "data-pane-group": "", + "data-direction": this.opts.direction.current, + "data-pane-group-id": this.opts.id.current, + style: { + display: "flex", + flexDirection: this.opts.direction.current === "horizontal" ? "row" : "column", + height: "100%", + overflow: "hidden", + width: "100%", + }, + }) as const + ); } type PaneResizerStateProps = WithRefProps< @@ -559,41 +532,28 @@ type PaneResizerStateProps = WithRefProps< const resizeKeys = ["ArrowDown", "ArrowLeft", "ArrowRight", "ArrowUp", "End", "Home"]; class PaneResizerState { - #id: PaneResizerStateProps["id"]; - #ref: PaneResizerStateProps["ref"]; - #onDraggingChange: PaneResizerStateProps["onDraggingChange"]; - #disabled: PaneResizerStateProps["disabled"]; - #tabIndex: PaneResizerStateProps["tabIndex"]; - #group: PaneGroupState; - #isDragging = $derived.by(() => this.#group.dragState?.dragHandleId === this.#id.current); + #isDragging = $derived.by(() => this.group.dragState?.dragHandleId === this.opts.id.current); #isFocused = $state(false); resizeHandler: ResizeHandler | null = null; - constructor(props: PaneResizerStateProps, group: PaneGroupState) { - this.#id = props.id; - this.#ref = props.ref; - this.#group = group; - this.#onDraggingChange = props.onDraggingChange; - this.#disabled = props.disabled; - this.#tabIndex = props.tabIndex; - - useRefById({ - id: this.#id, - ref: this.#ref, - }); + constructor( + readonly opts: PaneResizerStateProps, + readonly group: PaneGroupState + ) { + useRefById(opts); $effect(() => { - if (this.#disabled.current) { + if (this.opts.disabled.current) { this.resizeHandler = null; } else { - this.resizeHandler = this.#group.registerResizeHandle(this.#id.current); + this.resizeHandler = this.group.registerResizeHandle(this.opts.id.current); } }); $effect(() => { - const node = this.#ref.current; + const node = this.opts.ref.current; if (!node) return; - const disabled = this.#disabled.current; + const disabled = this.opts.disabled.current; const resizeHandler = this.resizeHandler; const isDragging = this.#isDragging; if (disabled || resizeHandler === null || !isDragging) return; @@ -608,41 +568,39 @@ class PaneResizerState { const stopDraggingAndBlur = () => { node.blur(); - this.#group.stopDragging(); - this.#onDraggingChange.current(false); + this.group.stopDragging(); + this.opts.onDraggingChange.current(false); }; - const unsub = executeCallbacks( - addEventListener(document.body, "contextmenu", stopDraggingAndBlur), - addEventListener(document.body, "mousemove", onMove), - addEventListener(document.body, "touchmove", onMove, { passive: false }), - addEventListener(document.body, "mouseleave", onMouseLeave), - addEventListener(window, "mouseup", stopDraggingAndBlur), - addEventListener(window, "touchend", stopDraggingAndBlur) + return executeCallbacks( + on(document.body, "contextmenu", stopDraggingAndBlur), + on(document.body, "mousemove", onMove), + on(document.body, "touchmove", onMove, { passive: false }), + on(document.body, "mouseleave", onMouseLeave), + on(window, "mouseup", stopDraggingAndBlur), + on(window, "touchend", stopDraggingAndBlur) ); - - return unsub; }); } #startDragging = (e: MouseEvent | TouchEvent) => { e.preventDefault(); - if (this.#disabled.current) return; - this.#group.startDragging(this.#id.current, e); - this.#onDraggingChange.current(true); + if (this.opts.disabled.current) return; + this.group.startDragging(this.opts.id.current, e); + this.opts.onDraggingChange.current(true); }; #stopDraggingAndBlur = () => { - const node = this.#ref.current; + const node = this.opts.ref.current; if (!node) return; node.blur(); - this.#group.stopDragging(); - this.#onDraggingChange.current(false); + this.group.stopDragging(); + this.opts.onDraggingChange.current(false); }; #onkeydown = (e: KeyboardEvent) => { - if (this.#disabled.current || !this.resizeHandler || e.defaultPrevented) return; + if (this.opts.disabled.current || !this.resizeHandler || e.defaultPrevented) return; if (resizeKeys.includes(e.key)) { e.preventDefault(); @@ -654,8 +612,8 @@ class PaneResizerState { e.preventDefault(); - const handles = getResizeHandleElementsForGroup(this.#group.id.current); - const index = getResizeHandleElementIndex(this.#group.id.current, this.#id.current); + const handles = getResizeHandleElementsForGroup(this.group.opts.id.current); + const index = getResizeHandleElementIndex(this.group.opts.id.current, this.opts.id.current); if (index === null) return; @@ -712,21 +670,21 @@ class PaneResizerState { props = $derived.by( () => ({ - id: this.#id.current, + id: this.opts.id.current, role: "separator", - "data-direction": this.#group.direction.current, - "data-pane-group-id": this.#group.id.current, + "data-direction": this.group.opts.direction.current, + "data-pane-group-id": this.group.opts.id.current, "data-active": this.#isDragging ? "pointer" : this.#isFocused ? "keyboard" : undefined, - "data-enabled": !this.#disabled.current, - "data-pane-resizer-id": this.#id.current, + "data-enabled": !this.opts.disabled.current, + "data-pane-resizer-id": this.opts.id.current, "data-pane-resizer": "", - tabIndex: this.#tabIndex.current, + tabIndex: this.opts.tabIndex.current, style: { - cursor: getCursorStyle(this.#group.direction.current), + cursor: getCursorStyle(this.group.opts.direction.current), touchAction: "none", userSelect: "none", "-webkit-user-select": "none", @@ -758,101 +716,77 @@ type PaneStateProps = WithRefProps< }> >; -class PaneState { - #id: PaneStateProps["id"]; - #ref: PaneStateProps["ref"]; - #collapsedSize: PaneStateProps["collapsedSize"]; - #collapsible: PaneStateProps["collapsible"]; - #defaultSize: PaneStateProps["defaultSize"]; - #maxSize: PaneStateProps["maxSize"]; - #minSize: PaneStateProps["minSize"]; - #order: PaneStateProps["order"]; - #onCollapse: PaneStateProps["onCollapse"]; - #onExpand: PaneStateProps["onExpand"]; - #onResize: PaneStateProps["onResize"]; - #group: PaneGroupState; - - #paneData = $derived.by(() => ({ - callbacks: { - onCollapse: this.#onCollapse.current, - onExpand: this.#onExpand.current, - onResize: this.#onResize.current, - }, - constraints: { - collapsedSize: this.#collapsedSize.current, - collapsible: this.#collapsible.current, - defaultSize: this.#defaultSize.current, - maxSize: this.#maxSize.current, - minSize: this.#minSize.current, - }, - id: this.#id.current, - idIsFromProps: false, - order: this.#order.current, +export class PaneState { + callbacks = $derived.by(() => ({ + onCollapse: this.opts.onCollapse.current, + onExpand: this.opts.onExpand.current, + onResize: this.opts.onResize.current, + })); + + constraints = $derived.by(() => ({ + collapsedSize: this.opts.collapsedSize.current, + collapsible: this.opts.collapsible.current, + defaultSize: this.opts.defaultSize.current, + maxSize: this.opts.maxSize.current, + minSize: this.opts.minSize.current, })); pane = { collapse: () => { - this.#group.collapsePane(this.#paneData); + this.group.collapsePane(this); }, - expand: () => this.#group.expandPane(this.#paneData), - getSize: () => this.#group.getPaneSize(this.#paneData), - isCollapsed: () => this.#group.isPaneCollapsed(this.#paneData), - isExpanded: () => this.#group.isPaneExpanded(this.#paneData), - resize: (size: number) => this.#group.resizePane(this.#paneData, size), - getId: () => this.#id.current, + expand: () => this.group.expandPane(this), + getSize: () => this.group.getPaneSize(this), + isCollapsed: () => this.group.isPaneCollapsed(this), + isExpanded: () => this.group.isPaneExpanded(this), + resize: (size: number) => this.group.resizePane(this, size), + getId: () => this.opts.id.current, }; - constructor(props: PaneStateProps, group: PaneGroupState) { - this.#id = props.id; - this.#ref = props.ref; - this.#collapsedSize = props.collapsedSize; - this.#collapsible = props.collapsible; - this.#defaultSize = props.defaultSize; - this.#maxSize = props.maxSize; - this.#minSize = props.minSize; - this.#order = props.order; - this.#onCollapse = props.onCollapse; - this.#onExpand = props.onExpand; - this.#onResize = props.onResize; - this.#group = group; - - useRefById({ - id: this.#id, - ref: this.#ref, - }); + constructor( + readonly opts: PaneStateProps, + readonly group: PaneGroupState + ) { + useRefById(opts); onMount(() => { - this.#group.registerPane(this.#paneData); - - return () => { - this.#group.unregisterPane(this.#paneData); - }; + return this.group.registerPane(this); }); + + watch( + () => $state.snapshot(this.constraints), + () => { + this.group.panesArrayChanged = true; + } + ); } - #isCollapsed = $derived.by(() => this.#group.isPaneCollapsed(this.#paneData)); + #isCollapsed = $derived.by(() => this.group.isPaneCollapsed(this)); - props = $derived.by(() => ({ - id: this.#id.current, - style: this.#group.getPaneStyle(this.#paneData, this.#defaultSize.current), - "data-pane": "", - "data-pane-id": this.#id.current, - "data-pane-group-id": this.#group.id.current, - "data-collapsed": this.#isCollapsed ? "" : undefined, - "data-expanded": this.#isCollapsed ? undefined : "", - })); + props = $derived.by( + () => + ({ + id: this.opts.id.current, + style: this.group.getPaneStyle(this, this.opts.defaultSize.current), + "data-pane": "", + "data-pane-id": this.opts.id.current, + "data-pane-group-id": this.group.opts.id.current, + "data-collapsed": this.#isCollapsed ? "" : undefined, + "data-expanded": this.#isCollapsed ? undefined : "", + }) as const + ); } -const [setPaneGroupContext, getPaneGroupContext] = createContext("PaneGroup"); +const PaneGroupContext = new Context("PaneGroup"); export function usePaneGroup(props: PaneGroupStateProps) { - return setPaneGroupContext(new PaneGroupState(props)); + return PaneGroupContext.set(new PaneGroupState(props)); } export function usePaneResizer(props: PaneResizerStateProps) { - return getPaneGroupContext().createResizer(props); + return new PaneResizerState(props, PaneGroupContext.get()); } export function usePane(props: PaneStateProps) { - return getPaneGroupContext().createPane(props); + return new PaneState(props, PaneGroupContext.get()); } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4375f63..7f5cf1b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -113,19 +113,22 @@ importers: packages/paneforge: dependencies: + runed: + specifier: ^0.23.4 + version: 0.23.4(svelte@5.20.2) svelte-toolbelt: specifier: ^0.7.1 - version: 0.7.1(svelte@5.20.1) + version: 0.7.1(svelte@5.20.2) devDependencies: '@sveltejs/kit': specifier: ^2.17.2 - version: 2.17.2(@sveltejs/vite-plugin-svelte@4.0.0(svelte@5.20.1)(vite@5.4.11(@types/node@20.17.10)(lightningcss@1.28.2)(terser@5.37.0)))(svelte@5.20.1)(vite@5.4.11(@types/node@20.17.10)(lightningcss@1.28.2)(terser@5.37.0)) + version: 2.17.2(@sveltejs/vite-plugin-svelte@4.0.0(svelte@5.20.2)(vite@5.4.11(@types/node@20.17.10)(lightningcss@1.28.2)(terser@5.37.0)))(svelte@5.20.2)(vite@5.4.11(@types/node@20.17.10)(lightningcss@1.28.2)(terser@5.37.0)) '@sveltejs/package': - specifier: ^2.3.0 - version: 2.3.7(svelte@5.20.1)(typescript@5.7.2) + specifier: ^2.3.10 + version: 2.3.10(svelte@5.20.2)(typescript@5.7.2) '@sveltejs/vite-plugin-svelte': specifier: 4.0.0 - version: 4.0.0(svelte@5.20.1)(vite@5.4.11(@types/node@20.17.10)(lightningcss@1.28.2)(terser@5.37.0)) + version: 4.0.0(svelte@5.20.2)(vite@5.4.11(@types/node@20.17.10)(lightningcss@1.28.2)(terser@5.37.0)) '@testing-library/dom': specifier: ^10.2.0 version: 10.4.0 @@ -134,7 +137,7 @@ importers: version: 6.6.3 '@testing-library/svelte': specifier: ^5.2.0 - version: 5.2.6(svelte@5.20.1)(vite@5.4.11(@types/node@20.17.10)(lightningcss@1.28.2)(terser@5.37.0))(vitest@1.6.0(@types/node@20.17.10)(jsdom@24.1.3)(lightningcss@1.28.2)(terser@5.37.0)) + version: 5.2.6(svelte@5.20.2)(vite@5.4.11(@types/node@20.17.10)(lightningcss@1.28.2)(terser@5.37.0))(vitest@1.6.0(@types/node@20.17.10)(jsdom@24.1.3)(lightningcss@1.28.2)(terser@5.37.0)) '@testing-library/user-event': specifier: ^14.5.2 version: 14.5.2(@testing-library/dom@10.4.0) @@ -151,11 +154,11 @@ importers: specifier: ^1.5.1 version: 1.5.1 svelte: - specifier: ^5.20.1 - version: 5.20.1 + specifier: ^5.20.2 + version: 5.20.2 svelte-check: specifier: ^4.1.4 - version: 4.1.4(svelte@5.20.1)(typescript@5.7.2) + version: 4.1.4(svelte@5.20.2)(typescript@5.7.2) tslib: specifier: ^2.4.1 version: 2.8.1 @@ -1079,8 +1082,8 @@ packages: svelte: ^4.0.0 || ^5.0.0-next.0 vite: ^5.0.3 || ^6.0.0 - '@sveltejs/package@2.3.7': - resolution: {integrity: sha512-LYgUkde5GUYqOpXbcoCGUpEH4Ctl3Wj4u4CVZBl56dEeLW5fGHE037ZL1qlK0Ky+QD5uUfwONSeGwIOIighFMQ==} + '@sveltejs/package@2.3.10': + resolution: {integrity: sha512-A4fQacgjJ7C/7oSmxR61/TdB14u6ecyMZ8V9JCR5Lol0bLj/PdJPU4uFodFBsKzO3iFiJMpNTgZZ+zYsYZNpUg==} engines: {node: ^16.14 || >=18} hasBin: true peerDependencies: @@ -1485,6 +1488,10 @@ packages: resolution: {integrity: sha512-/b57FK+bblSU+dfewfFe0rT1YjVDfOmeLQwCAuC+vwvgLkXboATqqmy+Ipux6JrF6L5joe5CBnFOw+gLWH6yKg==} engines: {node: '>= 14.16.0'} + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + ci-info@3.9.0: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} @@ -3114,8 +3121,8 @@ packages: peerDependencies: svelte: ^5.0.0 - svelte2tsx@0.7.31: - resolution: {integrity: sha512-exrN1o9mdCLAA7hTCudz731FIxomH/0SN9ZIX+WrY/XnlLuno/NNC1PF6JXPZVqp/4sMMDKteqyKoG44hliljQ==} + svelte2tsx@0.7.34: + resolution: {integrity: sha512-WTMhpNhFf8/h3SMtR5dkdSy2qfveomkhYei/QW9gSPccb0/b82tjHvLop6vT303ZkGswU/da1s6XvrLgthQPCw==} peerDependencies: svelte: ^3.55 || ^4.0.0-next.0 || ^4.0 || ^5.0.0-next.0 typescript: ^4.9.4 || ^5.0.0 @@ -3128,6 +3135,10 @@ packages: resolution: {integrity: sha512-aCARru2WTdzJl55Ws8SK27+kvQwd8tijl4kY7NoDUXUHtTHhxMa8Lf6QNZKmU7cuPu3jjFloDO1j5HgYJNIIWg==} engines: {node: '>=18'} + svelte@5.20.2: + resolution: {integrity: sha512-aYXJreNUiyTob0QOzRZeBXZMGeFZDch6SrSRV8QTncZb6zj0O3BEdUzPpojuHQ1pTvk+KX7I6rZCXPUf8pTPxA==} + engines: {node: '>=18'} + symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} @@ -4256,9 +4267,9 @@ snapshots: worktop: 0.8.0-next.18 wrangler: 3.96.0(@cloudflare/workers-types@4.20241218.0) - '@sveltejs/kit@2.17.2(@sveltejs/vite-plugin-svelte@4.0.0(svelte@5.20.1)(vite@5.4.11(@types/node@20.17.10)(lightningcss@1.28.2)(terser@5.37.0)))(svelte@5.20.1)(vite@5.4.11(@types/node@20.17.10)(lightningcss@1.28.2)(terser@5.37.0))': + '@sveltejs/kit@2.17.2(@sveltejs/vite-plugin-svelte@4.0.0(svelte@5.20.1)(vite@5.4.11(@types/node@22.10.2)(lightningcss@1.28.2)(terser@5.37.0)))(svelte@5.20.1)(vite@5.4.11(@types/node@22.10.2)(lightningcss@1.28.2)(terser@5.37.0))': dependencies: - '@sveltejs/vite-plugin-svelte': 4.0.0(svelte@5.20.1)(vite@5.4.11(@types/node@20.17.10)(lightningcss@1.28.2)(terser@5.37.0)) + '@sveltejs/vite-plugin-svelte': 4.0.0(svelte@5.20.1)(vite@5.4.11(@types/node@22.10.2)(lightningcss@1.28.2)(terser@5.37.0)) '@types/cookie': 0.6.0 cookie: 0.6.0 devalue: 5.1.1 @@ -4271,11 +4282,11 @@ snapshots: set-cookie-parser: 2.7.1 sirv: 3.0.0 svelte: 5.20.1 - vite: 5.4.11(@types/node@20.17.10)(lightningcss@1.28.2)(terser@5.37.0) + vite: 5.4.11(@types/node@22.10.2)(lightningcss@1.28.2)(terser@5.37.0) - '@sveltejs/kit@2.17.2(@sveltejs/vite-plugin-svelte@4.0.0(svelte@5.20.1)(vite@5.4.11(@types/node@22.10.2)(lightningcss@1.28.2)(terser@5.37.0)))(svelte@5.20.1)(vite@5.4.11(@types/node@22.10.2)(lightningcss@1.28.2)(terser@5.37.0))': + '@sveltejs/kit@2.17.2(@sveltejs/vite-plugin-svelte@4.0.0(svelte@5.20.2)(vite@5.4.11(@types/node@20.17.10)(lightningcss@1.28.2)(terser@5.37.0)))(svelte@5.20.2)(vite@5.4.11(@types/node@20.17.10)(lightningcss@1.28.2)(terser@5.37.0))': dependencies: - '@sveltejs/vite-plugin-svelte': 4.0.0(svelte@5.20.1)(vite@5.4.11(@types/node@22.10.2)(lightningcss@1.28.2)(terser@5.37.0)) + '@sveltejs/vite-plugin-svelte': 4.0.0(svelte@5.20.2)(vite@5.4.11(@types/node@20.17.10)(lightningcss@1.28.2)(terser@5.37.0)) '@types/cookie': 0.6.0 cookie: 0.6.0 devalue: 5.1.1 @@ -4287,29 +4298,20 @@ snapshots: sade: 1.8.1 set-cookie-parser: 2.7.1 sirv: 3.0.0 - svelte: 5.20.1 - vite: 5.4.11(@types/node@22.10.2)(lightningcss@1.28.2)(terser@5.37.0) + svelte: 5.20.2 + vite: 5.4.11(@types/node@20.17.10)(lightningcss@1.28.2)(terser@5.37.0) - '@sveltejs/package@2.3.7(svelte@5.20.1)(typescript@5.7.2)': + '@sveltejs/package@2.3.10(svelte@5.20.2)(typescript@5.7.2)': dependencies: - chokidar: 4.0.2 + chokidar: 4.0.3 kleur: 4.1.5 sade: 1.8.1 semver: 7.6.3 - svelte: 5.20.1 - svelte2tsx: 0.7.31(svelte@5.20.1)(typescript@5.7.2) + svelte: 5.20.2 + svelte2tsx: 0.7.34(svelte@5.20.2)(typescript@5.7.2) transitivePeerDependencies: - typescript - '@sveltejs/vite-plugin-svelte-inspector@3.0.1(@sveltejs/vite-plugin-svelte@4.0.0(svelte@5.20.1)(vite@5.4.11(@types/node@20.17.10)(lightningcss@1.28.2)(terser@5.37.0)))(svelte@5.20.1)(vite@5.4.11(@types/node@20.17.10)(lightningcss@1.28.2)(terser@5.37.0))': - dependencies: - '@sveltejs/vite-plugin-svelte': 4.0.0(svelte@5.20.1)(vite@5.4.11(@types/node@20.17.10)(lightningcss@1.28.2)(terser@5.37.0)) - debug: 4.4.0 - svelte: 5.20.1 - vite: 5.4.11(@types/node@20.17.10)(lightningcss@1.28.2)(terser@5.37.0) - transitivePeerDependencies: - - supports-color - '@sveltejs/vite-plugin-svelte-inspector@3.0.1(@sveltejs/vite-plugin-svelte@4.0.0(svelte@5.20.1)(vite@5.4.11(@types/node@22.10.2)(lightningcss@1.28.2)(terser@5.37.0)))(svelte@5.20.1)(vite@5.4.11(@types/node@22.10.2)(lightningcss@1.28.2)(terser@5.37.0))': dependencies: '@sveltejs/vite-plugin-svelte': 4.0.0(svelte@5.20.1)(vite@5.4.11(@types/node@22.10.2)(lightningcss@1.28.2)(terser@5.37.0)) @@ -4319,16 +4321,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@sveltejs/vite-plugin-svelte@4.0.0(svelte@5.20.1)(vite@5.4.11(@types/node@20.17.10)(lightningcss@1.28.2)(terser@5.37.0))': + '@sveltejs/vite-plugin-svelte-inspector@3.0.1(@sveltejs/vite-plugin-svelte@4.0.0(svelte@5.20.2)(vite@5.4.11(@types/node@20.17.10)(lightningcss@1.28.2)(terser@5.37.0)))(svelte@5.20.2)(vite@5.4.11(@types/node@20.17.10)(lightningcss@1.28.2)(terser@5.37.0))': dependencies: - '@sveltejs/vite-plugin-svelte-inspector': 3.0.1(@sveltejs/vite-plugin-svelte@4.0.0(svelte@5.20.1)(vite@5.4.11(@types/node@20.17.10)(lightningcss@1.28.2)(terser@5.37.0)))(svelte@5.20.1)(vite@5.4.11(@types/node@20.17.10)(lightningcss@1.28.2)(terser@5.37.0)) + '@sveltejs/vite-plugin-svelte': 4.0.0(svelte@5.20.2)(vite@5.4.11(@types/node@20.17.10)(lightningcss@1.28.2)(terser@5.37.0)) debug: 4.4.0 - deepmerge: 4.3.1 - kleur: 4.1.5 - magic-string: 0.30.17 - svelte: 5.20.1 + svelte: 5.20.2 vite: 5.4.11(@types/node@20.17.10)(lightningcss@1.28.2)(terser@5.37.0) - vitefu: 1.0.4(vite@5.4.11(@types/node@20.17.10)(lightningcss@1.28.2)(terser@5.37.0)) transitivePeerDependencies: - supports-color @@ -4345,6 +4343,19 @@ snapshots: transitivePeerDependencies: - supports-color + '@sveltejs/vite-plugin-svelte@4.0.0(svelte@5.20.2)(vite@5.4.11(@types/node@20.17.10)(lightningcss@1.28.2)(terser@5.37.0))': + dependencies: + '@sveltejs/vite-plugin-svelte-inspector': 3.0.1(@sveltejs/vite-plugin-svelte@4.0.0(svelte@5.20.2)(vite@5.4.11(@types/node@20.17.10)(lightningcss@1.28.2)(terser@5.37.0)))(svelte@5.20.2)(vite@5.4.11(@types/node@20.17.10)(lightningcss@1.28.2)(terser@5.37.0)) + debug: 4.4.0 + deepmerge: 4.3.1 + kleur: 4.1.5 + magic-string: 0.30.17 + svelte: 5.20.2 + vite: 5.4.11(@types/node@20.17.10)(lightningcss@1.28.2)(terser@5.37.0) + vitefu: 1.0.4(vite@5.4.11(@types/node@20.17.10)(lightningcss@1.28.2)(terser@5.37.0)) + transitivePeerDependencies: + - supports-color + '@svitejs/changesets-changelog-github-compact@1.2.0': dependencies: '@changesets/get-github-info': 0.6.0 @@ -4438,10 +4449,10 @@ snapshots: lodash: 4.17.21 redent: 3.0.0 - '@testing-library/svelte@5.2.6(svelte@5.20.1)(vite@5.4.11(@types/node@20.17.10)(lightningcss@1.28.2)(terser@5.37.0))(vitest@1.6.0(@types/node@20.17.10)(jsdom@24.1.3)(lightningcss@1.28.2)(terser@5.37.0))': + '@testing-library/svelte@5.2.6(svelte@5.20.2)(vite@5.4.11(@types/node@20.17.10)(lightningcss@1.28.2)(terser@5.37.0))(vitest@1.6.0(@types/node@20.17.10)(jsdom@24.1.3)(lightningcss@1.28.2)(terser@5.37.0))': dependencies: '@testing-library/dom': 10.4.0 - svelte: 5.20.1 + svelte: 5.20.2 optionalDependencies: vite: 5.4.11(@types/node@20.17.10)(lightningcss@1.28.2)(terser@5.37.0) vitest: 1.6.0(@types/node@20.17.10)(jsdom@24.1.3)(lightningcss@1.28.2)(terser@5.37.0) @@ -4753,6 +4764,10 @@ snapshots: dependencies: readdirp: 4.0.2 + chokidar@4.0.3: + dependencies: + readdirp: 4.0.2 + ci-info@3.9.0: {} clsx@2.1.1: {} @@ -6612,10 +6627,10 @@ snapshots: esm-env: 1.2.2 svelte: 5.20.1 - runed@0.23.4(svelte@5.20.1): + runed@0.23.4(svelte@5.20.2): dependencies: esm-env: 1.2.2 - svelte: 5.20.1 + svelte: 5.20.2 sade@1.8.1: dependencies: @@ -6775,6 +6790,18 @@ snapshots: transitivePeerDependencies: - picomatch + svelte-check@4.1.4(svelte@5.20.2)(typescript@5.7.2): + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + chokidar: 4.0.2 + fdir: 6.4.2 + picocolors: 1.1.1 + sade: 1.8.1 + svelte: 5.20.2 + typescript: 5.7.2 + transitivePeerDependencies: + - picomatch + svelte-eslint-parser@0.43.0(svelte@5.14.4): dependencies: eslint-scope: 7.2.2 @@ -6791,18 +6818,18 @@ snapshots: style-to-object: 1.0.8 svelte: 5.20.1 - svelte-toolbelt@0.7.1(svelte@5.20.1): + svelte-toolbelt@0.7.1(svelte@5.20.2): dependencies: clsx: 2.1.1 - runed: 0.23.4(svelte@5.20.1) + runed: 0.23.4(svelte@5.20.2) style-to-object: 1.0.8 - svelte: 5.20.1 + svelte: 5.20.2 - svelte2tsx@0.7.31(svelte@5.20.1)(typescript@5.7.2): + svelte2tsx@0.7.34(svelte@5.20.2)(typescript@5.7.2): dependencies: dedent-js: 1.0.1 pascal-case: 3.1.2 - svelte: 5.20.1 + svelte: 5.20.2 typescript: 5.7.2 svelte@5.14.4: @@ -6838,6 +6865,23 @@ snapshots: magic-string: 0.30.17 zimmerframe: 1.1.2 + svelte@5.20.2: + dependencies: + '@ampproject/remapping': 2.3.0 + '@jridgewell/sourcemap-codec': 1.5.0 + '@types/estree': 1.0.6 + acorn: 8.14.0 + acorn-typescript: 1.4.13(acorn@8.14.0) + aria-query: 5.3.2 + axobject-query: 4.1.0 + clsx: 2.1.1 + esm-env: 1.2.2 + esrap: 1.4.4 + is-reference: 3.0.3 + locate-character: 3.0.0 + magic-string: 0.30.17 + zimmerframe: 1.1.2 + symbol-tree@3.2.4: {} tailwind-merge@2.5.5: {}