@wordpress/editor 12.11.0 → 12.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2 -0
- package/build/components/document-outline/index.js +7 -9
- package/build/components/document-outline/index.js.map +1 -1
- package/build/components/error-boundary/index.js +3 -0
- package/build/components/error-boundary/index.js.map +1 -1
- package/build/components/index.js +49 -8
- package/build/components/index.js.map +1 -1
- package/build/components/page-attributes/order.js +3 -7
- package/build/components/page-attributes/order.js.map +1 -1
- package/build/components/page-attributes/parent.js +1 -1
- package/build/components/page-attributes/parent.js.map +1 -1
- package/build/components/post-format/index.js +5 -8
- package/build/components/post-format/index.js.map +1 -1
- package/build/components/post-schedule/label.js +3 -3
- package/build/components/post-schedule/label.js.map +1 -1
- package/build/components/post-slug/index.js +8 -13
- package/build/components/post-slug/index.js.map +1 -1
- package/build/components/post-taxonomies/flat-term-selector.js +1 -0
- package/build/components/post-taxonomies/flat-term-selector.js.map +1 -1
- package/build/components/post-taxonomies/hierarchical-term-selector.js +1 -0
- package/build/components/post-taxonomies/hierarchical-term-selector.js.map +1 -1
- package/build/components/post-taxonomies/index.js +3 -1
- package/build/components/post-taxonomies/index.js.map +1 -1
- package/build/components/post-template/index.js +1 -2
- package/build/components/post-template/index.js.map +1 -1
- package/build/components/post-url/check.js +54 -0
- package/build/components/post-url/check.js.map +1 -0
- package/build/components/post-url/index.js +115 -0
- package/build/components/post-url/index.js.map +1 -0
- package/build/components/post-url/label.js +30 -0
- package/build/components/post-url/label.js.map +1 -0
- package/build/components/post-visibility/label.js +5 -0
- package/build/components/post-visibility/label.js.map +1 -1
- package/build/components/table-of-contents/panel.js +5 -1
- package/build/components/table-of-contents/panel.js.map +1 -1
- package/build/components/time-to-read/index.js +60 -0
- package/build/components/time-to-read/index.js.map +1 -0
- package/build/store/selectors.js +2 -2
- package/build/store/selectors.js.map +1 -1
- package/build-module/components/document-outline/index.js +7 -8
- package/build-module/components/document-outline/index.js.map +1 -1
- package/build-module/components/error-boundary/index.js +2 -0
- package/build-module/components/error-boundary/index.js.map +1 -1
- package/build-module/components/index.js +6 -3
- package/build-module/components/index.js.map +1 -1
- package/build-module/components/page-attributes/order.js +3 -6
- package/build-module/components/page-attributes/order.js.map +1 -1
- package/build-module/components/page-attributes/parent.js +2 -2
- package/build-module/components/page-attributes/parent.js.map +1 -1
- package/build-module/components/post-format/index.js +5 -8
- package/build-module/components/post-format/index.js.map +1 -1
- package/build-module/components/post-schedule/label.js +3 -3
- package/build-module/components/post-schedule/label.js.map +1 -1
- package/build-module/components/post-slug/index.js +8 -14
- package/build-module/components/post-slug/index.js.map +1 -1
- package/build-module/components/post-taxonomies/flat-term-selector.js +1 -2
- package/build-module/components/post-taxonomies/flat-term-selector.js.map +1 -1
- package/build-module/components/post-taxonomies/hierarchical-term-selector.js +1 -2
- package/build-module/components/post-taxonomies/hierarchical-term-selector.js.map +1 -1
- package/build-module/components/post-taxonomies/index.js +4 -1
- package/build-module/components/post-taxonomies/index.js.map +1 -1
- package/build-module/components/post-template/index.js +1 -2
- package/build-module/components/post-template/index.js.map +1 -1
- package/build-module/components/post-url/check.js +44 -0
- package/build-module/components/post-url/check.js.map +1 -0
- package/build-module/components/post-url/index.js +102 -0
- package/build-module/components/post-url/index.js.map +1 -0
- package/build-module/components/post-url/label.js +18 -0
- package/build-module/components/post-url/label.js.map +1 -0
- package/build-module/components/post-visibility/label.js +3 -0
- package/build-module/components/post-visibility/label.js.map +1 -1
- package/build-module/components/table-of-contents/panel.js +4 -1
- package/build-module/components/table-of-contents/panel.js.map +1 -1
- package/build-module/components/time-to-read/index.js +50 -0
- package/build-module/components/time-to-read/index.js.map +1 -0
- package/build-module/store/selectors.js +3 -3
- package/build-module/store/selectors.js.map +1 -1
- package/build-style/style-rtl.css +15 -17
- package/build-style/style.css +19 -17
- package/package.json +28 -28
- package/src/components/document-outline/index.js +9 -8
- package/src/components/error-boundary/index.js +3 -0
- package/src/components/index.js +9 -3
- package/src/components/page-attributes/order.js +1 -9
- package/src/components/page-attributes/parent.js +1 -2
- package/src/components/post-format/index.js +13 -19
- package/src/components/post-format/style.scss +2 -17
- package/src/components/post-schedule/label.js +1 -1
- package/src/components/post-slug/index.js +7 -13
- package/src/components/post-slug/test/index.js +7 -6
- package/src/components/post-taxonomies/flat-term-selector.js +1 -1
- package/src/components/post-taxonomies/hierarchical-term-selector.js +1 -1
- package/src/components/post-taxonomies/index.js +3 -1
- package/src/components/post-template/index.js +1 -1
- package/src/components/post-url/check.js +38 -0
- package/src/components/post-url/index.js +122 -0
- package/src/components/post-url/label.js +22 -0
- package/src/components/post-url/style.scss +16 -0
- package/src/components/post-visibility/label.js +4 -0
- package/src/components/table-of-contents/panel.js +7 -2
- package/src/components/time-to-read/index.js +59 -0
- package/src/store/selectors.js +4 -5
- package/src/store/test/selectors.js +1 -1
- package/src/style.scss +1 -0
package/src/components/index.js
CHANGED
|
@@ -51,16 +51,22 @@ export { default as PostSticky } from './post-sticky';
|
|
|
51
51
|
export { default as PostStickyCheck } from './post-sticky/check';
|
|
52
52
|
export { default as PostSwitchToDraftButton } from './post-switch-to-draft-button';
|
|
53
53
|
export { default as PostTaxonomies } from './post-taxonomies';
|
|
54
|
-
export {
|
|
55
|
-
export {
|
|
54
|
+
export { FlatTermSelector as PostTaxonomiesFlatTermSelector } from './post-taxonomies/flat-term-selector';
|
|
55
|
+
export { HierarchicalTermSelector as PostTaxonomiesHierarchicalTermSelector } from './post-taxonomies/hierarchical-term-selector';
|
|
56
56
|
export { default as PostTaxonomiesCheck } from './post-taxonomies/check';
|
|
57
57
|
export { default as PostTextEditor } from './post-text-editor';
|
|
58
58
|
export { default as PostTitle } from './post-title';
|
|
59
59
|
export { default as PostTrash } from './post-trash';
|
|
60
60
|
export { default as PostTrashCheck } from './post-trash/check';
|
|
61
61
|
export { default as PostTypeSupportCheck } from './post-type-support-check';
|
|
62
|
+
export { default as PostURL } from './post-url';
|
|
63
|
+
export { default as PostURLCheck } from './post-url/check';
|
|
64
|
+
export { default as PostURLLabel, usePostURLLabel } from './post-url/label';
|
|
62
65
|
export { default as PostVisibility } from './post-visibility';
|
|
63
|
-
export {
|
|
66
|
+
export {
|
|
67
|
+
default as PostVisibilityLabel,
|
|
68
|
+
usePostVisibilityLabel,
|
|
69
|
+
} from './post-visibility/label';
|
|
64
70
|
export { default as PostVisibilityCheck } from './post-visibility/check';
|
|
65
71
|
export { default as TableOfContents } from './table-of-contents';
|
|
66
72
|
export { default as ThemeSupportCheck } from './theme-support-check';
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* External dependencies
|
|
3
|
-
*/
|
|
4
|
-
import { invoke } from 'lodash';
|
|
5
|
-
|
|
6
1
|
/**
|
|
7
2
|
* WordPress dependencies
|
|
8
3
|
*/
|
|
@@ -24,10 +19,7 @@ export const PageAttributesOrder = ( { onUpdateOrder, order = 0 } ) => {
|
|
|
24
19
|
const setUpdatedOrder = ( value ) => {
|
|
25
20
|
setOrderInput( value );
|
|
26
21
|
const newOrder = Number( value );
|
|
27
|
-
if (
|
|
28
|
-
Number.isInteger( newOrder ) &&
|
|
29
|
-
invoke( value, [ 'trim' ] ) !== ''
|
|
30
|
-
) {
|
|
22
|
+
if ( Number.isInteger( newOrder ) && value.trim?.() !== '' ) {
|
|
31
23
|
onUpdateOrder( Number( value ) );
|
|
32
24
|
}
|
|
33
25
|
};
|
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
get,
|
|
6
6
|
unescape as unescapeString,
|
|
7
7
|
debounce,
|
|
8
|
-
repeat,
|
|
9
8
|
find,
|
|
10
9
|
deburr,
|
|
11
10
|
} from 'lodash';
|
|
@@ -98,7 +97,7 @@ export function PageAttributesParent() {
|
|
|
98
97
|
{
|
|
99
98
|
value: treeNode.id,
|
|
100
99
|
label:
|
|
101
|
-
|
|
100
|
+
'— '.repeat( level ) + unescapeString( treeNode.name ),
|
|
102
101
|
rawName: treeNode.name,
|
|
103
102
|
},
|
|
104
103
|
...getOptionsFromTree( treeNode.children || [], level + 1 ),
|
|
@@ -81,24 +81,18 @@ export default function PostFormat() {
|
|
|
81
81
|
return (
|
|
82
82
|
<PostFormatCheck>
|
|
83
83
|
<div className="editor-post-format">
|
|
84
|
-
<
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
id
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
value: format.id,
|
|
95
|
-
} ) ) }
|
|
96
|
-
/>
|
|
97
|
-
</div>
|
|
98
|
-
|
|
84
|
+
<SelectControl
|
|
85
|
+
label={ __( 'Post Format' ) }
|
|
86
|
+
value={ postFormat }
|
|
87
|
+
onChange={ ( format ) => onUpdatePostFormat( format ) }
|
|
88
|
+
id={ postFormatSelectorId }
|
|
89
|
+
options={ formats.map( ( format ) => ( {
|
|
90
|
+
label: format.caption,
|
|
91
|
+
value: format.id,
|
|
92
|
+
} ) ) }
|
|
93
|
+
/>
|
|
99
94
|
{ suggestion && suggestion.id !== postFormat && (
|
|
100
|
-
<
|
|
101
|
-
{ __( 'Suggestion:' ) }{ ' ' }
|
|
95
|
+
<p className="editor-post-format__suggestion">
|
|
102
96
|
<Button
|
|
103
97
|
variant="link"
|
|
104
98
|
onClick={ () =>
|
|
@@ -107,11 +101,11 @@ export default function PostFormat() {
|
|
|
107
101
|
>
|
|
108
102
|
{ sprintf(
|
|
109
103
|
/* translators: %s: post format */
|
|
110
|
-
__( 'Apply format: %s' ),
|
|
104
|
+
__( 'Apply suggested format: %s' ),
|
|
111
105
|
suggestion.caption
|
|
112
106
|
) }
|
|
113
107
|
</Button>
|
|
114
|
-
</
|
|
108
|
+
</p>
|
|
115
109
|
) }
|
|
116
110
|
</div>
|
|
117
111
|
</PostFormatCheck>
|
|
@@ -1,18 +1,3 @@
|
|
|
1
|
-
.editor-post-
|
|
2
|
-
|
|
3
|
-
align-items: stretch;
|
|
4
|
-
width: 100%;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
.editor-post-format__content {
|
|
8
|
-
display: inline-flex;
|
|
9
|
-
justify-content: space-between;
|
|
10
|
-
align-items: center;
|
|
11
|
-
width: 100%;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
.editor-post-format__suggestion {
|
|
15
|
-
padding: $grid-unit-15 * 0.5;
|
|
16
|
-
text-align: right;
|
|
17
|
-
font-size: $default-font-size;
|
|
1
|
+
[class].editor-post-format__suggestion {
|
|
2
|
+
margin: $grid-unit-05 0 0 0;
|
|
18
3
|
}
|
|
@@ -14,7 +14,7 @@ export default function PostScheduleLabel( props ) {
|
|
|
14
14
|
return usePostScheduleLabel( props );
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
export function usePostScheduleLabel( { full } ) {
|
|
17
|
+
export function usePostScheduleLabel( { full = false } = {} ) {
|
|
18
18
|
const { date, isFloating } = useSelect(
|
|
19
19
|
( select ) => ( {
|
|
20
20
|
date: select( editorStore ).getEditedPostAttribute( 'date' ),
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
import { withDispatch, withSelect } from '@wordpress/data';
|
|
5
5
|
import { Component } from '@wordpress/element';
|
|
6
6
|
import { __ } from '@wordpress/i18n';
|
|
7
|
-
import {
|
|
7
|
+
import { compose } from '@wordpress/compose';
|
|
8
8
|
import { safeDecodeURIComponent, cleanForSlug } from '@wordpress/url';
|
|
9
|
+
import { TextControl } from '@wordpress/components';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Internal dependencies
|
|
@@ -41,25 +42,19 @@ export class PostSlug extends Component {
|
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
render() {
|
|
44
|
-
const { instanceId } = this.props;
|
|
45
45
|
const { editedSlug } = this.state;
|
|
46
|
-
|
|
47
|
-
const inputId = 'editor-post-slug-' + instanceId;
|
|
48
|
-
|
|
49
46
|
return (
|
|
50
47
|
<PostSlugCheck>
|
|
51
|
-
<
|
|
52
|
-
|
|
48
|
+
<TextControl
|
|
49
|
+
label={ __( 'Slug' ) }
|
|
53
50
|
autoComplete="off"
|
|
54
51
|
spellCheck="false"
|
|
55
|
-
type="text"
|
|
56
|
-
id={ inputId }
|
|
57
52
|
value={ editedSlug }
|
|
58
|
-
onChange={ (
|
|
59
|
-
this.setState( { editedSlug:
|
|
53
|
+
onChange={ ( slug ) =>
|
|
54
|
+
this.setState( { editedSlug: slug } )
|
|
60
55
|
}
|
|
61
56
|
onBlur={ this.setSlug }
|
|
62
|
-
className="editor-post-
|
|
57
|
+
className="editor-post-slug"
|
|
63
58
|
/>
|
|
64
59
|
</PostSlugCheck>
|
|
65
60
|
);
|
|
@@ -86,5 +81,4 @@ export default compose( [
|
|
|
86
81
|
},
|
|
87
82
|
};
|
|
88
83
|
} ),
|
|
89
|
-
withInstanceId,
|
|
90
84
|
] )( PostSlug );
|
|
@@ -3,6 +3,11 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { shallow } from 'enzyme';
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* WordPress dependencies
|
|
8
|
+
*/
|
|
9
|
+
import { TextControl } from '@wordpress/components';
|
|
10
|
+
|
|
6
11
|
/**
|
|
7
12
|
* Internal dependencies
|
|
8
13
|
*/
|
|
@@ -13,11 +18,7 @@ describe( 'PostSlug', () => {
|
|
|
13
18
|
it( 'should update internal slug', () => {
|
|
14
19
|
const wrapper = shallow( <PostSlug postSlug="index" /> );
|
|
15
20
|
|
|
16
|
-
wrapper.find( '
|
|
17
|
-
target: {
|
|
18
|
-
value: 'single',
|
|
19
|
-
},
|
|
20
|
-
} );
|
|
21
|
+
wrapper.find( TextControl ).prop( 'onChange' )( 'single' );
|
|
21
22
|
|
|
22
23
|
expect( wrapper.state().editedSlug ).toEqual( 'single' );
|
|
23
24
|
} );
|
|
@@ -28,7 +29,7 @@ describe( 'PostSlug', () => {
|
|
|
28
29
|
<PostSlug postSlug="index" onUpdateSlug={ onUpdateSlug } />
|
|
29
30
|
);
|
|
30
31
|
|
|
31
|
-
wrapper.find(
|
|
32
|
+
wrapper.find( TextControl ).prop( 'onBlur' )( {
|
|
32
33
|
target: {
|
|
33
34
|
value: 'single',
|
|
34
35
|
},
|
|
@@ -86,7 +86,7 @@ function findOrCreateTerm( termName, restBase, namespace ) {
|
|
|
86
86
|
.then( unescapeTerm );
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
function FlatTermSelector( { slug } ) {
|
|
89
|
+
export function FlatTermSelector( { slug } ) {
|
|
90
90
|
const [ values, setValues ] = useState( [] );
|
|
91
91
|
const [ search, setSearch ] = useState( '' );
|
|
92
92
|
const debouncedSearch = useDebounce( setSearch, 500 );
|
|
@@ -152,7 +152,7 @@ export function getFilterMatcher( filterValue ) {
|
|
|
152
152
|
* @param {string} props.slug Taxonomy slug.
|
|
153
153
|
* @return {WPElement} Hierarchical term selector component.
|
|
154
154
|
*/
|
|
155
|
-
function HierarchicalTermSelector( { slug } ) {
|
|
155
|
+
export function HierarchicalTermSelector( { slug } ) {
|
|
156
156
|
const [ adding, setAdding ] = useState( false );
|
|
157
157
|
const [ formName, setFormName ] = useState( '' );
|
|
158
158
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* External dependencies
|
|
3
3
|
*/
|
|
4
|
-
import { filter,
|
|
4
|
+
import { filter, includes } from 'lodash';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* WordPress dependencies
|
|
@@ -18,6 +18,8 @@ import HierarchicalTermSelector from './hierarchical-term-selector';
|
|
|
18
18
|
import FlatTermSelector from './flat-term-selector';
|
|
19
19
|
import { store as editorStore } from '../../store';
|
|
20
20
|
|
|
21
|
+
const identity = ( x ) => x;
|
|
22
|
+
|
|
21
23
|
export function PostTaxonomies( {
|
|
22
24
|
postType,
|
|
23
25
|
taxonomies,
|
|
@@ -16,7 +16,7 @@ import { store as coreStore } from '@wordpress/core-data';
|
|
|
16
16
|
*/
|
|
17
17
|
import { store as editorStore } from '../../store';
|
|
18
18
|
|
|
19
|
-
export function PostTemplate(
|
|
19
|
+
export function PostTemplate() {
|
|
20
20
|
const { availableTemplates, selectedTemplate, isViewable } = useSelect(
|
|
21
21
|
( select ) => {
|
|
22
22
|
const {
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { useSelect } from '@wordpress/data';
|
|
5
|
+
import { store as coreStore } from '@wordpress/core-data';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Internal dependencies
|
|
9
|
+
*/
|
|
10
|
+
import { store as editorStore } from '../../store';
|
|
11
|
+
|
|
12
|
+
export default function PostURLCheck( { children } ) {
|
|
13
|
+
const isVisible = useSelect( ( select ) => {
|
|
14
|
+
const postTypeSlug = select( editorStore ).getCurrentPostType();
|
|
15
|
+
const postType = select( coreStore ).getPostType( postTypeSlug );
|
|
16
|
+
if ( ! postType?.viewable ) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const post = select( editorStore ).getCurrentPost();
|
|
21
|
+
if ( ! post.link ) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const permalinkParts = select( editorStore ).getPermalinkParts();
|
|
26
|
+
if ( ! permalinkParts ) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return true;
|
|
31
|
+
}, [] );
|
|
32
|
+
|
|
33
|
+
if ( ! isVisible ) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return children;
|
|
38
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { useSelect, useDispatch } from '@wordpress/data';
|
|
5
|
+
import { safeDecodeURIComponent, cleanForSlug } from '@wordpress/url';
|
|
6
|
+
import { useState } from '@wordpress/element';
|
|
7
|
+
import { __experimentalInspectorPopoverHeader as InspectorPopoverHeader } from '@wordpress/block-editor';
|
|
8
|
+
import { __ } from '@wordpress/i18n';
|
|
9
|
+
import { TextControl, ExternalLink } from '@wordpress/components';
|
|
10
|
+
import { store as coreStore } from '@wordpress/core-data';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Internal dependencies
|
|
14
|
+
*/
|
|
15
|
+
import { store as editorStore } from '../../store';
|
|
16
|
+
|
|
17
|
+
export default function PostURL( { onClose } ) {
|
|
18
|
+
const {
|
|
19
|
+
isEditable,
|
|
20
|
+
postSlug,
|
|
21
|
+
viewPostLabel,
|
|
22
|
+
postLink,
|
|
23
|
+
permalinkPrefix,
|
|
24
|
+
permalinkSuffix,
|
|
25
|
+
} = useSelect( ( select ) => {
|
|
26
|
+
const postTypeSlug = select( editorStore ).getCurrentPostType();
|
|
27
|
+
const postType = select( coreStore ).getPostType( postTypeSlug );
|
|
28
|
+
const permalinkParts = select( editorStore ).getPermalinkParts();
|
|
29
|
+
return {
|
|
30
|
+
isEditable: select( editorStore ).isPermalinkEditable(),
|
|
31
|
+
postSlug: safeDecodeURIComponent(
|
|
32
|
+
select( editorStore ).getEditedPostSlug()
|
|
33
|
+
),
|
|
34
|
+
viewPostLabel: postType?.labels.view_item,
|
|
35
|
+
postLink: select( editorStore ).getCurrentPost().link,
|
|
36
|
+
permalinkPrefix: permalinkParts?.prefix,
|
|
37
|
+
permalinkSuffix: permalinkParts?.suffix,
|
|
38
|
+
};
|
|
39
|
+
}, [] );
|
|
40
|
+
|
|
41
|
+
const { editPost } = useDispatch( editorStore );
|
|
42
|
+
|
|
43
|
+
const [ forceEmptyField, setForceEmptyField ] = useState( false );
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<div className="editor-post-url">
|
|
47
|
+
<InspectorPopoverHeader title={ __( 'URL' ) } onClose={ onClose } />
|
|
48
|
+
{ isEditable && (
|
|
49
|
+
<TextControl
|
|
50
|
+
label={ __( 'Permalink' ) }
|
|
51
|
+
value={ forceEmptyField ? '' : postSlug }
|
|
52
|
+
autoComplete="off"
|
|
53
|
+
spellCheck="false"
|
|
54
|
+
help={
|
|
55
|
+
<>
|
|
56
|
+
{ __( 'The last part of the URL.' ) }{ ' ' }
|
|
57
|
+
<ExternalLink
|
|
58
|
+
href={ __(
|
|
59
|
+
'https://wordpress.org/support/article/settings-sidebar/#permalink'
|
|
60
|
+
) }
|
|
61
|
+
>
|
|
62
|
+
{ __( 'Learn more.' ) }
|
|
63
|
+
</ExternalLink>
|
|
64
|
+
</>
|
|
65
|
+
}
|
|
66
|
+
onChange={ ( newValue ) => {
|
|
67
|
+
editPost( { slug: newValue } );
|
|
68
|
+
// When we delete the field the permalink gets
|
|
69
|
+
// reverted to the original value.
|
|
70
|
+
// The forceEmptyField logic allows the user to have
|
|
71
|
+
// the field temporarily empty while typing.
|
|
72
|
+
if ( ! newValue ) {
|
|
73
|
+
if ( ! forceEmptyField ) {
|
|
74
|
+
setForceEmptyField( true );
|
|
75
|
+
}
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if ( forceEmptyField ) {
|
|
79
|
+
setForceEmptyField( false );
|
|
80
|
+
}
|
|
81
|
+
} }
|
|
82
|
+
onBlur={ ( event ) => {
|
|
83
|
+
editPost( {
|
|
84
|
+
slug: cleanForSlug( event.target.value ),
|
|
85
|
+
} );
|
|
86
|
+
if ( forceEmptyField ) {
|
|
87
|
+
setForceEmptyField( false );
|
|
88
|
+
}
|
|
89
|
+
} }
|
|
90
|
+
/>
|
|
91
|
+
) }
|
|
92
|
+
{ isEditable && (
|
|
93
|
+
<h3 className="editor-post-url__link-label">
|
|
94
|
+
{ viewPostLabel ?? __( 'View post' ) }
|
|
95
|
+
</h3>
|
|
96
|
+
) }
|
|
97
|
+
<p>
|
|
98
|
+
<ExternalLink
|
|
99
|
+
className="editor-post-url__link"
|
|
100
|
+
href={ postLink }
|
|
101
|
+
target="_blank"
|
|
102
|
+
>
|
|
103
|
+
{ isEditable ? (
|
|
104
|
+
<>
|
|
105
|
+
<span className="editor-post-url__link-prefix">
|
|
106
|
+
{ permalinkPrefix }
|
|
107
|
+
</span>
|
|
108
|
+
<span className="editor-post-url__link-slug">
|
|
109
|
+
{ postSlug }
|
|
110
|
+
</span>
|
|
111
|
+
<span className="editor-post-url__link-suffix">
|
|
112
|
+
{ permalinkSuffix }
|
|
113
|
+
</span>
|
|
114
|
+
</>
|
|
115
|
+
) : (
|
|
116
|
+
postLink
|
|
117
|
+
) }
|
|
118
|
+
</ExternalLink>
|
|
119
|
+
</p>
|
|
120
|
+
</div>
|
|
121
|
+
);
|
|
122
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { useSelect } from '@wordpress/data';
|
|
5
|
+
import { filterURLForDisplay } from '@wordpress/url';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Internal dependencies
|
|
9
|
+
*/
|
|
10
|
+
import { store as editorStore } from '../../store';
|
|
11
|
+
|
|
12
|
+
export default function PostURLLabel() {
|
|
13
|
+
return usePostURLLabel();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function usePostURLLabel() {
|
|
17
|
+
const postLink = useSelect(
|
|
18
|
+
( select ) => select( editorStore ).getCurrentPost().link,
|
|
19
|
+
[]
|
|
20
|
+
);
|
|
21
|
+
return filterURLForDisplay( postLink );
|
|
22
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
.editor-post-url__link-label {
|
|
2
|
+
font-size: $default-font-size;
|
|
3
|
+
font-weight: 400;
|
|
4
|
+
margin: 0;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/* rtl:begin:ignore */
|
|
8
|
+
.editor-post-url__link {
|
|
9
|
+
direction: ltr;
|
|
10
|
+
word-break: break-word;
|
|
11
|
+
}
|
|
12
|
+
/* rtl:end:ignore */
|
|
13
|
+
|
|
14
|
+
.editor-post-url__link-slug {
|
|
15
|
+
font-weight: 600;
|
|
16
|
+
}
|
|
@@ -10,6 +10,10 @@ import { visibilityOptions } from './utils';
|
|
|
10
10
|
import { store as editorStore } from '../../store';
|
|
11
11
|
|
|
12
12
|
export default function PostVisibilityLabel() {
|
|
13
|
+
return usePostVisibilityLabel();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function usePostVisibilityLabel() {
|
|
13
17
|
const visibility = useSelect( ( select ) =>
|
|
14
18
|
select( editorStore ).getEditedPostVisibility()
|
|
15
19
|
);
|
|
@@ -9,6 +9,7 @@ import { store as blockEditorStore } from '@wordpress/block-editor';
|
|
|
9
9
|
* Internal dependencies
|
|
10
10
|
*/
|
|
11
11
|
import WordCount from '../word-count';
|
|
12
|
+
import TimeToRead from '../time-to-read';
|
|
12
13
|
import DocumentOutline from '../document-outline';
|
|
13
14
|
import CharacterCount from '../character-count';
|
|
14
15
|
|
|
@@ -38,6 +39,10 @@ function TableOfContentsPanel( { hasOutlineItemsDisabled, onRequestClose } ) {
|
|
|
38
39
|
tabIndex="0"
|
|
39
40
|
>
|
|
40
41
|
<ul role="list" className="table-of-contents__counts">
|
|
42
|
+
<li className="table-of-contents__count">
|
|
43
|
+
{ __( 'Words' ) }
|
|
44
|
+
<WordCount />
|
|
45
|
+
</li>
|
|
41
46
|
<li className="table-of-contents__count">
|
|
42
47
|
{ __( 'Characters' ) }
|
|
43
48
|
<span className="table-of-contents__number">
|
|
@@ -45,8 +50,8 @@ function TableOfContentsPanel( { hasOutlineItemsDisabled, onRequestClose } ) {
|
|
|
45
50
|
</span>
|
|
46
51
|
</li>
|
|
47
52
|
<li className="table-of-contents__count">
|
|
48
|
-
{ __( '
|
|
49
|
-
<
|
|
53
|
+
{ __( 'Time to read' ) }
|
|
54
|
+
<TimeToRead />
|
|
50
55
|
</li>
|
|
51
56
|
<li className="table-of-contents__count">
|
|
52
57
|
{ __( 'Headings' ) }
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { useSelect } from '@wordpress/data';
|
|
5
|
+
import { _x, _n, __, sprintf } from '@wordpress/i18n';
|
|
6
|
+
import { count as wordCount } from '@wordpress/wordcount';
|
|
7
|
+
import { createInterpolateElement } from '@wordpress/element';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Internal dependencies
|
|
11
|
+
*/
|
|
12
|
+
import { store as editorStore } from '../../store';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Average reading rate - based on average taken from
|
|
16
|
+
* https://irisreading.com/average-reading-speed-in-various-languages/
|
|
17
|
+
* (Characters/minute used for Chinese rather than words).
|
|
18
|
+
*
|
|
19
|
+
* @type {number} A rough estimate of the average reading rate across multiple languages.
|
|
20
|
+
*/
|
|
21
|
+
const AVERAGE_READING_RATE = 189;
|
|
22
|
+
|
|
23
|
+
export default function TimeToRead() {
|
|
24
|
+
const content = useSelect(
|
|
25
|
+
( select ) => select( editorStore ).getEditedPostAttribute( 'content' ),
|
|
26
|
+
[]
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
/*
|
|
30
|
+
* translators: If your word count is based on single characters (e.g. East Asian characters),
|
|
31
|
+
* enter 'characters_excluding_spaces' or 'characters_including_spaces'. Otherwise, enter 'words'.
|
|
32
|
+
* Do not translate into your own language.
|
|
33
|
+
*/
|
|
34
|
+
const wordCountType = _x( 'words', 'Word count type. Do not translate!' );
|
|
35
|
+
const minutesToRead = Math.round(
|
|
36
|
+
wordCount( content, wordCountType ) / AVERAGE_READING_RATE
|
|
37
|
+
);
|
|
38
|
+
const minutesToReadString =
|
|
39
|
+
minutesToRead === 0
|
|
40
|
+
? createInterpolateElement( __( '<span>< 1</span> minute' ), {
|
|
41
|
+
span: <span className="table-of-contents__number" />,
|
|
42
|
+
} )
|
|
43
|
+
: createInterpolateElement(
|
|
44
|
+
sprintf(
|
|
45
|
+
/* translators: %s is the number of minutes the post will take to read. */
|
|
46
|
+
_n(
|
|
47
|
+
'<span>%d</span> minute',
|
|
48
|
+
'<span>%d</span> minutes',
|
|
49
|
+
minutesToRead
|
|
50
|
+
),
|
|
51
|
+
minutesToRead
|
|
52
|
+
),
|
|
53
|
+
{
|
|
54
|
+
span: <span className="table-of-contents__number" />,
|
|
55
|
+
}
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
return <span className="time-to-read">{ minutesToReadString }</span>;
|
|
59
|
+
}
|
package/src/store/selectors.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* External dependencies
|
|
3
3
|
*/
|
|
4
|
-
import { find, get, has,
|
|
4
|
+
import { find, get, has, includes, some } from 'lodash';
|
|
5
5
|
import createSelector from 'rememo';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -1605,10 +1605,9 @@ export function __experimentalGetTemplateInfo( state, template ) {
|
|
|
1605
1605
|
const { title: defaultTitle, description: defaultDescription } =
|
|
1606
1606
|
__experimentalGetDefaultTemplateType( state, slug );
|
|
1607
1607
|
|
|
1608
|
-
const templateTitle =
|
|
1609
|
-
const templateDescription =
|
|
1610
|
-
? description
|
|
1611
|
-
: description?.raw;
|
|
1608
|
+
const templateTitle = typeof title === 'string' ? title : title?.rendered;
|
|
1609
|
+
const templateDescription =
|
|
1610
|
+
typeof description === 'string' ? description : description?.raw;
|
|
1612
1611
|
const templateIcon =
|
|
1613
1612
|
__experimentalGetDefaultTemplatePartAreas( state ).find(
|
|
1614
1613
|
( item ) => area === item.area
|
package/src/style.scss
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
@import "./components/post-saved-state/style.scss";
|
|
15
15
|
@import "./components/post-taxonomies/style.scss";
|
|
16
16
|
@import "./components/post-text-editor/style.scss";
|
|
17
|
+
@import "./components/post-url/style.scss";
|
|
17
18
|
@import "./components/post-visibility/style.scss";
|
|
18
19
|
@import "./components/post-title/style.scss";
|
|
19
20
|
@import "./components/post-trash/style.scss";
|