Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inline text formatting #1323

Merged
merged 63 commits into from May 6, 2020
Merged

Inline text formatting #1323

merged 63 commits into from May 6, 2020

Conversation

barklund
Copy link
Contributor

@barklund barklund commented Apr 23, 2020

This is an initial implementation of inline text formatting.

Fixes #413.
Fixes #1007.
Fixes #925.

TL;DR:

It works for all the properties: bold, italic, underline font weight, letter spacing and text color, but there's still some stuff to do - however everything can and will be fixed! Also, there's a couple of open questions, that need be answered to fully implement.

Goal

The goal is to be able to update font weight (and bold as a subset of that), italic, underline, text color and letter-spacing both inline and on the entire text field.

This also includes that the text panel is aware of which of these features are currently set to which values while editing the text field - so when selecting text, that "B" button is correctly pressed or not based on whether the currently selected text is all (some) bold.

All of this has to work as before for multiple text fields as well and things should work when pasted too.

Implementation details

Structure

This introduces a new provider located just inside the CanvasProvider in Workspace.

Also, the entire rich text editor is moved to a new component that is then utilized by the text edit component. We might not need this component elsewhere, but the split made sense.

One caveat is, that the rich text provider directly accesses the editingElementState from the CanvasProvider. It would probably be cleaner to pass this in all the way from the text edit component. I might do that in the future.

The text edit component now only updates the HTML on unmount.

Formatting

This PR also completely overrules draftjs' built-in formatting and creates a completely new formatting setup with custom style names. There's a parser, a serializer and a set of rules for display.

This also re-implements the logic as to what it means to press "italic" (both by shortcut and button) by answering the question "is current selection italic or not?" explicitly. It seems like a trivial question, and kind of is for italic, but for bold is a lot more complex - what if some characters are semibold, others are black - what happens when you press the "bold" button? All this is answered in code in styleManipulation.

These same rules will be applied to the entire text field (in upcoming posts) as well as partial selection (which works now for a subset of the properties).

Status

This is the progress so far:

  • Bold by shortcut and button
  • Italic by shortcut and button
  • Underline by shortcut and button
  • Bold on entire text field
  • Italic on entire text field
  • Underline on entire text field
  • Font weight on selection
  • Font weight on entire text field
  • All the above "entire text field" rules applied to multiple selected text fields.
  • Deprecate old properties not used anymore (fontStyle, textDecoration, bold, fontWeight).
  • All the above for the "empty" selection. That is, if you're in edit mode but haven't selected anything, just placed your cursor somewhere, and press "bold" and "red", the next text you write at that point should now correctly start out as "bold" and "red". Seems easy enough to do though - just check if selection is collapsed and if so, apply inline style change to override rather than selection.
  • Letter spacing on selection
  • Letter spacing on entire text field (+multi-selection)
  • Color on selection
  • Color on entire text field (+multi-selection)
  • Deprecate old properties not used anymore (color, letterSpacing).
  • Display (multiple) in font weight dropdown when it's the case
  • Migrate old properties to new inline syntax (which will include a fun new exercise on merging diverging settings in fontWeight versus bold - I'm thinking that if fontWeight=400 and bold wrap everything in font-weight:700, else use actual font weight). Plus intensive unit test!
  • Refactor and cleanup code so text formatting options are in verticals, not horizontals (adding color as a new option required changing 7-8 files, should just be a single file).
  • Display "faux-selection" background when editor is unfocused
  • Unit test formatters
  • Unit test style manipulation functions
  • Make sure color presets still work for text fields – both for entire text field and selection. And both for adding and (re)using presets.
  • Update and amend unit tests for color presets
  • Fix font weights in text panel presets
  • Export proper font summary for text field for proper client-side font inclusion as added in Client-side font declarations #1273
  • Unit test text style panel section
  • Unit test font weight panel section
  • Unit test text color panel section
  • Integration test all this in connection

Known bugs:

  • Proper parsing of multiple styles applied to the same character (due to Allow multiple inlineStyles to be returned by customInlineFn sstur/draft-js-utils#155 going unmerged) - will fix with patch-package in a future commit) [bug can be seen by making some text both italic and bold, exiting edit mode and re-entering edit mode] Fixed in 854510f
  • Pasting formatted content doesn't correctly "reformat" to our new styles (will fix in future commit)
  • When creating inline style override using controls in the design panel, previous inline style overrides will be lost. Example: Move cursor to some non-bold, non-italic word without selecting anything. Press "bold" button (sets bold in inline override). Now press "italic" button (removes bold from inline override due to focus loss, but then sets italic override). This can be fixed, but it's a bit tricky - it's about remember the inline style override when losing focus, and merging old style back in when focus is regained. There's an open PR for this in Prevent Discarding InlineStyleOverride on focus change facebookarchive/draft-js#2022, but we can work around it without waiting for it to get merged.
  • When a single text element is selected, typing a single letter on the keyboard should make the text element go into edit mode with focus and the typed key replacing the entire old content. This is currently broken for unknown reasons.
  • When inline-selection covers text of all the same color but in a text field with multiple colors, it is not currently possible to add the currently selected color to neither text style nor text color presets.

Possible optimizations:

  • Output proper semantic HTML (currently using <span /> with class names and inline styles for all formatting) – proper semantic DOM is not easy due to limitations to draft-js-utils, where only one node can be returned per styled section, where something both bold and italic should have two surrounding nodes (thus the single <span /> used now with multiple styles and class names).
  • Don't directly access canvas provider from inside rich text provider.

Open questions:

  • What should the font weight drop down display, when multiple font weights are present in selection? (my current idea is to push a disabled <option>(multiple)</option> to the front of the list and mark it as selected) added as a proper task above
  • What should the letter spacing input display, when multiple letter spacings are present in selection? (currently going for (multiple) as used in inputs elsewhere) already handled by component
  • What should the font color component display, when multiple color are present in selection? (will implement some kind of (multiple) logic which currently doesn't exist for color display as far as I know). already handled by component
  • What happens to invalid font weights when you change font family? Not sure how to handle this yet.
  • Should you be able to reset color and letter spacing by keyboard shortcut?
  • Should you be able to set different font weights (other than bold or non-bold) by keyboard shortcut?

Demo

inline-text-editing-v1
(when you see the text change without the mouse being over the buttons, it's because I'm using shortcuts - forgot to include the on-screen key-logger for this video)

@github-actions
Copy link
Contributor

github-actions bot commented Apr 23, 2020

Size Change: +4.22 kB (0%)

Total Size: 830 kB

Filename Size Change
assets/js/edit-story.js 401 kB +3.49 kB (0%)
assets/js/stories-dashboard.js 423 kB +734 B (0%)
ℹ️ View Unchanged
Filename Size Change
assets/css/edit-story.css 3.04 kB 0 B
assets/css/stories-dashboard.css 3.04 kB 0 B

compressed-size-action

@barklund barklund mentioned this pull request Apr 23, 2020
@codecov
Copy link

codecov bot commented Apr 23, 2020

Codecov Report

Merging #1323 into master will not change coverage.
The diff coverage is n/a.

Impacted file tree graph

@@            Coverage Diff            @@
##             master    #1323   +/-   ##
=========================================
  Coverage     59.38%   59.38%           
  Complexity      216      216           
=========================================
  Files           555      555           
  Lines          9109     9109           
=========================================
  Hits           5409     5409           
  Misses         3700     3700           

@barklund
Copy link
Contributor Author

Most recent state can now also do font weight - both per selection and entire text field.

Also, multiple text fields are supported for bold, italic, underline and font weight.

Please note how the value in the font weight dropdown updates as selection and values change, also how the values of the B/I/U buttons update:
itf_font-weights

package.json Outdated Show resolved Hide resolved
@barklund barklund self-assigned this Apr 24, 2020
@barklund barklund added Elements: Text Group: Style Panel Type: Enhancement New feature or improvement of an existing feature labels Apr 24, 2020
Morten Barklund added 6 commits April 24, 2020 12:13
Actually the whole `forceFocus` variable was superfluous - `EditorState.forceSelection` autimatically forces focus to the editor. And selection was remembered, just not visible while unfocused, so things still work as expected.
Font weight dropdown simply gets a new placeholder, as the placeholder will only be shown, when there's multiple font weights selected.

For now, font weight logic is removed from font selector (but must be readded in a new version later), and tests are updated.
@barklund
Copy link
Contributor Author

barklund commented May 4, 2020

@barklund: Can reproduce now successfully the editor crashing with this:

  1. Add general color to a Text element
  2. Double click into selecting part of the text while the element is previously selected
  3. Switch to Highlight background mode.

Found and fixed the underlying issue this time - it's the faux selection removal, that caused errors if the component was remounted. Fixed in e03baf3.

Copy link
Contributor

@dvoytenko dvoytenko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I posted a few more responses on the existing threads. But otherwise my only question is what to do with !important styles for the output (and lesser extend the editor as well). Otherwise, I'm ready to approve this.

@barklund
Copy link
Contributor Author

barklund commented May 5, 2020

I posted a few more responses on the existing threads. But otherwise my only question is what to do with !important styles for the output (and lesser extend the editor as well). Otherwise, I'm ready to approve this.

@dvoytenko, I think I've addressed most/all of your points now - can you approve, so we can merge or how do you feel?

@barklund barklund requested a review from dvoytenko May 5, 2020 14:55
Copy link
Contributor

@dvoytenko dvoytenko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved, but at least one thing I'd like to change to add useMemo on valid content.

assets/src/edit-story/elements/text/output.js Outdated Show resolved Hide resolved
assets/src/edit-story/elements/text/display.js Outdated Show resolved Hide resolved
Copy link
Contributor

@dvoytenko dvoytenko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two more things noticed.

assets/src/edit-story/elements/text/display.js Outdated Show resolved Hide resolved
// Setting the text color of the entire block to black essentially removes all inline
// color styling allowing us to apply transparent to all of them.
const backgroundContent = useMemo(
() => getHTMLFormatters().setColor(content, createSolid(0, 0, 0)),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the createSolid missing an alpha 0?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No - we apply solid opaque black, which is default meaning that no color style will be applied to the entire text field. Thus allowing us to overwrite the whole thing with color:transparent.

@barklund barklund merged commit dd191a4 into master May 6, 2020
@barklund barklund deleted the feature/inline-rich-text branch May 6, 2020 18:13
obetomuniz added a commit that referenced this pull request May 6, 2020
* master: (53 commits)
  Inline text formatting (#1323)
  Bump terser-webpack-plugin from 2.3.6 to 3.0.1 (#1597)
  Allow disabling warning on exit in development (#1176)
  fixing indent that was missed by automation
  Deploy plugin bundle to wiki repo for easier QA (#1590)
  Fix initial height of preset panel (#1591)
  Fixes editor resizing after fullbleed (#1553)
  More error handling
  Fix file drag & drop crash for unsupported media types (#1431)
  Improve test
  Bump polished from 3.6.1 to 3.6.2 (#1577)
  Bump react-transition-group from 4.3.0 to 4.4.0 (#1565)
  Remove Delete Page shortcut tooltip (#1574)
  renaming filteredStories to just stories. they are not filtered.
  updating typeahead input and options for new designs. New colors, tighter space, different expanded view. Removing option to filter internally through typeahead since we do all of that outside of the component. some styled component cleanup
  Remove wp element.
  Bump @testing-library/dom from 7.2.2 to 7.3.0 (#1563)
  Remove wp element
  Lints in tests
  Add more tests
  ...
obetomuniz added a commit that referenced this pull request May 6, 2020
* master: (109 commits)
  Inline text formatting (#1323)
  Bump terser-webpack-plugin from 2.3.6 to 3.0.1 (#1597)
  Allow disabling warning on exit in development (#1176)
  fixing indent that was missed by automation
  Deploy plugin bundle to wiki repo for easier QA (#1590)
  Fix initial height of preset panel (#1591)
  Fixes editor resizing after fullbleed (#1553)
  More error handling
  Fix file drag & drop crash for unsupported media types (#1431)
  Improve test
  Bump polished from 3.6.1 to 3.6.2 (#1577)
  Bump react-transition-group from 4.3.0 to 4.4.0 (#1565)
  Remove Delete Page shortcut tooltip (#1574)
  renaming filteredStories to just stories. they are not filtered.
  updating typeahead input and options for new designs. New colors, tighter space, different expanded view. Removing option to filter internally through typeahead since we do all of that outside of the component. some styled component cleanup
  Remove wp element.
  Bump @testing-library/dom from 7.2.2 to 7.3.0 (#1563)
  Remove wp element
  Lints in tests
  Add more tests
  ...
obetomuniz added a commit that referenced this pull request May 7, 2020
barklund pushed a commit that referenced this pull request May 19, 2020
#1275)

* Add resize support to box when changing font-face on display/edit mode

* Cover unicode chars, font-weight, font-style

* Add ((MULTIPLE)) support proposal

* Improve docs.

* Fix problematic rest approach.

* Add fontSize support. Remove content support. Add a better support for MULTIPLE. Improve useLoadFontFiles.js

* Update textStyle tests

* Force display=auto on @font-face declaration while loading fonts from Google Fonts.

* Fix typo

* Add codecov to useLoadFontFiles

* Update tests to match new APIs proposed after merge.

* Address PR reviews

* Address some PR reviews.

* Adjustments after #1323 merge. Revert content as parameter to load font (To address #923).

* Address recent PR review

* Improve code performance/reusability. Thanks @dvoytenko

* Clean up promise logic a bit

Co-authored-by: Pascal Birchler <pascalb@google.com>
Co-authored-by: Morten Barklund <morten.barklund@xwp.co>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Elements: Text Group: Style Panel Type: Enhancement New feature or improvement of an existing feature
Projects
None yet
6 participants