@elementor/editor-app-bar 0.1.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/LICENSE +674 -0
- package/README.md +5 -0
- package/dist/index.d.ts +234 -0
- package/dist/index.js +1047 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1017 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +50 -0
- package/src/components/__tests__/top-bar.test.tsx +15 -0
- package/src/components/actions/action.tsx +33 -0
- package/src/components/actions/link.tsx +33 -0
- package/src/components/actions/toggle-action.tsx +35 -0
- package/src/components/app-bar.tsx +37 -0
- package/src/components/locations/__tests__/locations-components.test.tsx +37 -0
- package/src/components/locations/__tests__/menus.test.tsx +89 -0
- package/src/components/locations/main-menu-location.tsx +50 -0
- package/src/components/locations/page-indication-location.tsx +9 -0
- package/src/components/locations/primary-action-location.tsx +9 -0
- package/src/components/locations/responsive-location.tsx +9 -0
- package/src/components/locations/tools-menu-location.tsx +26 -0
- package/src/components/locations/utilities-menu-location.tsx +35 -0
- package/src/components/ui/popover-menu-item.tsx +39 -0
- package/src/components/ui/popover-menu.tsx +23 -0
- package/src/components/ui/toolbar-logo.tsx +80 -0
- package/src/components/ui/toolbar-menu-item.tsx +18 -0
- package/src/components/ui/toolbar-menu-more.tsx +29 -0
- package/src/components/ui/toolbar-menu-toggle-item.tsx +18 -0
- package/src/components/ui/toolbar-menu.tsx +15 -0
- package/src/contexts/menu-context.tsx +20 -0
- package/src/extensions/documents-indicator/components/__tests__/settings-button.test.tsx +46 -0
- package/src/extensions/documents-indicator/components/settings-button.tsx +43 -0
- package/src/extensions/documents-indicator/index.ts +12 -0
- package/src/extensions/documents-preview/hooks/__tests__/use-document-preview-props.test.ts +43 -0
- package/src/extensions/documents-preview/hooks/use-action-props.ts +17 -0
- package/src/extensions/documents-preview/index.ts +10 -0
- package/src/extensions/documents-save/components/__tests__/primary-action-menu.test.tsx +41 -0
- package/src/extensions/documents-save/components/__tests__/primary-action.test.tsx +176 -0
- package/src/extensions/documents-save/components/primary-action-menu.tsx +48 -0
- package/src/extensions/documents-save/components/primary-action.tsx +79 -0
- package/src/extensions/documents-save/hooks/__tests__/use-document-save-draft-props.test.ts +64 -0
- package/src/extensions/documents-save/hooks/__tests__/use-document-save-template-props.test.ts +27 -0
- package/src/extensions/documents-save/hooks/use-document-save-draft-props.ts +16 -0
- package/src/extensions/documents-save/hooks/use-document-save-template-props.ts +14 -0
- package/src/extensions/documents-save/index.ts +26 -0
- package/src/extensions/elements/hooks/__tests__/use-action-props.test.ts +33 -0
- package/src/extensions/elements/hooks/use-action-props.ts +15 -0
- package/src/extensions/elements/index.ts +13 -0
- package/src/extensions/elements/sync/__tests__/sync-panel-title.test.ts +92 -0
- package/src/extensions/elements/sync/sync-panel-title.ts +47 -0
- package/src/extensions/finder/hooks/__tests__/use-action-props.test.ts +36 -0
- package/src/extensions/finder/hooks/use-action-props.ts +18 -0
- package/src/extensions/finder/index.ts +10 -0
- package/src/extensions/help/index.ts +18 -0
- package/src/extensions/history/hooks/__tests__/use-action-props.test.ts +33 -0
- package/src/extensions/history/hooks/use-action-props.ts +15 -0
- package/src/extensions/history/index.ts +10 -0
- package/src/extensions/index.ts +34 -0
- package/src/extensions/keyboard-shortcuts/hooks/__tests__/use-action-props.test.ts +20 -0
- package/src/extensions/keyboard-shortcuts/hooks/use-action-props.ts +12 -0
- package/src/extensions/keyboard-shortcuts/index.ts +11 -0
- package/src/extensions/site-settings/components/__tests__/portalled-primary-action.test.tsx +94 -0
- package/src/extensions/site-settings/components/__tests__/primary-action.test.tsx +100 -0
- package/src/extensions/site-settings/components/portal.tsx +27 -0
- package/src/extensions/site-settings/components/portalled-primary-action.tsx +11 -0
- package/src/extensions/site-settings/components/primary-action.tsx +32 -0
- package/src/extensions/site-settings/hooks/__tests__/use-action-props.test.ts +49 -0
- package/src/extensions/site-settings/hooks/use-action-props.ts +22 -0
- package/src/extensions/site-settings/index.ts +18 -0
- package/src/extensions/structure/hooks/__tests__/use-action-props.test.ts +33 -0
- package/src/extensions/structure/hooks/use-action-props.ts +16 -0
- package/src/extensions/structure/index.ts +10 -0
- package/src/extensions/theme-builder/hooks/__tests__/use-action-props.test.ts +22 -0
- package/src/extensions/theme-builder/hooks/use-action-props.ts +12 -0
- package/src/extensions/theme-builder/index.ts +9 -0
- package/src/extensions/user-preferences/hooks/__tests__/use-action-props.test.ts +34 -0
- package/src/extensions/user-preferences/hooks/use-action-props.ts +16 -0
- package/src/extensions/user-preferences/index.ts +10 -0
- package/src/extensions/wordpress/index.ts +21 -0
- package/src/index.ts +13 -0
- package/src/init.ts +15 -0
- package/src/locations/__tests__/menus.test.tsx +229 -0
- package/src/locations/consts.ts +4 -0
- package/src/locations/index.ts +29 -0
- package/src/locations/menus.tsx +141 -0
- package/src/sync/__tests__/redirect-old-menus.test.ts +34 -0
- package/src/sync/redirect-old-menus.ts +9 -0
- package/src/types.ts +3 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Divider, styled } from '@elementor/ui';
|
|
3
|
+
import { documentOptionsMenu } from '../../../locations';
|
|
4
|
+
import PopoverMenu, { PopoverMenuProps } from '../../../components/ui/popover-menu';
|
|
5
|
+
|
|
6
|
+
const { useMenuItems } = documentOptionsMenu;
|
|
7
|
+
|
|
8
|
+
// CSS hack to hide dividers when a group is rendered empty (due to a limitation in our locations' mechanism).
|
|
9
|
+
// It doesn't cover all the cases (i.e. when there are multiple dividers at the end), but it's good enough for our use-case.
|
|
10
|
+
const StyledPopoverMenu = styled( PopoverMenu )`
|
|
11
|
+
& > .MuiPopover-paper > .MuiList-root > .MuiDivider-root {
|
|
12
|
+
&:only-child, /* A divider is being rendered lonely */
|
|
13
|
+
&:last-child, /* The last group renders empty but renders a divider */
|
|
14
|
+
& + .MuiDivider-root /* Multiple dividers due to multiple empty groups */ {
|
|
15
|
+
display: none;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
`;
|
|
19
|
+
|
|
20
|
+
export default function PrimaryActionMenu( props: PopoverMenuProps ) {
|
|
21
|
+
const { save: saveActions, default: defaultActions } = useMenuItems();
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<StyledPopoverMenu
|
|
25
|
+
{ ...props }
|
|
26
|
+
anchorOrigin={ {
|
|
27
|
+
vertical: 'bottom',
|
|
28
|
+
horizontal: 'right',
|
|
29
|
+
} }
|
|
30
|
+
transformOrigin={ {
|
|
31
|
+
vertical: 'top',
|
|
32
|
+
horizontal: 'right',
|
|
33
|
+
} }
|
|
34
|
+
PaperProps={ {
|
|
35
|
+
sx: { mt: 2, ml: 3 },
|
|
36
|
+
} }
|
|
37
|
+
>
|
|
38
|
+
{ saveActions.map( ( { MenuItem, id }, index ) => ( [
|
|
39
|
+
( index > 0 ) && <Divider key={ `${ id }-divider` } />,
|
|
40
|
+
<MenuItem key={ id } />,
|
|
41
|
+
] ) ) }
|
|
42
|
+
|
|
43
|
+
{ defaultActions.length > 0 && <Divider /> }
|
|
44
|
+
|
|
45
|
+
{ defaultActions.map( ( { MenuItem, id } ) => <MenuItem key={ id } /> ) }
|
|
46
|
+
</StyledPopoverMenu>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { __ } from '@wordpress/i18n';
|
|
3
|
+
import PrimaryActionMenu from './primary-action-menu';
|
|
4
|
+
import {
|
|
5
|
+
bindMenu,
|
|
6
|
+
bindTrigger,
|
|
7
|
+
Button,
|
|
8
|
+
ButtonGroup,
|
|
9
|
+
CircularProgress,
|
|
10
|
+
Tooltip,
|
|
11
|
+
usePopupState,
|
|
12
|
+
} from '@elementor/ui';
|
|
13
|
+
import { Document, useActiveDocument, useActiveDocumentActions } from '@elementor/editor-documents';
|
|
14
|
+
import { ChevronDownIcon } from '@elementor/icons';
|
|
15
|
+
|
|
16
|
+
export default function PrimaryAction() {
|
|
17
|
+
const document = useActiveDocument();
|
|
18
|
+
const { save } = useActiveDocumentActions();
|
|
19
|
+
|
|
20
|
+
const popupState = usePopupState( {
|
|
21
|
+
variant: 'popover',
|
|
22
|
+
popupId: 'document-save-options',
|
|
23
|
+
} );
|
|
24
|
+
|
|
25
|
+
if ( ! document ) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const isDisabled = ! isEnabled( document );
|
|
30
|
+
|
|
31
|
+
// When the document is being saved, the spinner should not appear.
|
|
32
|
+
// Usually happens when the Kit is being saved.
|
|
33
|
+
const shouldShowSpinner = document.isSaving && ! isDisabled;
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<>
|
|
37
|
+
<ButtonGroup size="large" variant="contained">
|
|
38
|
+
<Button
|
|
39
|
+
onClick={ () => ! document.isSaving && save() }
|
|
40
|
+
sx={ { width: '120px' } }
|
|
41
|
+
disabled={ isDisabled }
|
|
42
|
+
>
|
|
43
|
+
{ shouldShowSpinner ? <CircularProgress /> : getLabel( document ) }
|
|
44
|
+
</Button>
|
|
45
|
+
|
|
46
|
+
<Tooltip
|
|
47
|
+
title={ __( 'Save Options', 'elementor' ) }
|
|
48
|
+
PopperProps={ {
|
|
49
|
+
sx: {
|
|
50
|
+
'&.MuiTooltip-popper .MuiTooltip-tooltip.MuiTooltip-tooltipPlacementBottom': {
|
|
51
|
+
mt: 3,
|
|
52
|
+
mr: 1,
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
} }
|
|
56
|
+
>
|
|
57
|
+
<Button sx={ { px: 0 } } { ...bindTrigger( popupState ) }>
|
|
58
|
+
<ChevronDownIcon />
|
|
59
|
+
</Button>
|
|
60
|
+
</Tooltip>
|
|
61
|
+
</ButtonGroup>
|
|
62
|
+
<PrimaryActionMenu { ...bindMenu( popupState ) } onClick={ popupState.close } />
|
|
63
|
+
</>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function getLabel( document: Document ) {
|
|
68
|
+
return document.userCan.publish
|
|
69
|
+
? __( 'Publish', 'elementor' )
|
|
70
|
+
: __( 'Submit', 'elementor' );
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function isEnabled( document: Document ) {
|
|
74
|
+
if ( document.type.value === 'kit' ) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return document.isDirty || document.status.value === 'draft';
|
|
79
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { createMockDocument } from 'test-utils';
|
|
2
|
+
import { renderHook } from '@testing-library/react-hooks';
|
|
3
|
+
import useDocumentSaveDraftProps from '../use-document-save-draft-props';
|
|
4
|
+
import { useActiveDocument, useActiveDocumentActions } from '@elementor/editor-documents';
|
|
5
|
+
|
|
6
|
+
jest.mock( '@elementor/editor-documents', () => ( {
|
|
7
|
+
useActiveDocument: jest.fn(),
|
|
8
|
+
useActiveDocumentActions: jest.fn(),
|
|
9
|
+
} ) );
|
|
10
|
+
|
|
11
|
+
const documentActions = {
|
|
12
|
+
save: jest.fn(),
|
|
13
|
+
saveDraft: jest.fn(),
|
|
14
|
+
saveTemplate: jest.fn(),
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
describe( '@elementor/editor-app-bar - useDocumentSaveDraftProps', () => {
|
|
18
|
+
it( 'should save a draft of the current document', () => {
|
|
19
|
+
// Arrange.
|
|
20
|
+
jest.mocked( useActiveDocumentActions ).mockReturnValue( documentActions );
|
|
21
|
+
jest.mocked( useActiveDocument ).mockReturnValue( createMockDocument() );
|
|
22
|
+
|
|
23
|
+
// Act.
|
|
24
|
+
const { result } = renderHook( () => useDocumentSaveDraftProps() );
|
|
25
|
+
result.current.onClick?.();
|
|
26
|
+
|
|
27
|
+
// Assert.
|
|
28
|
+
expect( documentActions.saveDraft ).toBeCalledTimes( 1 );
|
|
29
|
+
} );
|
|
30
|
+
|
|
31
|
+
it.each( [
|
|
32
|
+
{
|
|
33
|
+
condition: 'there is no document',
|
|
34
|
+
document: null,
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
condition: 'a draft is being saved',
|
|
38
|
+
document: createMockDocument( {
|
|
39
|
+
isSavingDraft: true,
|
|
40
|
+
} ),
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
condition: 'the document is being saved',
|
|
44
|
+
document: createMockDocument( {
|
|
45
|
+
isSaving: true,
|
|
46
|
+
} ),
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
condition: 'the document is pristine',
|
|
50
|
+
document: createMockDocument( {
|
|
51
|
+
isDirty: false,
|
|
52
|
+
} ),
|
|
53
|
+
},
|
|
54
|
+
] )( 'should be disabled when $condition', ( { document } ) => {
|
|
55
|
+
// Arrange.
|
|
56
|
+
jest.mocked( useActiveDocument ).mockReturnValue( document );
|
|
57
|
+
|
|
58
|
+
// Act.
|
|
59
|
+
const { result } = renderHook( () => useDocumentSaveDraftProps() );
|
|
60
|
+
|
|
61
|
+
// Assert.
|
|
62
|
+
expect( result.current.disabled ).toBe( true );
|
|
63
|
+
} );
|
|
64
|
+
} );
|
package/src/extensions/documents-save/hooks/__tests__/use-document-save-template-props.test.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { renderHook } from '@testing-library/react-hooks';
|
|
2
|
+
import { useActiveDocumentActions } from '@elementor/editor-documents';
|
|
3
|
+
import useDocumentSaveTemplateProps from '../use-document-save-template-props';
|
|
4
|
+
|
|
5
|
+
jest.mock( '@elementor/editor-documents', () => ( {
|
|
6
|
+
useActiveDocumentActions: jest.fn(),
|
|
7
|
+
} ) );
|
|
8
|
+
|
|
9
|
+
const documentActions = {
|
|
10
|
+
save: jest.fn(),
|
|
11
|
+
saveDraft: jest.fn(),
|
|
12
|
+
saveTemplate: jest.fn(),
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
describe( '@elementor/editor-app-bar - useDocumentSaveTemplateProps', () => {
|
|
16
|
+
it( 'should open the "save as template" modal', () => {
|
|
17
|
+
// Arrange.
|
|
18
|
+
jest.mocked( useActiveDocumentActions ).mockReturnValue( documentActions );
|
|
19
|
+
|
|
20
|
+
// Act.
|
|
21
|
+
const { result } = renderHook( () => useDocumentSaveTemplateProps() );
|
|
22
|
+
result.current.onClick?.();
|
|
23
|
+
|
|
24
|
+
// Assert.
|
|
25
|
+
expect( documentActions.saveTemplate ).toBeCalledTimes( 1 );
|
|
26
|
+
} );
|
|
27
|
+
} );
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { __ } from '@wordpress/i18n';
|
|
2
|
+
import { ActionProps } from '../../../types';
|
|
3
|
+
import { FileReportIcon } from '@elementor/icons';
|
|
4
|
+
import { useActiveDocument, useActiveDocumentActions } from '@elementor/editor-documents';
|
|
5
|
+
|
|
6
|
+
export default function useDocumentSaveDraftProps(): ActionProps {
|
|
7
|
+
const document = useActiveDocument();
|
|
8
|
+
const { saveDraft } = useActiveDocumentActions();
|
|
9
|
+
|
|
10
|
+
return {
|
|
11
|
+
icon: FileReportIcon,
|
|
12
|
+
title: __( 'Save Draft', 'elementor' ),
|
|
13
|
+
onClick: saveDraft,
|
|
14
|
+
disabled: ! document || document.isSaving || document.isSavingDraft || ! document.isDirty,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { __ } from '@wordpress/i18n';
|
|
2
|
+
import { ActionProps } from '../../../types';
|
|
3
|
+
import { FolderIcon } from '@elementor/icons';
|
|
4
|
+
import { useActiveDocumentActions } from '@elementor/editor-documents';
|
|
5
|
+
|
|
6
|
+
export default function useDocumentSaveTemplateProps(): ActionProps {
|
|
7
|
+
const { saveTemplate } = useActiveDocumentActions();
|
|
8
|
+
|
|
9
|
+
return {
|
|
10
|
+
icon: FolderIcon,
|
|
11
|
+
title: __( 'Save as Template', 'elementor' ),
|
|
12
|
+
onClick: saveTemplate,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { documentOptionsMenu, injectIntoPrimaryAction } from '../../locations';
|
|
2
|
+
import useDocumentSaveDraftProps from './hooks/use-document-save-draft-props';
|
|
3
|
+
import useDocumentSaveTemplateProps from './hooks/use-document-save-template-props';
|
|
4
|
+
import PrimaryAction from './components/primary-action';
|
|
5
|
+
|
|
6
|
+
export function init() {
|
|
7
|
+
injectIntoPrimaryAction( {
|
|
8
|
+
name: 'document-primary-action',
|
|
9
|
+
filler: PrimaryAction,
|
|
10
|
+
} );
|
|
11
|
+
|
|
12
|
+
// Documents options menu.
|
|
13
|
+
documentOptionsMenu.registerAction( {
|
|
14
|
+
group: 'save',
|
|
15
|
+
name: 'document-save-draft',
|
|
16
|
+
priority: 10, // Before save as template.
|
|
17
|
+
useProps: useDocumentSaveDraftProps,
|
|
18
|
+
} );
|
|
19
|
+
|
|
20
|
+
documentOptionsMenu.registerAction( {
|
|
21
|
+
group: 'save',
|
|
22
|
+
name: 'document-save-as-template',
|
|
23
|
+
priority: 20, // After save draft.
|
|
24
|
+
useProps: useDocumentSaveTemplateProps,
|
|
25
|
+
} );
|
|
26
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import useActionProps from '../use-action-props';
|
|
2
|
+
import { renderHook } from '@testing-library/react-hooks';
|
|
3
|
+
import { openRoute, useRouteStatus } from '@elementor/editor-v1-adapters';
|
|
4
|
+
|
|
5
|
+
jest.mock( '@elementor/editor-v1-adapters', () => ( {
|
|
6
|
+
openRoute: jest.fn(),
|
|
7
|
+
useRouteStatus: jest.fn( () => ( { isActive: true, isBlocked: true } ) ),
|
|
8
|
+
} ) );
|
|
9
|
+
|
|
10
|
+
describe( '@elementor/editor-app-bar - useElementsPanelActionProps', () => {
|
|
11
|
+
it( 'should open the elements panel on click', () => {
|
|
12
|
+
// Arrange.
|
|
13
|
+
const { result } = renderHook( () => useActionProps() );
|
|
14
|
+
|
|
15
|
+
// Act.
|
|
16
|
+
result.current.onClick();
|
|
17
|
+
|
|
18
|
+
// Assert.
|
|
19
|
+
expect( openRoute ).toHaveBeenCalledTimes( 1 );
|
|
20
|
+
expect( openRoute ).toHaveBeenCalledWith( 'panel/elements/categories' );
|
|
21
|
+
} );
|
|
22
|
+
|
|
23
|
+
it( 'should have the correct props for disabled and selected', () => {
|
|
24
|
+
// Act.
|
|
25
|
+
const { result } = renderHook( () => useActionProps() );
|
|
26
|
+
|
|
27
|
+
// Assert.
|
|
28
|
+
expect( result.current.selected ).toBe( true );
|
|
29
|
+
expect( result.current.disabled ).toBe( true );
|
|
30
|
+
expect( useRouteStatus ).toHaveBeenCalledTimes( 1 );
|
|
31
|
+
expect( useRouteStatus ).toHaveBeenCalledWith( 'panel/elements' );
|
|
32
|
+
} );
|
|
33
|
+
} );
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { PlusIcon } from '@elementor/icons';
|
|
2
|
+
import { __ } from '@wordpress/i18n';
|
|
3
|
+
import { openRoute, useRouteStatus } from '@elementor/editor-v1-adapters';
|
|
4
|
+
|
|
5
|
+
export default function useActionProps() {
|
|
6
|
+
const { isActive, isBlocked } = useRouteStatus( 'panel/elements' );
|
|
7
|
+
|
|
8
|
+
return {
|
|
9
|
+
title: __( 'Add Element', 'elementor' ),
|
|
10
|
+
icon: PlusIcon,
|
|
11
|
+
onClick: () => openRoute( 'panel/elements/categories' ),
|
|
12
|
+
selected: isActive,
|
|
13
|
+
disabled: isBlocked,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import syncPanelTitle from './sync/sync-panel-title';
|
|
2
|
+
import { toolsMenu } from '../../locations';
|
|
3
|
+
import useActionProps from './hooks/use-action-props';
|
|
4
|
+
|
|
5
|
+
export function init() {
|
|
6
|
+
syncPanelTitle();
|
|
7
|
+
|
|
8
|
+
toolsMenu.registerToggleAction( {
|
|
9
|
+
name: 'open-elements-panel',
|
|
10
|
+
priority: 1,
|
|
11
|
+
useProps: useActionProps,
|
|
12
|
+
} );
|
|
13
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import syncPanelTitle from '../sync-panel-title';
|
|
2
|
+
import { isRouteActive } from '@elementor/editor-v1-adapters';
|
|
3
|
+
|
|
4
|
+
type ExtendedWindow = Window & {
|
|
5
|
+
elementor?: {
|
|
6
|
+
getPanelView: () => {
|
|
7
|
+
getHeaderView: () => {
|
|
8
|
+
setTitle: jest.Mock;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
jest.mock( '@elementor/editor-v1-adapters', () => ( {
|
|
15
|
+
...jest.requireActual( '@elementor/editor-v1-adapters' ),
|
|
16
|
+
isRouteActive: jest.fn().mockReturnValue( false ),
|
|
17
|
+
} ) );
|
|
18
|
+
|
|
19
|
+
const mockIsRouteActive = jest.mocked( isRouteActive );
|
|
20
|
+
|
|
21
|
+
describe( '@elementor/editor-app-bar - syncPanelTitle', () => {
|
|
22
|
+
let mockSetTitle: jest.Mock;
|
|
23
|
+
|
|
24
|
+
beforeEach( () => {
|
|
25
|
+
mockSetTitle = jest.fn();
|
|
26
|
+
|
|
27
|
+
( window as unknown as ExtendedWindow ).elementor = {
|
|
28
|
+
getPanelView: () => ( {
|
|
29
|
+
getHeaderView: () => ( {
|
|
30
|
+
setTitle: mockSetTitle,
|
|
31
|
+
} ),
|
|
32
|
+
} ),
|
|
33
|
+
};
|
|
34
|
+
} );
|
|
35
|
+
|
|
36
|
+
it( 'should change the panel title when opening the elements panel', () => {
|
|
37
|
+
// Arrange.
|
|
38
|
+
syncPanelTitle();
|
|
39
|
+
|
|
40
|
+
// Act.
|
|
41
|
+
window.dispatchEvent( new CustomEvent( 'elementor/routes/open', {
|
|
42
|
+
detail: {
|
|
43
|
+
route: 'panel/elements/categories',
|
|
44
|
+
},
|
|
45
|
+
} ) );
|
|
46
|
+
|
|
47
|
+
// Assert.
|
|
48
|
+
expect( mockSetTitle ).toHaveBeenCalledWith( 'Elements' );
|
|
49
|
+
} );
|
|
50
|
+
|
|
51
|
+
it( 'should change the panel title when V1 is ready and the elements panel is open', () => {
|
|
52
|
+
// Arrange.
|
|
53
|
+
mockIsRouteActive.mockImplementation( ( route ) => route === 'panel/elements' );
|
|
54
|
+
syncPanelTitle();
|
|
55
|
+
|
|
56
|
+
// Act.
|
|
57
|
+
window.dispatchEvent( new CustomEvent( 'elementor/initialized' ) );
|
|
58
|
+
|
|
59
|
+
// Assert.
|
|
60
|
+
expect( mockSetTitle ).toHaveBeenCalledWith( 'Elements' );
|
|
61
|
+
expect( mockIsRouteActive ).toHaveBeenCalledWith( 'panel/elements' );
|
|
62
|
+
} );
|
|
63
|
+
|
|
64
|
+
it( 'should not change the panel title when V1 is ready and the elements panel is not open', () => {
|
|
65
|
+
// Arrange.
|
|
66
|
+
mockIsRouteActive.mockImplementation( ( route ) => route === 'not/the/panel' );
|
|
67
|
+
syncPanelTitle();
|
|
68
|
+
|
|
69
|
+
// Act.
|
|
70
|
+
window.dispatchEvent( new CustomEvent( 'elementor/initialized' ) );
|
|
71
|
+
|
|
72
|
+
// Assert.
|
|
73
|
+
expect( mockSetTitle ).not.toHaveBeenCalled();
|
|
74
|
+
expect( mockIsRouteActive ).toHaveBeenCalledWith( 'panel/elements' );
|
|
75
|
+
} );
|
|
76
|
+
|
|
77
|
+
it( 'should not change the panel title when opening the site settings', () => {
|
|
78
|
+
// Arrange.
|
|
79
|
+
mockIsRouteActive.mockImplementation( ( route ) => route === 'panel/global/menu' );
|
|
80
|
+
syncPanelTitle();
|
|
81
|
+
|
|
82
|
+
// Act.
|
|
83
|
+
window.dispatchEvent( new CustomEvent( 'elementor/routes/open', {
|
|
84
|
+
detail: {
|
|
85
|
+
route: 'panel/global/menu',
|
|
86
|
+
},
|
|
87
|
+
} ) );
|
|
88
|
+
|
|
89
|
+
// Assert.
|
|
90
|
+
expect( mockSetTitle ).not.toHaveBeenCalled();
|
|
91
|
+
} );
|
|
92
|
+
} );
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { __ } from '@wordpress/i18n';
|
|
2
|
+
import { isRouteActive, listenTo, routeOpenEvent, v1ReadyEvent } from '@elementor/editor-v1-adapters';
|
|
3
|
+
|
|
4
|
+
type ExtendedWindow = Window & {
|
|
5
|
+
elementor: {
|
|
6
|
+
getPanelView: () => {
|
|
7
|
+
getHeaderView: () => {
|
|
8
|
+
setTitle: ( title: string ) => void;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export default function syncPanelTitle() {
|
|
15
|
+
const panelTitle = __( 'Elements', 'elementor' );
|
|
16
|
+
const tabTitle = __( 'Widgets', 'elementor' );
|
|
17
|
+
|
|
18
|
+
listenTo(
|
|
19
|
+
routeOpenEvent( 'panel/elements' ),
|
|
20
|
+
() => {
|
|
21
|
+
setPanelTitle( panelTitle );
|
|
22
|
+
setTabTitle( tabTitle );
|
|
23
|
+
}
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
listenTo(
|
|
27
|
+
v1ReadyEvent(),
|
|
28
|
+
() => {
|
|
29
|
+
if ( isRouteActive( 'panel/elements' ) ) {
|
|
30
|
+
setPanelTitle( panelTitle );
|
|
31
|
+
setTabTitle( tabTitle );
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function setPanelTitle( title: string ) {
|
|
38
|
+
( window as unknown as ExtendedWindow ).elementor?.getPanelView?.()?.getHeaderView?.()?.setTitle?.( title );
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function setTabTitle( title: string ) {
|
|
42
|
+
const tab = document.querySelector( '.elementor-component-tab[data-tab="categories"]' );
|
|
43
|
+
|
|
44
|
+
if ( tab ) {
|
|
45
|
+
tab.textContent = title;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import useActionProps from '../use-action-props';
|
|
2
|
+
import { renderHook } from '@testing-library/react-hooks';
|
|
3
|
+
import { runCommand, useRouteStatus } from '@elementor/editor-v1-adapters';
|
|
4
|
+
|
|
5
|
+
jest.mock( '@elementor/editor-v1-adapters', () => ( {
|
|
6
|
+
runCommand: jest.fn(),
|
|
7
|
+
useRouteStatus: jest.fn( () => ( { isActive: true, isBlocked: true } ) ),
|
|
8
|
+
} ) );
|
|
9
|
+
|
|
10
|
+
describe( '@elementor/editor-app-bar - useFinderActionProps', () => {
|
|
11
|
+
it( 'should toggle the finder state on click', () => {
|
|
12
|
+
// Arrange.
|
|
13
|
+
const { result } = renderHook( () => useActionProps() );
|
|
14
|
+
|
|
15
|
+
// Act.
|
|
16
|
+
result.current.onClick();
|
|
17
|
+
|
|
18
|
+
// Assert.
|
|
19
|
+
expect( runCommand ).toHaveBeenCalledTimes( 1 );
|
|
20
|
+
expect( runCommand ).toHaveBeenCalledWith( 'finder/toggle' );
|
|
21
|
+
} );
|
|
22
|
+
|
|
23
|
+
it( 'should have the correct props for disabled and selected', () => {
|
|
24
|
+
// Act.
|
|
25
|
+
const { result } = renderHook( () => useActionProps() );
|
|
26
|
+
|
|
27
|
+
// Assert.
|
|
28
|
+
expect( result.current.selected ).toBe( true );
|
|
29
|
+
expect( result.current.disabled ).toBe( true );
|
|
30
|
+
expect( useRouteStatus ).toHaveBeenCalledTimes( 1 );
|
|
31
|
+
expect( useRouteStatus ).toHaveBeenCalledWith( 'finder', {
|
|
32
|
+
blockOnKitRoutes: false,
|
|
33
|
+
blockOnPreviewMode: false,
|
|
34
|
+
} );
|
|
35
|
+
} );
|
|
36
|
+
} );
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { __ } from '@wordpress/i18n';
|
|
2
|
+
import { SearchIcon } from '@elementor/icons';
|
|
3
|
+
import { runCommand, useRouteStatus } from '@elementor/editor-v1-adapters';
|
|
4
|
+
|
|
5
|
+
export default function useActionProps() {
|
|
6
|
+
const { isActive, isBlocked } = useRouteStatus( 'finder', {
|
|
7
|
+
blockOnKitRoutes: false,
|
|
8
|
+
blockOnPreviewMode: false,
|
|
9
|
+
} );
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
title: __( 'Finder', 'elementor' ),
|
|
13
|
+
icon: SearchIcon,
|
|
14
|
+
onClick: () => runCommand( 'finder/toggle' ),
|
|
15
|
+
selected: isActive,
|
|
16
|
+
disabled: isBlocked,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { utilitiesMenu } from '../../locations';
|
|
2
|
+
import useActionProps from './hooks/use-action-props';
|
|
3
|
+
|
|
4
|
+
export function init() {
|
|
5
|
+
utilitiesMenu.registerToggleAction( {
|
|
6
|
+
name: 'toggle-finder',
|
|
7
|
+
priority: 10, // Before help.
|
|
8
|
+
useProps: useActionProps,
|
|
9
|
+
} );
|
|
10
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { utilitiesMenu } from '../../locations';
|
|
2
|
+
import { __ } from '@wordpress/i18n';
|
|
3
|
+
import { HelpIcon } from '@elementor/icons';
|
|
4
|
+
|
|
5
|
+
export function init() {
|
|
6
|
+
utilitiesMenu.registerLink( {
|
|
7
|
+
name: 'open-help-center',
|
|
8
|
+
priority: 20, // After Finder.
|
|
9
|
+
useProps: () => {
|
|
10
|
+
return {
|
|
11
|
+
title: __( 'Help', 'elementor' ),
|
|
12
|
+
href: 'https://go.elementor.com/editor-top-bar-learn/',
|
|
13
|
+
icon: HelpIcon,
|
|
14
|
+
target: '_blank',
|
|
15
|
+
};
|
|
16
|
+
},
|
|
17
|
+
} );
|
|
18
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import useActionProps from '../use-action-props';
|
|
2
|
+
import { renderHook } from '@testing-library/react-hooks';
|
|
3
|
+
import { openRoute, useRouteStatus } from '@elementor/editor-v1-adapters';
|
|
4
|
+
|
|
5
|
+
jest.mock( '@elementor/editor-v1-adapters', () => ( {
|
|
6
|
+
openRoute: jest.fn(),
|
|
7
|
+
useRouteStatus: jest.fn( () => ( { isActive: true, isBlocked: true } ) ),
|
|
8
|
+
} ) );
|
|
9
|
+
|
|
10
|
+
describe( '@elementor/editor-app-bar - useHistoryActionProps', () => {
|
|
11
|
+
it( 'should open the history panel when clicked', () => {
|
|
12
|
+
// Arrange.
|
|
13
|
+
const { result } = renderHook( () => useActionProps() );
|
|
14
|
+
|
|
15
|
+
// Act.
|
|
16
|
+
result.current.onClick();
|
|
17
|
+
|
|
18
|
+
// Assert.
|
|
19
|
+
expect( openRoute ).toHaveBeenCalledTimes( 1 );
|
|
20
|
+
expect( openRoute ).toHaveBeenCalledWith( 'panel/history/actions' );
|
|
21
|
+
} );
|
|
22
|
+
|
|
23
|
+
it( 'should have the correct props for disabled and selected', () => {
|
|
24
|
+
// Act.
|
|
25
|
+
const { result } = renderHook( () => useActionProps() );
|
|
26
|
+
|
|
27
|
+
// Assert.
|
|
28
|
+
expect( result.current.selected ).toBe( true );
|
|
29
|
+
expect( result.current.disabled ).toBe( true );
|
|
30
|
+
expect( useRouteStatus ).toHaveBeenCalledTimes( 1 );
|
|
31
|
+
expect( useRouteStatus ).toHaveBeenCalledWith( 'panel/history' );
|
|
32
|
+
} );
|
|
33
|
+
} );
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { HistoryIcon } from '@elementor/icons';
|
|
2
|
+
import { __ } from '@wordpress/i18n';
|
|
3
|
+
import { openRoute, useRouteStatus } from '@elementor/editor-v1-adapters';
|
|
4
|
+
|
|
5
|
+
export default function useActionProps() {
|
|
6
|
+
const { isActive, isBlocked } = useRouteStatus( 'panel/history' );
|
|
7
|
+
|
|
8
|
+
return {
|
|
9
|
+
title: __( 'History', 'elementor' ),
|
|
10
|
+
icon: HistoryIcon,
|
|
11
|
+
onClick: () => openRoute( 'panel/history/actions' ),
|
|
12
|
+
selected: isActive,
|
|
13
|
+
disabled: isBlocked,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* All the code in this directory is a temporary solution.
|
|
3
|
+
* The code should be moved to the appropriate packages.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { init as initDocumentsIndicator } from './documents-indicator';
|
|
7
|
+
import { init as initDocumentsPreview } from './documents-preview';
|
|
8
|
+
import { init as initDocumentsSave } from './documents-save';
|
|
9
|
+
import { init as initElements } from './elements';
|
|
10
|
+
import { init as initFinder } from './finder';
|
|
11
|
+
import { init as initHelp } from './help';
|
|
12
|
+
import { init as initHistory } from './history';
|
|
13
|
+
import { init as initKeyboardShortcuts } from './keyboard-shortcuts';
|
|
14
|
+
import { init as initSiteSettings } from './site-settings';
|
|
15
|
+
import { init as initStructure } from './structure';
|
|
16
|
+
import { init as initThemeBuilder } from './theme-builder';
|
|
17
|
+
import { init as initUserPreferences } from './user-preferences';
|
|
18
|
+
import { init as initWordpress } from './wordpress';
|
|
19
|
+
|
|
20
|
+
export function init() {
|
|
21
|
+
initDocumentsIndicator();
|
|
22
|
+
initDocumentsPreview();
|
|
23
|
+
initDocumentsSave();
|
|
24
|
+
initElements();
|
|
25
|
+
initFinder();
|
|
26
|
+
initHelp();
|
|
27
|
+
initHistory();
|
|
28
|
+
initKeyboardShortcuts();
|
|
29
|
+
initSiteSettings();
|
|
30
|
+
initStructure();
|
|
31
|
+
initThemeBuilder();
|
|
32
|
+
initUserPreferences();
|
|
33
|
+
initWordpress();
|
|
34
|
+
}
|