[GH-ISSUE #2171] [Bug] changing heading from one level to another from toolbar #879

Closed
opened 2026-03-23 20:42:25 +00:00 by mirror · 1 comment
Owner

Originally created by @zoli on GitHub (Apr 3, 2023).
Original GitHub issue: https://github.com/AppFlowy-IO/AppFlowy/issues/2171

Originally assigned to: @LucasXu0 on GitHub.

Bug Description

If we have a text with h2 heading, Changing it to h1 from toolbar will just reset it to plain text. The subtype attribute becomes null but the heading will be h1 which causes the "H1" highlighted in toolbar but Appflowy editor it renders it as plain text.

The problem is rooted in this part of code which is intended for toggling attribute so if we try to format a quote subtype text again to quote subtype it just removes the quote (toggles it).

How to Reproduce

From toolbar change plain text to "H2" heading then try to change it to "H1".

Expected Behavior

To change from "H2" heading to "H1".

Operating System

Arch Linux

AppFlowy Version(s)

0.1.2

Screenshots

No response

Additional Context

This test case does not pass. If I'm right it should get added to "format_rich_text_style_test.dart" file

testWidgets('formatHeading from h2 to h1', (tester) async {
      const text = 'Welcome to Appflowy 😁';
      final editor = tester.editor
        ..insertTextNode(text, attributes: {
          BuiltInAttributeKey.subtype: BuiltInAttributeKey.heading,
          BuiltInAttributeKey.heading: BuiltInAttributeKey.h2,
        });
      await editor.startTesting();
      await editor.updateSelection(
        Selection.single(path: [0], startOffset: 0, endOffset: text.length),
      );

      // format the text to Quote
      formatHeading(editor.editorState, BuiltInAttributeKey.h1);
      await tester.pumpAndSettle(const Duration(milliseconds: 100));
      expect(find.byType(HeadingTextNodeWidget), findsOneWidget);

      final tn = editor.nodeAtPath([0])!;
      expect(tn.attributes.containsKey(BuiltInAttributeKey.subtype), true);
      expect(tn.attributes[BuiltInAttributeKey.subtype],
          BuiltInAttributeKey.heading);
      expect(tn.attributes.containsKey(BuiltInAttributeKey.heading), true);
      expect(
          tn.attributes[BuiltInAttributeKey.heading], BuiltInAttributeKey.h1);
    });

I'm not sure about all the cases but maybe an applicable solution would be that on removing subtype we should check if all other keys are unchanged or not.

Originally created by @zoli on GitHub (Apr 3, 2023). Original GitHub issue: https://github.com/AppFlowy-IO/AppFlowy/issues/2171 Originally assigned to: @LucasXu0 on GitHub. ### Bug Description If we have a text with h2 heading, Changing it to h1 from toolbar will just reset it to plain text. The `subtype` attribute becomes null but the heading will be `h1` which causes the "H1" highlighted in toolbar but Appflowy editor it renders it as plain text. The problem is rooted in [this part](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/appflowy_flutter/packages/appflowy_editor/lib/src/service/default_text_operations/format_rich_text_style.dart#L123-L131) of code which is intended for toggling attribute so if we try to format a quote `subtype` text again to quote `subtype` it just removes the quote (toggles it). ### How to Reproduce From toolbar change plain text to "H2" heading then try to change it to "H1". ### Expected Behavior To change from "H2" heading to "H1". ### Operating System Arch Linux ### AppFlowy Version(s) 0.1.2 ### Screenshots _No response_ ### Additional Context This test case does not pass. If I'm right it should get added to "format_rich_text_style_test.dart" file ``` dart testWidgets('formatHeading from h2 to h1', (tester) async { const text = 'Welcome to Appflowy 😁'; final editor = tester.editor ..insertTextNode(text, attributes: { BuiltInAttributeKey.subtype: BuiltInAttributeKey.heading, BuiltInAttributeKey.heading: BuiltInAttributeKey.h2, }); await editor.startTesting(); await editor.updateSelection( Selection.single(path: [0], startOffset: 0, endOffset: text.length), ); // format the text to Quote formatHeading(editor.editorState, BuiltInAttributeKey.h1); await tester.pumpAndSettle(const Duration(milliseconds: 100)); expect(find.byType(HeadingTextNodeWidget), findsOneWidget); final tn = editor.nodeAtPath([0])!; expect(tn.attributes.containsKey(BuiltInAttributeKey.subtype), true); expect(tn.attributes[BuiltInAttributeKey.subtype], BuiltInAttributeKey.heading); expect(tn.attributes.containsKey(BuiltInAttributeKey.heading), true); expect( tn.attributes[BuiltInAttributeKey.heading], BuiltInAttributeKey.h1); }); ``` I'm not sure about all the cases but maybe an applicable solution would be that on removing `subtype` we should check if all other keys are unchanged or not.
mirror 2026-03-23 20:42:25 +00:00
  • closed this issue
  • added the
    bug
    editor
    labels
Author
Owner

@annieappflowy commented on GitHub (Apr 6, 2023):

Thanks for reporting!
I'm able to reproduce it on MacOS

<!-- gh-comment-id:1498974407 --> @annieappflowy commented on GitHub (Apr 6, 2023): Thanks for reporting! I'm able to reproduce it on MacOS
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
AppFlowy-IO/AppFlowy#879
No description provided.