import { useEffect , useMemo , useRef , useState } from 'react' ; import useLayoutEffect from 'use-isomorphic-layout-effect' ; import usePrevious from 'use-previous' ; import { AnyExtension , ErrorConstant , invariant , isArray , isNullOrUndefined } from '@remirror/core' ; import { ReactExtension } from '@remirror/preset-react' ; import { ReactFramework , ReactFrameworkOptions , ReactFrameworkProps } from '../react-framework' ; import type { ReactFrameworkOutput } from '../react-types' ; remarks internal export function useReactFramework < Extension extends AnyExtension > ( props ) { const { manager , state } = props ; const { placeholder , editable , suppressHydrationWarning } = props ; const firstUpdate = useRef ( true ) ; if ( firstUpdate . current && ! isNullOrUndefined ( placeholder ) ) { manager . getExtension ( ReactExtension ) . setOptions ( { placeholder } ) ; } useEffect ( ( ) => { manager . getExtension ( ReactExtension ) . setOptions ( { placeholder } ) ; } , [ placeholder , manager ] ) ; const fallback = manager . createEmptyDoc ( ) ; const [ initialContent , initialSelection ] = isArray ( props . initialContent ) ? props . initialContent : ( [ props . initialContent ?? fallback ] as const ) ; const initialEditorState = state ? state : manager . createState ( { content : initialContent , selection : initialSelection } ) ; const [ shouldRenderClient , setShouldRenderClient ] = useState < boolean | undefined > ( suppressHydrationWarning ? false : undefined ) ; const framework = useFramework < Extension > ( { initialEditorState , setShouldRenderClient , getProps : ( ) => props , getShouldRenderClient : ( ) => shouldRenderClient , } ) ; useEffect ( ( ) => { framework . onMount ( ) ; return ( ) => { framework . destroy ( ) ; } ; } , [ framework ] ) ; useEffect ( ( ) => { framework . onUpdate ( ) ; } , [ editable , framework ] ) ; useControlledEditor ( framework ) ; return framework . frameworkOutput ; } /**
 * A hook which creates a reference to the `ReactFramework` and updates the
 * parameters on every render.
 */ function useFramework < Extension extends AnyExtension > ( props ) { const propsRef = useRef ( props ) ; propsRef . current = props ; const framework = useMemo ( ( ) => new ReactFramework < Extension > ( propsRef . current ) , [ ] ) ; framework . update ( props ) ; return framework ; } /**
 * A hook which manages the controlled updates for the editor.
 */ function useControlledEditor < Extension extends AnyExtension > ( framework ) { const { state } = framework . props ; const isControlledRef = useRef ( ! ! state ) ; const previousValue = usePrevious ( state ) ; useLayoutEffect ( ( ) => { const validUpdate = state ? isControlledRef . current === true : isControlledRef . current === false ; invariant ( validUpdate , { code : ErrorConstant . REACT_CONTROLLED , message : isControlledRef . current ? 'You have attempted to switch from a controlled to an uncontrolled editor. Once you set up an editor as a controlled editor it must always provide a `state` prop.' : 'You have provided a `state` prop to an uncontrolled editor. In order to set up your editor as controlled you must provide the `state` prop from the very first render.' , } ) ; if ( ! state || state === previousValue ) { return ; } framework . updateControlledState ( state , previousValue ?? undefined ) ; } , [ state , previousValue , framework ] ) ; }