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={}
/>
+