UNPKG

mobx-bonsai

Version:

A fast lightweight alternative to MobX-State-Tree + Y.js two-way binding

68 lines (58 loc) 2.3 kB
import { isObservableObject } from "mobx" import type * as Y from "yjs" import { failure } from "../../error/failure" import { isArray, isPlainObject, isPrimitive } from "../../plainTypes/checks" import { Primitive } from "../../plainTypes/types" import { YjsValue } from "../yjsTypes/types" import { getNodeTypeAndKey } from "../../node/nodeTypeKey/nodeType" import { requireYjs } from "../requireYjs" /** * Converts a plain value to a Y.js value. * Objects are converted to Y.Maps, arrays to Y.Arrays, primitives are untouched. */ export function convertPlainToYjsValue<T extends Primitive>(v: T): T export function convertPlainToYjsValue(v: readonly any[]): Y.Array<YjsValue> export function convertPlainToYjsValue(v: Readonly<Record<string, any>>): Y.Map<YjsValue> export function convertPlainToYjsValue(v: any): YjsValue { if (isPrimitive(v)) { return v } const Y = requireYjs() if (isArray(v)) { const arr = new Y.Array<YjsValue>() applyPlainArrayToYArray(arr, v) return arr as YjsValue } if (isPlainObject(v) || isObservableObject(v)) { const frozenData = !!getNodeTypeAndKey(v).type?.isFrozen if (frozenData) { return v // store as is } const map = new Y.Map<YjsValue>() applyPlainObjectToYMap(map, v) return map as YjsValue } throw failure(`unsupported value type: ${v}`) } /** * Applies a plain array to a Y.Array, using the convertPlainToYjsValue to convert the values. * * @param dest - The Y.js Array that will receive the converted values. * @param source - The plain JavaScript array whose values will be converted and pushed to the destination. */ export const applyPlainArrayToYArray = (dest: Y.Array<any>, source: readonly any[]) => { const yjsVals = source.map(convertPlainToYjsValue) dest.push(yjsVals) } /** * Applies a plain object to a Y.Map, using the convertPlainToYjsValue to convert the values. * * @param dest - The destination Y.Map where the properties will be set * @param source - The plain JavaScript object whose properties will be applied to the Y.Map */ export const applyPlainObjectToYMap = (dest: Y.Map<any>, source: Readonly<Record<string, any>>) => { Object.entries(source).forEach(([k, v]) => { const yjsVal = convertPlainToYjsValue(v) dest.set(k, yjsVal) }) }