Rich text toolbar refinements from usability testing. Fix #9281 (#9905)

pull/9828/head
Thibaud Colas 2023-01-17 17:21:45 +00:00 zatwierdzone przez GitHub
rodzic b02f08d8d9
commit 34f6bab633
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
11 zmienionych plików z 184 dodań i 26 usunięć

Wyświetl plik

@ -25,6 +25,8 @@ Changelog
* Implement latest design for the admin dashboard header (Thibaud Colas, Steven Steinwand)
* Add base Axe accessibility checker integration within userbar, with error count (Albina Starykova)
* Allow configuring Axe accessibility checker integration via `construct_wagtail_userbar` hook (Sage Abdullah)
* Support pinning and un-pinning the rich text editor toolbar depending on user preference (Thibaud Colas)
* Make the rich text block trigger and slash-commands always available regardless of where the cursor is (Thibaud Colas)
* Fix: Make sure workflow timeline icons are visible in high-contrast mode (Loveth Omokaro)
* Fix: Ensure authentication forms (login, password reset) have a visible border in Windows high-contrast mode (Loveth Omokaro)
* Fix: Ensure visual consistency between buttons and links as buttons in Windows high-contrast mode (Albina Starykova)
@ -63,6 +65,9 @@ Changelog
* Fix: Resolve issue where workflow and other notification emails would not include the correct tab URL for account notification management (LB (Ben) Johnston)
* Fix: Use consistent spacing above and below page headers (Thibaud Colas)
* Fix: Use the correct icon sizes and spacing in slim header (Thibaud Colas)
* Fix: Use the correct color for placeholders in rich text fields (Thibaud Colas)
* Fix: Prevent obstructing the outline around rich text fields (Thibaud Colas)
* Fix: Page editor dropdowns now use indigo backgrounds like elsewhere in the admin interface (Thibaud Colas)
* Docs: Add custom permissions section to permissions documentation page (Dan Hayden)
* Docs: Add documentation for how to get started with contributing translations for the Wagtail admin (Ogunbanjo Oluwadamilare)
* Docs: Officially recommend `fnm` over `nvm` in development documentation (LB (Ben) Johnston)

Wyświetl plik

@ -682,6 +682,7 @@ Contributors
* Jhonatan Lopes
* Alex Simpson
* GLEF1X
* Nick Lee
Translators
===========

Wyświetl plik

@ -1,4 +1,5 @@
$draftail-editor-text: $color-input-text;
$draftail-placeholder-text: theme('colors.grey.400');
// w-body-text-large
$draftail-editor-font-size: theme('fontSize.18');
$draftail-editor-line-height: theme('lineHeight.normal');
@ -76,9 +77,14 @@ $draftail-editor-font-family: $font-sans;
}
.Draftail-Editor {
@include input-base();
// Number used inside a `calc` function, which doesnt support unitless zero.
// stylelint-disable-next-line length-zero-no-unit
--draftail-offset-inline-start: 0px;
&--focus {
outline: $focus-outline-width solid $color-focus-outline;
}
}
.Draftail-Editor__wrapper {
@ -107,13 +113,37 @@ $draftail-editor-font-family: $font-sans;
}
.Draftail-Toolbar {
border: 1px solid $color-grey-3;
border-width: 0;
// Remove once we drop support for Safari 14.
// stylelint-disable-next-line property-disallowed-list
border-bottom-left-radius: 0;
border-end-start-radius: 0;
// Remove once we drop support for Safari 14.
// stylelint-disable-next-line property-disallowed-list
border-bottom-right-radius: 0;
border-end-end-radius: 0;
background-color: $draftail-editor-background;
color: $draftail-placeholder-text;
.Draftail-Editor--focus & {
color: $draftail-editor-text;
top: calc(theme('spacing.slim-header') * 2);
@include media-breakpoint-up(sm) {
top: theme('spacing.slim-header');
}
}
}
.Draftail-MetaToolbar {
position: absolute;
inset-inline-end: 0;
visibility: hidden;
background-color: transparent;
&:empty {
display: none;
}
// Make sure the toolbar is always visible for devices that do not hover.
@media (hover: hover) {
@ -233,13 +263,6 @@ $draftail-editor-font-family: $font-sans;
display: none;
}
.Draftail-ToolbarGroup--controls::before {
display: inline-block;
height: 1.875rem;
background-color: $color-white;
opacity: 0.2;
}
.Draftail-ToolbarButton {
height: 1.875rem;
min-width: 1.875rem;
@ -260,9 +283,29 @@ $draftail-editor-font-family: $font-sans;
}
}
.Draftail-Editor__wrapper .public-DraftEditor-content {
@include input-base();
@include show-focus-outline-inside();
.Draftail-ToolbarButton--pin {
min-width: theme('spacing.6');
height: theme('spacing.6');
border: 1px solid theme('colors.primary.DEFAULT');
&:hover {
border-color: theme('colors.primary.DEFAULT');
}
.Draftail-Toolbar & {
border-color: $color-input-border;
background-color: theme('colors.grey.50');
border-top-width: 0;
border-inline-end-width: 0;
.Draftail-Editor:hover & {
border-color: $color-input-hover-border;
}
}
.icon {
transform: rotate(30deg);
}
}
.Draftail-block--blockquote {

Wyświetl plik

@ -38,6 +38,49 @@ const BR_ICON =
'M.436 633.471l296.897-296.898v241.823h616.586V94.117h109.517v593.796H297.333v242.456z';
const ADD_ICON = <Icon name="plus" />;
const pinButton = {
floatingIcon: <Icon name="thumbtack" />,
stickyIcon: <Icon name="thumbtack-crossed" />,
floatingDescription: gettext('Pin toolbar'),
stickyDescription: gettext('Unpin toolbar'),
};
const getSavedToolbar = () => {
let saved = 'floating';
try {
saved = localStorage.getItem('wagtail:draftail-toolbar') || saved;
} catch {
// Use the default if localStorage isnt available.
}
return saved;
};
/**
* Scroll to keep the field on the same spot when switching toolbars,
* and save the choice in localStorage.
*/
const onSetToolbar = (choice, callback) => {
const activeEditor = document.activeElement;
const before = activeEditor.getBoundingClientRect().top;
callback(choice);
// Delay scrolling until reflow has been fully computed.
requestAnimationFrame(() => {
const after = activeEditor.getBoundingClientRect().top;
const scrollArea = document.querySelector('#main');
scrollArea.scrollBy({
// Scroll by a positive amount if the editor moved down, negative if up.
top: after - before,
behavior: 'instant',
});
});
try {
localStorage.setItem('wagtail:draftail-toolbar', choice);
} catch {
// Skip saving the preference if localStorage isnt available.
}
};
/**
* Registry for client-side code of Draftail plugins.
*/
@ -153,7 +196,12 @@ const initEditor = (selector, originalOptions, currentScript) => {
comboPlaceholder={gettext('Search blocks')}
noResultsText={gettext('No results')}
/>
<InlineToolbar {...props} />
<InlineToolbar
{...props}
pinButton={pinButton}
defaultToolbar={getSavedToolbar()}
onSetToolbar={onSetToolbar}
/>
</>
),
bottomToolbar: MetaToolbar,

Wyświetl plik

@ -197,9 +197,8 @@ class DraftailInsertBlockCommand {
}
onSelect({ editorState }) {
// Reset the current block to unstyled and empty before splitting, so we remove the command prompt if used.
const result = window.draftail.splitState(
window.draftail.DraftUtils.resetBlockWithType(editorState, 'unstyled'),
window.draftail.DraftUtils.removeCommandPalettePrompt(editorState),
);
if (result.stateAfter.getCurrentContent().hasText()) {
// There is content after the insertion point, so need to split the existing block.
@ -246,7 +245,7 @@ class DraftailSplitCommand {
onSelect({ editorState }) {
const result = window.draftail.splitState(
window.draftail.DraftUtils.resetBlockWithType(editorState, 'unstyled'),
window.draftail.DraftUtils.removeCommandPalettePrompt(editorState),
);
// Run the split after a timeout to circumvent potential race condition.
setTimeout(() => {

Wyświetl plik

@ -37,6 +37,8 @@ Following from Wagtail 3.0, this release contains significant UI changes that af
Further updates to the page editor are expected in the next release. Those changes were implemented by Thibaud Colas. Development on this feature was sponsored by Google.
(rich_text_improvements_4)=
### Rich text improvements
As part of the page editor redesign project sponsored by Google, we have made a number of improvements to our rich text editor:

Wyświetl plik

@ -27,6 +27,16 @@ Wagtail now provides a `fullpageurl` template tag (for both Django templates and
This feature was developed by Jake Howard.
### Rich text improvements
Following feedback from Wagtail users on [rich text UI improvements in Wagtail 4.0](rich_text_improvements_4), we have further refined the behavior of rich text fields to cater for different scenarios:
- Users can now choose between an “inline” floating toolbar, and a fixed toolbar at the top of the editor. Both toolbars display all formatting options.
- The / command palette and block picker in rich text fields now contain all formatting options except text styles.
- The / command palette and block picker are now always available no matter where the cursor is placed, to support inserting content at any point within text, transforming existing content, and splitting StreamField blocks in the middle of a paragraph when needed.
Thank you to all who provided feedback, participants to our usability testing sessions, and to Nick Lee and Thibaud Colas for the implementation.
### Other features
* Test assertion [`WagtailPageTestCase.assertCanCreate`](testing_reference) now supports the kwarg `publish=True` to check publish redirection (Harry Percival, Akua Dokua Asiedu)
@ -87,6 +97,9 @@ This feature was developed by Jake Howard.
* Resolve issue where workflow and other notification emails would not include the correct tab URL for account notification management (LB (Ben) Johnston)
* Use consistent spacing above and below page headers (Thibaud Colas)
* Use the correct icon sizes and spacing in slim header (Thibaud Colas)
* Use the correct color for placeholders in rich text fields (Thibaud Colas)
* Prevent obstructing the outline around rich text fields (Thibaud Colas)
* Page editor dropdowns now use indigo backgrounds like elsewhere in the admin interface (Thibaud Colas)
### Documentation

63
package-lock.json wygenerowano
Wyświetl plik

@ -13,7 +13,7 @@
"a11y-dialog": "^7.4.0",
"axe-core": "^4.6.2",
"draft-js": "^0.10.5",
"draftail": "^2.0.0-rc.2",
"draftail": "^2.0.0-rc.5",
"draftjs-filters": "^3.0.1",
"focus-trap-react": "^8.4.2",
"immer": "^9.0.6",
@ -16540,6 +16540,7 @@
},
"node_modules/compute-scroll-into-view": {
"version": "1.0.17",
"dev": true,
"license": "MIT"
},
"node_modules/concat-map": {
@ -17962,6 +17963,7 @@
},
"node_modules/downshift": {
"version": "6.1.7",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.14.8",
@ -18004,13 +18006,13 @@
}
},
"node_modules/draftail": {
"version": "2.0.0-rc.2",
"resolved": "https://registry.npmjs.org/draftail/-/draftail-2.0.0-rc.2.tgz",
"integrity": "sha512-3KNMXv54k0yxAoOk8Ho9m/YRxJxArv7VwS/3X1yX0Xi2dUzvRzvYW5piGMSIX6vgYoWSN9p5bM+XtytciL93ig==",
"version": "2.0.0-rc.5",
"resolved": "https://registry.npmjs.org/draftail/-/draftail-2.0.0-rc.5.tgz",
"integrity": "sha512-t4o+483o7DY+7taNP6adgh2FAp4VBi0WxcteilPZdRZaotv3ePsLV5TPtfLiQtS4KGgGyP+RiGmPfPjJ/Ycbvg==",
"dependencies": {
"@tippyjs/react": "^4.2.6",
"decorate-component-with-props": "^1.0.2",
"downshift": "^6.1.7",
"downshift": "^7.0.4",
"draft-js-plugins-editor": "^2.1.1",
"draftjs-conductor": "^3.0.0",
"draftjs-filters": "^3.0.1"
@ -18021,6 +18023,26 @@
"react-dom": "^16.6.0"
}
},
"node_modules/draftail/node_modules/compute-scroll-into-view": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-2.0.4.tgz",
"integrity": "sha512-y/ZA3BGnxoM/QHHQ2Uy49CLtnWPbt4tTPpEEZiEmmiWBFKjej7nEyH8Ryz54jH0MLXflUYA3Er2zUxPSJu5R+g=="
},
"node_modules/draftail/node_modules/downshift": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/downshift/-/downshift-7.2.0.tgz",
"integrity": "sha512-dEn1Sshe7iTelUhmdbmiJhtIiwIBxBV8p15PuvEBh0qZcHXZnEt0geuCIIkCL4+ooaKRuLE0Wc+Fz9SwWuBIyg==",
"dependencies": {
"@babel/runtime": "^7.14.8",
"compute-scroll-into-view": "^2.0.4",
"prop-types": "^15.7.2",
"react-is": "^17.0.2",
"tslib": "^2.3.0"
},
"peerDependencies": {
"react": ">=16.12.0"
}
},
"node_modules/draftjs-conductor": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/draftjs-conductor/-/draftjs-conductor-3.0.0.tgz",
@ -43078,7 +43100,8 @@
}
},
"compute-scroll-into-view": {
"version": "1.0.17"
"version": "1.0.17",
"dev": true
},
"concat-map": {
"version": "0.0.1",
@ -44064,6 +44087,7 @@
},
"downshift": {
"version": "6.1.7",
"dev": true,
"requires": {
"@babel/runtime": "^7.14.8",
"compute-scroll-into-view": "^1.0.17",
@ -44091,16 +44115,35 @@
}
},
"draftail": {
"version": "2.0.0-rc.2",
"resolved": "https://registry.npmjs.org/draftail/-/draftail-2.0.0-rc.2.tgz",
"integrity": "sha512-3KNMXv54k0yxAoOk8Ho9m/YRxJxArv7VwS/3X1yX0Xi2dUzvRzvYW5piGMSIX6vgYoWSN9p5bM+XtytciL93ig==",
"version": "2.0.0-rc.5",
"resolved": "https://registry.npmjs.org/draftail/-/draftail-2.0.0-rc.5.tgz",
"integrity": "sha512-t4o+483o7DY+7taNP6adgh2FAp4VBi0WxcteilPZdRZaotv3ePsLV5TPtfLiQtS4KGgGyP+RiGmPfPjJ/Ycbvg==",
"requires": {
"@tippyjs/react": "^4.2.6",
"decorate-component-with-props": "^1.0.2",
"downshift": "^6.1.7",
"downshift": "^7.0.4",
"draft-js-plugins-editor": "^2.1.1",
"draftjs-conductor": "^3.0.0",
"draftjs-filters": "^3.0.1"
},
"dependencies": {
"compute-scroll-into-view": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-2.0.4.tgz",
"integrity": "sha512-y/ZA3BGnxoM/QHHQ2Uy49CLtnWPbt4tTPpEEZiEmmiWBFKjej7nEyH8Ryz54jH0MLXflUYA3Er2zUxPSJu5R+g=="
},
"downshift": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/downshift/-/downshift-7.2.0.tgz",
"integrity": "sha512-dEn1Sshe7iTelUhmdbmiJhtIiwIBxBV8p15PuvEBh0qZcHXZnEt0geuCIIkCL4+ooaKRuLE0Wc+Fz9SwWuBIyg==",
"requires": {
"@babel/runtime": "^7.14.8",
"compute-scroll-into-view": "^2.0.4",
"prop-types": "^15.7.2",
"react-is": "^17.0.2",
"tslib": "^2.3.0"
}
}
}
},
"draftjs-conductor": {

Wyświetl plik

@ -106,7 +106,7 @@
"a11y-dialog": "^7.4.0",
"axe-core": "^4.6.2",
"draft-js": "^0.10.5",
"draftail": "^2.0.0-rc.2",
"draftail": "^2.0.0-rc.5",
"draftjs-filters": "^3.0.1",
"focus-trap-react": "^8.4.2",
"immer": "^9.0.6",

Wyświetl plik

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" id="icon-thumbtack-crossed" viewBox="0 0 16 15">
<path d="M12.557 7.635H3.032a2.859 2.859 0 0 0-.486 1.578c0 .383.274.656.656.656h3.72v2.953l.655 1.313c.082.164.329.164.41 0l.657-1.313c0-.014.007-.027.014-.041a.097.097 0 0 0 .013-.041V9.869h3.719a.648.648 0 0 0 .656-.656c0-.583-.181-1.114-.489-1.578ZM10.34 2.869l.184 1.69H5.04l.185-1.69H4.077a.632.632 0 0 1-.656-.656V.9c0-.355.274-.656.656-.656h7.438c.355 0 .656.3.656.656v1.313c0 .382-.3.656-.656.656h-1.176ZM0 5.56h16v1.08H0V5.56Z"/>
</svg>

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 540 B

Wyświetl plik

@ -1126,6 +1126,7 @@ def register_icons(icons):
"tag.svg",
"tasks.svg",
"thumbtack.svg",
"thumbtack-crossed.svg",
"tick-inverse.svg",
"tick.svg",
"time.svg",