| ... | ... | @@ -725,6 +725,19 @@ function ComposerPromptEditorTiptapInner(props: ComposerPromptEditorProps) { |
| 725 | 725 | ); |
| 726 | 726 | }, []); |
| 727 | 727 | |
| 728 | const editorAttributes = useMemo( |
| 729 | () => ({ |
| 730 | class: cn( |
| 731 | "composer-tiptap block max-h-50 min-h-17.5 w-full overflow-y-auto whitespace-pre-wrap wrap-break-word bg-transparent leading-relaxed text-foreground focus:outline-none", |
| 732 | className, |
| 733 | ), |
| 734 | "data-testid": "composer-editor", |
| 735 | "data-composer-rich-text": richText ? "true" : "false", |
| 736 | "aria-placeholder": placeholder, |
| 737 | }), |
| 738 | [className, placeholder, richText], |
| 739 | ); |
| 740 | |
| 728 | 741 | const editor = useEditor( |
| 729 | 742 | { |
| 730 | 743 | extensions: [ |
| ... | ... | @@ -787,15 +800,7 @@ function ComposerPromptEditorTiptapInner(props: ComposerPromptEditorProps) { |
| 787 | 800 | ), |
| 788 | 801 | editable: !disabled, |
| 789 | 802 | editorProps: { |
| 790 | | attributes: { |
| 791 | | class: cn( |
| 792 | | "composer-tiptap block max-h-50 min-h-17.5 w-full overflow-y-auto whitespace-pre-wrap wrap-break-word bg-transparent leading-relaxed text-foreground focus:outline-none", |
| 793 | | className, |
| 794 | | ), |
| 795 | | "data-testid": "composer-editor", |
| 796 | | "data-composer-rich-text": richText ? "true" : "false", |
| 797 | | "aria-placeholder": placeholder, |
| 798 | | }, |
| 803 | attributes: editorAttributes, |
| 799 | 804 | handleKeyDown: (view, event) => { |
| 800 | 805 | if ( |
| 801 | 806 | isMacPlatform(navigator.platform) && |
| ... | ... | @@ -995,6 +1000,17 @@ function ComposerPromptEditorTiptapInner(props: ComposerPromptEditorProps) { |
| 995 | 1000 | editorHolder.current = editor; |
| 996 | 1001 | }, [editor]); |
| 997 | 1002 | |
| 1003 | // Tiptap forwards option changes to the view from a passive effect, so a |
| 1004 | // class change here would reach the ProseMirror element one tick after |
| 1005 | // React commits. The chat composer measures its resting and expanded |
| 1006 | // geometry in layout effects that run first, and it clamps the prompt |
| 1007 | // through `className`, so the attributes are pushed to the view here for |
| 1008 | // those measurements to see the layout they are about to reserve for. |
| 1009 | useLayoutEffect(() => { |
| 1010 | if (!editor?.isInitialized) return; |
| 1011 | editor.view.setProps({ attributes: editorAttributes }); |
| 1012 | }, [editor, editorAttributes]); |
| 1013 | |
| 998 | 1014 | const readSnapshot = useCallback(() => { |
| 999 | 1015 | const snapshot = snapshotRef.current; |
| 1000 | 1016 | if (!editor) return snapshot; |