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

Writing Flow/Rich Text: unify split logic #54543

Merged
merged 8 commits into from
May 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions docs/reference-guides/core-blocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ Prompt visitors to take action with a button-style link. ([Source](https://githu
- **Name:** core/button
- **Category:** design
- **Parent:** core/buttons
- **Supports:** anchor, color (background, gradients, text), interactivity (clientNavigation), shadow (), spacing (padding), typography (fontSize, lineHeight), ~~alignWide~~, ~~align~~, ~~reusable~~
- **Supports:** anchor, color (background, gradients, text), interactivity (clientNavigation), shadow (), spacing (padding), splitting, typography (fontSize, lineHeight), ~~alignWide~~, ~~align~~, ~~reusable~~
- **Attributes:** backgroundColor, gradient, linkTarget, placeholder, rel, tagName, text, textAlign, textColor, title, type, url, width

## Buttons
Expand Down Expand Up @@ -359,7 +359,7 @@ Introduce new sections and organize content to help visitors (and search engines

- **Name:** core/heading
- **Category:** text
- **Supports:** __unstablePasteTextInline, align (full, wide), anchor, className, color (background, gradients, link, text), interactivity (clientNavigation), spacing (margin, padding), typography (fontSize, lineHeight)
- **Supports:** __unstablePasteTextInline, align (full, wide), anchor, className, color (background, gradients, link, text), interactivity (clientNavigation), spacing (margin, padding), splitting, typography (fontSize, lineHeight)
- **Attributes:** content, level, placeholder, textAlign

## Home Link
Expand Down Expand Up @@ -426,7 +426,7 @@ Create a list item. ([Source](https://github.com/WordPress/gutenberg/tree/trunk/
- **Category:** text
- **Parent:** core/list
- **Allowed Blocks:** core/list
- **Supports:** interactivity (clientNavigation), spacing (margin, padding), typography (fontSize, lineHeight), ~~className~~
- **Supports:** interactivity (clientNavigation), spacing (margin, padding), splitting, typography (fontSize, lineHeight), ~~className~~
- **Attributes:** content, placeholder

## Login/out
Expand Down Expand Up @@ -531,7 +531,7 @@ Start with the basic building block of all narrative. ([Source](https://github.c

- **Name:** core/paragraph
- **Category:** text
- **Supports:** __unstablePasteTextInline, anchor, color (background, gradients, link, text), interactivity (clientNavigation), spacing (margin, padding), typography (fontSize, lineHeight), ~~className~~
- **Supports:** __unstablePasteTextInline, anchor, color (background, gradients, link, text), interactivity (clientNavigation), spacing (margin, padding), splitting, typography (fontSize, lineHeight), ~~className~~
- **Attributes:** align, content, direction, dropCap, placeholder

## Pattern placeholder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,6 @@ _Optional._ `Text` won't insert line breaks on `Enter` if set to `true`.
_Optional._ Placeholder text to show when the field is empty, similar to the
[`input` and `textarea` attribute of the same name](https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/HTML5_updates#The_placeholder_attribute).

### `onSplit( value: String ): Function`

_Optional._ Called when the content can be split, where `value` is a piece of content being split off. Here you should create a new block with that content and return it. Note that you also need to provide `onReplace` in order for this to take any effect.

### `onReplace( blocks: Array ): Function`

_Optional._ Called when the `Text` instance can be replaced with the given blocks.
Expand Down
8 changes: 8 additions & 0 deletions packages/block-editor/src/components/iframe/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,15 @@ function Iframe( {
event.currentTarget.ownerDocument !==
event.target.ownerDocument
) {
// We should only stop propagation of the React event,
// the native event should further bubble inside the
// iframe to the document and window.
// Alternatively, we could consider redispatching the
// native event in the iframe.
const { stopPropagation } = event.nativeEvent;
event.nativeEvent.stopPropagation = () => {};
event.stopPropagation();
event.nativeEvent.stopPropagation = stopPropagation;
bubbleEvent(
event,
window.KeyboardEvent,
Expand Down
4 changes: 0 additions & 4 deletions packages/block-editor/src/components/rich-text/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,6 @@ _Optional._ Disables inserting line breaks on `Enter` when it is set to `true`

_Optional._ By default, a line break will be inserted on <kbd>Enter</kbd>. If the editable field can contain multiple paragraphs, this property can be set to create new paragraphs on <kbd>Enter</kbd>.

### `onSplit( value: String ): Function`

_Optional._ Called when the content can be split, where `value` is a piece of content being split off. Here you should create a new block with that content and return it. Note that you also need to provide `onReplace` in order for this to take any effect.

### `onReplace( blocks: Array ): Function`

_Optional._ Called when the `RichText` instance can be replaced with the given blocks.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,37 @@
*/
import { ENTER } from '@wordpress/keycodes';
import { insert, remove } from '@wordpress/rich-text';
import { getBlockTransforms, findTransform } from '@wordpress/blocks';

/**
* Internal dependencies
*/
import { store as blockEditorStore } from '../../../store';
import { splitValue } from '../split-value';

export default ( props ) => ( element ) => {
function onKeyDown( event ) {
if ( event.target.contentEditable !== 'true' ) {
function onKeyDownDeprecated( event ) {
if ( event.keyCode !== ENTER ) {
return;
}

const { onReplace, onSplit } = props.current;

if ( onReplace && onSplit ) {
event.__deprecatedOnSplit = true;
}
}

function onKeyDown( event ) {
if ( event.defaultPrevented ) {
return;
}

// The event listener is attached to the window, so we need to check if
// the target is the element.
if ( event.target !== element ) {
return;
}

if ( event.keyCode !== ENTER ) {
return;
}

const {
removeEditorOnlyFormats,
value,
onReplace,
onSplit,
onChange,
disableLineBreaks,
onSplitAtEnd,
Expand All @@ -39,43 +43,12 @@ export default ( props ) => ( element ) => {

event.preventDefault();

const _value = { ...value };
_value.formats = removeEditorOnlyFormats( value );
const canSplit = onReplace && onSplit;

if ( onReplace ) {
const transforms = getBlockTransforms( 'from' ).filter(
( { type } ) => type === 'enter'
);
const transformation = findTransform( transforms, ( item ) => {
return item.regExp.test( _value.text );
} );

if ( transformation ) {
onReplace( [
transformation.transform( {
content: _value.text,
} ),
] );
registry
.dispatch( blockEditorStore )
.__unstableMarkAutomaticChange();
return;
}
}

const { text, start, end } = _value;
const { text, start, end } = value;

if ( event.shiftKey ) {
if ( ! disableLineBreaks ) {
onChange( insert( _value, '\n' ) );
onChange( insert( value, '\n' ) );
}
} else if ( canSplit ) {
splitValue( {
value: _value,
onReplace,
onSplit,
} );
} else if ( onSplitAtEnd && start === end && end === text.length ) {
onSplitAtEnd();
} else if (
Expand All @@ -88,17 +61,24 @@ export default ( props ) => ( element ) => {
text.slice( -2 ) === '\n\n'
) {
registry.batch( () => {
const _value = { ...value };
_value.start = _value.end - 2;
onChange( remove( _value ) );
onSplitAtDoubleLineEnd();
} );
} else if ( ! disableLineBreaks ) {
onChange( insert( _value, '\n' ) );
onChange( insert( value, '\n' ) );
}
}

element.addEventListener( 'keydown', onKeyDown );
const { defaultView } = element.ownerDocument;

// Attach the listener to the window so parent elements have the chance to
// prevent the default behavior.
defaultView.addEventListener( 'keydown', onKeyDown );
element.addEventListener( 'keydown', onKeyDownDeprecated );
return () => {
element.removeEventListener( 'keydown', onKeyDown );
defaultView.removeEventListener( 'keydown', onKeyDown );
element.removeEventListener( 'keydown', onKeyDownDeprecated );
};
};
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
/**
* WordPress dependencies
*/
import {
pasteHandler,
findTransform,
getBlockTransforms,
} from '@wordpress/blocks';
import { pasteHandler } from '@wordpress/blocks';
import { isEmpty, insert, create } from '@wordpress/rich-text';
import { isURL } from '@wordpress/url';

/**
* Internal dependencies
*/
import { addActiveFormats } from '../utils';
import { splitValue } from '../split-value';
import { getPasteEventData } from '../../../utils/pasting';

/** @typedef {import('@wordpress/rich-text').RichTextValue} RichTextValue */
Expand All @@ -27,12 +22,22 @@ export default ( props ) => ( element ) => {
formatTypes,
tagName,
onReplace,
onSplit,
__unstableEmbedURLOnPaste,
preserveWhiteSpace,
pastePlainText,
} = props.current;

const { plainText, html, files } = getPasteEventData( event );
// The event listener is attached to the window, so we need to check if
// the target is the element.
if ( event.target !== element ) {
return;
}

if ( event.defaultPrevented ) {
return;
}

const { plainText, html } = getPasteEventData( event );

event.preventDefault();

Expand Down Expand Up @@ -85,47 +90,7 @@ export default ( props ) => ( element ) => {
return;
}

if ( files?.length ) {
// Allows us to ask for this information when we get a report.
// eslint-disable-next-line no-console
window.console.log( 'Received items:\n\n', files );

const fromTransforms = getBlockTransforms( 'from' );
const blocks = files
.reduce( ( accumulator, file ) => {
const transformation = findTransform(
fromTransforms,
( transform ) =>
transform.type === 'files' &&
transform.isMatch( [ file ] )
);
if ( transformation ) {
accumulator.push(
transformation.transform( [ file ] )
);
}
return accumulator;
}, [] )
.flat();
if ( ! blocks.length ) {
return;
}

if ( onReplace && isEmpty( value ) ) {
onReplace( blocks );
} else {
splitValue( {
value,
pastedBlocks: blocks,
onReplace,
onSplit,
} );
}

return;
}

let mode = onReplace && onSplit ? 'AUTO' : 'INLINE';
let mode = 'INLINE';

const trimmedPlainText = plainText.trim();

Expand All @@ -144,26 +109,24 @@ export default ( props ) => ( element ) => {
plainText,
mode,
tagName,
preserveWhiteSpace,
} );

if ( typeof content === 'string' ) {
pasteInline( content );
} else if ( content.length > 0 ) {
if ( onReplace && isEmpty( value ) ) {
onReplace( content, content.length - 1, -1 );
} else {
splitValue( {
value,
pastedBlocks: content,
onReplace,
onSplit,
} );
}
}
}

element.addEventListener( 'paste', _onPaste );
const { defaultView } = element.ownerDocument;

// Attach the listener to the window so parent elements have the chance to
// prevent the default behavior.
defaultView.addEventListener( 'paste', _onPaste );
return () => {
element.removeEventListener( 'paste', _onPaste );
defaultView.removeEventListener( 'paste', _onPaste );
};
};
9 changes: 8 additions & 1 deletion packages/block-editor/src/components/rich-text/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
} from '@wordpress/rich-text';
import { Popover } from '@wordpress/components';
import { getBlockType, store as blocksStore } from '@wordpress/blocks';
import deprecated from '@wordpress/deprecated';

/**
* Internal dependencies
Expand Down Expand Up @@ -108,8 +109,14 @@ export function RichTextWrapper(
) {
props = removeNativeProps( props );

const instanceId = useInstanceId( RichTextWrapper );
if ( onSplit ) {
deprecated( 'wp.blockEditor.RichText onSplit prop', {
since: '6.4',
alternative: 'block.json support key: "splitting"',
} );
}

const instanceId = useInstanceId( RichTextWrapper );
const anchorRef = useRef();
const context = useBlockEditContext();
const { clientId, isSelected: isBlockSelected, name: blockName } = context;
Expand Down
Loading
Loading