UNPKG

@multisynq/react

Version:

React bindings for Multisynq

135 lines (134 loc) 6.71 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; import { jsx as _jsx } from "react/jsx-runtime"; import { useEffect, useState, useRef, useCallback } from 'react'; import { App } from '@multisynq/client'; import { setSyncedCallback } from '../MultisynqReactView'; import { MultisynqContext } from './MultisynqContext'; import { createMultisynqSession } from '../createMultisynqSession'; /** MultisynqRoot component implements the default implementation of the logic described for createMultisynqSession function. */ export function MultisynqRoot({ sessionParams, children, showChildrenWithoutSession = false, deferSession = false, }) { // Make sure we only create a new session once, even with strict mode const multisynqSessionRef = useRef(null); // Used for smooth session transitioning const nextSessionRef = useRef(null); const [multisynqSession, setMultisynqSession] = useState(null); const [multisynqView, setMultisynqView] = useState(null); const [currentSessionParams, setCurrentSessionParams] = useState(() => { if (!deferSession) { if (!sessionParams.name) { sessionParams.name = App.randomSession(); } if (!sessionParams.password) { sessionParams.password = App.randomPassword(); } } return Object.assign(Object.assign({}, sessionParams), { join: !deferSession }); }); // This function updates the state (session, view) const updateState = useCallback((session) => { var _a; setMultisynqSession(session); setMultisynqView((_a = session === null || session === void 0 ? void 0 : session.view) !== null && _a !== void 0 ? _a : null); }, [setMultisynqSession, setMultisynqView]); // Update currentSessionParams when props change useEffect(() => setCurrentSessionParams(Object.assign(Object.assign({}, sessionParams), { join: !deferSession })), [sessionParams, deferSession, setCurrentSessionParams]); // Session management // When joining a new session, we should setup view callbacks // Before joining a new session, we should leave the current one useEffect(() => { function join() { return __awaiter(this, void 0, void 0, function* () { // If already joined, do nothing if (multisynqSessionRef.current) return; // If explicitly told to not join, do not join if (!currentSessionParams.join) return; if (nextSessionRef.current) { // We are already joined to the next session multisynqSessionRef.current = nextSessionRef.current; nextSessionRef.current = null; } else { multisynqSessionRef.current = 'joining'; multisynqSessionRef.current = yield createMultisynqSession(currentSessionParams); } const session = multisynqSessionRef.current; updateState(session); setSyncedCallback((flag) => { const session = multisynqSessionRef.current; if (session !== null && session !== 'joining') { if (flag) updateState(session); if (session.view) { session.view.detachCallback = () => { setMultisynqView(null); }; } } }); }); } join(); return () => { const session = multisynqSessionRef.current; if (session !== null && session !== 'joining') { multisynqSessionRef.current = null; session.leave(); } }; }, [currentSessionParams, updateState]); const setSession = useCallback((params) => __awaiter(this, void 0, void 0, function* () { // Smooth session transitioning: Only update state // after we joined the next session const newParams = Object.assign(Object.assign(Object.assign({}, currentSessionParams), params), { join: true }); if (!newParams.name) { newParams.name = App.randomSession(); } if (!newParams.password) { newParams.password = App.randomPassword(); } // eslint-disable-next-line @typescript-eslint/no-unused-vars const { join } = newParams, args = __rest(newParams, ["join"]); createMultisynqSession(args).then((newSession) => { nextSessionRef.current = newSession; setCurrentSessionParams(newParams); }); }), [setCurrentSessionParams, currentSessionParams]); const leaveSession = useCallback(() => { setCurrentSessionParams((prev) => (Object.assign(Object.assign({}, prev), { join: false }))); updateState(null); }, [setCurrentSessionParams, updateState]); if ((currentSessionParams.join && multisynqView) || showChildrenWithoutSession) { const contextValue = { sessionParams: currentSessionParams, session: multisynqSession, view: multisynqView, model: (multisynqView === null || multisynqView === void 0 ? void 0 : multisynqView.model) || null, setSession, leaveSession }; return (_jsx(MultisynqContext.Provider, { value: contextValue, children: children })); } return null; }