@elementor/editor-site-navigation 0.22.5 → 0.22.7
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 +38 -328
- package/dist/index.js +147 -156
- package/dist/index.mjs +168 -175
- package/package.json +49 -49
- package/src/api/post.ts +18 -18
- package/src/api/recent-posts.ts +1 -1
- package/src/api/settings.ts +4 -4
- package/src/api/user.ts +4 -4
- package/src/components/panel/actions-menu/action-menu-item.tsx +7 -10
- package/src/components/panel/actions-menu/actions/__tests__/set-home.test.tsx +12 -9
- package/src/components/panel/actions-menu/actions/delete.tsx +27 -25
- package/src/components/panel/actions-menu/actions/duplicate.tsx +5 -7
- package/src/components/panel/actions-menu/actions/rename.tsx +11 -13
- package/src/components/panel/actions-menu/actions/set-home.tsx +6 -8
- package/src/components/panel/actions-menu/actions/view.tsx +3 -5
- package/src/components/panel/error-snackbar.tsx +4 -3
- package/src/components/panel/panel.ts +1 -5
- package/src/components/panel/posts-list/__tests__/posts-collapsible-list.test.tsx +66 -19
- package/src/components/panel/posts-list/collapsible-list.tsx +38 -29
- package/src/components/panel/posts-list/error-state.tsx +35 -27
- package/src/components/panel/posts-list/list-items/edit-mode-template.tsx +18 -40
- package/src/components/panel/posts-list/list-items/list-item-create.tsx +5 -1
- package/src/components/panel/posts-list/list-items/list-item-duplicate.tsx +5 -1
- package/src/components/panel/posts-list/list-items/list-item-rename.tsx +3 -5
- package/src/components/panel/posts-list/list-items/list-item-view.tsx +20 -19
- package/src/components/panel/posts-list/posts-collapsible-list.tsx +22 -24
- package/src/components/shared/page-title-and-status.tsx +4 -2
- package/src/components/top-bar/__tests__/add-new-page.test.tsx +33 -16
- package/src/components/top-bar/__tests__/recently-edited.test.tsx +157 -120
- package/src/components/top-bar/chip-doc-type.tsx +1 -3
- package/src/components/top-bar/create-post-list-item.tsx +1 -1
- package/src/components/top-bar/indicator.tsx +17 -15
- package/src/components/top-bar/post-list-item.tsx +2 -6
- package/src/components/top-bar/recently-edited.tsx +13 -19
- package/src/contexts/post-list-context.tsx +40 -34
- package/src/env.ts +2 -2
- package/src/hooks/__tests__/use-posts.test.ts +19 -3
- package/src/hooks/use-create-page.ts +2 -2
- package/src/hooks/use-homepage.ts +1 -1
- package/src/hooks/use-posts.ts +1 -1
- package/src/hooks/use-toggle-button-props.ts +1 -5
- package/src/hooks/use-user.ts +1 -1
- package/src/icons-map.ts +1 -1
- package/src/types.ts +22 -22
package/src/api/post.ts
CHANGED
|
@@ -3,14 +3,14 @@ import { Post } from '../types';
|
|
|
3
3
|
import { __ } from '@wordpress/i18n';
|
|
4
4
|
|
|
5
5
|
export type NewPost = {
|
|
6
|
-
title: string
|
|
7
|
-
status: 'publish' | 'draft'
|
|
6
|
+
title: string;
|
|
7
|
+
status: 'publish' | 'draft';
|
|
8
8
|
};
|
|
9
9
|
|
|
10
10
|
export type UpdatePost = {
|
|
11
|
-
id: number
|
|
12
|
-
title?: string
|
|
13
|
-
}
|
|
11
|
+
id: number;
|
|
12
|
+
title?: string;
|
|
13
|
+
};
|
|
14
14
|
|
|
15
15
|
export type Slug = keyof typeof postTypesMap;
|
|
16
16
|
|
|
@@ -27,23 +27,23 @@ export const postTypesMap = {
|
|
|
27
27
|
export const POST_PER_PAGE = 10;
|
|
28
28
|
|
|
29
29
|
type WpPostsResponse = {
|
|
30
|
-
json: () => Promise<Post[]
|
|
30
|
+
json: () => Promise< Post[] >;
|
|
31
31
|
headers: {
|
|
32
|
-
get: ( key: string ) => string | null
|
|
33
|
-
}
|
|
34
|
-
}
|
|
32
|
+
get: ( key: string ) => string | null;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
35
|
|
|
36
36
|
export type PostsResponse = {
|
|
37
|
-
data: Post[]
|
|
38
|
-
totalPages: number
|
|
39
|
-
totalPosts: number
|
|
40
|
-
currentPage: number
|
|
37
|
+
data: Post[];
|
|
38
|
+
totalPages: number;
|
|
39
|
+
totalPosts: number;
|
|
40
|
+
currentPage: number;
|
|
41
41
|
};
|
|
42
42
|
|
|
43
|
-
export const getRequest = async ( postTypeSlug: Slug, page: number ): Promise<PostsResponse> => {
|
|
43
|
+
export const getRequest = async ( postTypeSlug: Slug, page: number ): Promise< PostsResponse > => {
|
|
44
44
|
const baseUri = `/wp/v2/${ postTypesMap[ postTypeSlug ].rest_base }`;
|
|
45
45
|
|
|
46
|
-
const keys: Array<keyof Post> = [ 'id', 'type', 'title', 'link', 'status', 'user_can' ];
|
|
46
|
+
const keys: Array< keyof Post > = [ 'id', 'type', 'title', 'link', 'status', 'user_can' ];
|
|
47
47
|
|
|
48
48
|
const queryParams = new URLSearchParams( {
|
|
49
49
|
status: 'any',
|
|
@@ -55,7 +55,7 @@ export const getRequest = async ( postTypeSlug: Slug, page: number ): Promise<Po
|
|
|
55
55
|
|
|
56
56
|
const uri = baseUri + '?' + queryParams.toString();
|
|
57
57
|
|
|
58
|
-
const result = await apiFetch<WpPostsResponse>( { path: uri, parse: false } );
|
|
58
|
+
const result = await apiFetch< WpPostsResponse >( { path: uri, parse: false } );
|
|
59
59
|
const data = await result.json();
|
|
60
60
|
|
|
61
61
|
const totalPages = Number( result.headers.get( 'x-wp-totalpages' ) );
|
|
@@ -72,7 +72,7 @@ export const getRequest = async ( postTypeSlug: Slug, page: number ): Promise<Po
|
|
|
72
72
|
export const createRequest = ( postTypeSlug: Slug, newPost: NewPost ) => {
|
|
73
73
|
const path = `/wp/v2/${ postTypesMap[ postTypeSlug ].rest_base }`;
|
|
74
74
|
|
|
75
|
-
return apiFetch<{ id: number }>( {
|
|
75
|
+
return apiFetch< { id: number } >( {
|
|
76
76
|
path,
|
|
77
77
|
method: 'POST',
|
|
78
78
|
data: newPost,
|
|
@@ -102,7 +102,7 @@ export const deleteRequest = ( postTypeSlug: Slug, postId: number ) => {
|
|
|
102
102
|
export const duplicateRequest = ( originalPost: UpdatePost ) => {
|
|
103
103
|
const path = `/elementor/v1/site-navigation/duplicate-post`;
|
|
104
104
|
|
|
105
|
-
return apiFetch<{ post_id: number }>( {
|
|
105
|
+
return apiFetch< { post_id: number } >( {
|
|
106
106
|
path,
|
|
107
107
|
method: 'POST',
|
|
108
108
|
data: {
|
package/src/api/recent-posts.ts
CHANGED
package/src/api/settings.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import apiFetch from '@wordpress/api-fetch';
|
|
2
2
|
|
|
3
3
|
export type Settings = {
|
|
4
|
-
show_on_front: 'page' | ''
|
|
5
|
-
page_on_front: number
|
|
6
|
-
}
|
|
4
|
+
show_on_front: 'page' | '';
|
|
5
|
+
page_on_front: number;
|
|
6
|
+
};
|
|
7
7
|
|
|
8
8
|
type Homepage = number;
|
|
9
9
|
|
|
@@ -12,7 +12,7 @@ export const getSettings = () => {
|
|
|
12
12
|
|
|
13
13
|
const uri = baseUri;
|
|
14
14
|
|
|
15
|
-
return apiFetch<Homepage>( { path: uri } );
|
|
15
|
+
return apiFetch< Homepage >( { path: uri } );
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
export const updateSettings = ( settings: Settings ) => {
|
package/src/api/user.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import apiFetch from '@wordpress/api-fetch';
|
|
2
2
|
|
|
3
3
|
export type User = {
|
|
4
|
-
|
|
5
|
-
}
|
|
4
|
+
capabilities: Record< string, boolean >;
|
|
5
|
+
};
|
|
6
6
|
|
|
7
7
|
export const getUser = () => {
|
|
8
8
|
const baseUri = '/wp/v2/users/me';
|
|
9
9
|
|
|
10
|
-
const keys: Array<keyof User> = [ 'capabilities' ];
|
|
10
|
+
const keys: Array< keyof User > = [ 'capabilities' ];
|
|
11
11
|
|
|
12
12
|
const queryParams = new URLSearchParams( {
|
|
13
13
|
_fields: keys.join( ',' ),
|
|
@@ -16,5 +16,5 @@ export const getUser = () => {
|
|
|
16
16
|
|
|
17
17
|
const uri = baseUri + '?' + queryParams.toString();
|
|
18
18
|
|
|
19
|
-
return apiFetch<User>( { path: uri } );
|
|
19
|
+
return apiFetch< User >( { path: uri } );
|
|
20
20
|
};
|
|
@@ -1,24 +1,21 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
3
|
-
ListItemIcon,
|
|
4
|
-
ListItemText,
|
|
5
|
-
MenuItem,
|
|
6
|
-
MenuItemProps as MenuItemPropsType,
|
|
7
|
-
} from '@elementor/ui';
|
|
2
|
+
import { ListItemIcon, ListItemText, MenuItem, MenuItemProps as MenuItemPropsType } from '@elementor/ui';
|
|
8
3
|
import { ComponentType } from 'react';
|
|
9
4
|
|
|
10
5
|
export type Props = {
|
|
11
6
|
title: string;
|
|
12
7
|
icon: ComponentType;
|
|
13
8
|
MenuItemProps: MenuItemPropsType;
|
|
14
|
-
}
|
|
9
|
+
};
|
|
15
10
|
|
|
16
11
|
export default function ActionMenuItem( { title, icon: Icon, MenuItemProps }: Props ) {
|
|
17
12
|
return (
|
|
18
13
|
<MenuItem { ...MenuItemProps }>
|
|
19
|
-
<ListItemIcon
|
|
20
|
-
|
|
21
|
-
|
|
14
|
+
<ListItemIcon
|
|
15
|
+
sx={ {
|
|
16
|
+
color: 'inherit',
|
|
17
|
+
} }
|
|
18
|
+
>
|
|
22
19
|
<Icon />
|
|
23
20
|
</ListItemIcon>
|
|
24
21
|
<ListItemText primary={ title } />
|
|
@@ -15,14 +15,17 @@ jest.mock( '../../../../../hooks/use-homepage-actions', () => ( {
|
|
|
15
15
|
} ) ),
|
|
16
16
|
} ) );
|
|
17
17
|
|
|
18
|
-
jest.mock( '../../../../../hooks/use-user', () => (
|
|
19
|
-
{
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
18
|
+
jest.mock( '../../../../../hooks/use-user', () => ( {
|
|
19
|
+
default: jest.fn( () => ( {
|
|
20
|
+
isLoading: false,
|
|
21
|
+
data: {
|
|
22
|
+
capabilities: {
|
|
23
|
+
manage_options: true,
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
} ) ),
|
|
27
|
+
__esModule: true,
|
|
28
|
+
} ) );
|
|
26
29
|
|
|
27
30
|
describe( '@elementor/editor-site-navigation - SetHome', () => {
|
|
28
31
|
afterAll( () => {
|
|
@@ -92,7 +95,7 @@ describe( '@elementor/editor-site-navigation - SetHome', () => {
|
|
|
92
95
|
manage_options: false,
|
|
93
96
|
},
|
|
94
97
|
},
|
|
95
|
-
} as unknown as ReturnType<typeof useUser> );
|
|
98
|
+
} as unknown as ReturnType< typeof useUser > );
|
|
96
99
|
|
|
97
100
|
const post: Post = {
|
|
98
101
|
id: 1,
|
|
@@ -25,32 +25,32 @@ export default function Delete( { post }: { post: Post } ) {
|
|
|
25
25
|
const isPostActive = activeDocument?.id === post.id;
|
|
26
26
|
const userCanDelete = post.user_can.delete;
|
|
27
27
|
|
|
28
|
-
const isDisabled =
|
|
28
|
+
const isDisabled = ! userCanDelete || post.isHome || isPostActive;
|
|
29
29
|
|
|
30
30
|
return (
|
|
31
31
|
<>
|
|
32
32
|
<ActionMenuItem
|
|
33
33
|
title={ __( 'Delete', 'elementor' ) }
|
|
34
34
|
icon={ TrashIcon }
|
|
35
|
-
MenuItemProps={
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
}
|
|
35
|
+
MenuItemProps={ {
|
|
36
|
+
disabled: isDisabled,
|
|
37
|
+
onClick: () => setIsDialogOpen( true ),
|
|
38
|
+
sx: { '&:hover': { color: 'error.main' } },
|
|
39
|
+
} }
|
|
42
40
|
/>
|
|
43
41
|
|
|
44
|
-
{
|
|
45
|
-
isDialogOpen && (
|
|
46
|
-
<DeleteDialog post={ post } setIsDialogOpen={ setIsDialogOpen } />
|
|
47
|
-
)
|
|
48
|
-
}
|
|
42
|
+
{ isDialogOpen && <DeleteDialog post={ post } setIsDialogOpen={ setIsDialogOpen } /> }
|
|
49
43
|
</>
|
|
50
44
|
);
|
|
51
45
|
}
|
|
52
46
|
|
|
53
|
-
function DeleteDialog( {
|
|
47
|
+
function DeleteDialog( {
|
|
48
|
+
post,
|
|
49
|
+
setIsDialogOpen,
|
|
50
|
+
}: {
|
|
51
|
+
post: Post;
|
|
52
|
+
setIsDialogOpen: React.Dispatch< React.SetStateAction< boolean > >;
|
|
53
|
+
} ) {
|
|
54
54
|
const { type } = usePostListContext();
|
|
55
55
|
const { deletePost } = usePostActions( type );
|
|
56
56
|
const { setError } = usePostListContext();
|
|
@@ -76,25 +76,27 @@ function DeleteDialog( { post, setIsDialogOpen }: { post: Post, setIsDialogOpen:
|
|
|
76
76
|
};
|
|
77
77
|
|
|
78
78
|
return (
|
|
79
|
-
<Dialog
|
|
80
|
-
|
|
81
|
-
onClose={ handleCancel }
|
|
82
|
-
aria-labelledby="delete-dialog"
|
|
83
|
-
>
|
|
84
|
-
<DialogTitle noWrap>
|
|
85
|
-
{ dialogTitle }
|
|
86
|
-
</DialogTitle>
|
|
79
|
+
<Dialog open={ true } onClose={ handleCancel } aria-labelledby="delete-dialog">
|
|
80
|
+
<DialogTitle noWrap>{ dialogTitle }</DialogTitle>
|
|
87
81
|
<Divider />
|
|
88
82
|
<DialogContent>
|
|
89
83
|
<DialogContentText>
|
|
90
|
-
{ __(
|
|
84
|
+
{ __(
|
|
85
|
+
'The page and its content will be deleted forever and we won’t be able to recover them.',
|
|
86
|
+
'elementor'
|
|
87
|
+
) }
|
|
91
88
|
</DialogContentText>
|
|
92
89
|
</DialogContent>
|
|
93
90
|
<DialogActions>
|
|
94
|
-
<Button
|
|
91
|
+
<Button
|
|
92
|
+
variant="contained"
|
|
93
|
+
color="secondary"
|
|
94
|
+
onClick={ handleCancel }
|
|
95
|
+
disabled={ deletePost.isPending }
|
|
96
|
+
>
|
|
95
97
|
{ __( 'Cancel', 'elementor' ) }
|
|
96
98
|
</Button>
|
|
97
|
-
<Button variant="contained" color="error" onClick={ deletePage } disabled={ deletePost.isPending }
|
|
99
|
+
<Button variant="contained" color="error" onClick={ deletePage } disabled={ deletePost.isPending }>
|
|
98
100
|
{ ! deletePost.isPending ? __( 'Delete', 'elementor' ) : <CircularProgress /> }
|
|
99
101
|
</Button>
|
|
100
102
|
</DialogActions>
|
|
@@ -7,7 +7,7 @@ import { usePostListContext } from '../../../../contexts/post-list-context';
|
|
|
7
7
|
import { Post } from '../../../../types';
|
|
8
8
|
import useUser from '../../../../hooks/use-user';
|
|
9
9
|
|
|
10
|
-
export default function Duplicate( { post, popupState }: { post: Post
|
|
10
|
+
export default function Duplicate( { post, popupState }: { post: Post; popupState: PopupState } ) {
|
|
11
11
|
const { setEditMode } = usePostListContext();
|
|
12
12
|
const { data: user } = useUser();
|
|
13
13
|
const onClick = () => {
|
|
@@ -28,12 +28,10 @@ export default function Duplicate( { post, popupState }: { post: Post, popupStat
|
|
|
28
28
|
<ActionMenuItem
|
|
29
29
|
title={ __( 'Duplicate', 'elementor' ) }
|
|
30
30
|
icon={ CopyIcon }
|
|
31
|
-
MenuItemProps={
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
}
|
|
31
|
+
MenuItemProps={ {
|
|
32
|
+
disabled: isDisabled,
|
|
33
|
+
onClick,
|
|
34
|
+
} }
|
|
37
35
|
/>
|
|
38
36
|
);
|
|
39
37
|
}
|
|
@@ -12,19 +12,17 @@ export default function Rename( { post }: { post: Post } ) {
|
|
|
12
12
|
<ActionMenuItem
|
|
13
13
|
title={ __( 'Rename', 'elementor' ) }
|
|
14
14
|
icon={ EraseIcon }
|
|
15
|
-
MenuItemProps={
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
}
|
|
15
|
+
MenuItemProps={ {
|
|
16
|
+
disabled: ! post.user_can.edit,
|
|
17
|
+
onClick: () => {
|
|
18
|
+
setEditMode( {
|
|
19
|
+
mode: 'rename',
|
|
20
|
+
details: {
|
|
21
|
+
postId: post.id,
|
|
22
|
+
},
|
|
23
|
+
} );
|
|
24
|
+
},
|
|
25
|
+
} }
|
|
28
26
|
/>
|
|
29
27
|
);
|
|
30
28
|
}
|
|
@@ -8,7 +8,7 @@ import { CircularProgress } from '@elementor/ui';
|
|
|
8
8
|
import { usePostListContext } from '../../../../contexts/post-list-context';
|
|
9
9
|
import useUser from '../../../../hooks/use-user';
|
|
10
10
|
|
|
11
|
-
export default function SetHome( { post, closeMenu }: { post: Post
|
|
11
|
+
export default function SetHome( { post, closeMenu }: { post: Post; closeMenu: () => void } ) {
|
|
12
12
|
const { updateSettingsMutation } = useHomepageActions();
|
|
13
13
|
const { setError } = usePostListContext();
|
|
14
14
|
const { data: user } = useUser();
|
|
@@ -27,18 +27,16 @@ export default function SetHome( { post, closeMenu }: { post: Post, closeMenu: (
|
|
|
27
27
|
const isPostPublished = post.status === 'publish';
|
|
28
28
|
const isPostHomepage = !! post.isHome;
|
|
29
29
|
|
|
30
|
-
const isDisabled =
|
|
30
|
+
const isDisabled = ! canManageOptions || isPostHomepage || ! isPostPublished || updateSettingsMutation.isPending;
|
|
31
31
|
|
|
32
32
|
return (
|
|
33
33
|
<ActionMenuItem
|
|
34
34
|
title={ __( 'Set as homepage', 'elementor' ) }
|
|
35
35
|
icon={ ! updateSettingsMutation.isPending ? HomeIcon : CircularProgress }
|
|
36
|
-
MenuItemProps={
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
}
|
|
36
|
+
MenuItemProps={ {
|
|
37
|
+
disabled: isDisabled,
|
|
38
|
+
onClick: handleClick,
|
|
39
|
+
} }
|
|
42
40
|
/>
|
|
43
41
|
);
|
|
44
42
|
}
|
|
@@ -16,11 +16,9 @@ export default function View( { post }: { post: Post } ) {
|
|
|
16
16
|
<ActionMenuItem
|
|
17
17
|
title={ title }
|
|
18
18
|
icon={ EyeIcon }
|
|
19
|
-
MenuItemProps={
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
}
|
|
19
|
+
MenuItemProps={ {
|
|
20
|
+
onClick: () => window.open( post.link, '_blank' ),
|
|
21
|
+
} }
|
|
24
22
|
/>
|
|
25
23
|
);
|
|
26
24
|
}
|
|
@@ -21,10 +21,11 @@ const ErrorSnackbar = ( { open, onClose }: Props ) => {
|
|
|
21
21
|
component="span"
|
|
22
22
|
sx={ {
|
|
23
23
|
fontWeight: 'bold',
|
|
24
|
-
} }
|
|
24
|
+
} }
|
|
25
|
+
>
|
|
25
26
|
We couldn’t complete the action.
|
|
26
|
-
</Typography>
|
|
27
|
-
|
|
27
|
+
</Typography>{ ' ' }
|
|
28
|
+
Please try again
|
|
28
29
|
</Alert>
|
|
29
30
|
</Snackbar>
|
|
30
31
|
);
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import { __createPanel } from '@elementor/editor-panels';
|
|
2
2
|
import Shell from './shell';
|
|
3
3
|
|
|
4
|
-
export const {
|
|
5
|
-
panel,
|
|
6
|
-
usePanelStatus,
|
|
7
|
-
usePanelActions,
|
|
8
|
-
} = __createPanel( {
|
|
4
|
+
export const { panel, usePanelStatus, usePanelActions } = __createPanel( {
|
|
9
5
|
id: 'site-navigation-panel',
|
|
10
6
|
component: Shell,
|
|
11
7
|
} );
|
|
@@ -26,8 +26,22 @@ jest.mock( '../../../../hooks/use-posts', () => ( {
|
|
|
26
26
|
isLoading: false,
|
|
27
27
|
data: {
|
|
28
28
|
posts: [
|
|
29
|
-
{
|
|
30
|
-
|
|
29
|
+
{
|
|
30
|
+
id: 1,
|
|
31
|
+
type: 'page',
|
|
32
|
+
title: { rendered: 'Home' },
|
|
33
|
+
status: 'publish',
|
|
34
|
+
link: 'www.test.demo',
|
|
35
|
+
user_can: { edit: true, delete: true },
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: 2,
|
|
39
|
+
type: 'page',
|
|
40
|
+
title: { rendered: 'About' },
|
|
41
|
+
status: 'draft',
|
|
42
|
+
link: 'www.test.demo',
|
|
43
|
+
user_can: { edit: true, delete: true },
|
|
44
|
+
},
|
|
31
45
|
],
|
|
32
46
|
total: 2,
|
|
33
47
|
},
|
|
@@ -47,20 +61,25 @@ jest.mock( '@elementor/editor-documents', () => ( {
|
|
|
47
61
|
__useNavigateToDocument: jest.fn(),
|
|
48
62
|
} ) );
|
|
49
63
|
|
|
50
|
-
jest.mock( '../../../../hooks/use-user', () => (
|
|
51
|
-
{
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
64
|
+
jest.mock( '../../../../hooks/use-user', () => ( {
|
|
65
|
+
default: jest.fn( () => ( {
|
|
66
|
+
isLoading: false,
|
|
67
|
+
data: {
|
|
68
|
+
capabilities: {
|
|
69
|
+
edit_pages: true,
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
} ) ),
|
|
73
|
+
__esModule: true,
|
|
74
|
+
} ) );
|
|
58
75
|
|
|
59
76
|
describe( '@elementor/editor-site-navigation - PostsCollapsibleList', () => {
|
|
60
77
|
beforeEach( () => {
|
|
61
|
-
jest.mocked( useActiveDocument ).mockReturnValue(
|
|
62
|
-
|
|
63
|
-
|
|
78
|
+
jest.mocked( useActiveDocument ).mockReturnValue(
|
|
79
|
+
createMockDocument( {
|
|
80
|
+
id: 3,
|
|
81
|
+
} )
|
|
82
|
+
);
|
|
64
83
|
} );
|
|
65
84
|
|
|
66
85
|
afterEach( () => {
|
|
@@ -168,12 +187,26 @@ describe( '@elementor/editor-site-navigation - PostsCollapsibleList', () => {
|
|
|
168
187
|
isLoading: false,
|
|
169
188
|
data: {
|
|
170
189
|
posts: [
|
|
171
|
-
{
|
|
172
|
-
|
|
190
|
+
{
|
|
191
|
+
id: 1,
|
|
192
|
+
type: 'page',
|
|
193
|
+
title: { rendered: 'Home' },
|
|
194
|
+
status: 'publish',
|
|
195
|
+
link: 'www.test.demo',
|
|
196
|
+
user_can: { edit: true, delete: true },
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
id: 2,
|
|
200
|
+
type: 'page',
|
|
201
|
+
title: { rendered: 'About' },
|
|
202
|
+
status: 'draft',
|
|
203
|
+
link: 'www.test.demo',
|
|
204
|
+
user_can: { edit: true, delete: true },
|
|
205
|
+
},
|
|
173
206
|
],
|
|
174
207
|
total: 2,
|
|
175
208
|
},
|
|
176
|
-
} as ReturnType<typeof usePosts> );
|
|
209
|
+
} as ReturnType< typeof usePosts > );
|
|
177
210
|
renderWithQuery( <PostsCollapsibleList isOpenByDefault={ true } /> );
|
|
178
211
|
|
|
179
212
|
// Assert.
|
|
@@ -187,12 +220,26 @@ describe( '@elementor/editor-site-navigation - PostsCollapsibleList', () => {
|
|
|
187
220
|
isLoading: false,
|
|
188
221
|
data: {
|
|
189
222
|
posts: [
|
|
190
|
-
{
|
|
191
|
-
|
|
223
|
+
{
|
|
224
|
+
id: 1,
|
|
225
|
+
type: 'page',
|
|
226
|
+
title: { rendered: 'Home' },
|
|
227
|
+
status: 'publish',
|
|
228
|
+
link: 'www.test.demo',
|
|
229
|
+
user_can: { edit: true, delete: true },
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
id: 2,
|
|
233
|
+
type: 'page',
|
|
234
|
+
title: { rendered: 'About' },
|
|
235
|
+
status: 'draft',
|
|
236
|
+
link: 'www.test.demo',
|
|
237
|
+
user_can: { edit: true, delete: true },
|
|
238
|
+
},
|
|
192
239
|
],
|
|
193
240
|
total: 2,
|
|
194
241
|
},
|
|
195
|
-
} as ReturnType<typeof usePosts> );
|
|
242
|
+
} as ReturnType< typeof usePosts > );
|
|
196
243
|
renderWithQuery( <PostsCollapsibleList isOpenByDefault={ true } /> );
|
|
197
244
|
|
|
198
245
|
// Assert.
|
|
@@ -1,22 +1,32 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { PropsWithChildren, useState } from 'react';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
Collapse,
|
|
5
|
+
IconButton,
|
|
6
|
+
List,
|
|
7
|
+
ListItem,
|
|
8
|
+
ListItemIcon,
|
|
9
|
+
ListItemText,
|
|
10
|
+
styled,
|
|
11
|
+
SvgIconProps,
|
|
12
|
+
Divider,
|
|
13
|
+
} from '@elementor/ui';
|
|
4
14
|
import { ChevronDownIcon } from '@elementor/icons';
|
|
5
15
|
|
|
6
16
|
type Props = {
|
|
7
|
-
label: string
|
|
8
|
-
Icon: React.ForwardRefExoticComponent<Omit<SvgIconProps, 'ref'
|
|
9
|
-
isOpenByDefault?: boolean
|
|
10
|
-
}
|
|
17
|
+
label: string;
|
|
18
|
+
Icon: React.ForwardRefExoticComponent< Omit< SvgIconProps, 'ref' > >;
|
|
19
|
+
isOpenByDefault?: boolean;
|
|
20
|
+
};
|
|
11
21
|
|
|
12
22
|
interface RotateIconProps extends SvgIconProps {
|
|
13
|
-
isOpen: boolean
|
|
23
|
+
isOpen: boolean;
|
|
14
24
|
}
|
|
15
25
|
|
|
16
26
|
// TODO 21/06/2023 : Should replace this with future Rotate component that will be implemented in elementor-ui
|
|
17
27
|
const RotateIcon = styled( ChevronDownIcon, {
|
|
18
28
|
shouldForwardProp: ( prop ) => prop !== 'isOpen',
|
|
19
|
-
} )<RotateIconProps>( ( { theme, isOpen } ) => ( {
|
|
29
|
+
} )< RotateIconProps >( ( { theme, isOpen } ) => ( {
|
|
20
30
|
transform: isOpen ? 'rotate(0deg)' : 'rotate(-90deg)',
|
|
21
31
|
transition: theme.transitions.create( 'transform', {
|
|
22
32
|
duration: theme.transitions.duration.standard,
|
|
@@ -25,24 +35,24 @@ const RotateIcon = styled( ChevronDownIcon, {
|
|
|
25
35
|
|
|
26
36
|
const StyledListItemIcon = styled( ListItemIcon )( ( { theme } ) => ( {
|
|
27
37
|
minWidth: theme.spacing( 4 ),
|
|
28
|
-
} )
|
|
38
|
+
} ) );
|
|
29
39
|
|
|
30
|
-
export default function CollapsibleList(
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}: PropsWithChildren<Props>
|
|
37
|
-
) {
|
|
40
|
+
export default function CollapsibleList( {
|
|
41
|
+
label,
|
|
42
|
+
Icon,
|
|
43
|
+
isOpenByDefault = false,
|
|
44
|
+
children,
|
|
45
|
+
}: PropsWithChildren< Props > ) {
|
|
38
46
|
const [ isOpen, setIsOpen ] = useState( isOpenByDefault );
|
|
39
47
|
|
|
40
48
|
return (
|
|
41
49
|
<>
|
|
42
|
-
<ListItem
|
|
43
|
-
<StyledListItemIcon
|
|
44
|
-
|
|
45
|
-
|
|
50
|
+
<ListItem>
|
|
51
|
+
<StyledListItemIcon
|
|
52
|
+
sx={ {
|
|
53
|
+
color: 'text.secondary',
|
|
54
|
+
} }
|
|
55
|
+
>
|
|
46
56
|
<IconButton
|
|
47
57
|
onClick={ () => setIsOpen( ( prev ) => ! prev ) }
|
|
48
58
|
size="small"
|
|
@@ -57,18 +67,17 @@ export default function CollapsibleList(
|
|
|
57
67
|
size="small"
|
|
58
68
|
sx={ {
|
|
59
69
|
color: 'inherit',
|
|
60
|
-
} }
|
|
70
|
+
} }
|
|
71
|
+
>
|
|
61
72
|
<Icon fontSize="small" />
|
|
62
73
|
</StyledListItemIcon>
|
|
63
|
-
<ListItemText
|
|
74
|
+
<ListItemText
|
|
75
|
+
primaryTypographyProps={ { variant: 'subtitle2', component: 'span' } }
|
|
76
|
+
primary={ label }
|
|
77
|
+
/>
|
|
64
78
|
</ListItem>
|
|
65
|
-
<Collapse
|
|
66
|
-
|
|
67
|
-
timeout="auto"
|
|
68
|
-
unmountOnExit>
|
|
69
|
-
<List dense>
|
|
70
|
-
{ children }
|
|
71
|
-
</List>
|
|
79
|
+
<Collapse in={ isOpen } timeout="auto" unmountOnExit>
|
|
80
|
+
<List dense>{ children }</List>
|
|
72
81
|
</Collapse>
|
|
73
82
|
<Divider sx={ { mt: 1 } } />
|
|
74
83
|
</>
|