Skip to content

Commit

Permalink
Editable Component (#18361)
Browse files Browse the repository at this point in the history
* Text Component

* Rename

* Lint fixes
  • Loading branch information
ellatrix authored Mar 19, 2020
1 parent f90dc20 commit 0446ed1
Show file tree
Hide file tree
Showing 7 changed files with 195 additions and 3 deletions.
4 changes: 4 additions & 0 deletions packages/block-editor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,10 @@ _Returns_

Undocumented declaration.

<a name="Editable" href="#Editable">#</a> **Editable**

Renders an editable text input in which text formatting is not allowed.

<a name="FontSizePicker" href="#FontSizePicker">#</a> **FontSizePicker**

Undocumented declaration.
Expand Down
114 changes: 114 additions & 0 deletions packages/block-editor/src/components/editable/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# `Editable`

Renders an editable text input in which text formatting is not allowed.

## Properties

### `value: String`

*Required.* String to make editable.

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

*Required.* Called when the value changes.

### `tagName: String`

*Default: `div`.* The [tag name](https://www.w3.org/TR/html51/syntax.html#tag-name) of the editable element. Elements that display inline are not supported.

### `disableLineBreaks: Boolean`

*Optional.* `Text` won't insert line breaks on `Enter` if set to `true`.

### `placeholder: String`

*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).

### `keepPlaceholderOnFocus: Boolean`

*Optional.* Show placeholder even when selected/focused, as long as there is no content.

### `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.

### `onMerge( forward: Boolean ): Function`

*Optional.* Called when blocks can be merged. `forward` is true when merging with the next block, false when merging with the previous block.

### `onRemove( forward: Boolean ): Function`

*Optional.* Called when the block can be removed. `forward` is true when the selection is expected to move to the next block, false to the previous block.

## Editable.Content

`Text.Content` should be used in the `save` function of your block to correctly save text content.

## Example

{% codetabs %}
{% ES5 %}
```js
wp.blocks.registerBlockType( /* ... */, {
// ...

attributes: {
content: {
source: 'html',
selector: 'div',
},
},

edit: function( props ) {
return wp.element.createElement( wp.editor.Editable, {
className: props.className,
value: props.attributes.content,
onChange: function( content ) {
props.setAttributes( { content: content } );
}
} );
},

save: function( props ) {
return wp.element.createElement( wp.editor.Editable.Content, {
value: props.attributes.content
} );
}
} );
```
{% ESNext %}
```js
const { registerBlockType } = wp.blocks;
const { Editable } = wp.editor;

registerBlockType( /* ... */, {
// ...

attributes: {
content: {
source: 'html',
selector: '.text',
},
},

edit( { className, attributes, setAttributes } ) {
return (
<Editable
className={ className }
value={ attributes.content }
onChange={ ( content ) => setAttributes( { content } ) }
/>
);
},

save( { attributes } ) {
return <Editable.Content value={ attributes.content } />;
}
} );
```
{% end %}
17 changes: 17 additions & 0 deletions packages/block-editor/src/components/editable/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* Internal dependencies
*/
import RichText from '../rich-text';

function Editable( props ) {
return <RichText { ...props } __unstableDisableFormats />;
}

Editable.Content = ( { value = '', tagName: Tag = 'div', ...props } ) => {
return <Tag { ...props }>{ value }</Tag>;
};

/**
* Renders an editable text input in which text formatting is not allowed.
*/
export default Editable;
1 change: 1 addition & 0 deletions packages/block-editor/src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export {
RichTextToolbarButton,
__unstableRichTextInputEvent,
} from './rich-text';
export { default as Editable } from './editable';
export { default as ToolSelector } from './tool-selector';
export { default as URLInput } from './url-input';
export { default as URLInputButton } from './url-input/button';
Expand Down
24 changes: 21 additions & 3 deletions packages/block-editor/src/components/rich-text/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,15 @@ function getMultilineTag( multiline ) {
return multiline === true ? 'p' : multiline;
}

function getAllowedFormats( { allowedFormats, formattingControls } ) {
function getAllowedFormats( {
allowedFormats,
formattingControls,
disableFormats,
} ) {
if ( disableFormats ) {
return getAllowedFormats.EMPTY_ARRAY;
}

if ( ! allowedFormats && ! formattingControls ) {
return;
}
Expand All @@ -83,6 +91,8 @@ function getAllowedFormats( { allowedFormats, formattingControls } ) {
return formattingControls.map( ( name ) => `core/${ name }` );
}

getAllowedFormats.EMPTY_ARRAY = [];

function RichTextWrapper(
{
children,
Expand Down Expand Up @@ -112,6 +122,8 @@ function RichTextWrapper(
style,
preserveWhiteSpace,
__unstableEmbedURLOnPaste,
__unstableDisableFormats: disableFormats,
disableLineBreaks,
...props
},
forwardedRef
Expand Down Expand Up @@ -202,6 +214,7 @@ function RichTextWrapper(
const adjustedAllowedFormats = getAllowedFormats( {
allowedFormats,
formattingControls,
disableFormats,
} );
const hasFormats =
! adjustedAllowedFormats || adjustedAllowedFormats.length > 0;
Expand Down Expand Up @@ -329,14 +342,18 @@ function RichTextWrapper(

if ( multiline ) {
if ( shiftKey ) {
onChange( insert( value, '\n' ) );
if ( ! disableLineBreaks ) {
onChange( insert( value, '\n' ) );
}
} else if ( canSplit && isEmptyLine( value ) ) {
splitValue( value );
} else {
onChange( insertLineSeparator( value ) );
}
} else if ( shiftKey || ! canSplit ) {
onChange( insert( value, '\n' ) );
if ( ! disableLineBreaks ) {
onChange( insert( value, '\n' ) );
}
} else {
splitValue( value );
}
Expand Down Expand Up @@ -504,6 +521,7 @@ function RichTextWrapper(
__unstableMarkAutomaticChange={ __unstableMarkAutomaticChange }
__unstableDidAutomaticChange={ didAutomaticChange }
__unstableUndo={ undo }
__unstableDisableFormats={ disableFormats }
style={ style }
preserveWhiteSpace={ preserveWhiteSpace }
disabled={ disabled }
Expand Down
19 changes: 19 additions & 0 deletions packages/block-library/src/site-title/edit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* WordPress dependencies
*/
import { useEntityProp } from '@wordpress/core-data';
import { __ } from '@wordpress/i18n';
import { Editable } from '@wordpress/block-editor';

export default function SiteTitleEdit() {
const [ title, setTitle ] = useEntityProp( 'root', 'site', 'title' );
return (
<Editable
tagName="h1"
placeholder={ __( 'Site Title' ) }
value={ title }
onChange={ setTitle }
disableLineBreaks
/>
);
}
19 changes: 19 additions & 0 deletions packages/rich-text/src/component/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,11 @@ class RichText extends Component {
* created.
*/
onChange( record, { withoutHistory } = {} ) {
if ( this.props.__unstableDisableFormats ) {
record.formats = Array( record.text.length );
record.replacements = Array( record.text.length );
}

this.applyRecord( record );

const { start, end, activeFormats = [] } = record;
Expand Down Expand Up @@ -1005,8 +1010,17 @@ class RichText extends Component {
format,
__unstableMultilineTag: multilineTag,
preserveWhiteSpace,
__unstableDisableFormats: disableFormats,
} = this.props;

if ( disableFormats ) {
return {
text: value,
formats: Array( value.length ),
replacements: Array( value.length ),
};
}

if ( format !== 'string' ) {
return value;
}
Expand Down Expand Up @@ -1064,8 +1078,13 @@ class RichText extends Component {
format,
__unstableMultilineTag: multilineTag,
preserveWhiteSpace,
__unstableDisableFormats: disableFormats,
} = this.props;

if ( disableFormats ) {
return value.text;
}

value = this.removeEditorOnlyFormats( value );

if ( format !== 'string' ) {
Expand Down

0 comments on commit 0446ed1

Please sign in to comment.