'use client'; /** * LiveKit видеокомната — вариант из коробки (@livekit/components-react) */ import React, { Suspense, useEffect, useLayoutEffect, useRef, useState } from 'react'; import { createPortal } from 'react-dom'; /** Ошибка LiveKit updatePages (placeholder/track race) — не выкидываем пользователя из занятия. */ function isLiveKitLayoutError(error: unknown): boolean { const msg = error instanceof Error ? error.message : String(error); return ( msg.includes('Element not part of the array') || msg.includes('updatePages') || msg.includes('_placeholder not in') ); } class LiveKitLayoutErrorBoundary extends React.Component< { children: React.ReactNode }, { error: unknown; recoverKey: number } > { state = { error: null as unknown, recoverKey: 0 }; static getDerivedStateFromError(error: unknown) { return { error }; } componentDidCatch(error: unknown) { if (isLiveKitLayoutError(error)) { window.setTimeout(() => { this.setState((s) => ({ error: null, recoverKey: s.recoverKey + 1 })); }, 100); } } render() { if (this.state.error && !isLiveKitLayoutError(this.state.error)) { throw this.state.error; } if (this.state.error) { return (
); } return