-
Notifications
You must be signed in to change notification settings - Fork 0
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
Get minimum ProseMirror editor working #1
Conversation
Co-authored-by: Jonathon Herbert <jonathon.herbert@guardian.co.uk>
…rm to legacy <b> and <i> markup
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Epic PR! I've made a few suggestions, and haven't yet run through your test steps.
Apache License | ||
Version 2.0, January 2004 | ||
http://www.apache.org/licenses/ | ||
Copyright 2023 Guardian News and Media |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where did this license come from?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MIT license from: https://opensource.org/license/mit/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great. Surprised that it isn't normal for us to state that, but happy for us to stick with our convention
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like we do in some repos, I'll mention it for the convenience of others viewing the license.
README.md
Outdated
It is also designed to meet the features required by the rich text editor in [media-atom-maker](https://github.com/guardian/media-atom-maker/blob/3391bfd82ad27848dc9e06a08628320ce481006e/public/video-ui/src/components/FormFields/RichTextEditor.tsx#L2). | ||
|
||
It aims to provide: | ||
- A `RichTextEditor` serialising to one-to-many <p> tags containing the markip below - supporting only the requirements of the above editors, at least until we have further use cases. Specifically, from the first three editors: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you might need to escape <p>
to make this render correctly. Also, do you really mean <p>
here?
Typo:markip
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whoops - yes it should be <p>
but not be markip.
README.md
Outdated
- unlinking | ||
- strikethrough | ||
- superscript and subscript | ||
`media-atom-maker` adds some more requirements: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably need a -
here
package.json
Outdated
{ | ||
"name": "@guardian/prosemirror-editor", | ||
"version": "0.1.0", | ||
"description": "Providing implementations of ProseMirror for use in our tools.", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
our -> the Guardian ?
shouldAcceptCopiedText: boolean; | ||
} | ||
|
||
export const RichTextEditor = ({ value, onUpdate, config, label, shouldAcceptCopiedText = false }: RichTextEditorProps) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is a default value required for shouldAcceptCopiedText, which is a required field?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wise, optional now
src/ts/richtext/config.ts
Outdated
allowedMarks: string[]; | ||
}; | ||
|
||
type FlatTextMark = "strong" | "strike" | "em"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could avoid having to write these out again on line 27 with:
const flatTextMarks = ["strong", "strike", "em"] as const
type FlatTextMark = typeof flatTextMarks
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did start with this - but I had trouble getting Typescript happy with partial variants of the flatTextMarks
- it should be valid to have a customFlatTextConfig that only supports 'strong', for example. A greater Typescripter might find better way to do that than what I've ended up with - possibly similar to the above.
allowedNodes: string[] | ||
): OrderedMap<NodeSpec> => { | ||
let map = OrderedMap.from<NodeSpec>({}); | ||
nodes.forEach((key, node) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't it a shame that OrderedMap doesn't have filter
?
You could write your own and avoid the duplicated lines filterNodes and filterMarks. But for 2 uses, possibly not worth the complexity
src/ts/richtext/menu.ts
Outdated
import { isInNode, toggleBulletListCommand } from "./utils/listsHelpers"; | ||
import { linkItemCommand, unlinkItemCommand } from "./utils/command-helpers"; | ||
|
||
export const cmdItem = (cmd: Command, options: Partial<MenuItemSpec>) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To avoid having to cast options.title as string:
export const cmdItem = (cmd: Command, options: Partial<MenuItemSpec>) => { | |
export const cmdItem = (cmd: Command, options: Partial<MenuItemSpec> & { title: string }) => { |
(Applies multiple times in this file)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Delightful, implemented now.
src/ts/richtext/setup.ts
Outdated
// to format the outputHtml as an html string rather than a document fragment, we are creating a temporary div, adding it as a child, then using innerHTML which returns an html string | ||
const tmp = document.createElement('div'); | ||
tmp.appendChild(outputHtml); | ||
if (onChange) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is any of the work on line 45-49 valuable if onChange is undefined? Also, the types imply that onChange cannot be undefined?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, good point. Not sure how that made it's way in - think the code may be borrowed from my prosemirror
implementation in media-atom-maker
and can't remember why past me wrote it. I'll remove the if condition.
}; | ||
|
||
export const isTooLong = (value: string, maxWordLength: number): boolean => { | ||
const wordLength = getWords(value).reduce((length, word) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I appreciate that this is copy and pasted from elsewhere, but as far as I can see this calculates the total number of characters in all of the words in value
rather than just a count of the number of words in value
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, looks like it - it's a bit of validation from media-atom-maker most recently updated in guardian/media-atom-maker#1127 . Naming could be better - perhaps would be something like tooManyCharactersInAllWords
would be an improvement.
It looks like there's an assumption based into the original logic that spaces aren't including in Youtube's video title character limit, which might be wrong. Seems like it would be an odd restriction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No explanation of the odd logic in the original PR. I'd be inclined to go for a simple .length
on the string value
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm removing these functions for now as they're currently unused -when length validation is added I'll make it simpler.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great. I suspect there is an error in the original PR rather than the logic being intentionally odd. I'll open a PR in media-atom-maker to fix
Co-authored-by: David Furey <david@furey.me.uk>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
Co-authored with @samanthagottlieb
What does this change?
This gets a basic ProseMirror editor working. The aim is to create a general purpose editor that satisfied the requirements of:
media-atom-maker is a lower priority because it's already been moved to ProseMirror from Scribe (so there's no Scribe-based vulnerability), but we want to make this package compatible with media-atom-maker's requirements so it can be ported over in the future, so that the editors in the four repositories can all be managed via this one package.
This branch has been tested locally in tagmanager via
yalc
. The package has not yet been deployed tonpm
.Things this PR doesn't have, that we will want to add in future PRs:
npm
package.Currently, vanilla css styles are included in the built
dist
and need to be imported in the target package. Is this a good setup? (A google chat thread led to recommendations againstemotion
and I wanted to keep this package as un-opinionated as possible).How to test
yarn yalc
from the root of the projecttagmanager
locally.yalc add @guardian/prosemirror-editor
https://tagmanager.local.dev-gutools.co.uk/api/tag/71301
. Does the description sent in that request look valid? Is the bold text serialised as<b>
tags and the italic text as<i>
tags? (It should). Are new paragraphs serialised as new<p>
tags? (They should).