Skip to content

Commit

Permalink
URLInput: Pass the the search result object to props.onChange (#8662)
Browse files Browse the repository at this point in the history
* Pass the the search result object to props.onChange

This component is great however the number of use cases it can support increases a huge amount if it makes the search result object available to the `onChange()` prop as well.

Example use cases:

- Retrieving the post title, ID and post type, as well as URL to update block attributes
- Fetching other / additional post data using the `_links` property of the search result object

* Add a component readme

* Fix json syntax

* Fix code example indentation

* document URLInputButton as well

* No autoFocus prop for button

* Remove unneeded arg on onChange method

Thanks for the review @youknowriad

* Update docs to reflect nullable `post` arg [ci skip]

* remove first arg from selectLink

* Improve readability

Add some changes based on feedback from @tofumatt, much appreciated!
  • Loading branch information
roborourke authored and youknowriad committed Aug 13, 2018
1 parent 6ce1a6b commit fd6aa36
Show file tree
Hide file tree
Showing 2 changed files with 204 additions and 4 deletions.
200 changes: 200 additions & 0 deletions packages/editor/src/components/url-input/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
# `URLInputButton`

Render a URL input button that pops up an input to search for and select a post or enter any arbitrary URL.

## Properties

### `url: String`

*Required.* This should be set to the attribute (or component state) property used to store the URL.

### `onChange( url: String, ?post: Object ): Function`

*Required.* Called when the value changes. The second parameter is `null` unless the user selects a post from the suggestions dropdown. In those cases the `post` parameter will look like this:

```json
{
"id": 1,
"subtype": "page",
"title": "Sample Page",
"type": "post",
"url": "https://example.com/sample-page/",
"_links": {
"self": [ { "embeddable": true, "href": "https://example.com/wp-json/wp/v2/pages/1" } ],
"about": [ { "href": "https://example.com/wp-json/wp/v2/types/page" } ],
"collection": [ { "href": "https://example.com/wp-json/gutenberg/v1/search" } ]
}
}
```

This prop is passed directly to the `URLInput` component.

## Example

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

attributes: {
url: {
type: 'string'
},
text: {
type: 'string'
}
},

edit: function( props ) {
return wp.element.createElement( wp.editor.URLInputButton, {
className: props.className,
url: props.attributes.url,
onChange: function( url, post ) {
props.setAttributes( { url: url, text: (post && post.title) || 'Click here' } );
}
} );
},

save: function( props ) {
return wp.element.createElement( 'a', {
href: props.attributes.url,
}, props.attributes.text );
}
} );
```
{% ESNext %}
```js
const { registerBlockType } = wp.blocks;
const { URLInputButton } = wp.editor;

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

attributes: {
url: {
type: 'string',
},
text: {
type: 'string',
},
},

edit( { className, attributes, setAttributes } ) {
return (
<URLInputButton
url={ attributes.url }
onChange={ ( url, post ) => setAttributes( { url, text: (post && post.title) || 'Click here' } ) }
/>
);
},

save( { attributes } ) {
return <a href={ attributes.url }>{ attributes.text }</a>;
}
} );
```
{% end %}

# `URLInput`

Renders the URL input field used by the `URLInputButton` component. It can be used directly to display the input field in different ways such as in a `Popover` or inline.

## Properties

### `value: String`

*Required.* This should be set to the attribute (or component state) property used to store the URL.

### `onChange( url: String, ?post: Object ): Function`

*Required.* Called when the value changes. The second parameter is `null` unless the user selects a post from the suggestions dropdown. In those cases the `post` parameter will look like this:

```json
{
"id": 1,
"subtype": "page",
"title": "Sample Page",
"type": "post",
"url": "https://example.com/sample-page/",
"_links": {
"self": [ { "embeddable": true, "href": "https://example.com/wp-json/wp/v2/pages/1" } ],
"about": [ { "href": "https://example.com/wp-json/wp/v2/types/page" } ],
"collection": [ { "href": "https://example.com/wp-json/gutenberg/v1/search" } ]
}
}
```

### `autoFocus: Boolean`

*Optional.* By default, the input will gain focus when it is rendered, as typically it is displayed conditionally. For example when clicking on `URLInputButton` or editing a block.

If you are not conditionally rendering this component set this property to `false`.

## Example

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

attributes: {
url: {
type: 'string'
},
text: {
type: 'string'
}
},

edit: function( props ) {
return wp.element.createElement( wp.editor.URLInput, {
className: props.className,
value: props.attributes.url,
onChange: function( url, post ) {
props.setAttributes( { url: url, text: (post && post.title) || 'Click here' } );
}
} );
},

save: function( props ) {
return wp.element.createElement( 'a', {
href: props.attributes.url,
}, props.attributes.text );
}
} );
```
{% ESNext %}
```js
const { registerBlockType } = wp.blocks;
const { URLInput } = wp.editor;

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

attributes: {
url: {
type: 'string',
},
text: {
type: 'string',
},
},

edit( { className, attributes, setAttributes } ) {
return (
<URLInput
className={ className }
value={ attributes.url }
onChange={ ( url, post ) => setAttributes( { url, text: (post && post.title) || 'Click here' } ) }
/>
);
},

save( { attributes } ) {
return <a href={ attributes.url }>{ attributes.text }</a>;
}
} );
```
{% end %}
8 changes: 4 additions & 4 deletions packages/editor/src/components/url-input/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,14 +167,14 @@ class URLInput extends Component {
if ( this.state.selectedSuggestion !== null ) {
event.stopPropagation();
const post = this.state.posts[ this.state.selectedSuggestion ];
this.selectLink( post.url );
this.selectLink( post );
}
}
}
}

selectLink( link ) {
this.props.onChange( link );
selectLink( post ) {
this.props.onChange( post.url, post );
this.setState( {
selectedSuggestion: null,
showSuggestions: false,
Expand Down Expand Up @@ -226,7 +226,7 @@ class URLInput extends Component {
className={ classnames( 'editor-url-input__suggestion', {
'is-selected': index === selectedSuggestion,
} ) }
onClick={ () => this.selectLink( post.url ) }
onClick={ () => this.selectLink( post ) }
aria-selected={ index === selectedSuggestion }
>
{ decodeEntities( post.title ) || __( '(no title)' ) }
Expand Down

0 comments on commit fd6aa36

Please sign in to comment.