-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
Writing Flow/Rich Text: unify split logic #54543
Conversation
Size Change: +665 B (+0.04%) Total Size: 1.74 MB
ℹ️ View Unchanged
|
Flaky tests detected in f950d2f. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/8922587588
|
e317df8
to
193ba19
Compare
f4949be
to
92a26b3
Compare
ef85e8d
to
329a41d
Compare
6dab2f8
to
817802d
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.
UX/writing flow wise, this feels solid, with more expected results on copying/pasting across multiple blocks.
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.
Maybe we should leave the onSplit
callback if the block has more specific needs for this logic.
A good example would be the button block. Currently, it copies all attributes on the split action, including URLs. Which I think is a bug; only styling attributes and text included on the split action should be copied.
@Mamaduka Right, that's a good point. I don't like keeping onSplit though, maybe you should be able to opt-out of attributes in the block supports key? Or opt-in? What do you think?
Or maybe a transform? |
@ellatrix, I thought we'd have to support the legacy method for backward compatibility. |
@Mamaduka I meant, how to incorporate it in the new way? |
defaultView.addEventListener( 'copy', onCopy ); | ||
defaultView.addEventListener( 'cut', onCopy ); |
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.
This comment is a followup and context for my comment on the WP Dev Blog post that mentions this change, where I expressed confusion about this logic and its settings in My comment, for convenience:
Seeing this comment, @ellatrix asked to see my code to help clarify. Here is my block code:
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "baz-qux/page-tagline",
"title": "Page Tagline",
"category": "baz-qux",
"icon": "megaphone",
"description": "A short introduction to the page.",
"keywords": ["intro", "excerpt", "description"],
"supports": {
"anchor": false,
"align": false,
"splitting": false
},
"editorScript": "file:./page-tagline.js"
}
import metadata from './block.json';
const { registerBlockType } = wp.blocks;
const { useBlockProps, RichText } = wp.blockEditor;
registerBlockType( metadata.name, {
attributes: {
content: {
type: 'string',
source: 'text',
selector: 'p'
}
},
edit: (props) => {
return <RichText
{ ...useBlockProps() }
tagName="p"
className="wp-block wp-block-paragraph page-tagline"
value={ props.attributes.content }
placeholder="Add tagline"
onChange={ ( newContent ) => props.setAttributes({ content: newContent }) }
/>;
},
save: (props) => {
return <RichText.Content
{ ...useBlockProps.save() }
tagName="p"
className="page-tagline"
value={ props.attributes.content }
/>;
}
} ); Thank you for your help! |
Hi! I tried your code, and for me it looks like Now, you are right that setting <RichText
{ ...useBlockProps() }
identifier="content" This should allow the block to be split into two blocks. We should indeed mention that in documentation. It's also worth noting that if you'd like to allow merging these blocks back together, you should provide a merge( attributes, attributesToMerge ) {
return {
content:
( attributes.content || '' ) +
( attributesToMerge.content || '' ),
};
},
edit: function Edit( props ) {
return (
<RichText
{ ...useBlockProps() }
identifier="content"
onMerge={ props.mergeBlocks } |
I've added docs here: #63016 |
Thank you for the followup! This is helpful. I am now getting the behavior I expect, and it's nice that hitting Enter at the end of a block that has (Am I correct in assuming that the One more thing: I'm unclear from the discussion on this ticket whether |
As far as I know, there's no
|
Another regression: It appears that it is no longer possible to paste text from outside WordPress into non-modal classic block. See #64771. |
@ellatrix Can we please have some input here? #65274 (comment) |
Hi everyone. Theme / plugin developer here. Thanks for all the work you do on this project :) I have a question, from what I can tell this might be the best place to post it. With the changes to how onSplit works, I don't have access to the attributes of the new block that's created on split (as I understand). Could we add an option to the splitting block.json setting to have the new block copy the attribute values of the one being copied? So new block has all the same attribute values of old block. @ellatrix your comment here #54543 (comment) seems to reference this, but I wasn't sure if I fully understood. Usage: I have a custom paragraph block with an alignment attribute. With the new split behavior, if the original block is set to center align, the new block comes in with the align set to left, the block's default value. The author has set the alignment to "center" each time they add a new paragraph. Kind of annoying. Looks like I could have resolved this with the old implementation. Alternatively, is there a way to set default attributes on the new block added on split? I've been searching around, but haven't found any good info on this. Hence my post here. Thanks. |
Hm, when I split a core paragraph block, it keeps the alignment. Even when I split a core heading block with alignment, it keeps it on the newly created paragraph. Could you share some minimal block code that triggers the problem? |
Hey @ellatrix thanks for the reply :) I've included the block.json and edit function below. With this code, on split, the attribute "align" is set to the default value of "left" when the new block is added to the editor. Please let me know if there's any additional code or examples I can provide. Thanks. block.json {
"apiVersion": 3,
"name": "thirtysix-blocks/paragraph",
"title": "Paragraph",
"description": "Displays a rich text editor.",
"category": "layout",
"textdomain": "thirtysix-blocks",
"editorScript": "file:./index.js",
"viewScript": "file:./view.js",
"style": "file:./style-index.css",
"editorStyle": "file:./index.css",
"viewStyle": "file:./view.css",
"ancestor": [
"thirtysix-blocks/text",
"thirtysix-blocks/banner",
"thirtysix-blocks/column",
"thirtysix-blocks/posts"
],
"attributes": {
"text": {
"type": "string"
},
"align": {
"type": "string",
"default": "left"
},
"client_id": {
"type": "string"
}
},
"supports": {
"color": {
"text": true,
"background": false
},
"typography": {
"fontSize": true
},
"renaming": false,
"customClassName": false,
"splitting": true
}
} edit.js import "./editor.scss";
import "./style.scss";
import { useEffect } from "@wordpress/element";
import { useBlockProps, RichText } from "@wordpress/block-editor";
import ParagraphInspectorControls from "./_inspector-controls";
import ParagraphBlockControls from "./_block-controls";
export default function Edit({ attributes, setAttributes, clientId }) {
const blockProps = useBlockProps({
style: {
color: attributes.color,
textAlign: attributes.align,
},
});
useEffect(() => {
setAttributes({ client_id: clientId });
}, [clientId]);
return (
<>
<ParagraphInspectorControls
attributes={attributes}
setAttributes={setAttributes}
/>
<ParagraphBlockControls
attributes={attributes}
setAttributes={setAttributes}
/>
<section {...blockProps}>
<RichText
value={attributes.text}
allowedFormats={[
"core/text-color",
"core/bold",
"core/italic",
"core/link",
"core/superscript",
"core/subscript",
]}
tagName="p"
identifier={"text"}
placeholder="Lorem ipsum dolor sit amet, consectetur adipiscing elit..."
onChange={(value) => setAttributes({ text: value })}
/>
</section>
</>
);
} |
Hi @keepyourreceipt! Unfortunately I will need more information, because I don't see an alignment button. Here's the code you provided that is executable in the console: wp.blocks.registerBlockType('thirtysix-blocks/paragraph', {
apiVersion: 3,
name: "thirtysix-blocks/paragraph",
title: "Paragraph",
description: "Displays a rich text editor.",
category: "layout",
textdomain: "thirtysix-blocks",
attributes: {
text: {
type: "string"
},
align: {
type: "string",
default: "left"
},
client_id: {
type: "string"
}
},
supports: {
color: {
text: true,
background: false
},
typography: {
fontSize: true
},
renaming: false,
customClassName: false,
splitting: true
},
edit: function Edit({ attributes, setAttributes, clientId }) {
const blockProps = wp.blockEditor.useBlockProps({
style: {
color: attributes.color,
textAlign: attributes.align,
},
});
wp.element.useEffect(() => {
setAttributes({ client_id: clientId });
}, [clientId]);
return wp.element.createElement(
'section',
blockProps,
wp.element.createElement(wp.blockEditor.RichText, {
value: attributes.text,
allowedFormats: [
"core/text-color",
"core/bold",
"core/italic",
"core/link",
"core/superscript",
"core/subscript",
],
tagName: "p",
identifier: "text",
placeholder: "Lorem ipsum dolor sit amet, consectetur adipiscing elit...",
onChange: (value) => setAttributes({ text: value })
})
);
}
}); Could you add your alignment functionality to this? |
What/why?
Fixes #53076: when pasting blocks, the split block should be merged with the pasted blocks.
This PR aims to unify split logic (enter key and paste). Currently we have logic both in the block editor generally and rich text specifically when it contains selection. This PR moves all the logic to the block editor (writing flow), adding a block.json setting that tells us if we can split a block.
This removes the need for the block to pass an
onSplit
function, the behaviour can be turned on with just a setting. This is also quite convenient for extenders wishing to recreate the core blocks.This will also allow us to solve splitting for paste more easily, which is actually a split operation + merging the ends together.
How?
One implementation details is that change of how rich text listens for key events. Right now in trunk, the event listener is attached to the rich text node, so writing flow (listening on a wrapper node) cannot prevent default behaviour. To fix this, rich text can listen to the document instead. This is how it works for browser behaviour too. Default behaviour is cancelable until the event bubbled all the way through the DOM. Rich text is meant to be a sort of polyfill for the native
contenteditable
API: actions should be cancelable.Testing Instructions
Copy a few paragraphs and paste them into another paragraph. The result should be:
Testing Instructions for Keyboard
Screenshots or screencast