authorgravatar for 97427849+flamboh@users.noreply.github.comoliver <97427849+flamboh@users.noreply.github.com> 2026-09-20 14:31:38-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-20 18:31:38-03:00
log2d8f9a8f55d2195ac820c91f0f1e8f66a055f841
tree1e6277d85a4ab4ed70159211d9e4e6474ac69aa6
parent5d9e27a596884d30499c7401296916fd729c817f
signature Signed by PGP key B5690EEEBB952194

fix(web): keep the timeline still when the resting composer expands (#12771)


1 files changed, 25 insertions(+), 9 deletions(-)

apps/web/src/components/ComposerPromptEditorTiptap.tsx+25-9
...@@ -725,6 +725,19 @@ function ComposerPromptEditorTiptapInner(props: ComposerPromptEditorProps) {...@@ -725,6 +725,19 @@ function ComposerPromptEditorTiptapInner(props: ComposerPromptEditorProps) {
725 );725 );
726 }, []);726 }, []);
727727
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 const editor = useEditor(741 const editor = useEditor(
729 {742 {
730 extensions: [743 extensions: [
...@@ -787,15 +800,7 @@ function ComposerPromptEditorTiptapInner(props: ComposerPromptEditorProps) {...@@ -787,15 +800,7 @@ function ComposerPromptEditorTiptapInner(props: ComposerPromptEditorProps) {
787 ),800 ),
788 editable: !disabled,801 editable: !disabled,
789 editorProps: {802 editorProps: {
790 attributes: {803 attributes: editorAttributes,
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 },
799 handleKeyDown: (view, event) => {804 handleKeyDown: (view, event) => {
800 if (805 if (
801 isMacPlatform(navigator.platform) &&806 isMacPlatform(navigator.platform) &&
...@@ -995,6 +1000,17 @@ function ComposerPromptEditorTiptapInner(props: ComposerPromptEditorProps) {...@@ -995,6 +1000,17 @@ function ComposerPromptEditorTiptapInner(props: ComposerPromptEditorProps) {
995 editorHolder.current = editor;1000 editorHolder.current = editor;
996 }, [editor]);1001 }, [editor]);
9971002
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 const readSnapshot = useCallback(() => {1014 const readSnapshot = useCallback(() => {
999 const snapshot = snapshotRef.current;1015 const snapshot = snapshotRef.current;
1000 if (!editor) return snapshot;1016 if (!editor) return snapshot;