diff --git a/bindings/package.json b/bindings/package.json index 030f702..a391480 100644 --- a/bindings/package.json +++ b/bindings/package.json @@ -1,6 +1,6 @@ { "name": "@croquet/react", - "version": "2.0.0", + "version": "2.0.1", "description": "React bindings for Croquet", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/bindings/src/hooks/useReactModelRoot.tsx b/bindings/src/hooks/useReactModelRoot.tsx index 8279b00..13ca2e9 100644 --- a/bindings/src/hooks/useReactModelRoot.tsx +++ b/bindings/src/hooks/useReactModelRoot.tsx @@ -1,35 +1,59 @@ import { useModelRoot } from './useModelRoot' -import { usePublish } from './usePublish' import { ReactModel } from '../ReactModel' +import { useCroquetView } from './useCroquetView'; +import { CroquetReactView } from '../CroquetReactView'; -function getModelObject(model: T): T { +// We need to receive croquetView to pass it to eventual getModelObject calls +function convertRecursively(what: T, croquetView: CroquetReactView): T { + if (what instanceof ReactModel) { + return getModelObject(what, croquetView) + } + if(what instanceof Array) { + return what.map(w => convertRecursively(w, croquetView)) as T; + } + if (what instanceof Object) { + const result = {} + Object.entries(what).forEach(([key, value]) => { + // @ts-expect-error --- + result[key] = convertRecursively(value) + }) + + return result as T + } + return what +} + +// We need croquetView so that we can publish events +function getModelObject(model: T, croquetView: CroquetReactView): T { const methods: Partial = {} const excludeMethods = new Set(['view-join', 'view-exit']) model.__reactEvents .filter((e) => !excludeMethods.has(e.event)) .forEach(({ scope, event }) => { + // Should not use the usePublsh hook because + // the number of nested models may change over time + // and the number of hooks inside a component should be constant + // @ts-expect-error --- - methods[event] = usePublish((data) => [scope, event, data]) + methods[event] = (data) => croquetView.publish(scope, event, data) }) const properties: Partial = {} const excludeProperties = new Set(['__reactEvents']) - for (const p in model) { - if (!excludeProperties.has(p)) { - const prop = model[p] - if (prop instanceof ReactModel) { - properties[p] = getModelObject(prop) - } else { - properties[p] = prop - } - } - } + + Object.entries(model) + .filter(([key]) => !excludeProperties.has(key)) + .forEach(([key, value]) => { + // @ts-expect-error --- + properties[key] = convertRecursively(value, croquetView) + }) return { ...properties, ...methods } as T } export function useReactModelRoot(): T { const model = useModelRoot() as T + const croquetView = useCroquetView() - return getModelObject(model) + return getModelObject(model, croquetView!) }