{"version":3,"file":"liveblocks-plugin-provider.cjs","sources":["../src/liveblocks-plugin-provider.tsx"],"sourcesContent":["import { autoUpdate, useFloating } from \"@floating-ui/react-dom\";\nimport { CollaborationPlugin } from \"@lexical/react/LexicalCollaborationPlugin\";\nimport { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport type { Provider } from \"@lexical/yjs\";\nimport { TextEditorType } from \"@liveblocks/core\";\nimport { useRoom, useSelf } from \"@liveblocks/react\";\nimport {\n  useLayoutEffect,\n  useReportTextEditor,\n  useResolveMentionSuggestions,\n  useYjsProvider,\n} from \"@liveblocks/react/_private\";\nimport { getYjsProviderForRoom } from \"@liveblocks/yjs\";\nimport type { MutableRefObject, ReactNode } from \"react\";\nimport { useCallback, useEffect, useState, useSyncExternalStore } from \"react\";\nimport type { Doc } from \"yjs\";\n\nimport { CommentPluginProvider } from \"./comments/comment-plugin-provider\";\nimport { ThreadMarkNode } from \"./comments/thread-mark-node\";\nimport { GroupMentionNode } from \"./mentions/group-mention-node\";\nimport { MentionNode } from \"./mentions/mention-node\";\nimport { MentionPlugin } from \"./mentions/mention-plugin\";\nimport { useRootElement } from \"./use-root-element\";\n\n/**\n * Returns whether the editor has loaded the initial text contents from the\n * server and is ready to be used.\n */\nexport function useIsEditorReady(): boolean {\n  const yjsProvider = useYjsProvider();\n\n  const getSnapshot = useCallback(() => {\n    const status = yjsProvider?.getStatus();\n    return status === \"synchronizing\" || status === \"synchronized\";\n  }, [yjsProvider]);\n\n  const subscribe = useCallback(\n    (callback: () => void) => {\n      if (yjsProvider === undefined) return () => {};\n      yjsProvider.on(\"status\", callback);\n      return () => {\n        yjsProvider.off(\"status\", callback);\n      };\n    },\n    [yjsProvider]\n  );\n\n  return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\nexport type LiveblocksPluginProps = {\n  children?: ReactNode;\n};\n\n/**\n * Liveblocks plugin for Lexical that adds collaboration to your editor.\n *\n * `LiveblocksPlugin` should always be nested inside `LexicalComposer`.\n *\n * @example\n *\n * import { LexicalComposer } from \"@lexical/react/LexicalComposer\";\n * import { RichTextPlugin } from \"@lexical/react/LexicalRichTextPlugin\";\n * import { ContentEditable } from \"@lexical/react/LexicalContentEditable\";\n * import { LexicalErrorBoundary } from \"@lexical/react/LexicalErrorBoundary\";\n * import { liveblocksConfig, LiveblocksPlugin } from \"@liveblocks/react-lexical\";\n *\n * const initialConfig = liveblocksConfig({\n *   namespace: \"MyEditor\",\n *   theme: {},\n *   nodes: [],\n *   onError: (err) => console.error(err),\n * });\n *\n * function Editor() {\n *   return (\n *     <LexicalComposer initialConfig={initialConfig}>\n *       <LiveblocksPlugin />\n *       <RichTextPlugin\n *         contentEditable={<ContentEditable />}\n *         placeholder={<div>Enter some text...</div>}\n *         ErrorBoundary={LexicalErrorBoundary}\n *       />\n *     </LexicalComposer>\n *   );\n * }\n */\nexport const LiveblocksPlugin = ({\n  children,\n}: LiveblocksPluginProps): JSX.Element => {\n  const isResolveMentionSuggestionsDefined =\n    useResolveMentionSuggestions() !== undefined;\n  const [editor] = useLexicalComposerContext();\n  const room = useRoom();\n\n  if (!editor.hasNodes([ThreadMarkNode, MentionNode, GroupMentionNode])) {\n    throw new Error(\n      \"LiveblocksPlugin requires Lexical configuration to be wrapped in the `liveblocksConfig(options)` function. For more information: https://liveblocks.io/docs/api-reference/liveblocks-react-lexical#liveblocksConfig\"\n    );\n  }\n\n  const [containerRef, setContainerRef] = useState<\n    MutableRefObject<HTMLDivElement | null> | undefined\n  >(undefined);\n\n  const {\n    refs: { setReference, setFloating },\n    strategy,\n    x,\n    y,\n  } = useFloating({\n    strategy: \"fixed\",\n    placement: \"bottom\",\n    whileElementsMounted: (...args) => {\n      return autoUpdate(...args, {\n        animationFrame: true,\n      });\n    },\n  });\n\n  // Warn users if initialConfig.editorState, set on the composer, is not null\n  useEffect(() => {\n    // only in dev mode\n    if (process.env.NODE_ENV !== \"production\") {\n      // A user should not even be set an emptyState, but when passing null, getEditorState still has initial empty state\n      if (!editor.getEditorState().isEmpty()) {\n        console.warn(\n          \"Warning: LiveblocksPlugin: editorState in initialConfig detected, but must be null.\"\n        );\n      }\n    }\n\n    // we know editor is already defined as we're inside LexicalComposer, and we only want this running the first time\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, []);\n\n  useReportTextEditor(TextEditorType.Lexical, \"root\");\n\n  // Get user info or allow override from props\n  const self = useSelf();\n\n  const providerFactory = useCallback(\n    (id: string, yjsDocMap: Map<string, Doc>): Provider => {\n      const provider = getYjsProviderForRoom(room, {}, true);\n      yjsDocMap.set(id, provider.getYDoc());\n\n      return provider as Provider;\n    },\n    [room]\n  );\n\n  const root = useRootElement();\n\n  useLayoutEffect(() => {\n    if (root === null) return;\n    setReference({\n      getBoundingClientRect: () => root.getBoundingClientRect(),\n    });\n  }, [setReference, root]);\n\n  const handleFloatingRef = useCallback(\n    (node: HTMLDivElement) => {\n      setFloating(node);\n      setContainerRef({ current: node });\n    },\n    [setFloating, setContainerRef]\n  );\n\n  return (\n    <>\n      <div\n        ref={handleFloatingRef}\n        className=\"lb-root lb-lexical-cursors\"\n        style={{\n          position: strategy,\n          top: 0,\n          left: 0,\n          transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,\n          minWidth: \"max-content\",\n        }}\n      />\n\n      {self && (\n        <CollaborationPlugin\n          // Setting the key allows us to reset the internal Y.doc used by useYjsCollaboration\n          // without implementing `reload` event\n          key={room.id}\n          id={room.id}\n          providerFactory={providerFactory}\n          username={self.info?.name ?? \"\"} // use empty string to prevent random name\n          cursorColor={self.info?.color as string | undefined}\n          cursorsContainerRef={containerRef}\n          shouldBootstrap={true}\n        />\n      )}\n\n      {isResolveMentionSuggestionsDefined && <MentionPlugin />}\n      <CommentPluginProvider>{children}</CommentPluginProvider>\n    </>\n  );\n};\n"],"names":["useYjsProvider","useCallback","useSyncExternalStore","useResolveMentionSuggestions","useLexicalComposerContext","useRoom","ThreadMarkNode","MentionNode","GroupMentionNode","useState","useFloating","autoUpdate","useEffect","useReportTextEditor","TextEditorType","useSelf","getYjsProviderForRoom","useRootElement","useLayoutEffect","jsxs","Fragment","jsx","CollaborationPlugin","MentionPlugin","CommentPluginProvider"],"mappings":";;;;;;;;;;;;;;;;;;AA4BO,SAAS,gBAA4B,GAAA;AAC1C,EAAA,MAAM,cAAcA,uBAAe,EAAA,CAAA;AAEnC,EAAM,MAAA,WAAA,GAAcC,kBAAY,MAAM;AACpC,IAAM,MAAA,MAAA,GAAS,aAAa,SAAU,EAAA,CAAA;AACtC,IAAO,OAAA,MAAA,KAAW,mBAAmB,MAAW,KAAA,cAAA,CAAA;AAAA,GAClD,EAAG,CAAC,WAAW,CAAC,CAAA,CAAA;AAEhB,EAAA,MAAM,SAAY,GAAAA,iBAAA;AAAA,IAChB,CAAC,QAAyB,KAAA;AACxB,MAAI,IAAA,WAAA,KAAgB,KAAW,CAAA,EAAA,OAAO,MAAM;AAAA,OAAC,CAAA;AAC7C,MAAY,WAAA,CAAA,EAAA,CAAG,UAAU,QAAQ,CAAA,CAAA;AACjC,MAAA,OAAO,MAAM;AACX,QAAY,WAAA,CAAA,GAAA,CAAI,UAAU,QAAQ,CAAA,CAAA;AAAA,OACpC,CAAA;AAAA,KACF;AAAA,IACA,CAAC,WAAW,CAAA;AAAA,GACd,CAAA;AAEA,EAAO,OAAAC,0BAAA,CAAqB,SAAW,EAAA,WAAA,EAAa,WAAW,CAAA,CAAA;AACjE,CAAA;AAuCO,MAAM,mBAAmB,CAAC;AAAA,EAC/B,QAAA;AACF,CAA0C,KAAA;AACxC,EAAM,MAAA,kCAAA,GACJC,uCAAmC,KAAA,KAAA,CAAA,CAAA;AACrC,EAAM,MAAA,CAAC,MAAM,CAAA,GAAIC,gDAA0B,EAAA,CAAA;AAC3C,EAAA,MAAM,OAAOC,eAAQ,EAAA,CAAA;AAErB,EAAI,IAAA,CAAC,OAAO,QAAS,CAAA,CAACC,+BAAgBC,uBAAa,EAAAC,iCAAgB,CAAC,CAAG,EAAA;AACrE,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,qNAAA;AAAA,KACF,CAAA;AAAA,GACF;AAEA,EAAA,MAAM,CAAC,YAAA,EAAc,eAAe,CAAA,GAAIC,eAEtC,KAAS,CAAA,CAAA,CAAA;AAEX,EAAM,MAAA;AAAA,IACJ,IAAA,EAAM,EAAE,YAAA,EAAc,WAAY,EAAA;AAAA,IAClC,QAAA;AAAA,IACA,CAAA;AAAA,IACA,CAAA;AAAA,MACEC,oBAAY,CAAA;AAAA,IACd,QAAU,EAAA,OAAA;AAAA,IACV,SAAW,EAAA,QAAA;AAAA,IACX,oBAAA,EAAsB,IAAI,IAAS,KAAA;AACjC,MAAO,OAAAC,mBAAA,CAAW,GAAG,IAAM,EAAA;AAAA,QACzB,cAAgB,EAAA,IAAA;AAAA,OACjB,CAAA,CAAA;AAAA,KACH;AAAA,GACD,CAAA,CAAA;AAGD,EAAAC,eAAA,CAAU,MAAM;AAEd,IAAI,IAAA,OAAA,CAAQ,GAAI,CAAA,QAAA,KAAa,YAAc,EAAA;AAEzC,MAAA,IAAI,CAAC,MAAA,CAAO,cAAe,EAAA,CAAE,SAAW,EAAA;AACtC,QAAQ,OAAA,CAAA,IAAA;AAAA,UACN,qFAAA;AAAA,SACF,CAAA;AAAA,OACF;AAAA,KACF;AAAA,GAIF,EAAG,EAAE,CAAA,CAAA;AAEL,EAAoBC,4BAAA,CAAAC,mBAAA,CAAe,SAAS,MAAM,CAAA,CAAA;AAGlD,EAAA,MAAM,OAAOC,eAAQ,EAAA,CAAA;AAErB,EAAA,MAAM,eAAkB,GAAAd,iBAAA;AAAA,IACtB,CAAC,IAAY,SAA0C,KAAA;AACrD,MAAA,MAAM,QAAW,GAAAe,yBAAA,CAAsB,IAAM,EAAA,IAAI,IAAI,CAAA,CAAA;AACrD,MAAA,SAAA,CAAU,GAAI,CAAA,EAAA,EAAI,QAAS,CAAA,OAAA,EAAS,CAAA,CAAA;AAEpC,MAAO,OAAA,QAAA,CAAA;AAAA,KACT;AAAA,IACA,CAAC,IAAI,CAAA;AAAA,GACP,CAAA;AAEA,EAAA,MAAM,OAAOC,6BAAe,EAAA,CAAA;AAE5B,EAAAC,wBAAA,CAAgB,MAAM;AACpB,IAAA,IAAI,SAAS,IAAM,EAAA,OAAA;AACnB,IAAa,YAAA,CAAA;AAAA,MACX,qBAAA,EAAuB,MAAM,IAAA,CAAK,qBAAsB,EAAA;AAAA,KACzD,CAAA,CAAA;AAAA,GACA,EAAA,CAAC,YAAc,EAAA,IAAI,CAAC,CAAA,CAAA;AAEvB,EAAA,MAAM,iBAAoB,GAAAjB,iBAAA;AAAA,IACxB,CAAC,IAAyB,KAAA;AACxB,MAAA,WAAA,CAAY,IAAI,CAAA,CAAA;AAChB,MAAgB,eAAA,CAAA,EAAE,OAAS,EAAA,IAAA,EAAM,CAAA,CAAA;AAAA,KACnC;AAAA,IACA,CAAC,aAAa,eAAe,CAAA;AAAA,GAC/B,CAAA;AAEA,EAAA,uBAEIkB,eAAA,CAAAC,mBAAA,EAAA,EAAA,QAAA,EAAA;AAAA,oBAAAC,cAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,GAAK,EAAA,iBAAA;AAAA,QACL,SAAU,EAAA,4BAAA;AAAA,QACV,KAAO,EAAA;AAAA,UACL,QAAU,EAAA,QAAA;AAAA,UACV,GAAK,EAAA,CAAA;AAAA,UACL,IAAM,EAAA,CAAA;AAAA,UACN,SAAA,EAAW,CAAe,YAAA,EAAA,IAAA,CAAK,KAAM,CAAA,CAAC,CAAC,CAAO,IAAA,EAAA,IAAA,CAAK,KAAM,CAAA,CAAC,CAAC,CAAA,MAAA,CAAA;AAAA,UAC3D,QAAU,EAAA,aAAA;AAAA,SACZ;AAAA,OAAA;AAAA,KACF;AAAA,IAEC,IACC,oBAAAA,cAAA;AAAA,MAACC,8CAAA;AAAA,MAAA;AAAA,QAIC,IAAI,IAAK,CAAA,EAAA;AAAA,QACT,eAAA;AAAA,QACA,QAAA,EAAU,IAAK,CAAA,IAAA,EAAM,IAAQ,IAAA,EAAA;AAAA,QAC7B,WAAA,EAAa,KAAK,IAAM,EAAA,KAAA;AAAA,QACxB,mBAAqB,EAAA,YAAA;AAAA,QACrB,eAAiB,EAAA,IAAA;AAAA,OAAA;AAAA,MANZ,IAAK,CAAA,EAAA;AAAA,KAOZ;AAAA,IAGD,kCAAA,mCAAuCC,2BAAc,EAAA,EAAA,CAAA;AAAA,oBACtDF,cAAA,CAACG,+CAAuB,QAAS,EAAA,CAAA;AAAA,GACnC,EAAA,CAAA,CAAA;AAEJ;;;;;"}