diff --git a/.changeset/reatom-idiomatic-resize-observer.md b/.changeset/reatom-idiomatic-resize-observer.md new file mode 100644 index 00000000..4e2fcb1d --- /dev/null +++ b/.changeset/reatom-idiomatic-resize-observer.md @@ -0,0 +1,5 @@ +--- +"create-karkas": patch +--- + +Make `withResizeObserver` idiomatic Reatom: expose plain `Size` state (`{ width, height }`) instead of the live `ResizeObserverEntry` platform object, keep state serializable, and rename the derived atom from `sizeEntry` to `size`. diff --git a/apps/demo/src/shared/reatom/resize-observer.ts b/apps/demo/src/shared/reatom/resize-observer.ts index 63fc593b..9603f92c 100644 --- a/apps/demo/src/shared/reatom/resize-observer.ts +++ b/apps/demo/src/shared/reatom/resize-observer.ts @@ -1,17 +1,27 @@ import { computed, memo, reatomObservable, wrap, type Atom } from '@reatom/core' +export type Size = { width: number; height: number } + export const withResizeObserver = () => { return (target: Atom) => { - const sizeEntry = computed(() => { - const stateAtom = memo(() => { + const size = computed(() => { + const sizeAtom = memo(() => { const node = target() if (!node) return null - return reatomObservable({ - initState: undefined, + return reatomObservable({ + initState: null, subscribe: (set) => { const observer = new ResizeObserver( - wrap((entries) => set(entries.find((entry) => entry.target === node))), + wrap((entries) => { + const entry = entries.at(-1) + if (entry) { + set({ + width: entry.contentRect.width, + height: entry.contentRect.height, + }) + } + }), ) observer.observe(node) return () => observer.disconnect() @@ -19,9 +29,9 @@ export const withResizeObserver = () => { }) }) - return stateAtom?.() - }, `${target.name}.sizeEntry`) + return sizeAtom() + }, `${target.name}.size`) - return { sizeEntry } + return { size } } } diff --git a/apps/demo/src/widgets/app-shell/ui/AppShell.tsx b/apps/demo/src/widgets/app-shell/ui/AppShell.tsx index d3b69b01..17ac4510 100644 --- a/apps/demo/src/widgets/app-shell/ui/AppShell.tsx +++ b/apps/demo/src/widgets/app-shell/ui/AppShell.tsx @@ -35,7 +35,7 @@ const desktopSidebarCollapsedAtom = reatomBoolean(false, 'desktopSidebar.collaps const measureRefAtom = atom(null, 'appShell.measureRef').extend( withResizeObserver(), (target) => ({ - height: computed(() => target.sizeEntry()?.contentRect.height ?? 0, 'appShell.headerHeight'), + height: computed(() => target.size()?.height ?? 0, 'appShell.headerHeight'), }), ) diff --git a/packages/create-karkas/template/src/shared/reatom/resize-observer.ts b/packages/create-karkas/template/src/shared/reatom/resize-observer.ts index 63fc593b..9603f92c 100644 --- a/packages/create-karkas/template/src/shared/reatom/resize-observer.ts +++ b/packages/create-karkas/template/src/shared/reatom/resize-observer.ts @@ -1,17 +1,27 @@ import { computed, memo, reatomObservable, wrap, type Atom } from '@reatom/core' +export type Size = { width: number; height: number } + export const withResizeObserver = () => { return (target: Atom) => { - const sizeEntry = computed(() => { - const stateAtom = memo(() => { + const size = computed(() => { + const sizeAtom = memo(() => { const node = target() if (!node) return null - return reatomObservable({ - initState: undefined, + return reatomObservable({ + initState: null, subscribe: (set) => { const observer = new ResizeObserver( - wrap((entries) => set(entries.find((entry) => entry.target === node))), + wrap((entries) => { + const entry = entries.at(-1) + if (entry) { + set({ + width: entry.contentRect.width, + height: entry.contentRect.height, + }) + } + }), ) observer.observe(node) return () => observer.disconnect() @@ -19,9 +29,9 @@ export const withResizeObserver = () => { }) }) - return stateAtom?.() - }, `${target.name}.sizeEntry`) + return sizeAtom() + }, `${target.name}.size`) - return { sizeEntry } + return { size } } } diff --git a/packages/create-karkas/template/src/widgets/app-shell/ui/AppShell.tsx b/packages/create-karkas/template/src/widgets/app-shell/ui/AppShell.tsx index d3b69b01..17ac4510 100644 --- a/packages/create-karkas/template/src/widgets/app-shell/ui/AppShell.tsx +++ b/packages/create-karkas/template/src/widgets/app-shell/ui/AppShell.tsx @@ -35,7 +35,7 @@ const desktopSidebarCollapsedAtom = reatomBoolean(false, 'desktopSidebar.collaps const measureRefAtom = atom(null, 'appShell.measureRef').extend( withResizeObserver(), (target) => ({ - height: computed(() => target.sizeEntry()?.contentRect.height ?? 0, 'appShell.headerHeight'), + height: computed(() => target.size()?.height ?? 0, 'appShell.headerHeight'), }), )