Introduce ViewModel.ts

This commit is contained in:
Timo K
2026-05-11 17:29:41 +02:00
parent 9f6ae4ba55
commit 64d5e8ca24

39
src/state/ViewModel.ts Normal file
View File

@@ -0,0 +1,39 @@
/*
Copyright 2026 Element Software Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE in the repository root for full details.
*/
import { BehaviorSubject } from "rxjs";
import { useBehavior } from "../useBehavior";
import { type Behavior } from "./Behavior";
export type ViewModel<Snapshot> = {
[K in keyof Snapshot as `${string & K}$`]: Behavior<Snapshot[K]>;
};
export function useViewModel<Snapshot>(vm: ViewModel<Snapshot>): Snapshot {
const snapshot = {} as Snapshot;
for (const key in vm) {
const value$ = (vm as Record<string, Behavior<unknown>>)[key];
const snapshotKey = key.slice(0, -1) as keyof Snapshot;
// we allow using hooks in a loop here because we know the shape of the vm is static and won't change between renders, so the order of hooks calls will always be the same.
// eslint-disable-next-line react-hooks/rules-of-hooks
snapshot[snapshotKey] = useBehavior(value$) as Snapshot[keyof Snapshot];
}
return snapshot;
}
export function createMockedViewModel<Snapshot>(
snapshot: Snapshot,
): ViewModel<Snapshot> {
const vm = {} as ViewModel<Snapshot>;
for (const key in snapshot) {
(vm as Record<string, Behavior<unknown>>)[`${key}$`] = new BehaviorSubject(
snapshot[key],
);
}
return vm;
}