From 6052db1e8a91e07106946334c5b6e8de196e5f42 Mon Sep 17 00:00:00 2001 From: alunturner <56027671+alunturner@users.noreply.github.com> Date: Fri, 13 Jan 2023 15:44:35 +0000 Subject: [PATCH] Add list functionality to rich text editor (#9871) * adds buttons to toggle bulleted and numbered lists on and off * adds icons for those buttons * css changes to timeline display * adds tests for the new buttons, refactors existing tests --- res/css/views/rooms/_EventTile.pcss | 11 ++ .../wysiwyg_composer/components/_Editor.pcss | 14 ++ .../room/composer/bulleted_list.svg | 3 + .../room/composer/numbered_list.svg | 3 + .../wysiwyg_composer/components/Editor.tsx | 2 +- .../components/FormattingButtons.tsx | 14 ++ src/i18n/strings/en_EN.json | 2 + .../components/FormattingButtons-test.tsx | 160 ++++++++++-------- 8 files changed, 142 insertions(+), 67 deletions(-) create mode 100644 res/img/element-icons/room/composer/bulleted_list.svg create mode 100644 res/img/element-icons/room/composer/numbered_list.svg diff --git a/res/css/views/rooms/_EventTile.pcss b/res/css/views/rooms/_EventTile.pcss index c7e857fc9cb..57bf2ce3c88 100644 --- a/res/css/views/rooms/_EventTile.pcss +++ b/res/css/views/rooms/_EventTile.pcss @@ -619,6 +619,17 @@ $left-gutter: 64px; ul ol { list-style-type: revert; } + + /* Make list type disc to match rich text editor */ + > ul { + list-style-type: disc; + } + + /* Remove top and bottom margin for better consecutive list display */ + > :is(ol, ul) { + margin-top: 0; + margin-bottom: 0; + } } } diff --git a/res/css/views/rooms/wysiwyg_composer/components/_Editor.pcss b/res/css/views/rooms/wysiwyg_composer/components/_Editor.pcss index d48476cfd7f..7ff3f11a500 100644 --- a/res/css/views/rooms/wysiwyg_composer/components/_Editor.pcss +++ b/res/css/views/rooms/wysiwyg_composer/components/_Editor.pcss @@ -25,6 +25,7 @@ limitations under the License. } .mx_WysiwygComposer_Editor_content { + line-height: $font-22px; white-space: pre-wrap; word-wrap: break-word; outline: none; @@ -35,6 +36,19 @@ limitations under the License. .caretNode { user-select: all; } + + ul, + ol { + margin-top: 0; + margin-bottom: 0; + padding-inline-start: $spacing-28; + } + + // model output always includes a linebreak but we do not want the user + // to see it when writing input in lists + :is(ol, ul) + br:last-of-type { + display: none; + } } .mx_WysiwygComposer_Editor_content_placeholder::before { diff --git a/res/img/element-icons/room/composer/bulleted_list.svg b/res/img/element-icons/room/composer/bulleted_list.svg new file mode 100644 index 00000000000..828bb8ab038 --- /dev/null +++ b/res/img/element-icons/room/composer/bulleted_list.svg @@ -0,0 +1,3 @@ + + + diff --git a/res/img/element-icons/room/composer/numbered_list.svg b/res/img/element-icons/room/composer/numbered_list.svg new file mode 100644 index 00000000000..46a5438f3f6 --- /dev/null +++ b/res/img/element-icons/room/composer/numbered_list.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/views/rooms/wysiwyg_composer/components/Editor.tsx b/src/components/views/rooms/wysiwyg_composer/components/Editor.tsx index 215d3be84fb..43e46572d67 100644 --- a/src/components/views/rooms/wysiwyg_composer/components/Editor.tsx +++ b/src/components/views/rooms/wysiwyg_composer/components/Editor.tsx @@ -20,7 +20,7 @@ import React, { CSSProperties, forwardRef, memo, MutableRefObject, ReactNode } f import { useIsExpanded } from "../hooks/useIsExpanded"; import { useSelection } from "../hooks/useSelection"; -const HEIGHT_BREAKING_POINT = 20; +const HEIGHT_BREAKING_POINT = 24; interface EditorProps { disabled: boolean; diff --git a/src/components/views/rooms/wysiwyg_composer/components/FormattingButtons.tsx b/src/components/views/rooms/wysiwyg_composer/components/FormattingButtons.tsx index 1d3f44bee7e..7c1601b4416 100644 --- a/src/components/views/rooms/wysiwyg_composer/components/FormattingButtons.tsx +++ b/src/components/views/rooms/wysiwyg_composer/components/FormattingButtons.tsx @@ -24,6 +24,8 @@ import { Icon as UnderlineIcon } from "../../../../../../res/img/element-icons/r import { Icon as StrikeThroughIcon } from "../../../../../../res/img/element-icons/room/composer/strikethrough.svg"; import { Icon as InlineCodeIcon } from "../../../../../../res/img/element-icons/room/composer/inline_code.svg"; import { Icon as LinkIcon } from "../../../../../../res/img/element-icons/room/composer/link.svg"; +import { Icon as BulletedListIcon } from "../../../../../../res/img/element-icons/room/composer/bulleted_list.svg"; +import { Icon as NumberedListIcon } from "../../../../../../res/img/element-icons/room/composer/numbered_list.svg"; import AccessibleTooltipButton from "../../../elements/AccessibleTooltipButton"; import { Alignment } from "../../../elements/Tooltip"; import { KeyboardShortcut } from "../../../settings/KeyboardShortcut"; @@ -109,6 +111,18 @@ export function FormattingButtons({ composer, actionStates }: FormattingButtonsP onClick={() => composer.strikeThrough()} icon={} /> +