@liveblocks/react-tiptap 2.16.1-ai2 → 2.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/LiveblocksExtension.js +21 -120
  2. package/dist/LiveblocksExtension.js.map +1 -1
  3. package/dist/LiveblocksExtension.mjs +19 -118
  4. package/dist/LiveblocksExtension.mjs.map +1 -1
  5. package/dist/comments/CommentsExtension.js.map +1 -1
  6. package/dist/comments/CommentsExtension.mjs.map +1 -1
  7. package/dist/index.d.mts +14 -56
  8. package/dist/index.d.ts +14 -56
  9. package/dist/index.js +0 -2
  10. package/dist/index.js.map +1 -1
  11. package/dist/index.mjs +0 -1
  12. package/dist/index.mjs.map +1 -1
  13. package/dist/toolbar/FloatingToolbar.js +0 -7
  14. package/dist/toolbar/FloatingToolbar.js.map +1 -1
  15. package/dist/toolbar/FloatingToolbar.mjs +0 -7
  16. package/dist/toolbar/FloatingToolbar.mjs.map +1 -1
  17. package/dist/toolbar/Toolbar.js +1 -35
  18. package/dist/toolbar/Toolbar.js.map +1 -1
  19. package/dist/toolbar/Toolbar.mjs +2 -36
  20. package/dist/toolbar/Toolbar.mjs.map +1 -1
  21. package/dist/types.js.map +1 -1
  22. package/dist/types.mjs.map +1 -1
  23. package/dist/utils.js +1 -21
  24. package/dist/utils.js.map +1 -1
  25. package/dist/utils.mjs +2 -20
  26. package/dist/utils.mjs.map +1 -1
  27. package/dist/version.js +1 -1
  28. package/dist/version.js.map +1 -1
  29. package/dist/version.mjs +1 -1
  30. package/dist/version.mjs.map +1 -1
  31. package/package.json +6 -7
  32. package/src/styles/index.css +3 -322
  33. package/styles.css +1 -1
  34. package/styles.css.map +1 -1
  35. package/dist/ai/AiExtension.js +0 -299
  36. package/dist/ai/AiExtension.js.map +0 -1
  37. package/dist/ai/AiExtension.mjs +0 -296
  38. package/dist/ai/AiExtension.mjs.map +0 -1
  39. package/dist/ai/AiToolbar.js +0 -570
  40. package/dist/ai/AiToolbar.js.map +0 -1
  41. package/dist/ai/AiToolbar.mjs +0 -567
  42. package/dist/ai/AiToolbar.mjs.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"AiToolbar.js","sources":["../../src/ai/AiToolbar.tsx"],"sourcesContent":["import {\n autoUpdate,\n type DetectOverflowOptions,\n hide,\n type Middleware,\n offset,\n useFloating,\n type UseFloatingOptions,\n} from \"@floating-ui/react-dom\";\nimport { useLayoutEffect } from \"@liveblocks/react/_private\";\nimport {\n Button,\n CheckIcon,\n CrossIcon,\n EditIcon,\n LengthenIcon,\n QuestionMarkIcon,\n SendIcon,\n ShortcutTooltip,\n ShortenIcon,\n SparklesIcon,\n TooltipProvider,\n UndoIcon,\n useRefs,\n} from \"@liveblocks/react-ui/_private\";\nimport { type Editor, useEditorState } from \"@tiptap/react\";\nimport { Command, useCommandState } from \"cmdk\";\nimport type {\n ComponentProps,\n ComponentType,\n KeyboardEvent as ReactKeyboardEvent,\n PropsWithChildren,\n ReactNode,\n RefObject,\n} from \"react\";\nimport {\n createContext,\n forwardRef,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\n\nimport { classNames } from \"../classnames\";\nimport { EditorProvider, useCurrentEditor } from \"../context\";\nimport type {\n AiCommands,\n AiExtensionStorage,\n AiToolbarState,\n ChainedAiCommands,\n FloatingPosition,\n} from \"../types\";\nimport { getDomRangeFromSelection } from \"../utils\";\nimport { DEFAULT_STATE } from \"./AiExtension\";\n\nexport const AI_TOOLBAR_COLLISION_PADDING = 10;\n\nexport interface AiToolbarProps\n extends Omit<ComponentProps<\"div\">, \"value\" | \"defaultValue\"> {\n editor: Editor | null;\n position?: FloatingPosition;\n offset?: number;\n suggestions?: ReactNode | ComponentType<PropsWithChildren>;\n}\n\ninterface AiToolbarDropdownGroupProps extends ComponentProps<\"div\"> {\n label: string;\n}\n\ninterface AiToolbarDropdownItemProps\n extends ComponentProps<typeof Command.Item> {\n icon?: ReactNode;\n}\n\ntype AiToolbarSuggestionsGroupProps = AiToolbarDropdownGroupProps;\n\ninterface AiToolbarSuggestionProps extends ComponentProps<\"div\"> {\n prompt?: string;\n icon?: ReactNode;\n}\n\ninterface AiToolbarContext {\n state: AiToolbarState;\n toolbarRef: RefObject<HTMLDivElement>;\n dropdownRef: RefObject<HTMLDivElement>;\n isDropdownHidden: boolean;\n}\n\nconst AiToolbarContext = createContext<AiToolbarContext | null>(null);\n\nfunction useAiToolbarContext() {\n const context = useContext(AiToolbarContext);\n\n if (!context) {\n throw new Error(\"useAiToolbarContext must be used within an AiToolbar\");\n }\n\n return context;\n}\n\n/**\n * A custom Floating UI middleware to position/scale the toolbar:\n * - Vertically: relative to the reference (e.g. selection)\n * - Horizontally: relative to the editor\n * - Width: relative to the editor\n */\nfunction tiptapFloating(editor: Editor | null): Middleware {\n return {\n name: \"tiptap\",\n options: editor,\n fn({ elements }) {\n if (!editor) {\n return {};\n }\n\n const editorRect = editor.view.dom.getBoundingClientRect();\n\n elements.floating.style.setProperty(\n \"--lb-tiptap-editor-width\",\n `${editorRect.width}px`\n );\n elements.floating.style.setProperty(\n \"--lb-tiptap-editor-height\",\n `${editorRect.height}px`\n );\n\n return {\n x: editorRect.x,\n };\n },\n };\n}\n\nconst AiToolbarDropdownGroup = forwardRef<\n HTMLDivElement,\n AiToolbarDropdownGroupProps\n>(({ children, label, ...props }, forwardedRef) => {\n return (\n <Command.Group\n heading={<span className=\"lb-dropdown-label\">{label}</span>}\n {...props}\n ref={forwardedRef}\n >\n {children}\n </Command.Group>\n );\n});\n\nconst AiToolbarSuggestionsGroup = forwardRef<\n HTMLDivElement,\n AiToolbarSuggestionsGroupProps\n>((props, forwardedRef) => {\n return <AiToolbarDropdownGroup ref={forwardedRef} {...props} />;\n});\n\nconst AiToolbarDropdownItem = forwardRef<\n HTMLDivElement,\n AiToolbarDropdownItemProps\n>(({ children, onSelect, icon, ...props }, forwardedRef) => {\n return (\n <Command.Item\n className=\"lb-dropdown-item\"\n onSelect={onSelect}\n {...props}\n ref={forwardedRef}\n >\n {icon ? <span className=\"lb-icon-container\">{icon}</span> : null}\n {children ? (\n <span className=\"lb-dropdown-item-label\">{children}</span>\n ) : null}\n </Command.Item>\n );\n});\n\nconst AiToolbarSuggestion = forwardRef<\n HTMLDivElement,\n AiToolbarSuggestionProps\n>(({ prompt: manualPrompt, ...props }, forwardedRef) => {\n const editor = useCurrentEditor(\"Suggestion\", \"AiToolbar\");\n\n const handleSelect = useCallback(\n (prompt: string) => {\n (editor.commands as unknown as AiCommands).$startAiToolbarThinking(\n manualPrompt ?? prompt\n );\n },\n [editor, manualPrompt]\n );\n\n return (\n <AiToolbarDropdownItem\n {...props}\n onSelect={handleSelect}\n ref={forwardedRef}\n />\n );\n});\n\nfunction AiToolbarReviewingSuggestions() {\n const editor = useCurrentEditor(\"ReviewingSuggestions\", \"AiToolbar\");\n const { state } = useAiToolbarContext();\n const { output } = state as Extract<AiToolbarState, { phase: \"reviewing\" }>;\n\n const handleDiscard = useCallback(() => {\n (editor.commands as unknown as AiCommands).$closeAiToolbar();\n }, [editor]);\n\n const handleAccept = useCallback(() => {\n (editor.commands as unknown as AiCommands).$acceptAiToolbarOutput();\n }, [editor]);\n\n if (output.type === \"insert\" || output.type === \"modification\") {\n return (\n <>\n <AiToolbarDropdownItem icon={<CheckIcon />} onSelect={handleAccept}>\n Accept\n </AiToolbarDropdownItem>\n <AiToolbarDropdownItem icon={<UndoIcon />} disabled>\n Try again\n </AiToolbarDropdownItem>\n <AiToolbarDropdownItem icon={<CrossIcon />} onSelect={handleDiscard}>\n Discard\n </AiToolbarDropdownItem>\n </>\n );\n } else if (output.type === \"other\") {\n return (\n <>\n <AiToolbarDropdownItem icon={<CheckIcon />} disabled>\n Replace selection\n </AiToolbarDropdownItem>\n <AiToolbarDropdownItem icon={<CheckIcon />} disabled>\n Insert below\n </AiToolbarDropdownItem>\n <AiToolbarDropdownItem icon={<UndoIcon />} disabled>\n Try again\n </AiToolbarDropdownItem>\n <AiToolbarDropdownItem icon={<CrossIcon />} onSelect={handleDiscard}>\n Discard\n </AiToolbarDropdownItem>\n </>\n );\n }\n\n return null;\n}\n\nfunction AiToolbarCustomPromptContent({ disabled }: { disabled?: boolean }) {\n const editor = useCurrentEditor(\"CustomPromptContent\", \"AiToolbar\");\n const aiName = (editor.storage.liveblocksAi as AiExtensionStorage).name;\n const textAreaRef = useRef<HTMLTextAreaElement>(null);\n const { state, dropdownRef, isDropdownHidden } = useAiToolbarContext();\n const { customPrompt } = state as Exclude<\n AiToolbarState,\n { phase: \"closed\" }\n >;\n const isCustomPromptEmpty = useMemo(\n () => customPrompt.trim() === \"\",\n [customPrompt]\n );\n\n useLayoutEffect(\n () => {\n setTimeout(() => {\n const textArea = textAreaRef.current;\n\n if (!textArea) {\n return;\n }\n\n textArea.focus();\n textArea.setSelectionRange(\n textArea.value.length,\n textArea.value.length\n );\n }, 0);\n },\n [] // eslint-disable-line react-hooks/exhaustive-deps\n );\n\n const handlePromptKeyDown = (\n event: ReactKeyboardEvent<HTMLTextAreaElement>\n ) => {\n if (event.key === \"Enter\") {\n event.preventDefault();\n event.stopPropagation();\n\n if (event.shiftKey) {\n // If the shift key is pressed, add a new line\n (editor.commands as unknown as AiCommands)._updateAiToolbarCustomPrompt(\n (customPrompt) => customPrompt + \"\\n\"\n );\n } else {\n const selectedDropdownItem = dropdownRef.current?.querySelector(\n \"[role='option'][data-selected='true']\"\n ) as HTMLElement | null;\n\n if (!isDropdownHidden && selectedDropdownItem) {\n // If there's a selected dropdown item, select it\n selectedDropdownItem.click();\n } else if (!isCustomPromptEmpty) {\n // Otherwise, submit the custom prompt\n (editor.commands as unknown as AiCommands).$startAiToolbarThinking(\n customPrompt\n );\n }\n }\n }\n };\n\n const handleCustomPromptChange = useCallback(\n (customPrompt: string) => {\n (editor.commands as unknown as AiCommands)._updateAiToolbarCustomPrompt(\n customPrompt\n );\n },\n [editor]\n );\n\n const handleSendClick = useCallback(() => {\n if (isCustomPromptEmpty) {\n return;\n }\n\n (editor.commands as unknown as AiCommands).$startAiToolbarThinking(\n customPrompt\n );\n }, [editor, customPrompt, isCustomPromptEmpty]);\n\n return (\n <div className=\"lb-tiptap-ai-toolbar-content\">\n <span className=\"lb-icon-container lb-tiptap-ai-toolbar-icon-container\">\n <SparklesIcon />\n </span>\n <div\n className=\"lb-tiptap-ai-toolbar-custom-prompt-container\"\n data-value={customPrompt}\n >\n <Command.Input\n value={customPrompt}\n onValueChange={handleCustomPromptChange}\n asChild\n >\n <textarea\n ref={textAreaRef}\n className=\"lb-tiptap-ai-toolbar-custom-prompt\"\n placeholder={`Ask ${aiName} anything…`}\n onKeyDown={handlePromptKeyDown}\n rows={1}\n autoFocus\n disabled={disabled}\n />\n </Command.Input>\n </div>\n <div className=\"lb-tiptap-ai-toolbar-actions\">\n <ShortcutTooltip content={`Ask ${aiName}`} shortcut=\"Enter\">\n <Button\n className=\"lb-tiptap-ai-toolbar-action\"\n variant=\"primary\"\n aria-label={`Ask ${aiName}`}\n icon={<SendIcon />}\n disabled={isCustomPromptEmpty || disabled}\n onClick={handleSendClick}\n />\n </ShortcutTooltip>\n </div>\n </div>\n );\n}\n\nfunction AiToolbarAsking() {\n return <AiToolbarCustomPromptContent />;\n}\n\nfunction AiToolbarThinking() {\n const editor = useCurrentEditor(\"AiToolbarThinking\", \"AiToolbar\");\n const contentRef = useRef<HTMLDivElement>(null);\n const aiName = (editor.storage.liveblocksAi as AiExtensionStorage).name;\n\n const handleCancel = useCallback(() => {\n (editor.commands as unknown as AiCommands).$cancelAiToolbarThinking();\n }, [editor]);\n\n // Focus the toolbar content and clear the current window selection while thinking\n useLayoutEffect(() => {\n contentRef.current?.focus();\n window.getSelection()?.removeAllRanges();\n }, []);\n\n return (\n <>\n <div\n className=\"lb-tiptap-ai-toolbar-content\"\n tabIndex={0}\n ref={contentRef}\n >\n <span className=\"lb-icon-container lb-tiptap-ai-toolbar-icon-container\">\n <SparklesIcon />\n </span>\n <div className=\"lb-tiptap-ai-toolbar-thinking\">\n {aiName} is thinking…\n </div>\n <div className=\"lb-tiptap-ai-toolbar-actions\">\n <ShortcutTooltip content=\"Cancel\" shortcut=\"Escape\">\n <Button\n className=\"lb-tiptap-ai-toolbar-action\"\n variant=\"secondary\"\n aria-label=\"Cancel\"\n icon={<UndoIcon />}\n onClick={handleCancel}\n />\n </ShortcutTooltip>\n </div>\n </div>\n </>\n );\n}\n\nfunction AiToolbarReviewing() {\n const { state } = useAiToolbarContext();\n const { output } = state as Extract<AiToolbarState, { phase: \"reviewing\" }>;\n\n return (\n <>\n {output.type === \"other\" ? (\n <div className=\"lb-tiptap-ai-toolbar-output-container\">\n <div className=\"lb-tiptap-ai-toolbar-output\">{output.text}</div>\n </div>\n ) : null}\n {/* TODO: Allow to refine the output with another prompt */}\n <AiToolbarCustomPromptContent disabled />\n </>\n );\n}\n\nfunction AiToolbarContainer({\n state,\n toolbarRef,\n dropdownRef,\n children,\n}: PropsWithChildren<{\n state: AiToolbarState;\n toolbarRef: RefObject<HTMLDivElement>;\n dropdownRef: RefObject<HTMLDivElement>;\n}>) {\n const editor = useCurrentEditor(\"AiToolbarContainer\", \"AiToolbar\");\n const customPrompt = state.customPrompt;\n const isCustomPromptMultiline = useMemo(\n () => customPrompt?.includes(\"\\n\"),\n [customPrompt]\n );\n const hasDropdownItems = useCommandState(\n (state) => state.filtered.count > 0\n ) as boolean;\n const isDropdownHidden = isCustomPromptMultiline || !hasDropdownItems;\n\n useEffect(() => {\n if (!editor) {\n return;\n }\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (!event.defaultPrevented && event.key === \"Escape\") {\n event.preventDefault();\n event.stopPropagation();\n\n if (state.phase === \"thinking\") {\n (editor.commands as unknown as AiCommands).$cancelAiToolbarThinking();\n } else {\n (editor.chain() as ChainedAiCommands).$closeAiToolbar().focus().run();\n }\n }\n };\n\n document.addEventListener(\"keydown\", handleKeyDown);\n\n return () => {\n document.removeEventListener(\"keydown\", handleKeyDown);\n };\n }, [editor, state.phase]);\n\n return (\n <AiToolbarContext.Provider\n value={{ state, toolbarRef, dropdownRef, isDropdownHidden }}\n >\n <div className=\"lb-tiptap-ai-toolbar-container\">\n <div className=\"lb-elevation lb-tiptap-ai-toolbar\">\n {state.phase === \"asking\" ? (\n <AiToolbarAsking />\n ) : state.phase === \"thinking\" ? (\n <AiToolbarThinking />\n ) : state.phase === \"reviewing\" ? (\n <AiToolbarReviewing />\n ) : null}\n </div>\n <div\n className=\"lb-tiptap-ai-toolbar-halo\"\n data-active={state.phase === \"thinking\" ? \"\" : undefined}\n aria-hidden\n >\n <div className=\"lb-tiptap-ai-toolbar-halo-horizontal\" />\n <div className=\"lb-tiptap-ai-toolbar-halo-vertical\" />\n </div>\n </div>\n {state.phase === \"asking\" || state.phase === \"reviewing\" ? (\n <Command.List\n className=\"lb-elevation lb-dropdown lb-tiptap-ai-toolbar-dropdown\"\n data-hidden={isDropdownHidden ? \"\" : undefined}\n ref={dropdownRef}\n >\n {state.phase === \"reviewing\" ? (\n <AiToolbarReviewingSuggestions />\n ) : (\n children\n )}\n </Command.List>\n ) : null}\n </AiToolbarContext.Provider>\n );\n}\n\nconst defaultSuggestions = (\n <>\n <AiToolbarSuggestionsGroup label=\"Modify\">\n <AiToolbarSuggestion icon={<EditIcon />}>\n Improve writing\n </AiToolbarSuggestion>\n <AiToolbarSuggestion icon={<CheckIcon />}>\n Fix mistakes\n </AiToolbarSuggestion>\n <AiToolbarSuggestion icon={<ShortenIcon />}>Simplify</AiToolbarSuggestion>\n <AiToolbarSuggestion icon={<LengthenIcon />}>\n Add more detail\n </AiToolbarSuggestion>\n </AiToolbarSuggestionsGroup>\n <AiToolbarSuggestionsGroup label=\"Generate\">\n <AiToolbarSuggestion icon={<QuestionMarkIcon />}>\n Explain\n </AiToolbarSuggestion>\n </AiToolbarSuggestionsGroup>\n </>\n);\n\nexport const AiToolbar = Object.assign(\n forwardRef<HTMLDivElement, AiToolbarProps>(\n (\n {\n position = \"bottom\",\n offset: sideOffset = 6,\n editor,\n className,\n suggestions: Suggestions = defaultSuggestions,\n ...props\n },\n forwardedRef\n ) => {\n const state =\n useEditorState({\n editor,\n selector: (ctx) => {\n return (\n ctx.editor?.storage.liveblocksAi as AiExtensionStorage | undefined\n )?.state;\n },\n }) ?? DEFAULT_STATE;\n const selection = state.selection ?? editor?.state.selection;\n const floatingOptions: UseFloatingOptions = useMemo(() => {\n const detectOverflowOptions: DetectOverflowOptions = {\n padding: AI_TOOLBAR_COLLISION_PADDING,\n };\n\n return {\n strategy: \"fixed\",\n placement: position,\n middleware: [\n tiptapFloating(editor),\n hide(detectOverflowOptions),\n offset(sideOffset),\n ],\n whileElementsMounted: (...args) => {\n return autoUpdate(...args, {\n animationFrame: true,\n });\n },\n };\n }, [editor, position, sideOffset]);\n const isOpen = selection !== undefined && state.phase !== \"closed\";\n const {\n refs: { setReference, setFloating },\n strategy,\n x,\n y,\n isPositioned,\n } = useFloating({\n ...floatingOptions,\n open: isOpen,\n });\n const toolbarRef = useRef<HTMLDivElement>(null);\n const mergedRefs = useRefs(forwardedRef, toolbarRef, setFloating);\n const dropdownRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n if (!editor) {\n return;\n }\n\n if (!selection && state.phase !== \"closed\") {\n (editor.commands as unknown as AiCommands).$closeAiToolbar();\n }\n }, [state.phase, editor, selection]);\n\n useLayoutEffect(() => {\n if (!editor || !isOpen) {\n return;\n }\n\n setReference(null);\n\n setTimeout(() => {\n if (!selection) {\n setReference(null);\n } else {\n const domRange = getDomRangeFromSelection(selection, editor);\n setReference(domRange);\n }\n }, 0);\n }, [selection, editor, isOpen, setReference]);\n\n // Close the toolbar when clicking anywhere outside of it\n useEffect(() => {\n if (!editor || !isOpen) {\n return;\n }\n\n const handleOutsideEvent = (event: MouseEvent) => {\n if (!toolbarRef.current) {\n return;\n }\n\n if (\n event.target &&\n !toolbarRef.current.contains(event.target as Node) &&\n (dropdownRef.current\n ? !dropdownRef.current.contains(event.target as Node)\n : true)\n ) {\n (editor.commands as unknown as AiCommands).$closeAiToolbar();\n }\n };\n\n setTimeout(() => {\n document.addEventListener(\"pointerdown\", handleOutsideEvent);\n }, 0);\n\n return () => {\n document.removeEventListener(\"pointerdown\", handleOutsideEvent);\n };\n }, [editor, isOpen]);\n\n if (!editor || !isOpen) {\n return null;\n }\n\n return createPortal(\n <TooltipProvider>\n <EditorProvider editor={editor}>\n <Command\n role=\"toolbar\"\n label=\"AI toolbar\"\n aria-orientation=\"horizontal\"\n className={classNames(\n \"lb-root lb-portal lb-tiptap-ai-toolbar-portal\",\n className\n )}\n ref={mergedRefs}\n style={{\n position: strategy,\n top: 0,\n left: 0,\n transform: isPositioned\n ? `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`\n : \"translate3d(0, -200%, 0)\",\n }}\n {...props}\n >\n <AiToolbarContainer\n state={state}\n dropdownRef={dropdownRef}\n toolbarRef={toolbarRef}\n >\n {typeof Suggestions === \"function\" ? (\n <Suggestions children={defaultSuggestions} />\n ) : (\n Suggestions\n )}\n </AiToolbarContainer>\n </Command>\n </EditorProvider>\n </TooltipProvider>,\n document.body\n );\n }\n ),\n {\n SuggestionsGroup: AiToolbarSuggestionsGroup,\n Suggestion: AiToolbarSuggestion,\n }\n);\n"],"names":["createContext","useContext","forwardRef","jsx","Command","jsxs","useCurrentEditor","useCallback","Fragment","CheckIcon","UndoIcon","CrossIcon","useRef","useMemo","useLayoutEffect","customPrompt","SparklesIcon","ShortcutTooltip","Button","SendIcon","useCommandState","state","useEffect","EditIcon","ShortenIcon","LengthenIcon","QuestionMarkIcon","useEditorState","DEFAULT_STATE","hide","offset","autoUpdate","useFloating","useRefs","getDomRangeFromSelection","createPortal","TooltipProvider","EditorProvider","classNames"],"mappings":"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"}
@@ -1,567 +0,0 @@
1
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
- import { hide, offset, autoUpdate, useFloating } from '@floating-ui/react-dom';
3
- import { useLayoutEffect } from '@liveblocks/react/_private';
4
- import { CheckIcon, UndoIcon, CrossIcon, SparklesIcon, ShortcutTooltip, Button, SendIcon, EditIcon, ShortenIcon, LengthenIcon, QuestionMarkIcon, useRefs, TooltipProvider } from '@liveblocks/react-ui/_private';
5
- import { useEditorState } from '@tiptap/react';
6
- import { Command, useCommandState } from 'cmdk';
7
- import { createContext, useContext, forwardRef, useCallback, useRef, useMemo, useEffect } from 'react';
8
- import { createPortal } from 'react-dom';
9
- import { classNames } from '../classnames.mjs';
10
- import { useCurrentEditor, EditorProvider } from '../context.mjs';
11
- import { getDomRangeFromSelection } from '../utils.mjs';
12
- import { DEFAULT_STATE } from './AiExtension.mjs';
13
-
14
- const AI_TOOLBAR_COLLISION_PADDING = 10;
15
- const AiToolbarContext = createContext(null);
16
- function useAiToolbarContext() {
17
- const context = useContext(AiToolbarContext);
18
- if (!context) {
19
- throw new Error("useAiToolbarContext must be used within an AiToolbar");
20
- }
21
- return context;
22
- }
23
- function tiptapFloating(editor) {
24
- return {
25
- name: "tiptap",
26
- options: editor,
27
- fn({ elements }) {
28
- if (!editor) {
29
- return {};
30
- }
31
- const editorRect = editor.view.dom.getBoundingClientRect();
32
- elements.floating.style.setProperty(
33
- "--lb-tiptap-editor-width",
34
- `${editorRect.width}px`
35
- );
36
- elements.floating.style.setProperty(
37
- "--lb-tiptap-editor-height",
38
- `${editorRect.height}px`
39
- );
40
- return {
41
- x: editorRect.x
42
- };
43
- }
44
- };
45
- }
46
- const AiToolbarDropdownGroup = forwardRef(({ children, label, ...props }, forwardedRef) => {
47
- return /* @__PURE__ */ jsx(Command.Group, {
48
- heading: /* @__PURE__ */ jsx("span", {
49
- className: "lb-dropdown-label",
50
- children: label
51
- }),
52
- ...props,
53
- ref: forwardedRef,
54
- children
55
- });
56
- });
57
- const AiToolbarSuggestionsGroup = forwardRef((props, forwardedRef) => {
58
- return /* @__PURE__ */ jsx(AiToolbarDropdownGroup, {
59
- ref: forwardedRef,
60
- ...props
61
- });
62
- });
63
- const AiToolbarDropdownItem = forwardRef(({ children, onSelect, icon, ...props }, forwardedRef) => {
64
- return /* @__PURE__ */ jsxs(Command.Item, {
65
- className: "lb-dropdown-item",
66
- onSelect,
67
- ...props,
68
- ref: forwardedRef,
69
- children: [
70
- icon ? /* @__PURE__ */ jsx("span", {
71
- className: "lb-icon-container",
72
- children: icon
73
- }) : null,
74
- children ? /* @__PURE__ */ jsx("span", {
75
- className: "lb-dropdown-item-label",
76
- children
77
- }) : null
78
- ]
79
- });
80
- });
81
- const AiToolbarSuggestion = forwardRef(({ prompt: manualPrompt, ...props }, forwardedRef) => {
82
- const editor = useCurrentEditor("Suggestion", "AiToolbar");
83
- const handleSelect = useCallback(
84
- (prompt) => {
85
- editor.commands.$startAiToolbarThinking(
86
- manualPrompt ?? prompt
87
- );
88
- },
89
- [editor, manualPrompt]
90
- );
91
- return /* @__PURE__ */ jsx(AiToolbarDropdownItem, {
92
- ...props,
93
- onSelect: handleSelect,
94
- ref: forwardedRef
95
- });
96
- });
97
- function AiToolbarReviewingSuggestions() {
98
- const editor = useCurrentEditor("ReviewingSuggestions", "AiToolbar");
99
- const { state } = useAiToolbarContext();
100
- const { output } = state;
101
- const handleDiscard = useCallback(() => {
102
- editor.commands.$closeAiToolbar();
103
- }, [editor]);
104
- const handleAccept = useCallback(() => {
105
- editor.commands.$acceptAiToolbarOutput();
106
- }, [editor]);
107
- if (output.type === "insert" || output.type === "modification") {
108
- return /* @__PURE__ */ jsxs(Fragment, {
109
- children: [
110
- /* @__PURE__ */ jsx(AiToolbarDropdownItem, {
111
- icon: /* @__PURE__ */ jsx(CheckIcon, {}),
112
- onSelect: handleAccept,
113
- children: "Accept"
114
- }),
115
- /* @__PURE__ */ jsx(AiToolbarDropdownItem, {
116
- icon: /* @__PURE__ */ jsx(UndoIcon, {}),
117
- disabled: true,
118
- children: "Try again"
119
- }),
120
- /* @__PURE__ */ jsx(AiToolbarDropdownItem, {
121
- icon: /* @__PURE__ */ jsx(CrossIcon, {}),
122
- onSelect: handleDiscard,
123
- children: "Discard"
124
- })
125
- ]
126
- });
127
- } else if (output.type === "other") {
128
- return /* @__PURE__ */ jsxs(Fragment, {
129
- children: [
130
- /* @__PURE__ */ jsx(AiToolbarDropdownItem, {
131
- icon: /* @__PURE__ */ jsx(CheckIcon, {}),
132
- disabled: true,
133
- children: "Replace selection"
134
- }),
135
- /* @__PURE__ */ jsx(AiToolbarDropdownItem, {
136
- icon: /* @__PURE__ */ jsx(CheckIcon, {}),
137
- disabled: true,
138
- children: "Insert below"
139
- }),
140
- /* @__PURE__ */ jsx(AiToolbarDropdownItem, {
141
- icon: /* @__PURE__ */ jsx(UndoIcon, {}),
142
- disabled: true,
143
- children: "Try again"
144
- }),
145
- /* @__PURE__ */ jsx(AiToolbarDropdownItem, {
146
- icon: /* @__PURE__ */ jsx(CrossIcon, {}),
147
- onSelect: handleDiscard,
148
- children: "Discard"
149
- })
150
- ]
151
- });
152
- }
153
- return null;
154
- }
155
- function AiToolbarCustomPromptContent({ disabled }) {
156
- const editor = useCurrentEditor("CustomPromptContent", "AiToolbar");
157
- const aiName = editor.storage.liveblocksAi.name;
158
- const textAreaRef = useRef(null);
159
- const { state, dropdownRef, isDropdownHidden } = useAiToolbarContext();
160
- const { customPrompt } = state;
161
- const isCustomPromptEmpty = useMemo(
162
- () => customPrompt.trim() === "",
163
- [customPrompt]
164
- );
165
- useLayoutEffect(
166
- () => {
167
- setTimeout(() => {
168
- const textArea = textAreaRef.current;
169
- if (!textArea) {
170
- return;
171
- }
172
- textArea.focus();
173
- textArea.setSelectionRange(
174
- textArea.value.length,
175
- textArea.value.length
176
- );
177
- }, 0);
178
- },
179
- []
180
- );
181
- const handlePromptKeyDown = (event) => {
182
- if (event.key === "Enter") {
183
- event.preventDefault();
184
- event.stopPropagation();
185
- if (event.shiftKey) {
186
- editor.commands._updateAiToolbarCustomPrompt(
187
- (customPrompt2) => customPrompt2 + "\n"
188
- );
189
- } else {
190
- const selectedDropdownItem = dropdownRef.current?.querySelector(
191
- "[role='option'][data-selected='true']"
192
- );
193
- if (!isDropdownHidden && selectedDropdownItem) {
194
- selectedDropdownItem.click();
195
- } else if (!isCustomPromptEmpty) {
196
- editor.commands.$startAiToolbarThinking(
197
- customPrompt
198
- );
199
- }
200
- }
201
- }
202
- };
203
- const handleCustomPromptChange = useCallback(
204
- (customPrompt2) => {
205
- editor.commands._updateAiToolbarCustomPrompt(
206
- customPrompt2
207
- );
208
- },
209
- [editor]
210
- );
211
- const handleSendClick = useCallback(() => {
212
- if (isCustomPromptEmpty) {
213
- return;
214
- }
215
- editor.commands.$startAiToolbarThinking(
216
- customPrompt
217
- );
218
- }, [editor, customPrompt, isCustomPromptEmpty]);
219
- return /* @__PURE__ */ jsxs("div", {
220
- className: "lb-tiptap-ai-toolbar-content",
221
- children: [
222
- /* @__PURE__ */ jsx("span", {
223
- className: "lb-icon-container lb-tiptap-ai-toolbar-icon-container",
224
- children: /* @__PURE__ */ jsx(SparklesIcon, {})
225
- }),
226
- /* @__PURE__ */ jsx("div", {
227
- className: "lb-tiptap-ai-toolbar-custom-prompt-container",
228
- "data-value": customPrompt,
229
- children: /* @__PURE__ */ jsx(Command.Input, {
230
- value: customPrompt,
231
- onValueChange: handleCustomPromptChange,
232
- asChild: true,
233
- children: /* @__PURE__ */ jsx("textarea", {
234
- ref: textAreaRef,
235
- className: "lb-tiptap-ai-toolbar-custom-prompt",
236
- placeholder: `Ask ${aiName} anything\u2026`,
237
- onKeyDown: handlePromptKeyDown,
238
- rows: 1,
239
- autoFocus: true,
240
- disabled
241
- })
242
- })
243
- }),
244
- /* @__PURE__ */ jsx("div", {
245
- className: "lb-tiptap-ai-toolbar-actions",
246
- children: /* @__PURE__ */ jsx(ShortcutTooltip, {
247
- content: `Ask ${aiName}`,
248
- shortcut: "Enter",
249
- children: /* @__PURE__ */ jsx(Button, {
250
- className: "lb-tiptap-ai-toolbar-action",
251
- variant: "primary",
252
- "aria-label": `Ask ${aiName}`,
253
- icon: /* @__PURE__ */ jsx(SendIcon, {}),
254
- disabled: isCustomPromptEmpty || disabled,
255
- onClick: handleSendClick
256
- })
257
- })
258
- })
259
- ]
260
- });
261
- }
262
- function AiToolbarAsking() {
263
- return /* @__PURE__ */ jsx(AiToolbarCustomPromptContent, {});
264
- }
265
- function AiToolbarThinking() {
266
- const editor = useCurrentEditor("AiToolbarThinking", "AiToolbar");
267
- const contentRef = useRef(null);
268
- const aiName = editor.storage.liveblocksAi.name;
269
- const handleCancel = useCallback(() => {
270
- editor.commands.$cancelAiToolbarThinking();
271
- }, [editor]);
272
- useLayoutEffect(() => {
273
- contentRef.current?.focus();
274
- window.getSelection()?.removeAllRanges();
275
- }, []);
276
- return /* @__PURE__ */ jsx(Fragment, {
277
- children: /* @__PURE__ */ jsxs("div", {
278
- className: "lb-tiptap-ai-toolbar-content",
279
- tabIndex: 0,
280
- ref: contentRef,
281
- children: [
282
- /* @__PURE__ */ jsx("span", {
283
- className: "lb-icon-container lb-tiptap-ai-toolbar-icon-container",
284
- children: /* @__PURE__ */ jsx(SparklesIcon, {})
285
- }),
286
- /* @__PURE__ */ jsxs("div", {
287
- className: "lb-tiptap-ai-toolbar-thinking",
288
- children: [
289
- aiName,
290
- " is thinking\u2026"
291
- ]
292
- }),
293
- /* @__PURE__ */ jsx("div", {
294
- className: "lb-tiptap-ai-toolbar-actions",
295
- children: /* @__PURE__ */ jsx(ShortcutTooltip, {
296
- content: "Cancel",
297
- shortcut: "Escape",
298
- children: /* @__PURE__ */ jsx(Button, {
299
- className: "lb-tiptap-ai-toolbar-action",
300
- variant: "secondary",
301
- "aria-label": "Cancel",
302
- icon: /* @__PURE__ */ jsx(UndoIcon, {}),
303
- onClick: handleCancel
304
- })
305
- })
306
- })
307
- ]
308
- })
309
- });
310
- }
311
- function AiToolbarReviewing() {
312
- const { state } = useAiToolbarContext();
313
- const { output } = state;
314
- return /* @__PURE__ */ jsxs(Fragment, {
315
- children: [
316
- output.type === "other" ? /* @__PURE__ */ jsx("div", {
317
- className: "lb-tiptap-ai-toolbar-output-container",
318
- children: /* @__PURE__ */ jsx("div", {
319
- className: "lb-tiptap-ai-toolbar-output",
320
- children: output.text
321
- })
322
- }) : null,
323
- /* @__PURE__ */ jsx(AiToolbarCustomPromptContent, {
324
- disabled: true
325
- })
326
- ]
327
- });
328
- }
329
- function AiToolbarContainer({
330
- state,
331
- toolbarRef,
332
- dropdownRef,
333
- children
334
- }) {
335
- const editor = useCurrentEditor("AiToolbarContainer", "AiToolbar");
336
- const customPrompt = state.customPrompt;
337
- const isCustomPromptMultiline = useMemo(
338
- () => customPrompt?.includes("\n"),
339
- [customPrompt]
340
- );
341
- const hasDropdownItems = useCommandState(
342
- (state2) => state2.filtered.count > 0
343
- );
344
- const isDropdownHidden = isCustomPromptMultiline || !hasDropdownItems;
345
- useEffect(() => {
346
- if (!editor) {
347
- return;
348
- }
349
- const handleKeyDown = (event) => {
350
- if (!event.defaultPrevented && event.key === "Escape") {
351
- event.preventDefault();
352
- event.stopPropagation();
353
- if (state.phase === "thinking") {
354
- editor.commands.$cancelAiToolbarThinking();
355
- } else {
356
- editor.chain().$closeAiToolbar().focus().run();
357
- }
358
- }
359
- };
360
- document.addEventListener("keydown", handleKeyDown);
361
- return () => {
362
- document.removeEventListener("keydown", handleKeyDown);
363
- };
364
- }, [editor, state.phase]);
365
- return /* @__PURE__ */ jsxs(AiToolbarContext.Provider, {
366
- value: { state, toolbarRef, dropdownRef, isDropdownHidden },
367
- children: [
368
- /* @__PURE__ */ jsxs("div", {
369
- className: "lb-tiptap-ai-toolbar-container",
370
- children: [
371
- /* @__PURE__ */ jsx("div", {
372
- className: "lb-elevation lb-tiptap-ai-toolbar",
373
- children: state.phase === "asking" ? /* @__PURE__ */ jsx(AiToolbarAsking, {}) : state.phase === "thinking" ? /* @__PURE__ */ jsx(AiToolbarThinking, {}) : state.phase === "reviewing" ? /* @__PURE__ */ jsx(AiToolbarReviewing, {}) : null
374
- }),
375
- /* @__PURE__ */ jsxs("div", {
376
- className: "lb-tiptap-ai-toolbar-halo",
377
- "data-active": state.phase === "thinking" ? "" : void 0,
378
- "aria-hidden": true,
379
- children: [
380
- /* @__PURE__ */ jsx("div", {
381
- className: "lb-tiptap-ai-toolbar-halo-horizontal"
382
- }),
383
- /* @__PURE__ */ jsx("div", {
384
- className: "lb-tiptap-ai-toolbar-halo-vertical"
385
- })
386
- ]
387
- })
388
- ]
389
- }),
390
- state.phase === "asking" || state.phase === "reviewing" ? /* @__PURE__ */ jsx(Command.List, {
391
- className: "lb-elevation lb-dropdown lb-tiptap-ai-toolbar-dropdown",
392
- "data-hidden": isDropdownHidden ? "" : void 0,
393
- ref: dropdownRef,
394
- children: state.phase === "reviewing" ? /* @__PURE__ */ jsx(AiToolbarReviewingSuggestions, {}) : children
395
- }) : null
396
- ]
397
- });
398
- }
399
- const defaultSuggestions = /* @__PURE__ */ jsxs(Fragment, {
400
- children: [
401
- /* @__PURE__ */ jsxs(AiToolbarSuggestionsGroup, {
402
- label: "Modify",
403
- children: [
404
- /* @__PURE__ */ jsx(AiToolbarSuggestion, {
405
- icon: /* @__PURE__ */ jsx(EditIcon, {}),
406
- children: "Improve writing"
407
- }),
408
- /* @__PURE__ */ jsx(AiToolbarSuggestion, {
409
- icon: /* @__PURE__ */ jsx(CheckIcon, {}),
410
- children: "Fix mistakes"
411
- }),
412
- /* @__PURE__ */ jsx(AiToolbarSuggestion, {
413
- icon: /* @__PURE__ */ jsx(ShortenIcon, {}),
414
- children: "Simplify"
415
- }),
416
- /* @__PURE__ */ jsx(AiToolbarSuggestion, {
417
- icon: /* @__PURE__ */ jsx(LengthenIcon, {}),
418
- children: "Add more detail"
419
- })
420
- ]
421
- }),
422
- /* @__PURE__ */ jsx(AiToolbarSuggestionsGroup, {
423
- label: "Generate",
424
- children: /* @__PURE__ */ jsx(AiToolbarSuggestion, {
425
- icon: /* @__PURE__ */ jsx(QuestionMarkIcon, {}),
426
- children: "Explain"
427
- })
428
- })
429
- ]
430
- });
431
- const AiToolbar = Object.assign(
432
- forwardRef(
433
- ({
434
- position = "bottom",
435
- offset: sideOffset = 6,
436
- editor,
437
- className,
438
- suggestions: Suggestions = defaultSuggestions,
439
- ...props
440
- }, forwardedRef) => {
441
- const state = useEditorState({
442
- editor,
443
- selector: (ctx) => {
444
- return ctx.editor?.storage.liveblocksAi?.state;
445
- }
446
- }) ?? DEFAULT_STATE;
447
- const selection = state.selection ?? editor?.state.selection;
448
- const floatingOptions = useMemo(() => {
449
- const detectOverflowOptions = {
450
- padding: AI_TOOLBAR_COLLISION_PADDING
451
- };
452
- return {
453
- strategy: "fixed",
454
- placement: position,
455
- middleware: [
456
- tiptapFloating(editor),
457
- hide(detectOverflowOptions),
458
- offset(sideOffset)
459
- ],
460
- whileElementsMounted: (...args) => {
461
- return autoUpdate(...args, {
462
- animationFrame: true
463
- });
464
- }
465
- };
466
- }, [editor, position, sideOffset]);
467
- const isOpen = selection !== void 0 && state.phase !== "closed";
468
- const {
469
- refs: { setReference, setFloating },
470
- strategy,
471
- x,
472
- y,
473
- isPositioned
474
- } = useFloating({
475
- ...floatingOptions,
476
- open: isOpen
477
- });
478
- const toolbarRef = useRef(null);
479
- const mergedRefs = useRefs(forwardedRef, toolbarRef, setFloating);
480
- const dropdownRef = useRef(null);
481
- useEffect(() => {
482
- if (!editor) {
483
- return;
484
- }
485
- if (!selection && state.phase !== "closed") {
486
- editor.commands.$closeAiToolbar();
487
- }
488
- }, [state.phase, editor, selection]);
489
- useLayoutEffect(() => {
490
- if (!editor || !isOpen) {
491
- return;
492
- }
493
- setReference(null);
494
- setTimeout(() => {
495
- if (!selection) {
496
- setReference(null);
497
- } else {
498
- const domRange = getDomRangeFromSelection(selection, editor);
499
- setReference(domRange);
500
- }
501
- }, 0);
502
- }, [selection, editor, isOpen, setReference]);
503
- useEffect(() => {
504
- if (!editor || !isOpen) {
505
- return;
506
- }
507
- const handleOutsideEvent = (event) => {
508
- if (!toolbarRef.current) {
509
- return;
510
- }
511
- if (event.target && !toolbarRef.current.contains(event.target) && (dropdownRef.current ? !dropdownRef.current.contains(event.target) : true)) {
512
- editor.commands.$closeAiToolbar();
513
- }
514
- };
515
- setTimeout(() => {
516
- document.addEventListener("pointerdown", handleOutsideEvent);
517
- }, 0);
518
- return () => {
519
- document.removeEventListener("pointerdown", handleOutsideEvent);
520
- };
521
- }, [editor, isOpen]);
522
- if (!editor || !isOpen) {
523
- return null;
524
- }
525
- return createPortal(
526
- /* @__PURE__ */ jsx(TooltipProvider, {
527
- children: /* @__PURE__ */ jsx(EditorProvider, {
528
- editor,
529
- children: /* @__PURE__ */ jsx(Command, {
530
- role: "toolbar",
531
- label: "AI toolbar",
532
- "aria-orientation": "horizontal",
533
- className: classNames(
534
- "lb-root lb-portal lb-tiptap-ai-toolbar-portal",
535
- className
536
- ),
537
- ref: mergedRefs,
538
- style: {
539
- position: strategy,
540
- top: 0,
541
- left: 0,
542
- transform: isPositioned ? `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)` : "translate3d(0, -200%, 0)"
543
- },
544
- ...props,
545
- children: /* @__PURE__ */ jsx(AiToolbarContainer, {
546
- state,
547
- dropdownRef,
548
- toolbarRef,
549
- children: typeof Suggestions === "function" ? /* @__PURE__ */ jsx(Suggestions, {
550
- children: defaultSuggestions
551
- }) : Suggestions
552
- })
553
- })
554
- })
555
- }),
556
- document.body
557
- );
558
- }
559
- ),
560
- {
561
- SuggestionsGroup: AiToolbarSuggestionsGroup,
562
- Suggestion: AiToolbarSuggestion
563
- }
564
- );
565
-
566
- export { AI_TOOLBAR_COLLISION_PADDING, AiToolbar };
567
- //# sourceMappingURL=AiToolbar.mjs.map