Skip to content

Commit 4cf22bf

Browse files
authored
Merge pull request #305 from humanmade/28/video-control
28: VideoControl component
2 parents 7d30519 + e2e500c commit 4cf22bf

4 files changed

Lines changed: 231 additions & 0 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ One way to ensure all dependencies are loaded is to use the [`@wordpress/depende
5555
- [`PostTypeCheck`](src/components/PostTypeCheck)
5656
- [`RichTextWithLimit`](src/components/RichTextWithLimit)
5757
- [`TermSearchControl`](src/components/TermSearchControl)
58+
- [`VideoControl`](src/components/VideoControl)
5859

5960
## Hooks
6061

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
# VideoControl
2+
3+
The `VideoControl` component allows for selecting a single video from the Media Library in a sidebar panel.
4+
Internally, `VideoControl` is wrapping a [`MediaUpload`](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-editor/src/components/media-upload/index.js) inside a [`BaseControl`](https://github.com/WordPress/gutenberg/blob/trunk/packages/components/src/base-control/index.tsx) component.
5+
6+
| ![image-control--default.png](../../../assets/images/image-control--default.png) |
7+
|------------------------------------------------------------------------------------|
8+
| _`VideoControl` component._ |
9+
10+
| ![image-control--selected.png](../../../assets/images/image-control--selected.png) |
11+
|------------------------------------------------------------------------------------|
12+
| _`VideoControl` component displaying the selected video._ |
13+
14+
## Usage
15+
16+
For a minimum working setup, all you need to do is pass an video ID as `value`, as well as an `onChange` callback that accepts a video object.
17+
18+
```js
19+
import { VideoControl } from '@humanmade/block-editor-components';
20+
import { InspectorControls } from '@wordpress/block-editor';
21+
import { PanelBody } from '@wordpress/components';
22+
23+
function BlockEdit( props ) {
24+
const { attributes, setAttributes } = props;
25+
const { videoId } = attributes;
26+
27+
return (
28+
<InspectorControls>
29+
<PanelBody>
30+
<VideoControl
31+
value={ videoId }
32+
onChange={ ( video ) => setAttributes( { videoId: video?.id } ) }
33+
/>
34+
</PanelBody>
35+
</InspectorControls>
36+
);
37+
}
38+
```
39+
40+
You can also customize button texts, as well as the modal title.
41+
42+
```js
43+
import { VideoControl } from '@humanmade/block-editor-components';
44+
import { InspectorControls } from '@wordpress/block-editor';
45+
import { PanelBody } from '@wordpress/components';
46+
47+
function BlockEdit( props ) {
48+
const { attributes, setAttributes } = props;
49+
const { videoId } = attributes;
50+
51+
return (
52+
<InspectorControls>
53+
<PanelBody>
54+
<VideoControl
55+
buttonText="Select Video"
56+
modalTitle="Select Video"
57+
removeButtonText="Remove Video"
58+
replaceButtonText="Replace Video"
59+
value={ videoId }
60+
onChange={ ( video ) => setAttributes( { videoId: video?.id } ) }
61+
/>
62+
</PanelBody>
63+
</InspectorControls>
64+
);
65+
}
66+
```
67+
68+
Also, all stable props of `BaseControl` are supported.
69+
70+
## Props
71+
72+
The `VideoControl` component has custom props `value` and `onChange` for managing the image, as well as `buttonText`, `modalTitle`, `removeButtonText` and `replaceButtonText`.
73+
Also, it supports all stable props of the `BaseControl` component.
74+
75+
### `buttonText`
76+
77+
The button text to display if no image has been selected.
78+
79+
| Type | Required | Default |
80+
|--------------------------------------|--------------------------------------|--------------------------------------|
81+
| `string` | no | `'Select image'` |
82+
83+
### `modalTitle`
84+
85+
The modal title.
86+
87+
| Type | Required | Default |
88+
|--------------------------------------|--------------------------------------|--------------------------------------|
89+
| `string` | no | `'Select Video'` |
90+
91+
### `onChange`
92+
93+
The callback to use for handling changing the video.
94+
Please note that `onChange` will receive a video object from the Media Library.
95+
96+
| Type | Required | Default |
97+
|--------------------------------------|--------------------------------------|--------------------------------------|
98+
| `Function` | yes | `undefined` |
99+
100+
### `removeButtonText`
101+
102+
The text to display for the remove button.
103+
104+
| Type | Required | Default |
105+
|--------------------------------------|--------------------------------------|--------------------------------------|
106+
| `string` | no | `'Remove Video'` |
107+
108+
### `replaceButtonText`
109+
110+
The button text to display if an video has been selected.
111+
112+
| Type | Required | Default |
113+
|--------------------------------------|--------------------------------------|--------------------------------------|
114+
| `string` | no | `'Replace Video` |
115+
116+
### `size`
117+
118+
The video size to display in the sidebar.
119+
120+
| Type | Required | Default |
121+
|--------------------------------------|--------------------------------------|--------------------------------------|
122+
| `string` | no | `undefined` |
123+
124+
### `value`
125+
126+
A video ID.
127+
128+
| Type | Required | Default |
129+
|--------------------------------------|--------------------------------------|--------------------------------------|
130+
| `number` | yes | `undefined` |
131+
132+
## Dependencies
133+
134+
The `VideoControl` component requires the following dependencies, which are expected to be available:
135+
136+
- `@wordpress/block-editor`
137+
- `@wordpress/components`
138+
- `@wordpress/data`
139+
- `@wordpress/i18n`
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import React, { ReactNode } from 'react';
2+
3+
import { MediaUpload, MediaUploadCheck } from '@wordpress/block-editor';
4+
import { BaseControl, Button, Spinner } from '@wordpress/components';
5+
import { useSelect } from '@wordpress/data';
6+
import { __ } from '@wordpress/i18n';
7+
8+
const allowedTypes = [ 'video' ];
9+
10+
const BUTTON_TEXT = __( 'Select Video', 'block-editor-components' );
11+
const MODAL_TITLE = __( 'Select Video', 'block-editor-components' );
12+
const REMOVE_BUTTON_TEXT = __( 'Remove Video', 'block-editor-components' );
13+
const REPLACE_BUTTON_TEXT = __( 'Replace Video', 'block-editor-components' );
14+
15+
/**
16+
* Video sidebar control.
17+
*
18+
* @param {object} props - Component props.
19+
* @returns {ReactNode} Component.
20+
*/
21+
export default function VideoControl( props ) {
22+
const {
23+
buttonText = BUTTON_TEXT,
24+
className,
25+
help,
26+
id,
27+
label,
28+
modalTitle = MODAL_TITLE,
29+
removeButtonText = REMOVE_BUTTON_TEXT,
30+
replaceButtonText = REPLACE_BUTTON_TEXT,
31+
value,
32+
onChange,
33+
} = props;
34+
35+
const videoUrl = useSelect(
36+
( select ) => {
37+
const media = select( 'core' ).getMedia( value, { context: 'view' } );
38+
if ( ! media ) {
39+
return undefined;
40+
}
41+
42+
return media.source_url;
43+
},
44+
[ value ]
45+
);
46+
47+
return (
48+
<BaseControl
49+
className={ className }
50+
help={ help }
51+
id={ id }
52+
label={ label }
53+
>
54+
<MediaUploadCheck>
55+
<MediaUpload
56+
allowedTypes={ allowedTypes }
57+
render={ ( { open } ) => (
58+
<div>
59+
{ value && (
60+
videoUrl ? (
61+
<Button isLink onClick={ open }>
62+
<video
63+
controls
64+
loop
65+
muted
66+
src={ videoUrl }
67+
/>
68+
</Button>
69+
) : (
70+
<Spinner />
71+
)
72+
) }
73+
<Button isSecondary onClick={ open }>
74+
{ value ? replaceButtonText : buttonText }
75+
</Button>
76+
</div>
77+
) }
78+
title={ modalTitle }
79+
onSelect={ onChange }
80+
/>
81+
</MediaUploadCheck>
82+
<br />
83+
{ value ? (
84+
<Button isDestructive isLink onClick={ () => onChange( null ) }>
85+
{ removeButtonText }
86+
</Button>
87+
) : null }
88+
</BaseControl>
89+
);
90+
}

src/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export { default as PostTypeCheck } from './components/PostTypeCheck';
1414
export { default as RichTextWithLimit } from './components/RichTextWithLimit';
1515
export { default as TermSearchControl } from './components/TermSearchControl';
1616
export { default as TermSelector } from './components/TermSelector';
17+
export { default as VideoControl } from './components/VideoControl';
1718
export {
1819
PostPickerButton,
1920
PostPickerToolbarButton,

0 commit comments

Comments
 (0)