@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.
Files changed (38) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/index.js +445 -174
  3. package/dist/index.mjs +441 -161
  4. package/package.json +2 -2
  5. package/src/api/post.ts +14 -6
  6. package/src/components/panel/actions-menu/action-list-item.tsx +1 -1
  7. package/src/components/panel/{pages-actions → actions-menu/actions}/delete.tsx +5 -5
  8. package/src/components/panel/actions-menu/actions/duplicate.tsx +29 -0
  9. package/src/components/panel/actions-menu/actions/rename.tsx +25 -0
  10. package/src/components/panel/{pages-actions → actions-menu/actions}/set-home.tsx +4 -4
  11. package/src/components/panel/actions-menu/actions/view.tsx +25 -0
  12. package/src/components/panel/add-new-button.tsx +22 -0
  13. package/src/components/panel/{pages-list/__tests__/page-list-item.test.tsx → posts-list/__tests__/post-list-item.test.tsx} +21 -18
  14. package/src/components/panel/{pages-list/__tests__/pages-collapsible-list.test.tsx → posts-list/__tests__/posts-collapsible-list.test.tsx} +11 -14
  15. package/src/components/panel/{pages-list → posts-list}/collapsible-list.tsx +4 -4
  16. package/src/components/panel/posts-list/list-items/edit-mode-template.tsx +103 -0
  17. package/src/components/panel/posts-list/list-items/list-item-create.tsx +25 -0
  18. package/src/components/panel/posts-list/list-items/list-item-duplicate.tsx +29 -0
  19. package/src/components/panel/posts-list/list-items/list-item-rename.tsx +33 -0
  20. package/src/components/panel/posts-list/list-items/list-item-view.tsx +87 -0
  21. package/src/components/panel/posts-list/post-list-item.tsx +29 -0
  22. package/src/components/panel/posts-list/posts-collapsible-list.tsx +44 -0
  23. package/src/components/panel/shell.tsx +14 -13
  24. package/src/components/top-bar/__tests__/add-new-page.test.tsx +11 -12
  25. package/src/components/top-bar/__tests__/recently-edited.test.tsx +30 -30
  26. package/src/contexts/post-list-context.tsx +73 -0
  27. package/src/env.ts +2 -2
  28. package/src/hooks/__tests__/use-create-page.test.ts +6 -8
  29. package/src/hooks/__tests__/use-posts.test.ts +4 -6
  30. package/src/hooks/__tests__/use-recent-posts.test.ts +4 -4
  31. package/src/init.ts +1 -1
  32. package/src/components/panel/actions-menu/page-actions-menu.tsx +0 -29
  33. package/src/components/panel/add-new-page-button.tsx +0 -15
  34. package/src/components/panel/pages-actions/duplicate.tsx +0 -14
  35. package/src/components/panel/pages-actions/rename.tsx +0 -14
  36. package/src/components/panel/pages-actions/view.tsx +0 -14
  37. package/src/components/panel/pages-list/page-list-item.tsx +0 -66
  38. 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.10.3",
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": "e27c0b852121946fcc32d5ce8a5a1551c93d87a6"
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: 'pages',
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 }`,
@@ -7,7 +7,7 @@ export type Props = {
7
7
  title: string;
8
8
  icon: ComponentType;
9
9
  disabled?: boolean;
10
- onClick: ( page: Post ) => void;
10
+ onClick: ( post: Post ) => void;
11
11
  }
12
12
 
13
13
  export default function ActionListItem( { title, icon: Icon, disabled, onClick }: Props ) {
@@ -1,20 +1,20 @@
1
1
  import * as React from 'react';
2
2
  import { TrashIcon } from '@elementor/icons';
3
- import { Post } from '../../../types';
3
+ import { Post } from '../../../../types';
4
4
  import { useActiveDocument } from '@elementor/editor-documents';
5
5
  import { __ } from '@wordpress/i18n';
6
- import ActionMenuItem from '../actions-menu/action-menu-item';
6
+ import ActionMenuItem from '../action-menu-item';
7
7
 
8
- export default function Delete( { page }: { page: Post } ) {
8
+ export default function Delete( { post }: { post: Post } ) {
9
9
  const activeDocument = useActiveDocument();
10
10
 
11
- const isActive = activeDocument?.id === page.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={ page.isHome || isActive }
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 '../../../types';
2
+ import { Post } from '../../../../types';
3
3
  import { HomeIcon } from '@elementor/icons';
4
4
  import { __ } from '@wordpress/i18n';
5
- import ActionMenuItem from '../actions-menu/action-menu-item';
5
+ import ActionMenuItem from '../action-menu-item';
6
6
 
7
- export default function SetHome( { page }: { page: Post } ) {
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={ !! page.isHome }
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, render } from '@testing-library/react';
2
+ import { act, screen } from '@testing-library/react';
3
3
  import { Post } from '../../../../types';
4
- import PageListItem from '../page-list-item';
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 - PageListItem', () => {
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 page: Post = {
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
- const { getByText, queryByText } = render( <PageListItem page={ page } /> );
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 ).toBeNull();
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 page: Post = {
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
- const { getByText } = render( <PageListItem page={ page } /> );
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 page: Post = {
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
- const { getByText, getAllByRole } = render( <PageListItem page={ page } /> );
76
- const buttons = getAllByRole( 'button' );
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 page: Post = {
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
- const { getAllByRole } = render( <PageListItem page={ page } /> );
111
- const buttons = getAllByRole( 'button' );
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 { render } from '@testing-library/react';
3
- import PagesCollapsibleList from '../pages-collapsible-list';
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 - PagesCollapsibleList', () => {
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
- const { getByText, queryByText } = render(
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 ).toBeNull();
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
- const { getByText } = render(
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
+ }