@elementor/editor-responsive 0.10.5 → 0.11.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 +19 -220
- package/dist/index.d.mts +16 -1
- package/dist/index.d.ts +16 -1
- package/dist/index.js +59 -250
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +44 -248
- package/dist/index.mjs.map +1 -1
- package/package.json +40 -44
- package/src/hooks/__tests__/{use-breakpoints-actions.test.tsx → use-activate-breakpoint.test.ts} +6 -9
- package/src/hooks/__tests__/use-active-breakpoint.test.ts +50 -0
- package/src/hooks/__tests__/use-breakpoints.test.ts +90 -0
- package/src/hooks/use-activate-breakpoint.ts +9 -0
- package/src/hooks/use-active-breakpoint.ts +12 -0
- package/src/hooks/use-breakpoints.ts +46 -8
- package/src/index.ts +4 -2
- package/src/types.ts +27 -35
- package/src/components/__tests__/breakpoints-switcher.test.tsx +0 -121
- package/src/components/breakpoints-switcher.tsx +0 -112
- package/src/hooks/__tests__/use-breakpoints.test.tsx +0 -75
- package/src/hooks/use-breakpoints-actions.ts +0 -13
- package/src/init.ts +0 -27
- package/src/store/index.ts +0 -40
- package/src/store/selectors.ts +0 -38
- package/src/sync/__tests__/sync-store.test.ts +0 -158
- package/src/sync/sync-store.ts +0 -75
|
@@ -1,12 +1,50 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { __ } from '@wordpress/i18n';
|
|
2
|
+
import { Breakpoint, BreakpointId, ExtendedWindow } from '../types';
|
|
3
|
+
import { v1ReadyEvent, __privateUseListenTo as useListenTo } from '@elementor/editor-v1-adapters';
|
|
3
4
|
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
export function useBreakpoints() {
|
|
6
|
+
return useListenTo( v1ReadyEvent(), getBreakpoints );
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function getBreakpoints() {
|
|
10
|
+
const { breakpoints } = ( window as unknown as ExtendedWindow ).elementor?.config?.responsive || {};
|
|
11
|
+
|
|
12
|
+
if ( ! breakpoints || Object.entries( breakpoints ).length === 0 ) {
|
|
13
|
+
return [];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const minWidth: Breakpoint[] = [];
|
|
17
|
+
const maxWidth: Breakpoint[] = [];
|
|
18
|
+
|
|
19
|
+
const defaults: Breakpoint[] = [
|
|
20
|
+
// Desktop breakpoint is not included in V1 config.
|
|
21
|
+
{ id: 'desktop', label: __( 'Desktop', 'elementor' ) },
|
|
22
|
+
];
|
|
7
23
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
24
|
+
Object.entries( breakpoints ).forEach( ( [ id, v1Breakpoint ] ) => {
|
|
25
|
+
if ( ! v1Breakpoint.is_enabled ) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const breakpoint: Breakpoint = {
|
|
30
|
+
id: id as BreakpointId,
|
|
31
|
+
label: v1Breakpoint.label,
|
|
32
|
+
width: v1Breakpoint.value,
|
|
33
|
+
type: v1Breakpoint.direction === 'min' ? 'min-width' : 'max-width',
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
if ( ! breakpoint.width ) {
|
|
37
|
+
defaults.push( breakpoint );
|
|
38
|
+
} else if ( breakpoint.type === 'min-width' ) {
|
|
39
|
+
minWidth.push( breakpoint );
|
|
40
|
+
} else if ( breakpoint.type === 'max-width' ) {
|
|
41
|
+
maxWidth.push( breakpoint );
|
|
42
|
+
}
|
|
43
|
+
} );
|
|
44
|
+
|
|
45
|
+
const byWidth = ( a: Breakpoint, b: Breakpoint ) => {
|
|
46
|
+
return a.width && b.width ? b.width - a.width : 0;
|
|
11
47
|
};
|
|
48
|
+
|
|
49
|
+
return [ ...minWidth.sort( byWidth ), ...defaults, ...maxWidth.sort( byWidth ) ];
|
|
12
50
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
export { useBreakpoints } from './hooks/use-breakpoints';
|
|
2
|
+
export { useActiveBreakpoint } from './hooks/use-active-breakpoint';
|
|
3
|
+
export { useActivateBreakpoint } from './hooks/use-activate-breakpoint';
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
export type { BreakpointId, BreakpointSize, Breakpoint } from './types';
|
package/src/types.ts
CHANGED
|
@@ -5,40 +5,32 @@ export type BreakpointSize = number;
|
|
|
5
5
|
export type BreakpointLabel = string;
|
|
6
6
|
|
|
7
7
|
export type Breakpoint = {
|
|
8
|
-
id: BreakpointId
|
|
9
|
-
label: BreakpointLabel
|
|
10
|
-
width?: BreakpointSize
|
|
11
|
-
type?: 'min-width' | 'max-width'
|
|
12
|
-
}
|
|
8
|
+
id: BreakpointId;
|
|
9
|
+
label: BreakpointLabel;
|
|
10
|
+
width?: BreakpointSize;
|
|
11
|
+
type?: 'min-width' | 'max-width';
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export type V1Breakpoint = {
|
|
15
|
+
direction: 'min' | 'max';
|
|
16
|
+
is_enabled: boolean;
|
|
17
|
+
value: BreakpointSize;
|
|
18
|
+
label: BreakpointLabel;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export type V1Breakpoints = Record< Exclude< BreakpointId, 'desktop' >, V1Breakpoint >;
|
|
13
22
|
|
|
14
23
|
export type ExtendedWindow = Window & {
|
|
15
|
-
elementor
|
|
16
|
-
config
|
|
17
|
-
responsive
|
|
18
|
-
breakpoints
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
request: ( request: 'currentMode' ) => BreakpointId,
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
editorEvents: {
|
|
32
|
-
dispatchEvent: ( name: string, data: Record<string, string> ) => void
|
|
33
|
-
config: {
|
|
34
|
-
locations: Record<string, string>,
|
|
35
|
-
secondaryLocations: Record<string, string>,
|
|
36
|
-
triggers: Record<string, string>,
|
|
37
|
-
elements: Record<string, string>
|
|
38
|
-
names: {
|
|
39
|
-
topBar: Record<string, string>
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
24
|
+
elementor?: {
|
|
25
|
+
config?: {
|
|
26
|
+
responsive?: {
|
|
27
|
+
breakpoints?: V1Breakpoints;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
channels?: {
|
|
31
|
+
deviceMode?: {
|
|
32
|
+
request?: ( request: 'currentMode' ) => BreakpointId;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
};
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
import { Breakpoint } from '../../types';
|
|
3
|
-
import { fireEvent, render, screen } from '@testing-library/react';
|
|
4
|
-
import useBreakpoints from '../../hooks/use-breakpoints';
|
|
5
|
-
import BreakpointsSwitcher from '../breakpoints-switcher';
|
|
6
|
-
import useBreakpointsActions from '../../hooks/use-breakpoints-actions';
|
|
7
|
-
|
|
8
|
-
jest.mock( '../../hooks/use-breakpoints', () => jest.fn() );
|
|
9
|
-
jest.mock( '../../hooks/use-breakpoints-actions', () => jest.fn().mockReturnValue( {
|
|
10
|
-
activate: jest.fn(),
|
|
11
|
-
} ) );
|
|
12
|
-
|
|
13
|
-
describe( '@elementor/editor-responsive - Breakpoints Switcher', () => {
|
|
14
|
-
it( 'should not render when there are no breakpoints', () => {
|
|
15
|
-
// Arrange.
|
|
16
|
-
jest.mocked( useBreakpoints ).mockReturnValue( {
|
|
17
|
-
all: [],
|
|
18
|
-
active: {
|
|
19
|
-
id: 'desktop',
|
|
20
|
-
label: 'Desktop',
|
|
21
|
-
},
|
|
22
|
-
} );
|
|
23
|
-
|
|
24
|
-
// Act.
|
|
25
|
-
const { container } = render( <BreakpointsSwitcher /> );
|
|
26
|
-
|
|
27
|
-
// Assert.
|
|
28
|
-
expect( container ).toBeEmptyDOMElement();
|
|
29
|
-
} );
|
|
30
|
-
|
|
31
|
-
it( 'should not render when there is no active breakpoint', () => {
|
|
32
|
-
// Arrange.
|
|
33
|
-
jest.mocked( useBreakpoints ).mockReturnValue( {
|
|
34
|
-
active: null,
|
|
35
|
-
all: [ {
|
|
36
|
-
id: 'desktop',
|
|
37
|
-
label: 'Desktop',
|
|
38
|
-
} ],
|
|
39
|
-
} );
|
|
40
|
-
|
|
41
|
-
// Act.
|
|
42
|
-
const { container } = render( <BreakpointsSwitcher /> );
|
|
43
|
-
|
|
44
|
-
// Assert.
|
|
45
|
-
expect( container ).toBeEmptyDOMElement();
|
|
46
|
-
} );
|
|
47
|
-
|
|
48
|
-
it( 'should render all of the breakpoints', () => {
|
|
49
|
-
// Arrange.
|
|
50
|
-
const sortedBreakpoints: Breakpoint[] = [
|
|
51
|
-
{ id: 'widescreen', label: 'Widescreen', width: 2400, type: 'min-width' },
|
|
52
|
-
{ id: 'desktop', label: 'Desktop' },
|
|
53
|
-
{ id: 'laptop', label: 'Laptop', width: 1366, type: 'max-width' },
|
|
54
|
-
{ id: 'tablet_extra', label: 'Tablet Landscape', width: 1200, type: 'max-width' },
|
|
55
|
-
{ id: 'tablet', label: 'Tablet Portrait', width: 1024, type: 'max-width' },
|
|
56
|
-
{ id: 'mobile_extra', label: 'Mobile Landscape', width: 880, type: 'max-width' },
|
|
57
|
-
{ id: 'mobile', label: 'Mobile Portrait', width: 767, type: 'max-width' },
|
|
58
|
-
];
|
|
59
|
-
|
|
60
|
-
jest.mocked( useBreakpoints ).mockReturnValue( {
|
|
61
|
-
all: sortedBreakpoints,
|
|
62
|
-
active: { id: 'desktop', label: 'Desktop' },
|
|
63
|
-
} );
|
|
64
|
-
|
|
65
|
-
// Act.
|
|
66
|
-
render( <BreakpointsSwitcher /> );
|
|
67
|
-
|
|
68
|
-
// Assert.
|
|
69
|
-
const tabs = screen.getAllByRole( 'tab' );
|
|
70
|
-
const expectedLabels = [
|
|
71
|
-
'Widescreen (2400px and up)',
|
|
72
|
-
'Desktop',
|
|
73
|
-
'Laptop (up to 1366px)',
|
|
74
|
-
'Tablet Landscape (up to 1200px)',
|
|
75
|
-
'Tablet Portrait (up to 1024px)',
|
|
76
|
-
'Mobile Landscape (up to 880px)',
|
|
77
|
-
'Mobile Portrait (up to 767px)',
|
|
78
|
-
];
|
|
79
|
-
|
|
80
|
-
expect( tabs ).toHaveLength( 7 );
|
|
81
|
-
|
|
82
|
-
tabs.forEach( ( tab, index ) => {
|
|
83
|
-
expect( tab ).toHaveAttribute( 'aria-label', expectedLabels[ index ] );
|
|
84
|
-
} );
|
|
85
|
-
|
|
86
|
-
// Desktop should be active.
|
|
87
|
-
expect( tabs[ 1 ] ).toHaveAttribute( 'aria-selected', 'true' );
|
|
88
|
-
} );
|
|
89
|
-
|
|
90
|
-
it( 'should activate a breakpoint on click', () => {
|
|
91
|
-
// Arrange.
|
|
92
|
-
const activate = jest.fn();
|
|
93
|
-
|
|
94
|
-
jest.mocked( useBreakpointsActions ).mockReturnValue( {
|
|
95
|
-
activate,
|
|
96
|
-
} );
|
|
97
|
-
|
|
98
|
-
jest.mocked( useBreakpoints ).mockReturnValue( {
|
|
99
|
-
active: {
|
|
100
|
-
id: 'desktop',
|
|
101
|
-
label: 'Desktop',
|
|
102
|
-
},
|
|
103
|
-
all: [
|
|
104
|
-
{ id: 'mobile', label: 'Mobile Portrait' },
|
|
105
|
-
{ id: 'desktop', label: 'Desktop' },
|
|
106
|
-
],
|
|
107
|
-
} );
|
|
108
|
-
|
|
109
|
-
// Act.
|
|
110
|
-
render( <BreakpointsSwitcher /> );
|
|
111
|
-
|
|
112
|
-
const mobileTab = screen.getByLabelText( 'Mobile Portrait', {
|
|
113
|
-
selector: 'button',
|
|
114
|
-
} );
|
|
115
|
-
|
|
116
|
-
fireEvent.click( mobileTab );
|
|
117
|
-
|
|
118
|
-
// Assert.
|
|
119
|
-
expect( activate ).toHaveBeenCalledWith( 'mobile' );
|
|
120
|
-
} );
|
|
121
|
-
} );
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
import { __ } from '@wordpress/i18n';
|
|
3
|
-
import { BreakpointId, ExtendedWindow } from '../types';
|
|
4
|
-
import useBreakpoints from '../hooks/use-breakpoints';
|
|
5
|
-
import { Tab, Tabs, Tooltip as BaseTooltip, TooltipProps } from '@elementor/ui';
|
|
6
|
-
import {
|
|
7
|
-
DesktopIcon,
|
|
8
|
-
TabletPortraitIcon,
|
|
9
|
-
MobilePortraitIcon,
|
|
10
|
-
WidescreenIcon,
|
|
11
|
-
LaptopIcon,
|
|
12
|
-
TabletLandscapeIcon,
|
|
13
|
-
MobileLandscapeIcon,
|
|
14
|
-
} from '@elementor/icons';
|
|
15
|
-
import useBreakpointsActions from '../hooks/use-breakpoints-actions';
|
|
16
|
-
|
|
17
|
-
export default function BreakpointsSwitcher() {
|
|
18
|
-
const { all, active } = useBreakpoints();
|
|
19
|
-
const { activate } = useBreakpointsActions();
|
|
20
|
-
|
|
21
|
-
if ( ! all.length || ! active ) {
|
|
22
|
-
return null;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const onChange = ( _: unknown, value: BreakpointId ) => {
|
|
26
|
-
const extendedWindow = window as unknown as ExtendedWindow;
|
|
27
|
-
const config = extendedWindow?.elementor?.editorEvents?.config;
|
|
28
|
-
|
|
29
|
-
if ( config ) {
|
|
30
|
-
extendedWindow.elementor.editorEvents.dispatchEvent(
|
|
31
|
-
config.names.topBar.responsiveControls,
|
|
32
|
-
{
|
|
33
|
-
location: config.locations.topBar,
|
|
34
|
-
secondaryLocation: config.secondaryLocations.responsiveControls,
|
|
35
|
-
trigger: config.triggers.click,
|
|
36
|
-
element: config.elements.buttonIcon,
|
|
37
|
-
mode: value,
|
|
38
|
-
},
|
|
39
|
-
);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
activate( value );
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
return (
|
|
46
|
-
<Tabs
|
|
47
|
-
textColor="inherit"
|
|
48
|
-
indicatorColor="secondary"
|
|
49
|
-
value={ active.id }
|
|
50
|
-
onChange={ onChange }
|
|
51
|
-
aria-label={ __( 'Switch Device', 'elementor' ) }
|
|
52
|
-
sx={ {
|
|
53
|
-
'& .MuiTabs-indicator': {
|
|
54
|
-
backgroundColor: 'text.primary',
|
|
55
|
-
},
|
|
56
|
-
} }
|
|
57
|
-
>
|
|
58
|
-
{
|
|
59
|
-
all.map( ( { id, label, type, width } ) => {
|
|
60
|
-
const Icon = iconsMap[ id ];
|
|
61
|
-
|
|
62
|
-
const title = labelsMap[ type || 'default' ]
|
|
63
|
-
.replace( '%s', label )
|
|
64
|
-
.replace( '%d', width?.toString() || '' );
|
|
65
|
-
|
|
66
|
-
return (
|
|
67
|
-
<Tab value={ id }
|
|
68
|
-
key={ id }
|
|
69
|
-
aria-label={ title }
|
|
70
|
-
icon={ <Tooltip title={ title }><Icon /></Tooltip> }
|
|
71
|
-
sx={ { minWidth: 'auto' } }
|
|
72
|
-
data-testid={ `switch-device-to-${ id }` }
|
|
73
|
-
/>
|
|
74
|
-
);
|
|
75
|
-
} )
|
|
76
|
-
}
|
|
77
|
-
</Tabs>
|
|
78
|
-
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function Tooltip( props: TooltipProps ) {
|
|
83
|
-
return <BaseTooltip
|
|
84
|
-
PopperProps={ {
|
|
85
|
-
sx: {
|
|
86
|
-
'&.MuiTooltip-popper .MuiTooltip-tooltip.MuiTooltip-tooltipPlacementBottom': {
|
|
87
|
-
mt: 2.5,
|
|
88
|
-
},
|
|
89
|
-
},
|
|
90
|
-
} }
|
|
91
|
-
{ ...props }
|
|
92
|
-
/>;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const iconsMap = {
|
|
96
|
-
widescreen: WidescreenIcon,
|
|
97
|
-
desktop: DesktopIcon,
|
|
98
|
-
laptop: LaptopIcon,
|
|
99
|
-
tablet_extra: TabletLandscapeIcon,
|
|
100
|
-
tablet: TabletPortraitIcon,
|
|
101
|
-
mobile_extra: MobileLandscapeIcon,
|
|
102
|
-
mobile: MobilePortraitIcon,
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
const labelsMap = {
|
|
106
|
-
default: '%s',
|
|
107
|
-
// translators: %s: Breakpoint label, %d: Breakpoint size.
|
|
108
|
-
'min-width': __( '%s (%dpx and up)', 'elementor' ),
|
|
109
|
-
|
|
110
|
-
// translators: %s: Breakpoint label, %d: Breakpoint size.
|
|
111
|
-
'max-width': __( '%s (up to %dpx)', 'elementor' ),
|
|
112
|
-
} as const;
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
import { PropsWithChildren } from 'react';
|
|
3
|
-
import { slice } from '../../store';
|
|
4
|
-
import useBreakpoints from '../use-breakpoints';
|
|
5
|
-
import { renderHook } from '@testing-library/react';
|
|
6
|
-
import { __createStore, __dispatch, __registerSlice, SliceState, Store, __StoreProvider as StoreProvider } from '@elementor/store';
|
|
7
|
-
|
|
8
|
-
jest.mock( '@elementor/editor-v1-adapters', () => ( {
|
|
9
|
-
__privateRunCommand: jest.fn(),
|
|
10
|
-
} ) );
|
|
11
|
-
|
|
12
|
-
describe( '@elementor/editor-responsive - useBreakpoints', () => {
|
|
13
|
-
let store: Store<SliceState<typeof slice>>;
|
|
14
|
-
|
|
15
|
-
beforeEach( () => {
|
|
16
|
-
__registerSlice( slice );
|
|
17
|
-
store = __createStore();
|
|
18
|
-
} );
|
|
19
|
-
|
|
20
|
-
it( 'should return all breakpoints sorted by size', () => {
|
|
21
|
-
// Arrange.
|
|
22
|
-
__dispatch( slice.actions.init( {
|
|
23
|
-
activeId: null,
|
|
24
|
-
entities: [
|
|
25
|
-
{ id: 'tablet', label: 'Tablet Portrait', width: 1024, type: 'max-width' },
|
|
26
|
-
{ id: 'mobile', label: 'Mobile Portrait', width: 767, type: 'max-width' },
|
|
27
|
-
{ id: 'widescreen', label: 'Widescreen', width: 2400, type: 'min-width' },
|
|
28
|
-
{ id: 'desktop', label: 'Desktop' },
|
|
29
|
-
],
|
|
30
|
-
} ) );
|
|
31
|
-
|
|
32
|
-
// Act.
|
|
33
|
-
const { result } = renderHookWithStore( () => useBreakpoints(), store );
|
|
34
|
-
|
|
35
|
-
// Assert.
|
|
36
|
-
expect( result.current.all ).toEqual( [
|
|
37
|
-
{ id: 'widescreen', label: 'Widescreen', width: 2400, type: 'min-width' },
|
|
38
|
-
{ id: 'desktop', label: 'Desktop' },
|
|
39
|
-
{ id: 'tablet', label: 'Tablet Portrait', width: 1024, type: 'max-width' },
|
|
40
|
-
{ id: 'mobile', label: 'Mobile Portrait', width: 767, type: 'max-width' },
|
|
41
|
-
] );
|
|
42
|
-
} );
|
|
43
|
-
|
|
44
|
-
it( 'should return the active breakpoint', () => {
|
|
45
|
-
// Arrange.
|
|
46
|
-
__dispatch( slice.actions.init( {
|
|
47
|
-
activeId: 'tablet',
|
|
48
|
-
entities: [
|
|
49
|
-
{ id: 'desktop', label: 'Desktop' },
|
|
50
|
-
{ id: 'tablet', label: 'Tablet Portrait', type: 'max-width', width: 1024 },
|
|
51
|
-
],
|
|
52
|
-
} ) );
|
|
53
|
-
|
|
54
|
-
// Act.
|
|
55
|
-
const { result } = renderHookWithStore( () => useBreakpoints(), store );
|
|
56
|
-
|
|
57
|
-
// Assert.
|
|
58
|
-
expect( result.current.active ).toEqual( {
|
|
59
|
-
id: 'tablet',
|
|
60
|
-
label: 'Tablet Portrait',
|
|
61
|
-
type: 'max-width',
|
|
62
|
-
width: 1024,
|
|
63
|
-
} );
|
|
64
|
-
} );
|
|
65
|
-
} );
|
|
66
|
-
|
|
67
|
-
function renderHookWithStore<T>( hook: () => T, store: Store ) {
|
|
68
|
-
const wrapper = ( { children }: PropsWithChildren<unknown> ) => (
|
|
69
|
-
<StoreProvider store={ store }>
|
|
70
|
-
{ children }
|
|
71
|
-
</StoreProvider>
|
|
72
|
-
);
|
|
73
|
-
|
|
74
|
-
return renderHook( hook, { wrapper } );
|
|
75
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { useCallback } from 'react';
|
|
2
|
-
import { BreakpointId } from '../types';
|
|
3
|
-
import { __privateRunCommand as runCommand } from '@elementor/editor-v1-adapters';
|
|
4
|
-
|
|
5
|
-
export default function useBreakpointsActions() {
|
|
6
|
-
const activate = useCallback( ( device: BreakpointId ) => {
|
|
7
|
-
return runCommand( 'panel/change-device-mode', { device } );
|
|
8
|
-
}, [] );
|
|
9
|
-
|
|
10
|
-
return {
|
|
11
|
-
activate,
|
|
12
|
-
};
|
|
13
|
-
}
|
package/src/init.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { slice } from './store';
|
|
2
|
-
import syncStore from './sync/sync-store';
|
|
3
|
-
import { injectIntoResponsive } from '@elementor/editor-app-bar';
|
|
4
|
-
import BreakpointsSwitcher from './components/breakpoints-switcher';
|
|
5
|
-
import { __registerSlice } from '@elementor/store';
|
|
6
|
-
|
|
7
|
-
export default function init() {
|
|
8
|
-
initStore();
|
|
9
|
-
|
|
10
|
-
registerAppBarUI();
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function initStore() {
|
|
14
|
-
__registerSlice( slice );
|
|
15
|
-
|
|
16
|
-
syncStore();
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function registerAppBarUI() {
|
|
20
|
-
injectIntoResponsive( {
|
|
21
|
-
id: 'responsive-breakpoints-switcher',
|
|
22
|
-
component: BreakpointsSwitcher,
|
|
23
|
-
options: {
|
|
24
|
-
priority: 20, // After document indication.
|
|
25
|
-
},
|
|
26
|
-
} );
|
|
27
|
-
}
|
package/src/store/index.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { __createSlice, PayloadAction } from '@elementor/store';
|
|
2
|
-
import { Breakpoint, BreakpointId } from '../types';
|
|
3
|
-
|
|
4
|
-
export type State = {
|
|
5
|
-
entities: Record<BreakpointId, Breakpoint>,
|
|
6
|
-
activeId: BreakpointId | null,
|
|
7
|
-
}
|
|
8
|
-
const initialState: State = {
|
|
9
|
-
entities: {} as State['entities'],
|
|
10
|
-
activeId: null,
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
export const slice = __createSlice( {
|
|
14
|
-
name: 'breakpoints',
|
|
15
|
-
initialState,
|
|
16
|
-
reducers: {
|
|
17
|
-
init( state, action: PayloadAction<{
|
|
18
|
-
entities: Breakpoint[],
|
|
19
|
-
activeId: State['activeId'],
|
|
20
|
-
}> ) {
|
|
21
|
-
state.activeId = action.payload.activeId;
|
|
22
|
-
state.entities = normalizeEntities( action.payload.entities );
|
|
23
|
-
},
|
|
24
|
-
|
|
25
|
-
activateBreakpoint( state, action: PayloadAction<BreakpointId> ) {
|
|
26
|
-
if ( state.entities[ action.payload ] ) {
|
|
27
|
-
state.activeId = action.payload;
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
},
|
|
31
|
-
} );
|
|
32
|
-
|
|
33
|
-
function normalizeEntities( entities: Breakpoint[] ) {
|
|
34
|
-
return entities.reduce( ( acc, breakpoint ) => {
|
|
35
|
-
return {
|
|
36
|
-
...acc,
|
|
37
|
-
[ breakpoint.id ]: breakpoint,
|
|
38
|
-
};
|
|
39
|
-
}, {} as State['entities'] );
|
|
40
|
-
}
|
package/src/store/selectors.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { slice } from './index';
|
|
2
|
-
import { Breakpoint } from '../types';
|
|
3
|
-
import { __createSelector, SliceState } from '@elementor/store';
|
|
4
|
-
|
|
5
|
-
type State = SliceState<typeof slice>;
|
|
6
|
-
|
|
7
|
-
export const selectEntities = ( state: State ) => state.breakpoints.entities;
|
|
8
|
-
export const selectActiveId = ( state: State ) => state.breakpoints.activeId;
|
|
9
|
-
|
|
10
|
-
export const selectActiveBreakpoint = __createSelector(
|
|
11
|
-
selectEntities,
|
|
12
|
-
selectActiveId,
|
|
13
|
-
( entities, activeId ) => activeId && entities[ activeId ]
|
|
14
|
-
? entities[ activeId ]
|
|
15
|
-
: null,
|
|
16
|
-
);
|
|
17
|
-
|
|
18
|
-
export const selectSortedBreakpoints = __createSelector(
|
|
19
|
-
selectEntities,
|
|
20
|
-
( entities ) => {
|
|
21
|
-
const byWidth = ( a: Breakpoint, b: Breakpoint ) => {
|
|
22
|
-
return ( a.width && b.width ) ? b.width - a.width : 0;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
const all = Object.values( entities );
|
|
26
|
-
|
|
27
|
-
const defaults = all.filter( ( breakpoint ) => ! breakpoint.width ); // AKA Desktop.
|
|
28
|
-
const minWidth = all.filter( ( breakpoint ) => breakpoint.type === 'min-width' );
|
|
29
|
-
const maxWidth = all.filter( ( breakpoint ) => breakpoint.type === 'max-width' );
|
|
30
|
-
|
|
31
|
-
// Sort by size, big to small.
|
|
32
|
-
return [
|
|
33
|
-
...minWidth.sort( byWidth ),
|
|
34
|
-
...defaults,
|
|
35
|
-
...maxWidth.sort( byWidth ),
|
|
36
|
-
];
|
|
37
|
-
},
|
|
38
|
-
);
|