@wordpress/editor 14.22.0 → 14.23.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/post-author/check.js +3 -7
- package/build/components/post-author/check.js.map +1 -1
- package/build/components/post-author/panel.js +10 -2
- package/build/components/post-author/panel.js.map +1 -1
- package/build/components/post-template/swap-template-button.js +18 -4
- package/build/components/post-template/swap-template-button.js.map +1 -1
- package/build/components/visual-editor/index.js +1 -2
- package/build/components/visual-editor/index.js.map +1 -1
- package/build/utils/search-templates.js +75 -0
- package/build/utils/search-templates.js.map +1 -0
- package/build-module/components/post-author/check.js +3 -7
- package/build-module/components/post-author/check.js.map +1 -1
- package/build-module/components/post-author/panel.js +10 -2
- package/build-module/components/post-author/panel.js.map +1 -1
- package/build-module/components/post-template/swap-template-button.js +19 -5
- package/build-module/components/post-template/swap-template-button.js.map +1 -1
- package/build-module/components/visual-editor/index.js +1 -2
- package/build-module/components/visual-editor/index.js.map +1 -1
- package/build-module/utils/search-templates.js +68 -0
- package/build-module/utils/search-templates.js.map +1 -0
- package/build-style/style-rtl.css +13 -18
- package/build-style/style.css +13 -18
- package/build-types/components/post-author/check.d.ts.map +1 -1
- package/build-types/components/post-author/panel.d.ts.map +1 -1
- package/build-types/components/post-template/swap-template-button.d.ts.map +1 -1
- package/build-types/components/visual-editor/index.d.ts.map +1 -1
- package/build-types/utils/search-templates.d.ts +10 -0
- package/build-types/utils/search-templates.d.ts.map +1 -0
- package/package.json +37 -37
- package/src/components/editor-interface/style.scss +1 -2
- package/src/components/post-author/check.js +2 -7
- package/src/components/post-author/panel.js +10 -2
- package/src/components/post-author/test/check.js +3 -11
- package/src/components/post-template/style.scss +10 -0
- package/src/components/post-template/swap-template-button.js +23 -6
- package/src/components/visual-editor/index.js +0 -1
- package/src/components/visual-editor/style.scss +6 -29
- package/src/utils/search-templates.js +77 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -2,14 +2,12 @@
|
|
|
2
2
|
* WordPress dependencies
|
|
3
3
|
*/
|
|
4
4
|
import { useSelect } from '@wordpress/data';
|
|
5
|
-
import { store as coreStore } from '@wordpress/core-data';
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
7
|
* Internal dependencies
|
|
9
8
|
*/
|
|
10
9
|
import PostTypeSupportCheck from '../post-type-support-check';
|
|
11
10
|
import { store as editorStore } from '../../store';
|
|
12
|
-
import { AUTHORS_QUERY } from './constants';
|
|
13
11
|
|
|
14
12
|
/**
|
|
15
13
|
* Wrapper component that renders its children only if the post type supports the author.
|
|
@@ -21,20 +19,17 @@ import { AUTHORS_QUERY } from './constants';
|
|
|
21
19
|
* supports the author or if there are no authors available.
|
|
22
20
|
*/
|
|
23
21
|
export default function PostAuthorCheck( { children } ) {
|
|
24
|
-
const { hasAssignAuthorAction
|
|
22
|
+
const { hasAssignAuthorAction } = useSelect( ( select ) => {
|
|
25
23
|
const post = select( editorStore ).getCurrentPost();
|
|
26
24
|
const canAssignAuthor = post?._links?.[ 'wp:action-assign-author' ]
|
|
27
25
|
? true
|
|
28
26
|
: false;
|
|
29
27
|
return {
|
|
30
28
|
hasAssignAuthorAction: canAssignAuthor,
|
|
31
|
-
hasAuthors: canAssignAuthor
|
|
32
|
-
? select( coreStore ).getUsers( AUTHORS_QUERY )?.length >= 1
|
|
33
|
-
: false,
|
|
34
29
|
};
|
|
35
30
|
}, [] );
|
|
36
31
|
|
|
37
|
-
if ( ! hasAssignAuthorAction
|
|
32
|
+
if ( ! hasAssignAuthorAction ) {
|
|
38
33
|
return null;
|
|
39
34
|
}
|
|
40
35
|
|
|
@@ -6,6 +6,8 @@ import { Button, Dropdown } from '@wordpress/components';
|
|
|
6
6
|
import { useState, useMemo } from '@wordpress/element';
|
|
7
7
|
import { decodeEntities } from '@wordpress/html-entities';
|
|
8
8
|
import { __experimentalInspectorPopoverHeader as InspectorPopoverHeader } from '@wordpress/block-editor';
|
|
9
|
+
import { useSelect } from '@wordpress/data';
|
|
10
|
+
import { store as coreStore } from '@wordpress/core-data';
|
|
9
11
|
|
|
10
12
|
/**
|
|
11
13
|
* Internal dependencies
|
|
@@ -13,10 +15,16 @@ import { __experimentalInspectorPopoverHeader as InspectorPopoverHeader } from '
|
|
|
13
15
|
import PostAuthorCheck from './check';
|
|
14
16
|
import PostAuthorForm from './index';
|
|
15
17
|
import PostPanelRow from '../post-panel-row';
|
|
16
|
-
import {
|
|
18
|
+
import { BASE_QUERY } from './constants';
|
|
19
|
+
import { store as editorStore } from '../../store';
|
|
17
20
|
|
|
18
21
|
function PostAuthorToggle( { isOpen, onClick } ) {
|
|
19
|
-
const { postAuthor } =
|
|
22
|
+
const { postAuthor } = useSelect( ( select ) => {
|
|
23
|
+
const id = select( editorStore ).getEditedPostAttribute( 'author' );
|
|
24
|
+
return {
|
|
25
|
+
postAuthor: select( coreStore ).getUser( id, BASE_QUERY ),
|
|
26
|
+
};
|
|
27
|
+
}, [] );
|
|
20
28
|
const authorName =
|
|
21
29
|
decodeEntities( postAuthor?.name ) || __( '(No author)' );
|
|
22
30
|
return (
|
|
@@ -19,7 +19,7 @@ jest.mock( '@wordpress/data/src/components/use-select', () => {
|
|
|
19
19
|
return mock;
|
|
20
20
|
} );
|
|
21
21
|
|
|
22
|
-
function setupUseSelectMock( hasAssignAuthorAction
|
|
22
|
+
function setupUseSelectMock( hasAssignAuthorAction ) {
|
|
23
23
|
useSelect.mockImplementation( ( cb ) => {
|
|
24
24
|
return cb( () => ( {
|
|
25
25
|
getPostType: () => ( { supports: { author: true } } ),
|
|
@@ -29,28 +29,20 @@ function setupUseSelectMock( hasAssignAuthorAction, hasAuthors ) {
|
|
|
29
29
|
'wp:action-assign-author': hasAssignAuthorAction,
|
|
30
30
|
},
|
|
31
31
|
} ),
|
|
32
|
-
getUsers: () => Array( hasAuthors ? 1 : 0 ).fill( {} ),
|
|
33
32
|
} ) );
|
|
34
33
|
} );
|
|
35
34
|
}
|
|
36
35
|
|
|
37
36
|
describe( 'PostAuthorCheck', () => {
|
|
38
|
-
it( 'should not render anything if has no authors', () => {
|
|
39
|
-
setupUseSelectMock( false, true );
|
|
40
|
-
|
|
41
|
-
render( <PostAuthorCheck>authors</PostAuthorCheck> );
|
|
42
|
-
expect( screen.queryByText( 'authors' ) ).not.toBeInTheDocument();
|
|
43
|
-
} );
|
|
44
|
-
|
|
45
37
|
it( "should not render anything if doesn't have author action", () => {
|
|
46
|
-
setupUseSelectMock(
|
|
38
|
+
setupUseSelectMock( false );
|
|
47
39
|
|
|
48
40
|
render( <PostAuthorCheck>authors</PostAuthorCheck> );
|
|
49
41
|
expect( screen.queryByText( 'authors' ) ).not.toBeInTheDocument();
|
|
50
42
|
} );
|
|
51
43
|
|
|
52
44
|
it( 'should render control', () => {
|
|
53
|
-
setupUseSelectMock( true
|
|
45
|
+
setupUseSelectMock( true );
|
|
54
46
|
|
|
55
47
|
render( <PostAuthorCheck>authors</PostAuthorCheck> );
|
|
56
48
|
expect( screen.getByText( 'authors' ) ).toBeVisible();
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
.editor-post-template__swap-template-modal {
|
|
2
2
|
z-index: z-index(".editor-post-template__swap-template-modal");
|
|
3
|
+
|
|
4
|
+
.editor-post-template__swap-template-search {
|
|
5
|
+
background: $white;
|
|
6
|
+
position: sticky;
|
|
7
|
+
top: 0;
|
|
8
|
+
padding: $grid-unit-20 0;
|
|
9
|
+
transform: translateY(- $grid-unit-05); // Offsets the top padding on the modal content container
|
|
10
|
+
margin-bottom: - $grid-unit-05;
|
|
11
|
+
z-index: z-index(".editor-post-template__swap-template-search");
|
|
12
|
+
}
|
|
3
13
|
}
|
|
4
14
|
|
|
5
15
|
.editor-post-template__create-template-modal {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { useMemo, useState } from '@wordpress/element';
|
|
5
5
|
import { decodeEntities } from '@wordpress/html-entities';
|
|
6
6
|
import { __experimentalBlockPatternsList as BlockPatternsList } from '@wordpress/block-editor';
|
|
7
|
-
import { MenuItem, Modal } from '@wordpress/components';
|
|
7
|
+
import { MenuItem, Modal, SearchControl } from '@wordpress/components';
|
|
8
8
|
import { __ } from '@wordpress/i18n';
|
|
9
9
|
import { useDispatch } from '@wordpress/data';
|
|
10
10
|
import { store as coreStore } from '@wordpress/core-data';
|
|
@@ -14,6 +14,7 @@ import { parse } from '@wordpress/blocks';
|
|
|
14
14
|
* Internal dependencies
|
|
15
15
|
*/
|
|
16
16
|
import { useAvailableTemplates, useEditedPostContext } from './hooks';
|
|
17
|
+
import { searchTemplates } from '../../utils/search-templates';
|
|
17
18
|
|
|
18
19
|
export default function SwapTemplateButton( { onClick } ) {
|
|
19
20
|
const [ showModal, setShowModal ] = useState( false );
|
|
@@ -61,6 +62,7 @@ export default function SwapTemplateButton( { onClick } ) {
|
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
function TemplatesList( { postType, onSelect } ) {
|
|
65
|
+
const [ searchValue, setSearchValue ] = useState( '' );
|
|
64
66
|
const availableTemplates = useAvailableTemplates( postType );
|
|
65
67
|
const templatesAsPatterns = useMemo(
|
|
66
68
|
() =>
|
|
@@ -72,11 +74,26 @@ function TemplatesList( { postType, onSelect } ) {
|
|
|
72
74
|
} ) ),
|
|
73
75
|
[ availableTemplates ]
|
|
74
76
|
);
|
|
77
|
+
|
|
78
|
+
const filteredBlockTemplates = useMemo( () => {
|
|
79
|
+
return searchTemplates( templatesAsPatterns, searchValue );
|
|
80
|
+
}, [ templatesAsPatterns, searchValue ] );
|
|
81
|
+
|
|
75
82
|
return (
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
83
|
+
<>
|
|
84
|
+
<SearchControl
|
|
85
|
+
__nextHasNoMarginBottom
|
|
86
|
+
onChange={ setSearchValue }
|
|
87
|
+
value={ searchValue }
|
|
88
|
+
label={ __( 'Search' ) }
|
|
89
|
+
placeholder={ __( 'Search' ) }
|
|
90
|
+
className="editor-post-template__swap-template-search"
|
|
91
|
+
/>
|
|
92
|
+
<BlockPatternsList
|
|
93
|
+
label={ __( 'Templates' ) }
|
|
94
|
+
blockPatterns={ filteredBlockTemplates }
|
|
95
|
+
onClickPattern={ onSelect }
|
|
96
|
+
/>
|
|
97
|
+
</>
|
|
81
98
|
);
|
|
82
99
|
}
|
|
@@ -6,9 +6,6 @@
|
|
|
6
6
|
// when the iframe doesn't cover the whole canvas
|
|
7
7
|
// like the "focused entities".
|
|
8
8
|
background-color: $gray-300;
|
|
9
|
-
// Allows the height to fit the parent container and avoids parent scrolling contexts from
|
|
10
|
-
// having overflow due to popovers of block tools.
|
|
11
|
-
overflow: hidden;
|
|
12
9
|
|
|
13
10
|
// This overrides the iframe background since it's applied again here
|
|
14
11
|
// It also prevents some style glitches if `editor-visual-editor`
|
|
@@ -28,6 +25,12 @@
|
|
|
28
25
|
padding: $grid-unit-30 $grid-unit-30 0;
|
|
29
26
|
}
|
|
30
27
|
|
|
28
|
+
// In the iframed canvas this keeps extra scrollbars from appearing (when block toolbars overflow). In the
|
|
29
|
+
// legacy (non-iframed) canvas, overflow must not be hidden in order to maintain support for sticky positioning.
|
|
30
|
+
&.is-iframed {
|
|
31
|
+
overflow: hidden;
|
|
32
|
+
}
|
|
33
|
+
|
|
31
34
|
// The button element easily inherits styles that are meant for the editor style.
|
|
32
35
|
// These rules enhance the specificity to reduce that inheritance.
|
|
33
36
|
// This is duplicated in edit-site.
|
|
@@ -41,30 +44,4 @@
|
|
|
41
44
|
padding: 6px;
|
|
42
45
|
}
|
|
43
46
|
}
|
|
44
|
-
|
|
45
|
-
// The cases for this are non-iframed editor canvas or previewing devices. The block canvas is
|
|
46
|
-
// made the scrolling context.
|
|
47
|
-
&.is-scrollable .block-editor-block-canvas {
|
|
48
|
-
overflow: auto;
|
|
49
|
-
|
|
50
|
-
// Applicable only when legacy (non-iframed).
|
|
51
|
-
> .block-editor-writing-flow {
|
|
52
|
-
display: flow-root;
|
|
53
|
-
min-height: 100%;
|
|
54
|
-
box-sizing: border-box; // Ensures that 100% min-height doesn’t create overflow.
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Applicable only when iframed. These styles ensure that if the the iframe is
|
|
58
|
-
// given a fixed height and it’s taller than the viewport then scrolling is
|
|
59
|
-
// allowed. This is needed for device previews.
|
|
60
|
-
> .block-editor-iframe__container {
|
|
61
|
-
display: flex;
|
|
62
|
-
flex-direction: column;
|
|
63
|
-
|
|
64
|
-
> .block-editor-iframe__scale-container {
|
|
65
|
-
flex: 1 0 fit-content;
|
|
66
|
-
display: flow-root;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
47
|
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import removeAccents from 'remove-accents';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Sanitizes the search input string.
|
|
8
|
+
*
|
|
9
|
+
* @param {string} input The search input to normalize.
|
|
10
|
+
*
|
|
11
|
+
* @return {string} The normalized search input.
|
|
12
|
+
*/
|
|
13
|
+
function normalizeSearchInput( input = '' ) {
|
|
14
|
+
// Disregard diacritics.
|
|
15
|
+
input = removeAccents( input );
|
|
16
|
+
|
|
17
|
+
// Trim & Lowercase.
|
|
18
|
+
input = input.trim().toLowerCase();
|
|
19
|
+
|
|
20
|
+
return input;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Get the search rank for a given template and a specific search term.
|
|
25
|
+
*
|
|
26
|
+
* @param {Object} template Template to rank
|
|
27
|
+
* @param {string} searchValue Search term
|
|
28
|
+
*
|
|
29
|
+
* @return {number} A template search rank
|
|
30
|
+
*/
|
|
31
|
+
function getTemplateSearchRank( template, searchValue ) {
|
|
32
|
+
const normalizedSearchValue = normalizeSearchInput( searchValue );
|
|
33
|
+
const normalizedTitle = normalizeSearchInput( template.title );
|
|
34
|
+
|
|
35
|
+
let rank = 0;
|
|
36
|
+
|
|
37
|
+
if ( normalizedSearchValue === normalizedTitle ) {
|
|
38
|
+
rank += 30;
|
|
39
|
+
} else if ( normalizedTitle.startsWith( normalizedSearchValue ) ) {
|
|
40
|
+
rank += 20;
|
|
41
|
+
} else {
|
|
42
|
+
const searchTerms = normalizedSearchValue.split( ' ' );
|
|
43
|
+
const hasMatchedTerms = searchTerms.every( ( searchTerm ) =>
|
|
44
|
+
normalizedTitle.includes( searchTerm )
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
// Prefer template with every search word in the title.
|
|
48
|
+
if ( hasMatchedTerms ) {
|
|
49
|
+
rank += 10;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return rank;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Filters a template list given a search term.
|
|
58
|
+
*
|
|
59
|
+
* @param {Array} templates Item list
|
|
60
|
+
* @param {string} searchValue Search input.
|
|
61
|
+
*
|
|
62
|
+
* @return {Array} Filtered template list.
|
|
63
|
+
*/
|
|
64
|
+
export function searchTemplates( templates = [], searchValue = '' ) {
|
|
65
|
+
if ( ! searchValue ) {
|
|
66
|
+
return templates;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const rankedTemplates = templates
|
|
70
|
+
.map( ( template ) => {
|
|
71
|
+
return [ template, getTemplateSearchRank( template, searchValue ) ];
|
|
72
|
+
} )
|
|
73
|
+
.filter( ( [ , rank ] ) => rank > 0 );
|
|
74
|
+
|
|
75
|
+
rankedTemplates.sort( ( [ , rank1 ], [ , rank2 ] ) => rank2 - rank1 );
|
|
76
|
+
return rankedTemplates.map( ( [ template ] ) => template );
|
|
77
|
+
}
|