@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
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import {
|
|
3
|
+
bindMenu,
|
|
4
|
+
bindTrigger,
|
|
5
|
+
Divider,
|
|
6
|
+
ListItem,
|
|
7
|
+
ListItemButton,
|
|
8
|
+
ListItemIcon,
|
|
9
|
+
ListItemText,
|
|
10
|
+
Menu,
|
|
11
|
+
ToggleButton,
|
|
12
|
+
usePopupState,
|
|
13
|
+
} from '@elementor/ui';
|
|
14
|
+
import { DotsVerticalIcon, HomeIcon } from '@elementor/icons';
|
|
15
|
+
import { useActiveDocument, useNavigateToDocument } from '@elementor/editor-documents';
|
|
16
|
+
import PageTitleAndStatus from '../../../shared/page-title-and-status';
|
|
17
|
+
import Rename from '../../actions-menu/actions/rename';
|
|
18
|
+
import Duplicate from '../../actions-menu/actions/duplicate';
|
|
19
|
+
import Delete from '../../actions-menu/actions/delete';
|
|
20
|
+
import View from '../../actions-menu/actions/view';
|
|
21
|
+
import SetHome from '../../actions-menu/actions/set-home';
|
|
22
|
+
import { Post } from '../../../../types';
|
|
23
|
+
|
|
24
|
+
export default function ListItemView( { post }: { post: Post } ) {
|
|
25
|
+
const activeDocument = useActiveDocument();
|
|
26
|
+
const navigateToDocument = useNavigateToDocument();
|
|
27
|
+
|
|
28
|
+
const popupState = usePopupState( {
|
|
29
|
+
variant: 'popover',
|
|
30
|
+
popupId: 'post-actions',
|
|
31
|
+
disableAutoFocus: true,
|
|
32
|
+
} );
|
|
33
|
+
|
|
34
|
+
const isActive = activeDocument?.id === post.id;
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<>
|
|
38
|
+
<ListItem
|
|
39
|
+
disablePadding
|
|
40
|
+
secondaryAction={
|
|
41
|
+
<ToggleButton
|
|
42
|
+
value
|
|
43
|
+
size="small"
|
|
44
|
+
selected={ popupState.isOpen }
|
|
45
|
+
{ ...bindTrigger( popupState ) }
|
|
46
|
+
>
|
|
47
|
+
<DotsVerticalIcon fontSize="small" />
|
|
48
|
+
</ToggleButton>
|
|
49
|
+
}
|
|
50
|
+
>
|
|
51
|
+
<ListItemButton
|
|
52
|
+
selected={ isActive }
|
|
53
|
+
onClick={ () => {
|
|
54
|
+
if ( ! isActive ) {
|
|
55
|
+
navigateToDocument( post.id );
|
|
56
|
+
}
|
|
57
|
+
} }
|
|
58
|
+
dense
|
|
59
|
+
>
|
|
60
|
+
<ListItemIcon />
|
|
61
|
+
<ListItemText
|
|
62
|
+
disableTypography={ true }
|
|
63
|
+
>
|
|
64
|
+
<PageTitleAndStatus page={ post } />
|
|
65
|
+
</ListItemText>
|
|
66
|
+
{ post.isHome &&
|
|
67
|
+
<ListItemIcon>
|
|
68
|
+
<HomeIcon color="disabled" />
|
|
69
|
+
</ListItemIcon>
|
|
70
|
+
}
|
|
71
|
+
</ListItemButton>
|
|
72
|
+
</ListItem>
|
|
73
|
+
<Menu
|
|
74
|
+
PaperProps={ { sx: { mt: 4, width: 200 } } }
|
|
75
|
+
MenuListProps={ { dense: true } }
|
|
76
|
+
{ ...bindMenu( popupState ) }
|
|
77
|
+
>
|
|
78
|
+
<Rename post={ post } />
|
|
79
|
+
<Duplicate post={ post } popupState={ popupState } />
|
|
80
|
+
<Delete post={ post } />
|
|
81
|
+
<View post={ post } />
|
|
82
|
+
<Divider />
|
|
83
|
+
<SetHome post={ post } />
|
|
84
|
+
</Menu>
|
|
85
|
+
</>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Post } from '../../../types';
|
|
3
|
+
import ListItemRename from './list-items/list-item-rename';
|
|
4
|
+
import ListItemCreate from './list-items/list-item-create';
|
|
5
|
+
import ListItemDuplicate from './list-items/list-item-duplicate';
|
|
6
|
+
import ListItemView from './list-items/list-item-view';
|
|
7
|
+
import { usePostListContext } from '../../../contexts/post-list-context';
|
|
8
|
+
|
|
9
|
+
export default function PostListItem( { post }: { post?: Post } ) {
|
|
10
|
+
const { editMode } = usePostListContext();
|
|
11
|
+
|
|
12
|
+
if ( 'rename' === editMode.mode && post?.id && post?.id === editMode.details.postId ) {
|
|
13
|
+
return <ListItemRename post={ post } />;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if ( 'create' === editMode.mode && ! post ) {
|
|
17
|
+
return <ListItemCreate />;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if ( 'duplicate' === editMode.mode && ! post ) {
|
|
21
|
+
return <ListItemDuplicate />;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if ( ! post ) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return <ListItemView post={ post } />;
|
|
29
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { PageTypeIcon } from '@elementor/icons';
|
|
3
|
+
import { Skeleton, Box, List } from '@elementor/ui';
|
|
4
|
+
import { usePosts } from '../../../hooks/use-posts';
|
|
5
|
+
import { usePostListContext } from '../../../contexts/post-list-context';
|
|
6
|
+
import { postTypesMap } from '../../../api/post';
|
|
7
|
+
import CollapsibleList from './collapsible-list';
|
|
8
|
+
import PostListItem from './post-list-item';
|
|
9
|
+
|
|
10
|
+
type Props = {
|
|
11
|
+
isOpenByDefault?: boolean,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export default function PostsCollapsibleList( { isOpenByDefault = false }: Props ) {
|
|
15
|
+
const { type, editMode } = usePostListContext();
|
|
16
|
+
const { data: posts, isLoading: postsLoading } = usePosts( type );
|
|
17
|
+
|
|
18
|
+
if ( ! posts || postsLoading ) {
|
|
19
|
+
return (
|
|
20
|
+
<Box spacing={ 4 } sx={ { px: 6 } }>
|
|
21
|
+
<Skeleton variant="text" sx={ { fontSize: '2rem' } } />
|
|
22
|
+
<Skeleton variant="rounded" width="100%" height="48" />
|
|
23
|
+
</Box>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const label = `${ postTypesMap[ type ].labels.plural_name } (${ posts.length.toString() })`;
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<List dense>
|
|
31
|
+
<CollapsibleList
|
|
32
|
+
label={ label }
|
|
33
|
+
Icon={ PageTypeIcon }
|
|
34
|
+
isOpenByDefault={ isOpenByDefault || false }
|
|
35
|
+
>
|
|
36
|
+
{ posts.map( ( post ) => <PostListItem key={ post.id } post={ post } /> ) }
|
|
37
|
+
{
|
|
38
|
+
[ 'duplicate', 'create' ].includes( editMode.mode ) &&
|
|
39
|
+
<PostListItem />
|
|
40
|
+
}
|
|
41
|
+
</CollapsibleList>
|
|
42
|
+
</List>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { Box
|
|
2
|
+
import { Box } from '@elementor/ui';
|
|
3
3
|
import { Panel, PanelBody, PanelHeader, PanelHeaderTitle } from '@elementor/editor-panels';
|
|
4
|
-
import PagesCollapsibleList from './pages-list/pages-collapsible-list';
|
|
5
4
|
import { __ } from '@wordpress/i18n';
|
|
6
|
-
import
|
|
5
|
+
import PostsCollapsibleList from './posts-list/posts-collapsible-list';
|
|
6
|
+
import { PostListContextProvider } from '../../contexts/post-list-context';
|
|
7
|
+
import AddNewButton from './add-new-button';
|
|
7
8
|
|
|
8
9
|
const Shell = () => {
|
|
9
10
|
return (
|
|
@@ -12,16 +13,16 @@ const Shell = () => {
|
|
|
12
13
|
<PanelHeaderTitle>{ __( 'Pages', 'elementor' ) }</PanelHeaderTitle>
|
|
13
14
|
</PanelHeader>
|
|
14
15
|
<PanelBody>
|
|
15
|
-
<
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
<
|
|
24
|
-
</
|
|
16
|
+
<PostListContextProvider type={ 'page' }>
|
|
17
|
+
<Box
|
|
18
|
+
display="flex"
|
|
19
|
+
justifyContent="flex-end"
|
|
20
|
+
alignItems="center"
|
|
21
|
+
>
|
|
22
|
+
<AddNewButton />
|
|
23
|
+
</Box>
|
|
24
|
+
<PostsCollapsibleList isOpenByDefault={ true } />
|
|
25
|
+
</PostListContextProvider>
|
|
25
26
|
</PanelBody>
|
|
26
27
|
</Panel>
|
|
27
28
|
);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { fireEvent, render, waitFor } from '@testing-library/react';
|
|
2
|
+
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
|
3
3
|
import { useHostDocument, useActiveDocument, useNavigateToDocument } from '@elementor/editor-documents';
|
|
4
4
|
import RecentlyEdited from '../recently-edited';
|
|
5
5
|
import { createMockDocument } from 'test-utils';
|
|
@@ -45,14 +45,14 @@ describe( '@elementor/recently-edited - Top bar add new page', () => {
|
|
|
45
45
|
|
|
46
46
|
jest.mocked( useRecentPosts ).mockReturnValue( { isLoading, recentPosts } );
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
render( <RecentlyEdited /> );
|
|
49
49
|
|
|
50
50
|
// Act.
|
|
51
|
-
const buttons = getAllByRole( 'button' );
|
|
51
|
+
const buttons = screen.getAllByRole( 'button' );
|
|
52
52
|
fireEvent.click( buttons[ 0 ] ); // Opens the recently edited menu
|
|
53
53
|
|
|
54
54
|
// Assert.
|
|
55
|
-
const label = getByText( 'Add new page', { exact: false } );
|
|
55
|
+
const label = screen.getByText( 'Add new page', { exact: false } );
|
|
56
56
|
expect( label ).toBeInTheDocument();
|
|
57
57
|
} );
|
|
58
58
|
|
|
@@ -69,22 +69,21 @@ describe( '@elementor/recently-edited - Top bar add new page', () => {
|
|
|
69
69
|
jest.mocked( useCreatePage ).mockReturnValue( { isLoading, create } );
|
|
70
70
|
jest.mocked( useNavigateToDocument ).mockReturnValue( navigateToDocument );
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
render( <RecentlyEdited /> );
|
|
73
73
|
|
|
74
74
|
// Act.
|
|
75
|
-
const buttons = getAllByRole( 'button' );
|
|
75
|
+
const buttons = screen.getAllByRole( 'button' );
|
|
76
76
|
fireEvent.click( buttons[ 0 ] ); // Opens the recently edited menu
|
|
77
77
|
|
|
78
|
-
const addNewPage = getByText( 'Add new page', { exact: false } );
|
|
78
|
+
const addNewPage = screen.getByText( 'Add new page', { exact: false } );
|
|
79
79
|
fireEvent.click( addNewPage );
|
|
80
80
|
|
|
81
81
|
// Assert.
|
|
82
|
-
|
|
83
|
-
expect( create ).toHaveBeenCalledTimes( 1 );
|
|
82
|
+
expect( create ).toHaveBeenCalledTimes( 1 );
|
|
84
83
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
84
|
+
await waitFor( () => expect( navigateToDocument ).toHaveBeenCalledTimes( 1 ) );
|
|
85
|
+
|
|
86
|
+
expect( navigateToDocument ).toHaveBeenCalledWith( 123 );
|
|
88
87
|
} );
|
|
89
88
|
} );
|
|
90
89
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { fireEvent, render } from '@testing-library/react';
|
|
2
|
+
import { fireEvent, render, screen } from '@testing-library/react';
|
|
3
3
|
import { useHostDocument, useActiveDocument, useNavigateToDocument } from '@elementor/editor-documents';
|
|
4
4
|
import RecentlyEdited from '../recently-edited';
|
|
5
5
|
import { createMockDocument } from 'test-utils';
|
|
@@ -31,11 +31,11 @@ describe( '@elementor/recently-edited - Top bar Recently Edited', () => {
|
|
|
31
31
|
|
|
32
32
|
it( 'should show the title of the active document without its status when the document is published', async () => {
|
|
33
33
|
// Act.
|
|
34
|
-
|
|
34
|
+
render( <RecentlyEdited /> );
|
|
35
35
|
|
|
36
36
|
// Assert.
|
|
37
|
-
expect(
|
|
38
|
-
expect( queryByText( '(publish)' ) ).not.
|
|
37
|
+
expect( screen.getByText( 'Active Document' ) ).toBeInTheDocument();
|
|
38
|
+
expect( screen.queryByText( '(publish)' ) ).not.toBeInTheDocument();
|
|
39
39
|
} );
|
|
40
40
|
|
|
41
41
|
it( 'should show the title of the active document with its status when the document is not published', async () => {
|
|
@@ -52,11 +52,11 @@ describe( '@elementor/recently-edited - Top bar Recently Edited', () => {
|
|
|
52
52
|
);
|
|
53
53
|
|
|
54
54
|
// Act.
|
|
55
|
-
|
|
55
|
+
render( <RecentlyEdited /> );
|
|
56
56
|
|
|
57
57
|
// Assert.
|
|
58
|
-
expect(
|
|
59
|
-
expect(
|
|
58
|
+
expect( screen.getByText( 'Active Document' ) ).toBeInTheDocument();
|
|
59
|
+
expect( screen.getByText( '(Draft)' ) ).toBeInTheDocument();
|
|
60
60
|
} );
|
|
61
61
|
|
|
62
62
|
it( 'should show the title of the host document when there is no active document', () => {
|
|
@@ -64,10 +64,10 @@ describe( '@elementor/recently-edited - Top bar Recently Edited', () => {
|
|
|
64
64
|
jest.mocked( useActiveDocument ).mockImplementation( () => null );
|
|
65
65
|
|
|
66
66
|
// Act.
|
|
67
|
-
|
|
67
|
+
render( <RecentlyEdited /> );
|
|
68
68
|
|
|
69
69
|
// Assert.
|
|
70
|
-
expect(
|
|
70
|
+
expect( screen.getByText( 'Host Document' ) ).toBeInTheDocument();
|
|
71
71
|
} );
|
|
72
72
|
|
|
73
73
|
it( 'should show the title of the host document when the active document is kit', () => {
|
|
@@ -85,10 +85,10 @@ describe( '@elementor/recently-edited - Top bar Recently Edited', () => {
|
|
|
85
85
|
);
|
|
86
86
|
|
|
87
87
|
// Act.
|
|
88
|
-
|
|
88
|
+
render( <RecentlyEdited /> );
|
|
89
89
|
|
|
90
90
|
// Assert.
|
|
91
|
-
expect(
|
|
91
|
+
expect( screen.getByText( 'Host Document' ) ).toBeInTheDocument();
|
|
92
92
|
} );
|
|
93
93
|
|
|
94
94
|
it( 'should show nothing if there are no documents', () => {
|
|
@@ -97,11 +97,11 @@ describe( '@elementor/recently-edited - Top bar Recently Edited', () => {
|
|
|
97
97
|
jest.mocked( useHostDocument ).mockImplementation( () => null );
|
|
98
98
|
|
|
99
99
|
// Act.
|
|
100
|
-
|
|
100
|
+
render( <RecentlyEdited /> );
|
|
101
101
|
|
|
102
102
|
// Assert.
|
|
103
|
-
expect( queryByText( 'Host Document' ) ).not.
|
|
104
|
-
expect( queryByText( 'Active Document' ) ).not.
|
|
103
|
+
expect( screen.queryByText( 'Host Document' ) ).not.toBeInTheDocument();
|
|
104
|
+
expect( screen.queryByText( 'Active Document' ) ).not.toBeInTheDocument();
|
|
105
105
|
} );
|
|
106
106
|
|
|
107
107
|
it( 'should show empty state', () => {
|
|
@@ -122,14 +122,14 @@ describe( '@elementor/recently-edited - Top bar Recently Edited', () => {
|
|
|
122
122
|
|
|
123
123
|
jest.mocked( useRecentPosts ).mockReturnValue( { isLoading, recentPosts } );
|
|
124
124
|
|
|
125
|
-
|
|
125
|
+
render( <RecentlyEdited /> );
|
|
126
126
|
|
|
127
127
|
// Act.
|
|
128
|
-
const buttons = getAllByRole( 'button' );
|
|
128
|
+
const buttons = screen.getAllByRole( 'button' );
|
|
129
129
|
fireEvent.click( buttons[ 0 ] ); // Opens the recently edited menu
|
|
130
130
|
|
|
131
131
|
// Assert.
|
|
132
|
-
const label = getByText( 'There are no other pages or templates on this site yet', { exact: false } );
|
|
132
|
+
const label = screen.getByText( 'There are no other pages or templates on this site yet', { exact: false } );
|
|
133
133
|
expect( label ).toBeInTheDocument();
|
|
134
134
|
} );
|
|
135
135
|
|
|
@@ -161,20 +161,20 @@ describe( '@elementor/recently-edited - Top bar Recently Edited', () => {
|
|
|
161
161
|
|
|
162
162
|
jest.mocked( useRecentPosts ).mockReturnValue( { isLoading, recentPosts } );
|
|
163
163
|
|
|
164
|
-
|
|
164
|
+
render( <RecentlyEdited /> );
|
|
165
165
|
|
|
166
166
|
// Act.
|
|
167
|
-
const buttons = getAllByRole( 'button' );
|
|
167
|
+
const buttons = screen.getAllByRole( 'button' );
|
|
168
168
|
fireEvent.click( buttons[ 0 ] ); // Opens the recently edited menu
|
|
169
169
|
|
|
170
170
|
// Assert.
|
|
171
|
-
const menu = getByRole( 'menu' );
|
|
171
|
+
const menu = screen.getByRole( 'menu' );
|
|
172
172
|
expect( menu ).toBeInTheDocument();
|
|
173
173
|
|
|
174
|
-
const label = getByText( 'Recent' );
|
|
174
|
+
const label = screen.getByText( 'Recent' );
|
|
175
175
|
expect( label ).toBeInTheDocument();
|
|
176
176
|
|
|
177
|
-
expect( getByText( 'Test post' ) ).toBeInTheDocument();
|
|
177
|
+
expect( screen.getByText( 'Test post' ) ).toBeInTheDocument();
|
|
178
178
|
} );
|
|
179
179
|
|
|
180
180
|
it( 'should render titles with HTML entities', () => {
|
|
@@ -219,17 +219,17 @@ describe( '@elementor/recently-edited - Top bar Recently Edited', () => {
|
|
|
219
219
|
jest.mocked( useRecentPosts ).mockReturnValue( { isLoading, recentPosts } );
|
|
220
220
|
|
|
221
221
|
// Act.
|
|
222
|
-
|
|
222
|
+
render( <RecentlyEdited /> );
|
|
223
223
|
|
|
224
224
|
// Assert - the document title should be rendered with the HTML entity.
|
|
225
|
-
expect( getByText( 'Header title with special char ¥' ) ).toBeInTheDocument();
|
|
225
|
+
expect( screen.getByText( 'Header title with special char ¥' ) ).toBeInTheDocument();
|
|
226
226
|
|
|
227
227
|
// Open the posts list.
|
|
228
|
-
fireEvent.click( getByRole( 'button' ) );
|
|
228
|
+
fireEvent.click( screen.getByRole( 'button' ) );
|
|
229
229
|
|
|
230
230
|
// Assert - the post title should be rendered with the HTML entity.
|
|
231
|
-
expect( getByText( 'Post title with <h1>HTML</h1>' ) ).toBeInTheDocument();
|
|
232
|
-
expect( getByText( 'Post title with <HTML entities>' ) ).toBeInTheDocument();
|
|
231
|
+
expect( screen.getByText( 'Post title with <h1>HTML</h1>' ) ).toBeInTheDocument();
|
|
232
|
+
expect( screen.getByText( 'Post title with <HTML entities>' ) ).toBeInTheDocument();
|
|
233
233
|
} );
|
|
234
234
|
|
|
235
235
|
it( 'should navigate to document on click', () => {
|
|
@@ -253,13 +253,13 @@ describe( '@elementor/recently-edited - Top bar Recently Edited', () => {
|
|
|
253
253
|
} ],
|
|
254
254
|
} );
|
|
255
255
|
|
|
256
|
-
|
|
256
|
+
render( <RecentlyEdited /> );
|
|
257
257
|
|
|
258
258
|
// Open the posts list.
|
|
259
|
-
fireEvent.click( getByRole( 'button' ) );
|
|
259
|
+
fireEvent.click( screen.getByRole( 'button' ) );
|
|
260
260
|
|
|
261
261
|
// Act.
|
|
262
|
-
fireEvent.click( getByText( 'Test post' ) );
|
|
262
|
+
fireEvent.click( screen.getByText( 'Test post' ) );
|
|
263
263
|
|
|
264
264
|
// Assert.
|
|
265
265
|
expect( navigateToDocument ).toHaveBeenCalledTimes( 1 );
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useState, useContext, createContext, Dispatch, SetStateAction, ReactNode } from 'react';
|
|
3
|
+
import { Slug } from '../api/post';
|
|
4
|
+
|
|
5
|
+
export type EditMode = {
|
|
6
|
+
mode: 'rename',
|
|
7
|
+
details: {
|
|
8
|
+
postId: number,
|
|
9
|
+
},
|
|
10
|
+
} | {
|
|
11
|
+
mode: 'create',
|
|
12
|
+
details: Record<string, never>,
|
|
13
|
+
} | {
|
|
14
|
+
mode: 'duplicate',
|
|
15
|
+
details: {
|
|
16
|
+
postId: number,
|
|
17
|
+
title: string,
|
|
18
|
+
},
|
|
19
|
+
} | {
|
|
20
|
+
mode: 'none',
|
|
21
|
+
details: Record<string, never>,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
type ContextType = {
|
|
25
|
+
type: Slug,
|
|
26
|
+
editMode: EditMode,
|
|
27
|
+
setEditMode: Dispatch<SetStateAction<EditMode>>,
|
|
28
|
+
resetEditMode: () => void,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const defaultValues: ContextType = {
|
|
32
|
+
type: 'page',
|
|
33
|
+
editMode: { mode: 'none', details: {} },
|
|
34
|
+
setEditMode: () => null,
|
|
35
|
+
resetEditMode: () => null,
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export const PostListContext = createContext<ContextType>( defaultValues );
|
|
39
|
+
|
|
40
|
+
export const PostListContextProvider = ( {
|
|
41
|
+
type,
|
|
42
|
+
children,
|
|
43
|
+
}: {
|
|
44
|
+
type: ContextType[ 'type' ],
|
|
45
|
+
children: ReactNode,
|
|
46
|
+
} ) => {
|
|
47
|
+
const [ editMode, setEditMode ] = useState( defaultValues.editMode );
|
|
48
|
+
|
|
49
|
+
const resetEditMode = () => {
|
|
50
|
+
setEditMode( defaultValues.editMode );
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<PostListContext.Provider value={ {
|
|
55
|
+
type,
|
|
56
|
+
editMode,
|
|
57
|
+
setEditMode,
|
|
58
|
+
resetEditMode,
|
|
59
|
+
} }>
|
|
60
|
+
{ children }
|
|
61
|
+
</PostListContext.Provider>
|
|
62
|
+
);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export function usePostListContext() {
|
|
66
|
+
const context = useContext( PostListContext );
|
|
67
|
+
|
|
68
|
+
if ( ! context ) {
|
|
69
|
+
throw new Error( 'The `usePostListContext()` hook must be used within an `<PostListContextProvider />`' );
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return context;
|
|
73
|
+
}
|
package/src/env.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { parseEnv } from '@elementor/env';
|
|
2
2
|
|
|
3
3
|
export const { env, validateEnv } = parseEnv<{
|
|
4
|
-
|
|
4
|
+
is_pages_panel_active: boolean;
|
|
5
5
|
}>( '@elementor/editor-site-navigation', ( envData ) => {
|
|
6
6
|
return envData as {
|
|
7
|
-
|
|
7
|
+
is_pages_panel_active: boolean;
|
|
8
8
|
};
|
|
9
9
|
} );
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { renderHook } from '@testing-library/react';
|
|
2
2
|
import apiFetch from '@wordpress/api-fetch';
|
|
3
3
|
import useCreatePage, { endpointPath } from '../use-create-page';
|
|
4
4
|
|
|
@@ -29,13 +29,11 @@ describe( '@elementor/recently-edited/use-page', () => {
|
|
|
29
29
|
create();
|
|
30
30
|
|
|
31
31
|
// Assert.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
} );
|
|
38
|
-
expect( apiFetch ).toHaveBeenCalledTimes( 1 );
|
|
32
|
+
expect( apiFetch ).toHaveBeenCalledTimes( 1 );
|
|
33
|
+
expect( apiFetch ).toHaveBeenCalledWith( {
|
|
34
|
+
data: { post_type: 'page' },
|
|
35
|
+
method: 'POST',
|
|
36
|
+
path: endpointPath,
|
|
39
37
|
} );
|
|
40
38
|
} );
|
|
41
39
|
} );
|
|
@@ -27,14 +27,12 @@ describe( '@elementor/site-settings/use-posts', () => {
|
|
|
27
27
|
const { component } = renderHookWithQuery( () => usePosts( 'page' ) );
|
|
28
28
|
|
|
29
29
|
// Assert.
|
|
30
|
-
const expectedPath = `/wp/v2/pages?status=any&per_page=-1&_fields=${ encodeURIComponent( 'id,type,title,link,status' ) }`;
|
|
30
|
+
const expectedPath = `/wp/v2/pages?status=any&per_page=-1&order=asc&_fields=${ encodeURIComponent( 'id,type,title,link,status' ) }`;
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
path: expectedPath,
|
|
35
|
-
} );
|
|
36
|
-
expect( apiFetch ).toHaveBeenCalledTimes( 1 );
|
|
32
|
+
expect( apiFetch ).toHaveBeenCalledWith( {
|
|
33
|
+
path: expectedPath,
|
|
37
34
|
} );
|
|
35
|
+
expect( apiFetch ).toHaveBeenCalledTimes( 1 );
|
|
38
36
|
|
|
39
37
|
await waitFor( () => {
|
|
40
38
|
return component.result.current.isSuccess;
|
|
@@ -30,11 +30,11 @@ describe( 'useRecentPosts', () => {
|
|
|
30
30
|
|
|
31
31
|
const { result } = renderHook( () => useRecentPosts( 1 ) );
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
} );
|
|
33
|
+
expect( apiFetch ).toHaveBeenCalledWith( {
|
|
34
|
+
path: endpointPath + '?posts_per_page=5&post__not_in=1',
|
|
35
|
+
} );
|
|
37
36
|
|
|
37
|
+
await waitFor( () => {
|
|
38
38
|
expect( result.current.recentPosts ).toBe( posts );
|
|
39
39
|
} );
|
|
40
40
|
} );
|
package/src/init.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { env } from './env';
|
|
|
8
8
|
export default function init() {
|
|
9
9
|
registerTopBarMenuItems();
|
|
10
10
|
// TODO 06/06/2023 : remove if when we are production ready
|
|
11
|
-
if ( env.
|
|
11
|
+
if ( env.is_pages_panel_active ) {
|
|
12
12
|
registerPanel( panel );
|
|
13
13
|
registerButton();
|
|
14
14
|
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
import { Divider, Menu, MenuProps } from '@elementor/ui';
|
|
3
|
-
import Rename from '../pages-actions/rename';
|
|
4
|
-
import Duplicate from '../pages-actions/duplicate';
|
|
5
|
-
import Delete from '../pages-actions/delete';
|
|
6
|
-
import { Post } from '../../../types';
|
|
7
|
-
import View from '../pages-actions/view';
|
|
8
|
-
import SetHome from '../pages-actions/set-home';
|
|
9
|
-
|
|
10
|
-
type Props = MenuProps & {
|
|
11
|
-
page: Post
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
export default function PageActionsMenu( { page, ...props }: Props ) {
|
|
15
|
-
return (
|
|
16
|
-
<Menu
|
|
17
|
-
PaperProps={ { sx: { mt: 4, width: 200 } } }
|
|
18
|
-
MenuListProps={ { dense: true } }
|
|
19
|
-
{ ...props }
|
|
20
|
-
>
|
|
21
|
-
<Rename />
|
|
22
|
-
<Duplicate />
|
|
23
|
-
<Delete page={ page } />
|
|
24
|
-
<View />
|
|
25
|
-
<Divider />
|
|
26
|
-
<SetHome page={ page } />
|
|
27
|
-
</Menu>
|
|
28
|
-
);
|
|
29
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { Button } from '@elementor/ui';
|
|
2
|
-
import { PlusIcon } from '@elementor/icons';
|
|
3
|
-
import * as React from 'react';
|
|
4
|
-
|
|
5
|
-
export default function AddNewPageButton() {
|
|
6
|
-
return (
|
|
7
|
-
<Button
|
|
8
|
-
sx={ { mt: 4, mb: 4, mr: 5 } }
|
|
9
|
-
startIcon={ <PlusIcon /> }
|
|
10
|
-
onClick={ () => null }
|
|
11
|
-
>
|
|
12
|
-
Add New
|
|
13
|
-
</Button>
|
|
14
|
-
);
|
|
15
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
import { __ } from '@wordpress/i18n';
|
|
3
|
-
import { CopyIcon } from '@elementor/icons';
|
|
4
|
-
import ActionMenuItem from '../actions-menu/action-menu-item';
|
|
5
|
-
|
|
6
|
-
export default function Duplicate() {
|
|
7
|
-
return (
|
|
8
|
-
<ActionMenuItem
|
|
9
|
-
title={ __( 'Duplicate', 'elementor' ) }
|
|
10
|
-
icon={ CopyIcon }
|
|
11
|
-
onClick={ () => null }
|
|
12
|
-
/>
|
|
13
|
-
);
|
|
14
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
import { EraseIcon } from '@elementor/icons';
|
|
3
|
-
import { __ } from '@wordpress/i18n';
|
|
4
|
-
import ActionMenuItem from '../actions-menu/action-menu-item';
|
|
5
|
-
|
|
6
|
-
export default function Rename() {
|
|
7
|
-
return (
|
|
8
|
-
<ActionMenuItem
|
|
9
|
-
title={ __( 'Rename', 'elementor' ) }
|
|
10
|
-
icon={ EraseIcon }
|
|
11
|
-
onClick={ () => null }
|
|
12
|
-
/>
|
|
13
|
-
);
|
|
14
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
import { EyeIcon } from '@elementor/icons';
|
|
3
|
-
import { __ } from '@wordpress/i18n';
|
|
4
|
-
import ActionMenuItem from '../actions-menu/action-menu-item';
|
|
5
|
-
|
|
6
|
-
export default function View() {
|
|
7
|
-
return (
|
|
8
|
-
<ActionMenuItem
|
|
9
|
-
title={ __( 'View Page', 'elementor' ) } // TODO 21/06/2023 : post label should come from post type
|
|
10
|
-
icon={ EyeIcon }
|
|
11
|
-
onClick={ () => null }
|
|
12
|
-
/>
|
|
13
|
-
);
|
|
14
|
-
}
|