-
Notifications
You must be signed in to change notification settings - Fork 6
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
Add NestedElementField #324
Conversation
as we expect the child editor to reflect parent's behaviour
as its content will be a part of the document proper
…eateNestedFieldView from package
…f blur for use in main prosemirror editor (in program consuming prosemirror-elements)
meant eslint was unhappy with the naming convention
As discussed before, I'm unsure on the best name for this. Perhaps |
I went with |
getPos, | ||
offset, | ||
decorations, | ||
// Allow plugins without a plugin key, but exclude those that are explicitly blocked |
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.
// Allow plugins without a plugin key, but exclude those that are explicitly blocked | |
Disallow plugins which have a plugin key, or are explicitly blocked. |
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 this is clearer, but not sure, feel free to ignore.
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 my initial comment is not great here (mostly duplicating the code), I think the useful information would actually be:
"Keys are an optional unique identifier for plugins; we should expect to encounter plugins without keys."
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.
Currently more plugins exist without keys than with keys in Composer, and they are likely to be doing important work. That's why I've gone with a blocklist rather than an allowlist.
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.
@rhystmills and I paired on this briefly to clarify the code. Worth noting my suggestion above was incorrect!
demo/index.ts
Outdated
/* | ||
* We must allow 2 text elements to exists side by side | ||
* so that when we delete an element we can then join it. | ||
*/ |
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.
Not entirely sure I understand this. Is this just a general bug that's being fixed here, or is it related to the nested elements?
Also, the comment here mentions two text elements but the content field is talking in terms of blocks, just thought I would flag in case that's unintended.
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 - I think I unintentionally committed that after borrowing the base node spec from Composer's block editor.
Definitely not relevant to the PR!
const nodeSpec = getNodeSpecForField( | ||
"exampleElement", | ||
"exampleNestedElementField", | ||
createNestedElementField({ content: "element*" }) |
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.
Elsewhere this is defined with content as block*
, is this an inconsistency?
I would have thought that a nested element would contain element*
, but I suppose the nested elements are also nested in blocks?
I've said nested too many times... 🪆
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.
🪆
The top level block*
content expression is specific to the demo in prosemirror-elements
- element+
/element*
is closer to what we'll see in flexible-content where the top level editor has an element+
content expression. At the moment there's a bit of a compromise to allow Composer and the demo to both work.
It would be good to align the demo more closely with what we see in flexible-content so we don't have this discrepancy. I could add that as a follow-up card to follow this one, or we could fix in this PR?
The demo could do with some love in general, e.g. having far fewer elements.
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.
That makes sense and sounds good to me. The difference between demo and Composer does confuse me from time to time (the Alt Styles element in this PR for example threw me).
src/plugin/field.ts
Outdated
@@ -55,6 +55,8 @@ export const getFieldsFromNode = <FDesc extends FieldDescriptions<string>>({ | |||
const fieldDescription = fieldDescriptions[fieldName]; | |||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- strictly, we should check. | |||
if (!fieldDescription) { | |||
console.log({ fieldNode, fieldDescriptions, fieldName }); |
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.
Might not be needed?
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.
Tis gone.
import { createRepeaterField } from "../../fieldViews/RepeaterFieldView"; | ||
import { createTextField } from "../../fieldViews/TextFieldView"; | ||
import { RepeaterFieldMapIDKey } from "../constants"; | ||
import { createEditorWithElements, createNoopElement } from "../test"; | ||
import { maxLength, required } from "../validation"; | ||
|
||
export const elements = { | ||
nestedElement: createNoopElement({ | ||
content: createTextField({ |
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.
Interested in this as it seems to be doing something similar but different to the nestedElementField
below. Also it's called nestedElement
, but seems to be a text no-op element with a text field? Is that what a nestedElement
is, secretly?
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.
Unclear naming on my part I think - this is essentially a test element, separate from the 'example' element used in the tests, to put in the nestedElementField
in the tests.
I think exampleElementToNest
might be better. Have now renamed.
I can't copy / cut an element that is nested - I can select it, but the copy and cut functions don't seem to work. I don't know if this is related to the repeater fields bug, or is something separate. |
I also can't reorder nested elements using the single arrows (I can using the double arrows). |
This might be an issue with the demo tool, but if I delete all the text in a Nested Element Field, and there's another element nested, I can't edit the field (or can't click into it to type / add elements). |
I see you've mentioned this as work for a follow-up PR. 👍 |
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.
A great, hefty piece of work that moves us closer to our OKR, amazing stuff.
There are a few bugs and edge cases, but I think it makes sense to fix forwards and address these in smaller PRs. It would be good too to document some of these changes in a README somewhere; at a glance I found myself getting confused between Nested and Repeater fields, but the code is also fairly self-explanatory.
4a9e3ed
to
33a5f04
Compare
Co-authored-by: Tom Richards <tom.richards@guardian.co.uk>
33a5f04
to
74a837d
Compare
…ocklist with allowedPlugin list Co-authored-by: Freddie Preece <40991816+fweddi@users.noreply.github.com>
…w` since it's just a vehicle for other elements so doesn't need to worry about decorations itself Co-authored-by: Rhys Mills <34686302+rhystmills@users.noreply.github.com>
Co-authored-by: Freddie Preece <40991816+Fweddi@users.noreply.github.com>
…ed to NestedField for decoration management
// We use a disallow list (rather than an allow list) because we expect most plugins to work, | ||
// and only want to disallow those that cause problems. |
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.
We'll need to remove this comment now we've changed to an allowlist.
ee2c43b
to
b0d8e0e
Compare
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.
Subsequent nodes of the repeater field now work as expected 👍
There are still some small issues around decorations but I think this puts us in a good place to merge.
Co-authored with @davidfurey and @jonathonherbert - first few commits were David's but I unintentionally rebased his name out of the commit history.
What does this change?
This PR adds the nested element field. This field is a rich text editor that is itself able to contain elements. This will enable us to build larger, 'structural' elements within Composer that can contain elements like images and videos.
There is some further work to do in future PRs:
This PR could do with some tests for nested element fields - I'll add some when I'm back from holiday.
How to test
yarn start
.You may also want to test this PR in Composer via yalc with: https://github.com/guardian/flexible-content/pull/4492