@elementor/editor-site-navigation 0.10.3 → 0.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 +22 -0
- package/dist/index.js +445 -174
- package/dist/index.mjs +441 -161
- package/package.json +2 -2
- package/src/api/post.ts +14 -6
- package/src/components/panel/actions-menu/action-list-item.tsx +1 -1
- package/src/components/panel/{pages-actions → actions-menu/actions}/delete.tsx +5 -5
- package/src/components/panel/actions-menu/actions/duplicate.tsx +29 -0
- package/src/components/panel/actions-menu/actions/rename.tsx +25 -0
- package/src/components/panel/{pages-actions → actions-menu/actions}/set-home.tsx +4 -4
- package/src/components/panel/actions-menu/actions/view.tsx +25 -0
- package/src/components/panel/add-new-button.tsx +22 -0
- package/src/components/panel/{pages-list/__tests__/page-list-item.test.tsx → posts-list/__tests__/post-list-item.test.tsx} +21 -18
- package/src/components/panel/{pages-list/__tests__/pages-collapsible-list.test.tsx → posts-list/__tests__/posts-collapsible-list.test.tsx} +11 -14
- package/src/components/panel/{pages-list → posts-list}/collapsible-list.tsx +4 -4
- package/src/components/panel/posts-list/list-items/edit-mode-template.tsx +103 -0
- package/src/components/panel/posts-list/list-items/list-item-create.tsx +25 -0
- package/src/components/panel/posts-list/list-items/list-item-duplicate.tsx +29 -0
- package/src/components/panel/posts-list/list-items/list-item-rename.tsx +33 -0
- package/src/components/panel/posts-list/list-items/list-item-view.tsx +87 -0
- package/src/components/panel/posts-list/post-list-item.tsx +29 -0
- package/src/components/panel/posts-list/posts-collapsible-list.tsx +44 -0
- package/src/components/panel/shell.tsx +14 -13
- package/src/components/top-bar/__tests__/add-new-page.test.tsx +11 -12
- package/src/components/top-bar/__tests__/recently-edited.test.tsx +30 -30
- package/src/contexts/post-list-context.tsx +73 -0
- package/src/env.ts +2 -2
- package/src/hooks/__tests__/use-create-page.test.ts +6 -8
- package/src/hooks/__tests__/use-posts.test.ts +4 -6
- package/src/hooks/__tests__/use-recent-posts.test.ts +4 -4
- package/src/init.ts +1 -1
- package/src/components/panel/actions-menu/page-actions-menu.tsx +0 -29
- package/src/components/panel/add-new-page-button.tsx +0 -15
- package/src/components/panel/pages-actions/duplicate.tsx +0 -14
- package/src/components/panel/pages-actions/rename.tsx +0 -14
- package/src/components/panel/pages-actions/view.tsx +0 -14
- package/src/components/panel/pages-list/page-list-item.tsx +0 -66
- package/src/components/panel/pages-list/pages-collapsible-list.tsx +0 -37
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elementor/editor-site-navigation",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"author": "Elementor Team",
|
|
6
6
|
"homepage": "https://elementor.com/",
|
|
@@ -49,5 +49,5 @@
|
|
|
49
49
|
"elementor": {
|
|
50
50
|
"type": "extension"
|
|
51
51
|
},
|
|
52
|
-
"gitHead": "
|
|
52
|
+
"gitHead": "e8add4d4645e1c8f62a11ddac8d26d50341b6ed2"
|
|
53
53
|
}
|
package/src/api/post.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import apiFetch from '@wordpress/api-fetch';
|
|
2
2
|
import { Post } from '../types';
|
|
3
|
+
import { __ } from '@wordpress/i18n';
|
|
3
4
|
|
|
4
5
|
export type NewPost = {
|
|
5
6
|
title: string,
|
|
@@ -13,18 +14,25 @@ export type UpdatePost = {
|
|
|
13
14
|
|
|
14
15
|
export type Slug = keyof typeof postTypesMap;
|
|
15
16
|
|
|
16
|
-
const postTypesMap = {
|
|
17
|
-
page:
|
|
17
|
+
export const postTypesMap = {
|
|
18
|
+
page: {
|
|
19
|
+
labels: {
|
|
20
|
+
singular_name: __( 'Page', 'elementor' ),
|
|
21
|
+
plural_name: __( 'Pages', 'elementor' ),
|
|
22
|
+
},
|
|
23
|
+
rest_base: 'pages',
|
|
24
|
+
},
|
|
18
25
|
};
|
|
19
26
|
|
|
20
27
|
export const getRequest = ( postTypeSlug: Slug ) => {
|
|
21
|
-
const baseUri = `/wp/v2/${ postTypesMap[ postTypeSlug ] }`;
|
|
28
|
+
const baseUri = `/wp/v2/${ postTypesMap[ postTypeSlug ].rest_base }`;
|
|
22
29
|
|
|
23
30
|
const keys: Array<keyof Post> = [ 'id', 'type', 'title', 'link', 'status' ];
|
|
24
31
|
|
|
25
32
|
const queryParams = new URLSearchParams( {
|
|
26
33
|
status: 'any',
|
|
27
34
|
per_page: '-1',
|
|
35
|
+
order: 'asc',
|
|
28
36
|
_fields: keys.join( ',' ),
|
|
29
37
|
} );
|
|
30
38
|
|
|
@@ -34,7 +42,7 @@ export const getRequest = ( postTypeSlug: Slug ) => {
|
|
|
34
42
|
};
|
|
35
43
|
|
|
36
44
|
export const createRequest = ( postTypeSlug: Slug, newPost: NewPost ) => {
|
|
37
|
-
const path = `/wp/v2/${ postTypesMap[ postTypeSlug ] }`;
|
|
45
|
+
const path = `/wp/v2/${ postTypesMap[ postTypeSlug ].rest_base }`;
|
|
38
46
|
|
|
39
47
|
return apiFetch( {
|
|
40
48
|
path,
|
|
@@ -44,7 +52,7 @@ export const createRequest = ( postTypeSlug: Slug, newPost: NewPost ) => {
|
|
|
44
52
|
};
|
|
45
53
|
|
|
46
54
|
export const updateRequest = ( postTypeSlug: Slug, updatedPost: UpdatePost ) => {
|
|
47
|
-
const path = `/wp/v2/${ postTypesMap[ postTypeSlug ] }`;
|
|
55
|
+
const path = `/wp/v2/${ postTypesMap[ postTypeSlug ].rest_base }`;
|
|
48
56
|
const { id, ...data } = updatedPost;
|
|
49
57
|
|
|
50
58
|
return apiFetch( {
|
|
@@ -55,7 +63,7 @@ export const updateRequest = ( postTypeSlug: Slug, updatedPost: UpdatePost ) =>
|
|
|
55
63
|
};
|
|
56
64
|
|
|
57
65
|
export const deleteRequest = ( postTypeSlug: Slug, postId: number ) => {
|
|
58
|
-
const path = `/wp/v2/${ postTypesMap[ postTypeSlug ] }`;
|
|
66
|
+
const path = `/wp/v2/${ postTypesMap[ postTypeSlug ].rest_base }`;
|
|
59
67
|
|
|
60
68
|
return apiFetch( {
|
|
61
69
|
path: `${ path }/${ postId }`,
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { TrashIcon } from '@elementor/icons';
|
|
3
|
-
import { Post } from '
|
|
3
|
+
import { Post } from '../../../../types';
|
|
4
4
|
import { useActiveDocument } from '@elementor/editor-documents';
|
|
5
5
|
import { __ } from '@wordpress/i18n';
|
|
6
|
-
import ActionMenuItem from '../
|
|
6
|
+
import ActionMenuItem from '../action-menu-item';
|
|
7
7
|
|
|
8
|
-
export default function Delete( {
|
|
8
|
+
export default function Delete( { post }: { post: Post } ) {
|
|
9
9
|
const activeDocument = useActiveDocument();
|
|
10
10
|
|
|
11
|
-
const isActive = activeDocument?.id ===
|
|
11
|
+
const isActive = activeDocument?.id === post.id;
|
|
12
12
|
|
|
13
13
|
return (
|
|
14
14
|
<ActionMenuItem
|
|
15
15
|
title={ __( 'Delete', 'elementor' ) }
|
|
16
16
|
icon={ TrashIcon }
|
|
17
|
-
disabled={
|
|
17
|
+
disabled={ post.isHome || isActive }
|
|
18
18
|
onClick={ () => null }
|
|
19
19
|
/>
|
|
20
20
|
);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { PopupState } from '@elementor/ui';
|
|
3
|
+
import { CopyIcon } from '@elementor/icons';
|
|
4
|
+
import { __ } from '@wordpress/i18n';
|
|
5
|
+
import ActionMenuItem from '../action-menu-item';
|
|
6
|
+
import { usePostListContext } from '../../../../contexts/post-list-context';
|
|
7
|
+
import { Post } from '../../../../types';
|
|
8
|
+
|
|
9
|
+
export default function Duplicate( { post, popupState }: { post: Post, popupState: PopupState } ) {
|
|
10
|
+
const { setEditMode } = usePostListContext();
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<ActionMenuItem
|
|
14
|
+
title={ __( 'Duplicate', 'elementor' ) }
|
|
15
|
+
icon={ CopyIcon }
|
|
16
|
+
onClick={ () => {
|
|
17
|
+
popupState.close();
|
|
18
|
+
|
|
19
|
+
setEditMode( {
|
|
20
|
+
mode: 'duplicate',
|
|
21
|
+
details: {
|
|
22
|
+
postId: post.id,
|
|
23
|
+
title: post.title.rendered,
|
|
24
|
+
},
|
|
25
|
+
} );
|
|
26
|
+
} }
|
|
27
|
+
/>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { EraseIcon } from '@elementor/icons';
|
|
3
|
+
import { __ } from '@wordpress/i18n';
|
|
4
|
+
import ActionMenuItem from '../action-menu-item';
|
|
5
|
+
import { usePostListContext } from '../../../../contexts/post-list-context';
|
|
6
|
+
import { Post } from '../../../../types';
|
|
7
|
+
|
|
8
|
+
export default function Rename( { post }: { post: Post } ) {
|
|
9
|
+
const { setEditMode } = usePostListContext();
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<ActionMenuItem
|
|
13
|
+
title={ __( 'Rename', 'elementor' ) }
|
|
14
|
+
icon={ EraseIcon }
|
|
15
|
+
onClick={ () => {
|
|
16
|
+
setEditMode( {
|
|
17
|
+
mode: 'rename',
|
|
18
|
+
details: {
|
|
19
|
+
postId: post.id,
|
|
20
|
+
},
|
|
21
|
+
} );
|
|
22
|
+
} }
|
|
23
|
+
/>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { Post } from '
|
|
2
|
+
import { Post } from '../../../../types';
|
|
3
3
|
import { HomeIcon } from '@elementor/icons';
|
|
4
4
|
import { __ } from '@wordpress/i18n';
|
|
5
|
-
import ActionMenuItem from '../
|
|
5
|
+
import ActionMenuItem from '../action-menu-item';
|
|
6
6
|
|
|
7
|
-
export default function SetHome( {
|
|
7
|
+
export default function SetHome( { post }: { post: Post } ) {
|
|
8
8
|
return (
|
|
9
9
|
<ActionMenuItem
|
|
10
10
|
title={ __( 'Set as homepage', 'elementor' ) }
|
|
11
11
|
icon={ HomeIcon }
|
|
12
|
-
disabled={ !!
|
|
12
|
+
disabled={ !! post.isHome }
|
|
13
13
|
onClick={ () => null }
|
|
14
14
|
/>
|
|
15
15
|
);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { EyeIcon } from '@elementor/icons';
|
|
3
|
+
import { __ } from '@wordpress/i18n';
|
|
4
|
+
import ActionMenuItem from '../action-menu-item';
|
|
5
|
+
import { Post } from '../../../../types';
|
|
6
|
+
import { postTypesMap } from '../../../../api/post';
|
|
7
|
+
import { usePostListContext } from '../../../../contexts/post-list-context';
|
|
8
|
+
|
|
9
|
+
export default function View( { post }: { post: Post } ) {
|
|
10
|
+
const { type } = usePostListContext();
|
|
11
|
+
|
|
12
|
+
// translators: %s: Post type (e.g. Page, Post, etc.)
|
|
13
|
+
const title = __( 'View %s', 'elementor' ).replace( '%s', postTypesMap[ type ].labels.singular_name );
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<ActionMenuItem
|
|
17
|
+
title={ title }
|
|
18
|
+
icon={ EyeIcon }
|
|
19
|
+
onClick={ () => {
|
|
20
|
+
// eslint-disable-next-line no-console
|
|
21
|
+
console.log( post );
|
|
22
|
+
} }
|
|
23
|
+
/>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Button } from '@elementor/ui';
|
|
3
|
+
import { PlusIcon } from '@elementor/icons';
|
|
4
|
+
import { __ } from '@wordpress/i18n';
|
|
5
|
+
import { usePostListContext } from '../../contexts/post-list-context';
|
|
6
|
+
|
|
7
|
+
export default function AddNewButton() {
|
|
8
|
+
const { setEditMode } = usePostListContext();
|
|
9
|
+
|
|
10
|
+
return (
|
|
11
|
+
<Button
|
|
12
|
+
size={ 'small' }
|
|
13
|
+
sx={ { mt: 4, mb: 4, mr: 5 } }
|
|
14
|
+
startIcon={ <PlusIcon /> }
|
|
15
|
+
onClick={ () => {
|
|
16
|
+
setEditMode( { mode: 'create', details: {} } );
|
|
17
|
+
} }
|
|
18
|
+
>
|
|
19
|
+
{ __( 'Add New', 'elementor' ) }
|
|
20
|
+
</Button>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { act,
|
|
2
|
+
import { act, screen } from '@testing-library/react';
|
|
3
3
|
import { Post } from '../../../../types';
|
|
4
|
-
import
|
|
4
|
+
import PostListItem from '../post-list-item';
|
|
5
5
|
import { useNavigateToDocument } from '@elementor/editor-documents';
|
|
6
|
+
import { renderWithQuery } from 'test-utils';
|
|
6
7
|
|
|
7
8
|
jest.mock( '@elementor/editor-documents', () => ( {
|
|
8
9
|
useActiveDocument: jest.fn(),
|
|
9
10
|
useNavigateToDocument: jest.fn(),
|
|
10
11
|
} ) );
|
|
11
12
|
|
|
12
|
-
describe( '@elementor/editor-site-navigation -
|
|
13
|
+
describe( '@elementor/editor-site-navigation - PostListItem', () => {
|
|
13
14
|
afterAll( () => {
|
|
14
15
|
jest.clearAllMocks();
|
|
15
16
|
} );
|
|
16
17
|
|
|
17
18
|
it( 'should render a published page', () => {
|
|
18
19
|
// Arrange.
|
|
19
|
-
const
|
|
20
|
+
const post: Post = {
|
|
20
21
|
id: 1,
|
|
21
22
|
title: {
|
|
22
23
|
rendered: 'Test Page',
|
|
@@ -27,19 +28,19 @@ describe( '@elementor/editor-site-navigation - PageListItem', () => {
|
|
|
27
28
|
};
|
|
28
29
|
|
|
29
30
|
// Act.
|
|
30
|
-
|
|
31
|
+
renderWithQuery( <PostListItem post={ post } /> );
|
|
31
32
|
|
|
32
33
|
// Assert.
|
|
33
|
-
const label = getByText( 'Test Page' );
|
|
34
|
-
const publishedLabel = queryByText( 'publish', { exact: false } );
|
|
34
|
+
const label = screen.getByText( 'Test Page' );
|
|
35
|
+
const publishedLabel = screen.queryByText( 'publish', { exact: false } );
|
|
35
36
|
|
|
36
37
|
expect( label ).toBeInTheDocument();
|
|
37
|
-
expect( publishedLabel ).
|
|
38
|
+
expect( publishedLabel ).not.toBeInTheDocument();
|
|
38
39
|
} );
|
|
39
40
|
|
|
40
41
|
it( 'should show the page status for non-published pages', () => {
|
|
41
42
|
// Arrange.
|
|
42
|
-
const
|
|
43
|
+
const post: Post = {
|
|
43
44
|
id: 1,
|
|
44
45
|
title: {
|
|
45
46
|
rendered: 'Test Page',
|
|
@@ -50,16 +51,16 @@ describe( '@elementor/editor-site-navigation - PageListItem', () => {
|
|
|
50
51
|
};
|
|
51
52
|
|
|
52
53
|
// Act.
|
|
53
|
-
|
|
54
|
+
renderWithQuery( <PostListItem post={ post } /> );
|
|
54
55
|
|
|
55
56
|
// Assert.
|
|
56
|
-
const label = getByText( 'draft', { exact: false } );
|
|
57
|
+
const label = screen.getByText( 'draft', { exact: false } );
|
|
57
58
|
expect( label ).toBeInTheDocument();
|
|
58
59
|
} );
|
|
59
60
|
|
|
60
61
|
it( 'should render actions menu', () => {
|
|
61
62
|
// Arrange.
|
|
62
|
-
const
|
|
63
|
+
const post: Post = {
|
|
63
64
|
id: 1,
|
|
64
65
|
title: {
|
|
65
66
|
rendered: 'Test Page',
|
|
@@ -72,8 +73,9 @@ describe( '@elementor/editor-site-navigation - PageListItem', () => {
|
|
|
72
73
|
const actions = [ 'View Page', 'Rename', 'Duplicate', 'Delete', 'Set as homepage' ];
|
|
73
74
|
|
|
74
75
|
// Act.
|
|
75
|
-
|
|
76
|
-
|
|
76
|
+
renderWithQuery( <PostListItem post={ post } /> );
|
|
77
|
+
|
|
78
|
+
const buttons = screen.getAllByRole( 'button' );
|
|
77
79
|
// Button to open menu
|
|
78
80
|
const button = buttons[ 1 ];
|
|
79
81
|
|
|
@@ -84,7 +86,7 @@ describe( '@elementor/editor-site-navigation - PageListItem', () => {
|
|
|
84
86
|
|
|
85
87
|
// Assert.
|
|
86
88
|
actions.forEach( ( action ) => {
|
|
87
|
-
const label = getByText( action );
|
|
89
|
+
const label = screen.getByText( action );
|
|
88
90
|
expect( label ).toBeInTheDocument();
|
|
89
91
|
} );
|
|
90
92
|
} );
|
|
@@ -96,7 +98,7 @@ describe( '@elementor/editor-site-navigation - PageListItem', () => {
|
|
|
96
98
|
|
|
97
99
|
const id = 10;
|
|
98
100
|
|
|
99
|
-
const
|
|
101
|
+
const post: Post = {
|
|
100
102
|
id,
|
|
101
103
|
title: {
|
|
102
104
|
rendered: 'Test Page',
|
|
@@ -107,8 +109,9 @@ describe( '@elementor/editor-site-navigation - PageListItem', () => {
|
|
|
107
109
|
};
|
|
108
110
|
|
|
109
111
|
// Act.
|
|
110
|
-
|
|
111
|
-
|
|
112
|
+
renderWithQuery( <PostListItem post={ post } /> );
|
|
113
|
+
|
|
114
|
+
const buttons = screen.getAllByRole( 'button' );
|
|
112
115
|
const button = buttons[ 0 ];
|
|
113
116
|
|
|
114
117
|
act( () => {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
2
|
+
import { screen } from '@testing-library/react';
|
|
3
|
+
import PostsCollapsibleList from '../posts-collapsible-list';
|
|
4
|
+
import { renderWithQuery } from 'test-utils';
|
|
4
5
|
|
|
5
6
|
jest.mock( '../../../../hooks/use-posts', () => ( {
|
|
6
7
|
__esModule: true,
|
|
@@ -22,36 +23,32 @@ jest.mock( '@elementor/editor-documents', () => ( {
|
|
|
22
23
|
useNavigateToDocument: jest.fn(),
|
|
23
24
|
} ) );
|
|
24
25
|
|
|
25
|
-
describe( '@elementor/editor-site-navigation -
|
|
26
|
+
describe( '@elementor/editor-site-navigation - PostsCollapsibleList', () => {
|
|
26
27
|
afterEach( () => {
|
|
27
28
|
jest.clearAllMocks();
|
|
28
29
|
} );
|
|
29
30
|
|
|
30
31
|
it( 'should render closed list', () => {
|
|
31
32
|
// Act.
|
|
32
|
-
|
|
33
|
-
<PagesCollapsibleList isOpenByDefault={ false } />,
|
|
34
|
-
);
|
|
33
|
+
renderWithQuery( <PostsCollapsibleList isOpenByDefault={ false } /> );
|
|
35
34
|
|
|
36
35
|
// Assert.
|
|
37
|
-
const label = getByText( `Pages (3)` );
|
|
36
|
+
const label = screen.getByText( `Pages (3)` );
|
|
38
37
|
expect( label ).toBeInTheDocument();
|
|
39
38
|
|
|
40
|
-
const postInList = queryByText( 'Services' );
|
|
41
|
-
expect( postInList ).
|
|
39
|
+
const postInList = screen.queryByText( 'Services' );
|
|
40
|
+
expect( postInList ).not.toBeInTheDocument();
|
|
42
41
|
} );
|
|
43
42
|
|
|
44
43
|
it( 'should render open list', () => {
|
|
45
44
|
// Act.
|
|
46
|
-
|
|
47
|
-
<PagesCollapsibleList isOpenByDefault={ true } />,
|
|
48
|
-
);
|
|
45
|
+
renderWithQuery( <PostsCollapsibleList isOpenByDefault={ true } /> );
|
|
49
46
|
|
|
50
47
|
// Assert.
|
|
51
|
-
const label = getByText( `Pages (3)` );
|
|
48
|
+
const label = screen.getByText( `Pages (3)` );
|
|
52
49
|
expect( label ).toBeInTheDocument();
|
|
53
50
|
|
|
54
|
-
const postInList = getByText( 'Services' );
|
|
51
|
+
const postInList = screen.getByText( 'Services' );
|
|
55
52
|
expect( postInList ).toBeInTheDocument();
|
|
56
53
|
} );
|
|
57
54
|
} );
|
|
@@ -4,13 +4,13 @@ import { Collapse, IconButton, List, ListItem, ListItemIcon, ListItemText, style
|
|
|
4
4
|
import { ChevronDownIcon } from '@elementor/icons';
|
|
5
5
|
|
|
6
6
|
type Props = {
|
|
7
|
-
label: string
|
|
8
|
-
Icon: ComponentType
|
|
9
|
-
isOpenByDefault?: boolean
|
|
7
|
+
label: string,
|
|
8
|
+
Icon: ComponentType,
|
|
9
|
+
isOpenByDefault?: boolean,
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
interface RotateIconProps extends SvgIconProps {
|
|
13
|
-
isOpen: boolean
|
|
13
|
+
isOpen: boolean,
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
// TODO 21/06/2023 : Should replace this with future Rotate component that will be implemented in elementor-ui
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useState, useRef, FormEvent, MutableRefObject, FocusEvent } from 'react';
|
|
3
|
+
import {
|
|
4
|
+
Box,
|
|
5
|
+
ListItem,
|
|
6
|
+
ListItemIcon,
|
|
7
|
+
TextField,
|
|
8
|
+
IconButton,
|
|
9
|
+
CircularProgress,
|
|
10
|
+
} from '@elementor/ui';
|
|
11
|
+
import { XIcon } from '@elementor/icons';
|
|
12
|
+
import { __ } from '@wordpress/i18n';
|
|
13
|
+
import { usePostListContext } from '../../../../contexts/post-list-context';
|
|
14
|
+
|
|
15
|
+
type Props = {
|
|
16
|
+
postTitle: string,
|
|
17
|
+
isLoading: boolean,
|
|
18
|
+
callback: ( inputValue: string ) => void,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export default function EditModeTemplate( { postTitle, isLoading, callback }: Props ) {
|
|
22
|
+
const inputRef = useRef<HTMLInputElement>();
|
|
23
|
+
const [ inputError, setInputError ] = useState( '' );
|
|
24
|
+
const closeButton = useRef<HTMLButtonElement>();
|
|
25
|
+
|
|
26
|
+
const onBlur = ( e: FocusEvent ) => {
|
|
27
|
+
if ( closeButton.current === e.relatedTarget ) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
runCallback();
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const onFormSubmit = ( e: FormEvent<HTMLFormElement> ) => {
|
|
35
|
+
e.preventDefault();
|
|
36
|
+
runCallback();
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const validateInput = () => {
|
|
40
|
+
let isValid = true;
|
|
41
|
+
|
|
42
|
+
if ( inputRef.current?.value === '' ) {
|
|
43
|
+
isValid = false;
|
|
44
|
+
setInputError( __( 'Name is required', 'elementor' ) );
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return isValid;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const runCallback = () => {
|
|
51
|
+
if ( ! validateInput() ) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
callback( inputRef.current?.value || '' );
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<ListItem
|
|
60
|
+
selected={ true }
|
|
61
|
+
disablePadding
|
|
62
|
+
secondaryAction={ <CloseButton isLoading={ isLoading } closeButton={ closeButton } /> }
|
|
63
|
+
>
|
|
64
|
+
<ListItemIcon />
|
|
65
|
+
<Box component="form" onSubmit={ onFormSubmit }>
|
|
66
|
+
<TextField
|
|
67
|
+
autoFocus // eslint-disable-line jsx-a11y/no-autofocus
|
|
68
|
+
ref={ inputRef }
|
|
69
|
+
defaultValue={ postTitle }
|
|
70
|
+
disabled={ isLoading }
|
|
71
|
+
error={ !! inputError }
|
|
72
|
+
onBlur={ onBlur }
|
|
73
|
+
variant="outlined"
|
|
74
|
+
size="small"
|
|
75
|
+
/>
|
|
76
|
+
</Box>
|
|
77
|
+
</ListItem>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
type CloseButtonProps = {
|
|
82
|
+
isLoading: boolean,
|
|
83
|
+
closeButton: MutableRefObject<HTMLButtonElement | undefined>,
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function CloseButton( { isLoading, closeButton }: CloseButtonProps ) {
|
|
87
|
+
const { resetEditMode } = usePostListContext();
|
|
88
|
+
|
|
89
|
+
return (
|
|
90
|
+
<IconButton
|
|
91
|
+
size="small"
|
|
92
|
+
onClick={ resetEditMode }
|
|
93
|
+
ref={ closeButton }
|
|
94
|
+
disabled={ isLoading }
|
|
95
|
+
>
|
|
96
|
+
{
|
|
97
|
+
isLoading
|
|
98
|
+
? <CircularProgress />
|
|
99
|
+
: <XIcon fontSize="small" />
|
|
100
|
+
}
|
|
101
|
+
</IconButton>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { __ } from '@wordpress/i18n';
|
|
3
|
+
import { usePostListContext } from '../../../../contexts/post-list-context';
|
|
4
|
+
import { usePostActions } from '../../../../hooks/use-posts-actions';
|
|
5
|
+
import EditModeTemplate from './edit-mode-template';
|
|
6
|
+
|
|
7
|
+
export default function ListItemCreate() {
|
|
8
|
+
const { type, resetEditMode } = usePostListContext();
|
|
9
|
+
const { createPost } = usePostActions( type );
|
|
10
|
+
|
|
11
|
+
const createPostCallback = ( inputValue: string ) => {
|
|
12
|
+
createPost.mutateAsync( {
|
|
13
|
+
title: inputValue,
|
|
14
|
+
status: 'draft',
|
|
15
|
+
}, {
|
|
16
|
+
onSuccess: () => {
|
|
17
|
+
resetEditMode();
|
|
18
|
+
},
|
|
19
|
+
} );
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<EditModeTemplate postTitle={ __( 'New Page', 'elementor' ) } isLoading={ createPost.isLoading } callback={ createPostCallback } />
|
|
24
|
+
);
|
|
25
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { __ } from '@wordpress/i18n';
|
|
3
|
+
import { usePostListContext } from '../../../../contexts/post-list-context';
|
|
4
|
+
import { usePostActions } from '../../../../hooks/use-posts-actions';
|
|
5
|
+
import EditModeTemplate from './edit-mode-template';
|
|
6
|
+
|
|
7
|
+
export default function ListItemDuplicate() {
|
|
8
|
+
const { type, editMode, resetEditMode } = usePostListContext();
|
|
9
|
+
const { createPost } = usePostActions( type );
|
|
10
|
+
|
|
11
|
+
if ( 'duplicate' !== editMode.mode ) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const duplicatePostCallback = ( inputValue: string ) => {
|
|
16
|
+
createPost.mutateAsync( {
|
|
17
|
+
title: inputValue,
|
|
18
|
+
status: 'draft',
|
|
19
|
+
}, {
|
|
20
|
+
onSuccess: () => {
|
|
21
|
+
resetEditMode();
|
|
22
|
+
},
|
|
23
|
+
} );
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<EditModeTemplate postTitle={ `${ editMode.details.title } ${ __( 'copy', 'elementor' ) }` } isLoading={ createPost.isLoading } callback={ duplicatePostCallback } />
|
|
28
|
+
);
|
|
29
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { usePostListContext } from '../../../../contexts/post-list-context';
|
|
3
|
+
import { usePostActions } from '../../../../hooks/use-posts-actions';
|
|
4
|
+
import { Post } from '../../../../types';
|
|
5
|
+
import EditModeTemplate from './edit-mode-template';
|
|
6
|
+
|
|
7
|
+
type Props = {
|
|
8
|
+
post: Post,
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export default function ListItemRename( { post }: Props ) {
|
|
12
|
+
const { type, resetEditMode } = usePostListContext();
|
|
13
|
+
const { updatePost } = usePostActions( type );
|
|
14
|
+
|
|
15
|
+
const renamePostCallback = ( inputValue: string ) => {
|
|
16
|
+
if ( inputValue === post.title.rendered ) {
|
|
17
|
+
resetEditMode();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
updatePost.mutateAsync( {
|
|
21
|
+
id: post.id,
|
|
22
|
+
title: inputValue,
|
|
23
|
+
}, {
|
|
24
|
+
onSuccess: () => {
|
|
25
|
+
resetEditMode();
|
|
26
|
+
},
|
|
27
|
+
} );
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<EditModeTemplate postTitle={ post.title.rendered } isLoading={ updatePost.isLoading } callback={ renamePostCallback } />
|
|
32
|
+
);
|
|
33
|
+
}
|