From 01858354f837f5a3d3068d9883a21c5f0906e5d0 Mon Sep 17 00:00:00 2001 From: Florian Duros Date: Thu, 13 Oct 2022 12:20:31 +0200 Subject: [PATCH 1/9] Add formatting buttons for WysisygComposer --- res/css/_components.pcss | 1 + res/css/views/rooms/_MessageComposer.pcss | 11 ++ .../wysiwyg_composer/_FormattingButtons.pcss | 114 ++++++++++++++++++ res/img/element-icons/room/composer/bold.svg | 3 + .../element-icons/room/composer/italic.svg | 3 + .../room/composer/strike_through.svg | 4 + .../element-icons/room/composer/underline.svg | 3 + .../views/rooms/MessageComposer.tsx | 4 +- .../views/rooms/wysiwyg_composer/Editor.tsx | 41 +++++++ .../wysiwyg_composer/FormattingButtons.tsx | 69 +++++++++++ .../wysiwyg_composer/WysiwygComposer.tsx | 30 ++--- .../views/settings/KeyboardShortcut.tsx | 5 +- src/i18n/strings/en_EN.json | 5 +- src/settings/Settings.tsx | 2 +- 14 files changed, 271 insertions(+), 24 deletions(-) create mode 100644 res/css/views/rooms/wysiwyg_composer/_FormattingButtons.pcss create mode 100644 res/img/element-icons/room/composer/bold.svg create mode 100644 res/img/element-icons/room/composer/italic.svg create mode 100644 res/img/element-icons/room/composer/strike_through.svg create mode 100644 res/img/element-icons/room/composer/underline.svg create mode 100644 src/components/views/rooms/wysiwyg_composer/Editor.tsx create mode 100644 src/components/views/rooms/wysiwyg_composer/FormattingButtons.tsx diff --git a/res/css/_components.pcss b/res/css/_components.pcss index b2a3752628..dd546efbd6 100644 --- a/res/css/_components.pcss +++ b/res/css/_components.pcss @@ -295,6 +295,7 @@ @import "./views/rooms/_TopUnreadMessagesBar.pcss"; @import "./views/rooms/_VoiceRecordComposerTile.pcss"; @import "./views/rooms/_WhoIsTypingTile.pcss"; +@import "./views/rooms/wysiwyg_composer/_FormattingButtons.pcss"; @import "./views/rooms/wysiwyg_composer/_WysiwygComposer.pcss"; @import "./views/settings/_AvatarSetting.pcss"; @import "./views/settings/_CrossSigningPanel.pcss"; diff --git a/res/css/views/rooms/_MessageComposer.pcss b/res/css/views/rooms/_MessageComposer.pcss index 4284eac56d..4cddf31084 100644 --- a/res/css/views/rooms/_MessageComposer.pcss +++ b/res/css/views/rooms/_MessageComposer.pcss @@ -233,6 +233,17 @@ limitations under the License. } } +/* + The wysisyg composer increase the size of the MessageComposer. We temporary move the buttons + Soon the dom structure of the MessageComposer will change with the next evolution of the wysiwyg composer + and this workaround will disappear +*/ +.mx_MessageComposer_wysiwyg { + .mx_MessageComposer_e2eIcon.mx_E2EIcon,.mx_MessageComposer_button, .mx_MessageComposer_sendMessage { + margin-top: 22px; + } +} + .mx_MessageComposer_upload::before { mask-image: url('$(res)/img/element-icons/room/composer/attach.svg'); } diff --git a/res/css/views/rooms/wysiwyg_composer/_FormattingButtons.pcss b/res/css/views/rooms/wysiwyg_composer/_FormattingButtons.pcss new file mode 100644 index 0000000000..cae56e0266 --- /dev/null +++ b/res/css/views/rooms/wysiwyg_composer/_FormattingButtons.pcss @@ -0,0 +1,114 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_FormattingButtons { + display: flex; + justify-content: start; + + .mx_FormattingButtons_Button { + --size: 26px; + position: relative; + cursor: pointer; + height: var(--size); + line-height: var(--size); + width: auto; + padding-left: var(--size); + margin-right: 6px; + background-color: transparent; + border: none; + + &:last-child { + margin-right: auto; + } + + &::before { + content: ''; + position: absolute; + top: 7px; + left: 7px; + height: 12px; + width: 12px; + background-color: $icon-button-color; + mask-repeat: no-repeat; + mask-size: contain; + mask-position: center; + } + + &::after { + content: ''; + position: absolute; + left: 0; + top: 0; + z-index: 0; + width: var(--size); + height: var(--size); + border-radius: 5px; + } + + &:hover { + &::after { + background: rgba($secondary-content, 0.1); + } + + &::before { + background-color: $secondary-content; + } + } + } + + .mx_FormattingButtons_active { + &::after { + background: rgba($accent, 0.1); + } + + &::before { + background-color: $accent; + } + } + + .mx_FormattingButtons_Button_bold::before { + mask-image: url('$(res)/img/element-icons/room/composer/bold.svg'); + } + + .mx_FormattingButtons_Button_italic::before { + mask-image: url('$(res)/img/element-icons/room/composer/italic.svg'); + } + + .mx_FormattingButtons_Button_underline::before { + mask-image: url('$(res)/img/element-icons/room/composer/underline.svg'); + } + + .mx_FormattingButtons_Button_strike-through::before { + mask-image: url('$(res)/img/element-icons/room/composer/strike_through.svg'); + } +} + +.mx_FormattingButtons_Tooltip { + padding: 0 2px 0 2px; + + .mx_FormattingButtons_Tooltip_KeyboardShortcut { + color: $tertiary-content; + + kbd { + margin-top: 2px; + text-align: center; + display: inline-block; + text-transform: capitalize; + font-size: 12px; + font-family: Inter, sans-serif; + } + } +} diff --git a/res/img/element-icons/room/composer/bold.svg b/res/img/element-icons/room/composer/bold.svg new file mode 100644 index 0000000000..fa92101e51 --- /dev/null +++ b/res/img/element-icons/room/composer/bold.svg @@ -0,0 +1,3 @@ + + + diff --git a/res/img/element-icons/room/composer/italic.svg b/res/img/element-icons/room/composer/italic.svg new file mode 100644 index 0000000000..5f162344f0 --- /dev/null +++ b/res/img/element-icons/room/composer/italic.svg @@ -0,0 +1,3 @@ + + + diff --git a/res/img/element-icons/room/composer/strike_through.svg b/res/img/element-icons/room/composer/strike_through.svg new file mode 100644 index 0000000000..5d1119bd9b --- /dev/null +++ b/res/img/element-icons/room/composer/strike_through.svg @@ -0,0 +1,4 @@ + + + + diff --git a/res/img/element-icons/room/composer/underline.svg b/res/img/element-icons/room/composer/underline.svg new file mode 100644 index 0000000000..f9f8dc7fc1 --- /dev/null +++ b/res/img/element-icons/room/composer/underline.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/views/rooms/MessageComposer.tsx b/src/components/views/rooms/MessageComposer.tsx index b82a991f2e..9783e30756 100644 --- a/src/components/views/rooms/MessageComposer.tsx +++ b/src/components/views/rooms/MessageComposer.tsx @@ -389,6 +389,7 @@ export default class MessageComposer extends React.Component { } public render() { + const isWysiwygComposerEnabled = SettingsStore.getValue("feature_wysiwyg_composer"); const controls = [ this.props.e2eStatus ? : @@ -403,8 +404,6 @@ export default class MessageComposer extends React.Component { const canSendMessages = this.context.canSendMessages && !this.context.tombstone; if (canSendMessages) { - const isWysiwygComposerEnabled = SettingsStore.getValue("feature_wysiwyg_composer"); - if (isWysiwygComposerEnabled) { controls.push( { "mx_MessageComposer": true, "mx_MessageComposer--compact": this.props.compact, "mx_MessageComposer_e2eStatus": this.props.e2eStatus != undefined, + "mx_MessageComposer_wysiwyg": isWysiwygComposerEnabled, }); return ( diff --git a/src/components/views/rooms/wysiwyg_composer/Editor.tsx b/src/components/views/rooms/wysiwyg_composer/Editor.tsx new file mode 100644 index 0000000000..ab6fca9de9 --- /dev/null +++ b/src/components/views/rooms/wysiwyg_composer/Editor.tsx @@ -0,0 +1,41 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React, { forwardRef, memo } from 'react'; + +interface EditorProps { + disabled: boolean; +} + +export const Editor = memo( + forwardRef( + function Editor({ disabled }: EditorProps, ref, + ) { + return
+
+
; + }, + ), +); diff --git a/src/components/views/rooms/wysiwyg_composer/FormattingButtons.tsx b/src/components/views/rooms/wysiwyg_composer/FormattingButtons.tsx new file mode 100644 index 0000000000..b82fce5201 --- /dev/null +++ b/src/components/views/rooms/wysiwyg_composer/FormattingButtons.tsx @@ -0,0 +1,69 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React from "react"; +import { useWysiwyg } from "@matrix-org/matrix-wysiwyg"; +import classNames from "classnames"; + +import AccessibleTooltipButton from "../../elements/AccessibleTooltipButton"; +import { Alignment } from "../../elements/Tooltip"; +import { KeyboardShortcut } from "../../settings/KeyboardShortcut"; +import { KeyCombo } from "../../../../KeyBindingsManager"; +import { _td } from "../../../../languageHandler"; + +interface TooltipProps { + label: string; + keyCombo?: KeyCombo; +} + +function Tooltip({ label, keyCombo }: TooltipProps) { + return
+ { label } + { keyCombo && } +
; +} + +interface ButtonProps extends TooltipProps { + className: string; + isActive: boolean; + onClick: () => void; +} + +function Button({ label, keyCombo, onClick, isActive, className }: ButtonProps) { + return } + alignment={Alignment.Top} + />; +} + +interface FormattingButtonsProps { + wysiwyg: ReturnType['wysiwyg']; + formattingStates: ReturnType['formattingStates']; +} + +export function FormattingButtons({ wysiwyg, formattingStates }: FormattingButtonsProps) { + return
+
; +} diff --git a/src/components/views/rooms/wysiwyg_composer/WysiwygComposer.tsx b/src/components/views/rooms/wysiwyg_composer/WysiwygComposer.tsx index e45324982d..898be56795 100644 --- a/src/components/views/rooms/wysiwyg_composer/WysiwygComposer.tsx +++ b/src/components/views/rooms/wysiwyg_composer/WysiwygComposer.tsx @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, { useCallback, useState } from 'react'; +import React, { useCallback, useEffect } from 'react'; import { useWysiwyg } from "@matrix-org/matrix-wysiwyg"; import { IEventRelation, MatrixEvent } from 'matrix-js-sdk/src/models/event'; @@ -22,6 +22,8 @@ import { useRoomContext } from '../../../../contexts/RoomContext'; import { sendMessage } from './message'; import { RoomPermalinkCreator } from '../../../../utils/permalinks/Permalinks'; import { useMatrixClientContext } from '../../../../contexts/MatrixClientContext'; +import { FormattingButtons } from './FormattingButtons'; +import { Editor } from './Editor'; interface WysiwygProps { disabled?: boolean; @@ -39,11 +41,13 @@ export function WysiwygComposer( const roomContext = useRoomContext(); const mxClient = useMatrixClientContext(); - const [content, setContent] = useState(); - const { ref, isWysiwygReady, wysiwyg } = useWysiwyg({ onChange: (_content) => { - setContent(_content); - onChange(_content); - } }); + const { ref, isWysiwygReady, content, formattingStates, wysiwyg } = useWysiwyg(); + + useEffect(() => { + if (content !== null) { + onChange(content); + } + }, [onChange, content]); const memoizedSendMessage = useCallback(() => { sendMessage(content, { mxClient, roomContext, ...props }); @@ -53,18 +57,8 @@ export function WysiwygComposer( return (
-
-
-
+ + { children?.(memoizedSendMessage) }
); diff --git a/src/components/views/settings/KeyboardShortcut.tsx b/src/components/views/settings/KeyboardShortcut.tsx index 0f35ea0e7a..fc183a4a02 100644 --- a/src/components/views/settings/KeyboardShortcut.tsx +++ b/src/components/views/settings/KeyboardShortcut.tsx @@ -38,9 +38,10 @@ export const KeyboardKey: React.FC = ({ name, last }) => { interface IKeyboardShortcutProps { value: KeyCombo; + className?: string; } -export const KeyboardShortcut: React.FC = ({ value }) => { +export const KeyboardShortcut: React.FC = ({ value, className = 'mx_KeyboardShortcut' }) => { if (!value) return null; const modifiersElement = []; @@ -58,7 +59,7 @@ export const KeyboardShortcut: React.FC = ({ value }) => modifiersElement.push(); } - return
+ return
{ modifiersElement }
; diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 737f3e8879..a5ddd5d707 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -901,7 +901,7 @@ "How can I leave the beta?": "How can I leave the beta?", "To leave, return to this page and use the ā€œ%(leaveTheBeta)sā€ button.": "To leave, return to this page and use the ā€œ%(leaveTheBeta)sā€ button.", "Leave the beta": "Leave the beta", - "Wysiwyg composer (plain text mode coming soon) (under active development)": "Wysiwyg composer (plain text mode coming soon) (under active development)", + "Try out the rich text editor (plain text mode coming soon)": "Try out the rich text editor (plain text mode coming soon)", "Render simple counters in room header": "Render simple counters in room header", "Try out new ways to ignore people (experimental)": "Try out new ways to ignore people (experimental)", "Support adding custom themes": "Support adding custom themes", @@ -2054,6 +2054,9 @@ "No microphone found": "No microphone found", "We didn't find a microphone on your device. Please check your settings and try again.": "We didn't find a microphone on your device. Please check your settings and try again.", "Stop recording": "Stop recording", + "Italic": "Italic", + "Underline": "Underline", + "Strike through": "Strike through", "Error updating main address": "Error updating main address", "There was an error updating the room's main address. It may not be allowed by the server or a temporary failure occurred.": "There was an error updating the room's main address. It may not be allowed by the server or a temporary failure occurred.", "There was an error updating the room's alternative addresses. It may not be allowed by the server or a temporary failure occurred.": "There was an error updating the room's alternative addresses. It may not be allowed by the server or a temporary failure occurred.", diff --git a/src/settings/Settings.tsx b/src/settings/Settings.tsx index a4e55e6fcd..803823b262 100644 --- a/src/settings/Settings.tsx +++ b/src/settings/Settings.tsx @@ -306,7 +306,7 @@ export const SETTINGS: {[setting: string]: ISetting} = { "feature_wysiwyg_composer": { isFeature: true, labsGroup: LabGroup.Messaging, - displayName: _td("Wysiwyg composer (plain text mode coming soon) (under active development)"), + displayName: _td("Try out the rich text editor (plain text mode coming soon)"), supportedLevels: LEVELS_FEATURE, default: false, }, From a96aea29a95e94a8a0b84192908c9e566e87fe54 Mon Sep 17 00:00:00 2001 From: Florian Duros Date: Thu, 13 Oct 2022 15:36:54 +0200 Subject: [PATCH 2/9] Fix buttons size --- .../views/rooms/wysiwyg_composer/_FormattingButtons.pcss | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/res/css/views/rooms/wysiwyg_composer/_FormattingButtons.pcss b/res/css/views/rooms/wysiwyg_composer/_FormattingButtons.pcss index cae56e0266..b57d610488 100644 --- a/res/css/views/rooms/wysiwyg_composer/_FormattingButtons.pcss +++ b/res/css/views/rooms/wysiwyg_composer/_FormattingButtons.pcss @@ -19,14 +19,14 @@ limitations under the License. justify-content: start; .mx_FormattingButtons_Button { - --size: 26px; + --size: 28px; position: relative; cursor: pointer; height: var(--size); line-height: var(--size); width: auto; padding-left: var(--size); - margin-right: 6px; + margin-right: 2px; background-color: transparent; border: none; @@ -37,8 +37,8 @@ limitations under the License. &::before { content: ''; position: absolute; - top: 7px; - left: 7px; + top: 8px; + left: 8px; height: 12px; width: 12px; background-color: $icon-button-color; From ac8397aa0f6697340bccab350cc46e3fa7781cae Mon Sep 17 00:00:00 2001 From: Florian Duros Date: Thu, 13 Oct 2022 16:46:47 +0200 Subject: [PATCH 3/9] Fix test --- package.json | 2 +- .../views/rooms/wysiwyg_composer/Editor.tsx | 2 +- .../rooms/wysiwyg_composer/WysiwygComposer.tsx | 4 ++-- .../components/views/rooms/MessageComposer-test.tsx | 5 +++-- .../rooms/wysiwyg_composer/WysiwygComposer-test.tsx | 12 ++++-------- yarn.lock | 13 +++++++++---- 6 files changed, 20 insertions(+), 18 deletions(-) diff --git a/package.json b/package.json index f5c817ffd8..6d4a05570a 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "dependencies": { "@babel/runtime": "^7.12.5", "@matrix-org/analytics-events": "^0.2.0", - "@matrix-org/matrix-wysiwyg": "^0.0.2", + "@matrix-org/matrix-wysiwyg": "^0.2.0", "@matrix-org/react-sdk-module-api": "^0.0.3", "@sentry/browser": "^6.11.0", "@sentry/tracing": "^6.11.0", diff --git a/src/components/views/rooms/wysiwyg_composer/Editor.tsx b/src/components/views/rooms/wysiwyg_composer/Editor.tsx index ab6fca9de9..cca66f6c38 100644 --- a/src/components/views/rooms/wysiwyg_composer/Editor.tsx +++ b/src/components/views/rooms/wysiwyg_composer/Editor.tsx @@ -26,7 +26,7 @@ export const Editor = memo( ) { return
{ - if (content !== null) { + if (!disabled && content !== null) { onChange(content); } - }, [onChange, content]); + }, [onChange, content, disabled]); const memoizedSendMessage = useCallback(() => { sendMessage(content, { mxClient, roomContext, ...props }); diff --git a/test/components/views/rooms/MessageComposer-test.tsx b/test/components/views/rooms/MessageComposer-test.tsx index b8ff024cd8..bc0b26f745 100644 --- a/test/components/views/rooms/MessageComposer-test.tsx +++ b/test/components/views/rooms/MessageComposer-test.tsx @@ -44,8 +44,9 @@ import { WysiwygComposer } from "../../../../src/components/views/rooms/wysiwyg_ // The wysiwyg fetch wasm bytes and a specific workaround is needed to make it works in a node (jest) environnement // See https://github.com/matrix-org/matrix-wysiwyg/blob/main/platforms/web/test.setup.ts jest.mock("@matrix-org/matrix-wysiwyg", () => ({ - useWysiwyg: ({ onChange }) => { - return { ref: { current: null }, isWysiwygReady: true, wysiwyg: { clear: () => void 0 } }; + useWysiwyg: () => { + return { ref: { current: null }, isWysiwygReady: true, wysiwyg: { clear: () => void 0 }, + formattingStates: { bold: 'enabled', italic: 'enabled', underline: 'enabled', strikeThrough: 'enabled' } }; }, })); diff --git a/test/components/views/rooms/wysiwyg_composer/WysiwygComposer-test.tsx b/test/components/views/rooms/wysiwyg_composer/WysiwygComposer-test.tsx index 171455bfbc..d1d4596f5a 100644 --- a/test/components/views/rooms/wysiwyg_composer/WysiwygComposer-test.tsx +++ b/test/components/views/rooms/wysiwyg_composer/WysiwygComposer-test.tsx @@ -16,7 +16,6 @@ limitations under the License. import React from "react"; import { act, render, screen } from "@testing-library/react"; -import "@testing-library/jest-dom"; import { IRoomState } from "../../../../../src/components/structures/RoomView"; import RoomContext, { TimelineRenderingType } from "../../../../../src/contexts/RoomContext"; @@ -25,14 +24,12 @@ import { createTestClient, mkEvent, mkStubRoom } from "../../../../test-utils"; import MatrixClientContext from "../../../../../src/contexts/MatrixClientContext"; import { WysiwygComposer } from "../../../../../src/components/views/rooms/wysiwyg_composer/WysiwygComposer"; -let callOnChange: (content: string) => void; - // The wysiwyg fetch wasm bytes and a specific workaround is needed to make it works in a node (jest) environnement // See https://github.com/matrix-org/matrix-wysiwyg/blob/main/platforms/web/test.setup.ts jest.mock("@matrix-org/matrix-wysiwyg", () => ({ - useWysiwyg: ({ onChange }) => { - callOnChange = onChange; - return { ref: { current: null }, isWysiwygReady: true, wysiwyg: { clear: () => void 0 } }; + useWysiwyg: () => { + return { ref: { current: null }, content: 'html', isWysiwygReady: true, wysiwyg: { clear: () => void 0 }, + formattingStates: { bold: 'enabled', italic: 'enabled', underline: 'enabled', strikeThrough: 'enabled' } }; }, })); @@ -122,7 +119,7 @@ describe('WysiwygComposer', () => { expect(content).toBe((html)); done(); }); - act(() => callOnChange(html)); + // act(() => callOnChange(html)); }); it('Should send message, call clear and focus the textbox', async () => { @@ -130,7 +127,6 @@ describe('WysiwygComposer', () => { const html = 'html'; await new Promise((resolve) => { customRender(() => resolve(null)); - act(() => callOnChange(html)); }); act(() => sendMessage()); diff --git a/yarn.lock b/yarn.lock index 154f58e620..af6e5e5e71 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1660,10 +1660,10 @@ resolved "https://registry.yarnpkg.com/@matrix-org/analytics-events/-/analytics-events-0.2.0.tgz#453925c939ecdd5ca6c797d293deb8cf0933f1b8" integrity sha512-+0/Sydm4MNOcqd8iySJmojVPB74Axba4BXlwTsiKmL5fgYqdUkwmqkO39K7Pn8i+a+8pg11oNvBPkpWs3O5Qww== -"@matrix-org/matrix-wysiwyg@^0.0.2": - version "0.0.2" - resolved "https://registry.yarnpkg.com/@matrix-org/matrix-wysiwyg/-/matrix-wysiwyg-0.0.2.tgz#c1a18f5f9ac061c4147a0fbbf9303a3c82e626e6" - integrity sha512-AY4sbmgcaFZhNxJfn3Va1SiKH4/gIdvWV9c/iehcIi3/xFB7lKCIwe7NNxzPpFOp+b+fEIbdHf3fhS5vJBi7xg== +"@matrix-org/matrix-wysiwyg@^0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@matrix-org/matrix-wysiwyg/-/matrix-wysiwyg-0.2.0.tgz#651002ad67be3004698d4a89806cf344283a4ca3" + integrity sha512-m9R1NOd0ogkhrjqFNg159TMXL5dpME90G9RDrZrO106263Qtoj0TazyBaLhNjgvPkogbzbCJUULQWPFiLQfTjw== "@matrix-org/olm@https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.8.tgz": version "3.2.8" @@ -3198,6 +3198,11 @@ browser-process-hrtime@^1.0.0: resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== +browser-request@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/browser-request/-/browser-request-0.3.3.tgz#9ece5b5aca89a29932242e18bf933def9876cc17" + integrity sha512-YyNI4qJJ+piQG6MMEuo7J3Bzaqssufx04zpEKYfSrl/1Op59HWali9zMtBpXnkmqMcOuWJPZvudrm9wISmnCbg== + browserslist@^4.20.2, browserslist@^4.21.3: version "4.21.3" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.3.tgz#5df277694eb3c48bc5c4b05af3e8b7e09c5a6d1a" From b190163a4bea95d9775dd08d46235b1d989e8eba Mon Sep 17 00:00:00 2001 From: Florian Duros Date: Thu, 13 Oct 2022 16:56:31 +0200 Subject: [PATCH 4/9] Fix typo --- src/i18n/strings/en_EN.json | 1 - 1 file changed, 1 deletion(-) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 9309f7ce30..2e042df2db 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -2060,7 +2060,6 @@ "Stop recording": "Stop recording", "Italic": "Italic", "Underline": "Underline", - "Strike through": "Strike through", "Error updating main address": "Error updating main address", "There was an error updating the room's main address. It may not be allowed by the server or a temporary failure occurred.": "There was an error updating the room's main address. It may not be allowed by the server or a temporary failure occurred.", "There was an error updating the room's alternative addresses. It may not be allowed by the server or a temporary failure occurred.": "There was an error updating the room's alternative addresses. It may not be allowed by the server or a temporary failure occurred.", From 3f8baa45470fd0eac14154fd774aca22ad829edd Mon Sep 17 00:00:00 2001 From: Florian Duros Date: Thu, 13 Oct 2022 17:14:08 +0200 Subject: [PATCH 5/9] improve Formatting buttons style --- .../views/rooms/wysiwyg_composer/_FormattingButtons.pcss | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/res/css/views/rooms/wysiwyg_composer/_FormattingButtons.pcss b/res/css/views/rooms/wysiwyg_composer/_FormattingButtons.pcss index b57d610488..cedb2f4be0 100644 --- a/res/css/views/rooms/wysiwyg_composer/_FormattingButtons.pcss +++ b/res/css/views/rooms/wysiwyg_composer/_FormattingButtons.pcss @@ -25,11 +25,15 @@ limitations under the License. height: var(--size); line-height: var(--size); width: auto; - padding-left: var(--size); - margin-right: 2px; + padding-left: 22px; + margin-right: 8px; background-color: transparent; border: none; + &:first-child { + margin-left: 12px; + } + &:last-child { margin-right: auto; } From 0f2652c8664ec0f4018f356b9cdb3d12ac3876b1 Mon Sep 17 00:00:00 2001 From: Florian Duros Date: Thu, 13 Oct 2022 17:50:46 +0200 Subject: [PATCH 6/9] Change icon --- .../rooms/wysiwyg_composer/_FormattingButtons.pcss | 12 ++++++------ res/img/element-icons/room/composer/bold.svg | 4 ++-- res/img/element-icons/room/composer/italic.svg | 4 ++-- .../element-icons/room/composer/strike_through.svg | 4 ---- .../element-icons/room/composer/strikethrough.svg | 4 ++++ res/img/element-icons/room/composer/underline.svg | 4 ++-- .../rooms/wysiwyg_composer/FormattingButtons.tsx | 2 +- 7 files changed, 17 insertions(+), 17 deletions(-) delete mode 100644 res/img/element-icons/room/composer/strike_through.svg create mode 100644 res/img/element-icons/room/composer/strikethrough.svg diff --git a/res/css/views/rooms/wysiwyg_composer/_FormattingButtons.pcss b/res/css/views/rooms/wysiwyg_composer/_FormattingButtons.pcss index cedb2f4be0..36f84ae5f1 100644 --- a/res/css/views/rooms/wysiwyg_composer/_FormattingButtons.pcss +++ b/res/css/views/rooms/wysiwyg_composer/_FormattingButtons.pcss @@ -41,10 +41,10 @@ limitations under the License. &::before { content: ''; position: absolute; - top: 8px; - left: 8px; - height: 12px; - width: 12px; + top: 6px; + left: 6px; + height: 16px; + width: 16px; background-color: $icon-button-color; mask-repeat: no-repeat; mask-size: contain; @@ -95,8 +95,8 @@ limitations under the License. mask-image: url('$(res)/img/element-icons/room/composer/underline.svg'); } - .mx_FormattingButtons_Button_strike-through::before { - mask-image: url('$(res)/img/element-icons/room/composer/strike_through.svg'); + .mx_FormattingButtons_Button_strikethrough::before { + mask-image: url('$(res)/img/element-icons/room/composer/strikethrough.svg'); } } diff --git a/res/img/element-icons/room/composer/bold.svg b/res/img/element-icons/room/composer/bold.svg index fa92101e51..4a5cb184cf 100644 --- a/res/img/element-icons/room/composer/bold.svg +++ b/res/img/element-icons/room/composer/bold.svg @@ -1,3 +1,3 @@ - - + + diff --git a/res/img/element-icons/room/composer/italic.svg b/res/img/element-icons/room/composer/italic.svg index 5f162344f0..2299fc1fa2 100644 --- a/res/img/element-icons/room/composer/italic.svg +++ b/res/img/element-icons/room/composer/italic.svg @@ -1,3 +1,3 @@ - - + + diff --git a/res/img/element-icons/room/composer/strike_through.svg b/res/img/element-icons/room/composer/strike_through.svg deleted file mode 100644 index 5d1119bd9b..0000000000 --- a/res/img/element-icons/room/composer/strike_through.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/res/img/element-icons/room/composer/strikethrough.svg b/res/img/element-icons/room/composer/strikethrough.svg new file mode 100644 index 0000000000..0ed63b2139 --- /dev/null +++ b/res/img/element-icons/room/composer/strikethrough.svg @@ -0,0 +1,4 @@ + + + + diff --git a/res/img/element-icons/room/composer/underline.svg b/res/img/element-icons/room/composer/underline.svg index f9f8dc7fc1..b74e562ec8 100644 --- a/res/img/element-icons/room/composer/underline.svg +++ b/res/img/element-icons/room/composer/underline.svg @@ -1,3 +1,3 @@ - - + + diff --git a/src/components/views/rooms/wysiwyg_composer/FormattingButtons.tsx b/src/components/views/rooms/wysiwyg_composer/FormattingButtons.tsx index b82fce5201..9106fd3f62 100644 --- a/src/components/views/rooms/wysiwyg_composer/FormattingButtons.tsx +++ b/src/components/views/rooms/wysiwyg_composer/FormattingButtons.tsx @@ -64,6 +64,6 @@ export function FormattingButtons({ wysiwyg, formattingStates }: FormattingButto
; } From 53fce572aad1f434323b812c02aa8fd634d7f158 Mon Sep 17 00:00:00 2001 From: Florian Duros Date: Thu, 13 Oct 2022 18:53:20 +0200 Subject: [PATCH 7/9] Add FormattingButtons test --- .../FormattingButtons-test.tsx | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 test/components/views/rooms/wysiwyg_composer/FormattingButtons-test.tsx diff --git a/test/components/views/rooms/wysiwyg_composer/FormattingButtons-test.tsx b/test/components/views/rooms/wysiwyg_composer/FormattingButtons-test.tsx new file mode 100644 index 0000000000..da3cfa887c --- /dev/null +++ b/test/components/views/rooms/wysiwyg_composer/FormattingButtons-test.tsx @@ -0,0 +1,77 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React from 'react'; +import { render, screen } from "@testing-library/react"; +import userEvent from '@testing-library/user-event'; + +import { FormattingButtons } from "../../../../../src/components/views/rooms/wysiwyg_composer/FormattingButtons"; + +describe('FormattingButtons', () => { + const wysiwyg = { + bold: jest.fn(), + italic: jest.fn(), + underline: jest.fn(), + strikeThrough: jest.fn(), + } as any; + + const formattingStates = { + bold: 'reversed', + italic: 'reversed', + underline: 'enabled', + strikeThrough: 'enabled', + } as any; + + afterEach(() => { + jest.resetAllMocks(); + }); + + it('Should have the correspond CSS classes', () => { + // When + render(); + + // Then + expect(screen.getByLabelText('Bold')).toHaveClass('mx_FormattingButtons_active'); + expect(screen.getByLabelText('Italic')).toHaveClass('mx_FormattingButtons_active'); + expect(screen.getByLabelText('Underline')).not.toHaveClass('mx_FormattingButtons_active'); + expect(screen.getByLabelText('Strikethrough')).not.toHaveClass('mx_FormattingButtons_active'); + }); + + it('Should call wysiwyg function on button click', () => { + // When + render(); + screen.getByLabelText('Bold').click(); + screen.getByLabelText('Italic').click(); + screen.getByLabelText('Underline').click(); + screen.getByLabelText('Strikethrough').click(); + + // Then + expect(wysiwyg.bold).toHaveBeenCalledTimes(1); + expect(wysiwyg.italic).toHaveBeenCalledTimes(1); + expect(wysiwyg.underline).toHaveBeenCalledTimes(1); + expect(wysiwyg.strikeThrough).toHaveBeenCalledTimes(1); + }); + + it('Should display the tooltip on mouse over', async () => { + // When + const user = userEvent.setup(); + render(); + await user.hover(screen.getByLabelText('Bold')); + + // Then + expect(await screen.findByText('Bold')).toBeTruthy(); + }); +}); From 6b6af28ea9f4a78282ae72f7a2e3a666941eff16 Mon Sep 17 00:00:00 2001 From: Florian Duros Date: Fri, 14 Oct 2022 10:28:04 +0200 Subject: [PATCH 8/9] Use MouseEventHandler as type --- .../views/rooms/wysiwyg_composer/FormattingButtons.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/rooms/wysiwyg_composer/FormattingButtons.tsx b/src/components/views/rooms/wysiwyg_composer/FormattingButtons.tsx index 9106fd3f62..90a4ec2b1e 100644 --- a/src/components/views/rooms/wysiwyg_composer/FormattingButtons.tsx +++ b/src/components/views/rooms/wysiwyg_composer/FormattingButtons.tsx @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from "react"; +import React, { MouseEventHandler } from "react"; import { useWysiwyg } from "@matrix-org/matrix-wysiwyg"; import classNames from "classnames"; @@ -39,7 +39,7 @@ function Tooltip({ label, keyCombo }: TooltipProps) { interface ButtonProps extends TooltipProps { className: string; isActive: boolean; - onClick: () => void; + onClick: MouseEventHandler; } function Button({ label, keyCombo, onClick, isActive, className }: ButtonProps) { From c0bf45fddc95001198705a7b3038a914f5141c73 Mon Sep 17 00:00:00 2001 From: Florian Duros Date: Fri, 14 Oct 2022 10:56:34 +0200 Subject: [PATCH 9/9] Rename wysiwyg prop into composer --- .../rooms/wysiwyg_composer/FormattingButtons.tsx | 12 ++++++------ .../views/rooms/wysiwyg_composer/WysiwygComposer.tsx | 2 +- .../wysiwyg_composer/FormattingButtons-test.tsx | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/components/views/rooms/wysiwyg_composer/FormattingButtons.tsx b/src/components/views/rooms/wysiwyg_composer/FormattingButtons.tsx index 90a4ec2b1e..19941ad3f9 100644 --- a/src/components/views/rooms/wysiwyg_composer/FormattingButtons.tsx +++ b/src/components/views/rooms/wysiwyg_composer/FormattingButtons.tsx @@ -55,15 +55,15 @@ function Button({ label, keyCombo, onClick, isActive, className }: ButtonProps) } interface FormattingButtonsProps { - wysiwyg: ReturnType['wysiwyg']; + composer: ReturnType['wysiwyg']; formattingStates: ReturnType['formattingStates']; } -export function FormattingButtons({ wysiwyg, formattingStates }: FormattingButtonsProps) { +export function FormattingButtons({ composer, formattingStates }: FormattingButtonsProps) { return
-
; } diff --git a/src/components/views/rooms/wysiwyg_composer/WysiwygComposer.tsx b/src/components/views/rooms/wysiwyg_composer/WysiwygComposer.tsx index 1747fe5170..300417f66d 100644 --- a/src/components/views/rooms/wysiwyg_composer/WysiwygComposer.tsx +++ b/src/components/views/rooms/wysiwyg_composer/WysiwygComposer.tsx @@ -57,7 +57,7 @@ export function WysiwygComposer( return (
- + { children?.(memoizedSendMessage) }
diff --git a/test/components/views/rooms/wysiwyg_composer/FormattingButtons-test.tsx b/test/components/views/rooms/wysiwyg_composer/FormattingButtons-test.tsx index da3cfa887c..6c3e8573ae 100644 --- a/test/components/views/rooms/wysiwyg_composer/FormattingButtons-test.tsx +++ b/test/components/views/rooms/wysiwyg_composer/FormattingButtons-test.tsx @@ -41,7 +41,7 @@ describe('FormattingButtons', () => { it('Should have the correspond CSS classes', () => { // When - render(); + render(); // Then expect(screen.getByLabelText('Bold')).toHaveClass('mx_FormattingButtons_active'); @@ -52,7 +52,7 @@ describe('FormattingButtons', () => { it('Should call wysiwyg function on button click', () => { // When - render(); + render(); screen.getByLabelText('Bold').click(); screen.getByLabelText('Italic').click(); screen.getByLabelText('Underline').click(); @@ -68,7 +68,7 @@ describe('FormattingButtons', () => { it('Should display the tooltip on mouse over', async () => { // When const user = userEvent.setup(); - render(); + render(); await user.hover(screen.getByLabelText('Bold')); // Then