@elementor/editor-responsive 0.10.6 → 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 +6 -0
- package/dist/index.d.mts +16 -1
- package/dist/index.d.ts +16 -1
- package/dist/index.js +57 -237
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +43 -236
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -7
- package/src/hooks/__tests__/{use-breakpoints-actions.test.tsx → use-activate-breakpoint.test.ts} +5 -5
- 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 +16 -27
- package/src/components/__tests__/breakpoints-switcher.test.tsx +0 -125
- package/src/components/breakpoints-switcher.tsx +0 -113
- package/src/hooks/__tests__/use-breakpoints.test.tsx +0 -84
- package/src/hooks/use-breakpoints-actions.ts +0 -13
- package/src/init.ts +0 -27
- package/src/store/index.ts +0 -46
- package/src/store/selectors.ts +0 -27
- package/src/sync/__tests__/sync-store.test.ts +0 -162
- package/src/sync/sync-store.ts +0 -70
package/dist/index.mjs
CHANGED
|
@@ -1,258 +1,65 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
import { __createSlice } from "@elementor/store";
|
|
3
|
-
var initialState = {
|
|
4
|
-
entities: {},
|
|
5
|
-
activeId: null
|
|
6
|
-
};
|
|
7
|
-
var slice = __createSlice({
|
|
8
|
-
name: "breakpoints",
|
|
9
|
-
initialState,
|
|
10
|
-
reducers: {
|
|
11
|
-
init(state, action) {
|
|
12
|
-
state.activeId = action.payload.activeId;
|
|
13
|
-
state.entities = normalizeEntities(action.payload.entities);
|
|
14
|
-
},
|
|
15
|
-
activateBreakpoint(state, action) {
|
|
16
|
-
if (state.entities[action.payload]) {
|
|
17
|
-
state.activeId = action.payload;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
});
|
|
22
|
-
function normalizeEntities(entities) {
|
|
23
|
-
return entities.reduce(
|
|
24
|
-
(acc, breakpoint) => {
|
|
25
|
-
return {
|
|
26
|
-
...acc,
|
|
27
|
-
[breakpoint.id]: breakpoint
|
|
28
|
-
};
|
|
29
|
-
},
|
|
30
|
-
{}
|
|
31
|
-
);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// src/sync/sync-store.ts
|
|
35
|
-
import { __dispatch } from "@elementor/store";
|
|
36
|
-
import { __privateListenTo as listenTo, v1ReadyEvent, windowEvent } from "@elementor/editor-v1-adapters";
|
|
1
|
+
// src/hooks/use-breakpoints.ts
|
|
37
2
|
import { __ } from "@wordpress/i18n";
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
function syncInitialization() {
|
|
43
|
-
const { init: init2 } = slice.actions;
|
|
44
|
-
listenTo(v1ReadyEvent(), () => {
|
|
45
|
-
__dispatch(
|
|
46
|
-
init2({
|
|
47
|
-
entities: getBreakpoints(),
|
|
48
|
-
activeId: getActiveBreakpoint()
|
|
49
|
-
})
|
|
50
|
-
);
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
function syncOnChange() {
|
|
54
|
-
const { activateBreakpoint } = slice.actions;
|
|
55
|
-
listenTo(deviceModeChangeEvent(), () => {
|
|
56
|
-
const activeBreakpoint = getActiveBreakpoint();
|
|
57
|
-
__dispatch(activateBreakpoint(activeBreakpoint));
|
|
58
|
-
});
|
|
3
|
+
import { v1ReadyEvent, __privateUseListenTo as useListenTo } from "@elementor/editor-v1-adapters";
|
|
4
|
+
function useBreakpoints() {
|
|
5
|
+
return useListenTo(v1ReadyEvent(), getBreakpoints);
|
|
59
6
|
}
|
|
60
7
|
function getBreakpoints() {
|
|
61
8
|
const { breakpoints } = window.elementor?.config?.responsive || {};
|
|
62
|
-
if (!breakpoints) {
|
|
9
|
+
if (!breakpoints || Object.entries(breakpoints).length === 0) {
|
|
63
10
|
return [];
|
|
64
11
|
}
|
|
65
|
-
const
|
|
66
|
-
|
|
12
|
+
const minWidth = [];
|
|
13
|
+
const maxWidth = [];
|
|
14
|
+
const defaults = [
|
|
15
|
+
// Desktop breakpoint is not included in V1 config.
|
|
16
|
+
{ id: "desktop", label: __("Desktop", "elementor") }
|
|
17
|
+
];
|
|
18
|
+
Object.entries(breakpoints).forEach(([id, v1Breakpoint]) => {
|
|
19
|
+
if (!v1Breakpoint.is_enabled) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const breakpoint = {
|
|
67
23
|
id,
|
|
68
|
-
label,
|
|
69
|
-
width: value,
|
|
70
|
-
type: direction === "min" ? "min-width" : "max-width"
|
|
24
|
+
label: v1Breakpoint.label,
|
|
25
|
+
width: v1Breakpoint.value,
|
|
26
|
+
type: v1Breakpoint.direction === "min" ? "min-width" : "max-width"
|
|
71
27
|
};
|
|
28
|
+
if (!breakpoint.width) {
|
|
29
|
+
defaults.push(breakpoint);
|
|
30
|
+
} else if (breakpoint.type === "min-width") {
|
|
31
|
+
minWidth.push(breakpoint);
|
|
32
|
+
} else if (breakpoint.type === "max-width") {
|
|
33
|
+
maxWidth.push(breakpoint);
|
|
34
|
+
}
|
|
72
35
|
});
|
|
73
|
-
entities.push({
|
|
74
|
-
id: "desktop",
|
|
75
|
-
label: __("Desktop", "elementor")
|
|
76
|
-
});
|
|
77
|
-
return entities;
|
|
78
|
-
}
|
|
79
|
-
function getActiveBreakpoint() {
|
|
80
|
-
const extendedWindow = window;
|
|
81
|
-
return extendedWindow.elementor?.channels?.deviceMode?.request?.("currentMode") || null;
|
|
82
|
-
}
|
|
83
|
-
function deviceModeChangeEvent() {
|
|
84
|
-
return windowEvent("elementor/device-mode/change");
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// src/init.ts
|
|
88
|
-
import { injectIntoResponsive } from "@elementor/editor-app-bar";
|
|
89
|
-
|
|
90
|
-
// src/components/breakpoints-switcher.tsx
|
|
91
|
-
import * as React from "react";
|
|
92
|
-
import { __ as __2 } from "@wordpress/i18n";
|
|
93
|
-
|
|
94
|
-
// src/hooks/use-breakpoints.ts
|
|
95
|
-
import { __useSelector as useSelector } from "@elementor/store";
|
|
96
|
-
|
|
97
|
-
// src/store/selectors.ts
|
|
98
|
-
import { __createSelector } from "@elementor/store";
|
|
99
|
-
var selectEntities = (state) => state.breakpoints.entities;
|
|
100
|
-
var selectActiveId = (state) => state.breakpoints.activeId;
|
|
101
|
-
var selectActiveBreakpoint = __createSelector(
|
|
102
|
-
selectEntities,
|
|
103
|
-
selectActiveId,
|
|
104
|
-
(entities, activeId) => activeId && entities[activeId] ? entities[activeId] : null
|
|
105
|
-
);
|
|
106
|
-
var selectSortedBreakpoints = __createSelector(selectEntities, (entities) => {
|
|
107
36
|
const byWidth = (a, b) => {
|
|
108
37
|
return a.width && b.width ? b.width - a.width : 0;
|
|
109
38
|
};
|
|
110
|
-
const all = Object.values(entities);
|
|
111
|
-
const defaults = all.filter((breakpoint) => !breakpoint.width);
|
|
112
|
-
const minWidth = all.filter((breakpoint) => breakpoint.type === "min-width");
|
|
113
|
-
const maxWidth = all.filter((breakpoint) => breakpoint.type === "max-width");
|
|
114
39
|
return [...minWidth.sort(byWidth), ...defaults, ...maxWidth.sort(byWidth)];
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
// src/hooks/use-breakpoints.ts
|
|
118
|
-
function useBreakpoints() {
|
|
119
|
-
const all = useSelector(selectSortedBreakpoints);
|
|
120
|
-
const active = useSelector(selectActiveBreakpoint);
|
|
121
|
-
return {
|
|
122
|
-
all,
|
|
123
|
-
active
|
|
124
|
-
};
|
|
125
40
|
}
|
|
126
41
|
|
|
127
|
-
// src/
|
|
128
|
-
import {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
MobileLandscapeIcon
|
|
137
|
-
} from "@elementor/icons";
|
|
42
|
+
// src/hooks/use-active-breakpoint.ts
|
|
43
|
+
import { __privateUseListenTo as useListenTo2, windowEvent } from "@elementor/editor-v1-adapters";
|
|
44
|
+
function useActiveBreakpoint() {
|
|
45
|
+
return useListenTo2(windowEvent("elementor/device-mode/change"), getActiveBreakpoint);
|
|
46
|
+
}
|
|
47
|
+
function getActiveBreakpoint() {
|
|
48
|
+
const extendedWindow = window;
|
|
49
|
+
return extendedWindow.elementor?.channels?.deviceMode?.request?.("currentMode") || null;
|
|
50
|
+
}
|
|
138
51
|
|
|
139
|
-
// src/hooks/use-
|
|
52
|
+
// src/hooks/use-activate-breakpoint.ts
|
|
140
53
|
import { useCallback } from "react";
|
|
141
54
|
import { __privateRunCommand as runCommand } from "@elementor/editor-v1-adapters";
|
|
142
|
-
function
|
|
143
|
-
|
|
144
|
-
return runCommand("panel/change-device-mode", { device });
|
|
55
|
+
function useActivateBreakpoint() {
|
|
56
|
+
return useCallback((breakpoint) => {
|
|
57
|
+
return runCommand("panel/change-device-mode", { device: breakpoint });
|
|
145
58
|
}, []);
|
|
146
|
-
return {
|
|
147
|
-
activate
|
|
148
|
-
};
|
|
149
59
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
const { activate } = useBreakpointsActions();
|
|
155
|
-
if (!all.length || !active) {
|
|
156
|
-
return null;
|
|
157
|
-
}
|
|
158
|
-
const onChange = (_, value) => {
|
|
159
|
-
const extendedWindow = window;
|
|
160
|
-
const config = extendedWindow?.elementor?.editorEvents?.config;
|
|
161
|
-
if (config) {
|
|
162
|
-
extendedWindow.elementor.editorEvents.dispatchEvent(config.names.topBar.responsiveControls, {
|
|
163
|
-
location: config.locations.topBar,
|
|
164
|
-
secondaryLocation: config.secondaryLocations.responsiveControls,
|
|
165
|
-
trigger: config.triggers.click,
|
|
166
|
-
element: config.elements.buttonIcon,
|
|
167
|
-
mode: value
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
activate(value);
|
|
171
|
-
};
|
|
172
|
-
return /* @__PURE__ */ React.createElement(
|
|
173
|
-
Tabs,
|
|
174
|
-
{
|
|
175
|
-
textColor: "inherit",
|
|
176
|
-
indicatorColor: "secondary",
|
|
177
|
-
value: active.id,
|
|
178
|
-
onChange,
|
|
179
|
-
"aria-label": __2("Switch Device", "elementor"),
|
|
180
|
-
sx: {
|
|
181
|
-
"& .MuiTabs-indicator": {
|
|
182
|
-
backgroundColor: "text.primary"
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
},
|
|
186
|
-
all.map(({ id, label, type, width }) => {
|
|
187
|
-
const Icon = iconsMap[id];
|
|
188
|
-
const title = labelsMap[type || "default"].replace("%s", label).replace("%d", width?.toString() || "");
|
|
189
|
-
return /* @__PURE__ */ React.createElement(
|
|
190
|
-
Tab,
|
|
191
|
-
{
|
|
192
|
-
value: id,
|
|
193
|
-
key: id,
|
|
194
|
-
"aria-label": title,
|
|
195
|
-
icon: /* @__PURE__ */ React.createElement(Tooltip, { title }, /* @__PURE__ */ React.createElement(Icon, null)),
|
|
196
|
-
sx: { minWidth: "auto" },
|
|
197
|
-
"data-testid": `switch-device-to-${id}`
|
|
198
|
-
}
|
|
199
|
-
);
|
|
200
|
-
})
|
|
201
|
-
);
|
|
202
|
-
}
|
|
203
|
-
function Tooltip(props) {
|
|
204
|
-
return /* @__PURE__ */ React.createElement(
|
|
205
|
-
BaseTooltip,
|
|
206
|
-
{
|
|
207
|
-
PopperProps: {
|
|
208
|
-
sx: {
|
|
209
|
-
"&.MuiTooltip-popper .MuiTooltip-tooltip.MuiTooltip-tooltipPlacementBottom": {
|
|
210
|
-
mt: 2.5
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
},
|
|
214
|
-
...props
|
|
215
|
-
}
|
|
216
|
-
);
|
|
217
|
-
}
|
|
218
|
-
var iconsMap = {
|
|
219
|
-
widescreen: WidescreenIcon,
|
|
220
|
-
desktop: DesktopIcon,
|
|
221
|
-
laptop: LaptopIcon,
|
|
222
|
-
tablet_extra: TabletLandscapeIcon,
|
|
223
|
-
tablet: TabletPortraitIcon,
|
|
224
|
-
mobile_extra: MobileLandscapeIcon,
|
|
225
|
-
mobile: MobilePortraitIcon
|
|
226
|
-
};
|
|
227
|
-
var labelsMap = {
|
|
228
|
-
default: "%s",
|
|
229
|
-
// translators: %s: Breakpoint label, %d: Breakpoint size.
|
|
230
|
-
"min-width": __2("%s (%dpx and up)", "elementor"),
|
|
231
|
-
// translators: %s: Breakpoint label, %d: Breakpoint size.
|
|
232
|
-
"max-width": __2("%s (up to %dpx)", "elementor")
|
|
60
|
+
export {
|
|
61
|
+
useActivateBreakpoint,
|
|
62
|
+
useActiveBreakpoint,
|
|
63
|
+
useBreakpoints
|
|
233
64
|
};
|
|
234
|
-
|
|
235
|
-
// src/init.ts
|
|
236
|
-
import { __registerSlice } from "@elementor/store";
|
|
237
|
-
function init() {
|
|
238
|
-
initStore();
|
|
239
|
-
registerAppBarUI();
|
|
240
|
-
}
|
|
241
|
-
function initStore() {
|
|
242
|
-
__registerSlice(slice);
|
|
243
|
-
syncStore();
|
|
244
|
-
}
|
|
245
|
-
function registerAppBarUI() {
|
|
246
|
-
injectIntoResponsive({
|
|
247
|
-
id: "responsive-breakpoints-switcher",
|
|
248
|
-
component: BreakpointsSwitcher,
|
|
249
|
-
options: {
|
|
250
|
-
priority: 20
|
|
251
|
-
// After document indication.
|
|
252
|
-
}
|
|
253
|
-
});
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// src/index.ts
|
|
257
|
-
init();
|
|
258
65
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/store/index.ts","../src/sync/sync-store.ts","../src/init.ts","../src/components/breakpoints-switcher.tsx","../src/hooks/use-breakpoints.ts","../src/store/selectors.ts","../src/hooks/use-breakpoints-actions.ts","../src/index.ts"],"sourcesContent":["import { __createSlice, PayloadAction } from '@elementor/store';\nimport { Breakpoint, BreakpointId } from '../types';\n\nexport type State = {\n\tentities: Record< BreakpointId, Breakpoint >;\n\tactiveId: BreakpointId | null;\n};\nconst initialState: State = {\n\tentities: {} as State[ 'entities' ],\n\tactiveId: null,\n};\n\nexport const slice = __createSlice( {\n\tname: 'breakpoints',\n\tinitialState,\n\treducers: {\n\t\tinit(\n\t\t\tstate,\n\t\t\taction: PayloadAction< {\n\t\t\t\tentities: Breakpoint[];\n\t\t\t\tactiveId: State[ 'activeId' ];\n\t\t\t} >\n\t\t) {\n\t\t\tstate.activeId = action.payload.activeId;\n\t\t\tstate.entities = normalizeEntities( action.payload.entities );\n\t\t},\n\n\t\tactivateBreakpoint( state, action: PayloadAction< BreakpointId > ) {\n\t\t\tif ( state.entities[ action.payload ] ) {\n\t\t\t\tstate.activeId = action.payload;\n\t\t\t}\n\t\t},\n\t},\n} );\n\nfunction normalizeEntities( entities: Breakpoint[] ) {\n\treturn entities.reduce(\n\t\t( acc, breakpoint ) => {\n\t\t\treturn {\n\t\t\t\t...acc,\n\t\t\t\t[ breakpoint.id ]: breakpoint,\n\t\t\t};\n\t\t},\n\t\t{} as State[ 'entities' ]\n\t);\n}\n","import { slice } from '../store';\nimport { __dispatch } from '@elementor/store';\nimport { Breakpoint, ExtendedWindow } from '../types';\nimport { __privateListenTo as listenTo, v1ReadyEvent, windowEvent } from '@elementor/editor-v1-adapters';\nimport { __ } from '@wordpress/i18n';\n\nexport default function syncStore() {\n\tsyncInitialization();\n\tsyncOnChange();\n}\n\nfunction syncInitialization() {\n\tconst { init } = slice.actions;\n\n\tlistenTo( v1ReadyEvent(), () => {\n\t\t__dispatch(\n\t\t\tinit( {\n\t\t\t\tentities: getBreakpoints(),\n\t\t\t\tactiveId: getActiveBreakpoint(),\n\t\t\t} )\n\t\t);\n\t} );\n}\n\nfunction syncOnChange() {\n\tconst { activateBreakpoint } = slice.actions;\n\n\tlistenTo( deviceModeChangeEvent(), () => {\n\t\tconst activeBreakpoint = getActiveBreakpoint();\n\n\t\t__dispatch( activateBreakpoint( activeBreakpoint ) );\n\t} );\n}\n\nfunction getBreakpoints() {\n\tconst { breakpoints } = ( window as unknown as ExtendedWindow ).elementor?.config?.responsive || {};\n\n\tif ( ! breakpoints ) {\n\t\treturn [];\n\t}\n\n\tconst entities = Object.entries( breakpoints )\n\t\t.filter( ( [ , breakpoint ] ) => breakpoint.is_enabled )\n\t\t.map( ( [ id, { value, direction, label } ] ) => {\n\t\t\treturn {\n\t\t\t\tid,\n\t\t\t\tlabel,\n\t\t\t\twidth: value,\n\t\t\t\ttype: direction === 'min' ? 'min-width' : 'max-width',\n\t\t\t} as Breakpoint;\n\t\t} );\n\n\t// Desktop breakpoint is not included in V1 config.\n\tentities.push( {\n\t\tid: 'desktop',\n\t\tlabel: __( 'Desktop', 'elementor' ),\n\t} );\n\n\treturn entities;\n}\n\nfunction getActiveBreakpoint() {\n\tconst extendedWindow = window as unknown as ExtendedWindow;\n\n\treturn extendedWindow.elementor?.channels?.deviceMode?.request?.( 'currentMode' ) || null;\n}\n\nfunction deviceModeChangeEvent() {\n\treturn windowEvent( 'elementor/device-mode/change' );\n}\n","import { slice } from './store';\nimport syncStore from './sync/sync-store';\nimport { injectIntoResponsive } from '@elementor/editor-app-bar';\nimport BreakpointsSwitcher from './components/breakpoints-switcher';\nimport { __registerSlice } from '@elementor/store';\n\nexport default function init() {\n\tinitStore();\n\n\tregisterAppBarUI();\n}\n\nfunction initStore() {\n\t__registerSlice( slice );\n\n\tsyncStore();\n}\n\nfunction registerAppBarUI() {\n\tinjectIntoResponsive( {\n\t\tid: 'responsive-breakpoints-switcher',\n\t\tcomponent: BreakpointsSwitcher,\n\t\toptions: {\n\t\t\tpriority: 20, // After document indication.\n\t\t},\n\t} );\n}\n","import * as React from 'react';\nimport { __ } from '@wordpress/i18n';\nimport { BreakpointId, ExtendedWindow } from '../types';\nimport useBreakpoints from '../hooks/use-breakpoints';\nimport { Tab, Tabs, Tooltip as BaseTooltip, TooltipProps } from '@elementor/ui';\nimport {\n\tDesktopIcon,\n\tTabletPortraitIcon,\n\tMobilePortraitIcon,\n\tWidescreenIcon,\n\tLaptopIcon,\n\tTabletLandscapeIcon,\n\tMobileLandscapeIcon,\n} from '@elementor/icons';\nimport useBreakpointsActions from '../hooks/use-breakpoints-actions';\n\nexport default function BreakpointsSwitcher() {\n\tconst { all, active } = useBreakpoints();\n\tconst { activate } = useBreakpointsActions();\n\n\tif ( ! all.length || ! active ) {\n\t\treturn null;\n\t}\n\n\tconst onChange = ( _: unknown, value: BreakpointId ) => {\n\t\tconst extendedWindow = window as unknown as ExtendedWindow;\n\t\tconst config = extendedWindow?.elementor?.editorEvents?.config;\n\n\t\tif ( config ) {\n\t\t\textendedWindow.elementor.editorEvents.dispatchEvent( config.names.topBar.responsiveControls, {\n\t\t\t\tlocation: config.locations.topBar,\n\t\t\t\tsecondaryLocation: config.secondaryLocations.responsiveControls,\n\t\t\t\ttrigger: config.triggers.click,\n\t\t\t\telement: config.elements.buttonIcon,\n\t\t\t\tmode: value,\n\t\t\t} );\n\t\t}\n\n\t\tactivate( value );\n\t};\n\n\treturn (\n\t\t<Tabs\n\t\t\ttextColor=\"inherit\"\n\t\t\tindicatorColor=\"secondary\"\n\t\t\tvalue={ active.id }\n\t\t\tonChange={ onChange }\n\t\t\taria-label={ __( 'Switch Device', 'elementor' ) }\n\t\t\tsx={ {\n\t\t\t\t'& .MuiTabs-indicator': {\n\t\t\t\t\tbackgroundColor: 'text.primary',\n\t\t\t\t},\n\t\t\t} }\n\t\t>\n\t\t\t{ all.map( ( { id, label, type, width } ) => {\n\t\t\t\tconst Icon = iconsMap[ id ];\n\n\t\t\t\tconst title = labelsMap[ type || 'default' ]\n\t\t\t\t\t.replace( '%s', label )\n\t\t\t\t\t.replace( '%d', width?.toString() || '' );\n\n\t\t\t\treturn (\n\t\t\t\t\t<Tab\n\t\t\t\t\t\tvalue={ id }\n\t\t\t\t\t\tkey={ id }\n\t\t\t\t\t\taria-label={ title }\n\t\t\t\t\t\ticon={\n\t\t\t\t\t\t\t<Tooltip title={ title }>\n\t\t\t\t\t\t\t\t<Icon />\n\t\t\t\t\t\t\t</Tooltip>\n\t\t\t\t\t\t}\n\t\t\t\t\t\tsx={ { minWidth: 'auto' } }\n\t\t\t\t\t\tdata-testid={ `switch-device-to-${ id }` }\n\t\t\t\t\t/>\n\t\t\t\t);\n\t\t\t} ) }\n\t\t</Tabs>\n\t);\n}\n\nfunction Tooltip( props: TooltipProps ) {\n\treturn (\n\t\t<BaseTooltip\n\t\t\tPopperProps={ {\n\t\t\t\tsx: {\n\t\t\t\t\t'&.MuiTooltip-popper .MuiTooltip-tooltip.MuiTooltip-tooltipPlacementBottom': {\n\t\t\t\t\t\tmt: 2.5,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t} }\n\t\t\t{ ...props }\n\t\t/>\n\t);\n}\n\nconst iconsMap = {\n\twidescreen: WidescreenIcon,\n\tdesktop: DesktopIcon,\n\tlaptop: LaptopIcon,\n\ttablet_extra: TabletLandscapeIcon,\n\ttablet: TabletPortraitIcon,\n\tmobile_extra: MobileLandscapeIcon,\n\tmobile: MobilePortraitIcon,\n};\n\nconst labelsMap = {\n\tdefault: '%s',\n\t// translators: %s: Breakpoint label, %d: Breakpoint size.\n\t'min-width': __( '%s (%dpx and up)', 'elementor' ),\n\n\t// translators: %s: Breakpoint label, %d: Breakpoint size.\n\t'max-width': __( '%s (up to %dpx)', 'elementor' ),\n} as const;\n","import { __useSelector as useSelector } from '@elementor/store';\nimport { selectActiveBreakpoint, selectSortedBreakpoints } from '../store/selectors';\n\nexport default function useBreakpoints() {\n\tconst all = useSelector( selectSortedBreakpoints );\n\tconst active = useSelector( selectActiveBreakpoint );\n\n\treturn {\n\t\tall,\n\t\tactive,\n\t};\n}\n","import { slice } from './index';\nimport { Breakpoint } from '../types';\nimport { __createSelector, SliceState } from '@elementor/store';\n\ntype State = SliceState< typeof slice >;\n\nexport const selectEntities = ( state: State ) => state.breakpoints.entities;\nexport const selectActiveId = ( state: State ) => state.breakpoints.activeId;\n\nexport const selectActiveBreakpoint = __createSelector( selectEntities, selectActiveId, ( entities, activeId ) =>\n\tactiveId && entities[ activeId ] ? entities[ activeId ] : null\n);\n\nexport const selectSortedBreakpoints = __createSelector( selectEntities, ( entities ) => {\n\tconst byWidth = ( a: Breakpoint, b: Breakpoint ) => {\n\t\treturn a.width && b.width ? b.width - a.width : 0;\n\t};\n\n\tconst all = Object.values( entities );\n\n\tconst defaults = all.filter( ( breakpoint ) => ! breakpoint.width ); // AKA Desktop.\n\tconst minWidth = all.filter( ( breakpoint ) => breakpoint.type === 'min-width' );\n\tconst maxWidth = all.filter( ( breakpoint ) => breakpoint.type === 'max-width' );\n\n\t// Sort by size, big to small.\n\treturn [ ...minWidth.sort( byWidth ), ...defaults, ...maxWidth.sort( byWidth ) ];\n} );\n","import { useCallback } from 'react';\nimport { BreakpointId } from '../types';\nimport { __privateRunCommand as runCommand } from '@elementor/editor-v1-adapters';\n\nexport default function useBreakpointsActions() {\n\tconst activate = useCallback( ( device: BreakpointId ) => {\n\t\treturn runCommand( 'panel/change-device-mode', { device } );\n\t}, [] );\n\n\treturn {\n\t\tactivate,\n\t};\n}\n","import init from './init';\n\ninit();\n"],"mappings":"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","names":["init","__","__"]}
|
|
1
|
+
{"version":3,"sources":["../src/hooks/use-breakpoints.ts","../src/hooks/use-active-breakpoint.ts","../src/hooks/use-activate-breakpoint.ts"],"sourcesContent":["import { __ } from '@wordpress/i18n';\nimport { Breakpoint, BreakpointId, ExtendedWindow } from '../types';\nimport { v1ReadyEvent, __privateUseListenTo as useListenTo } from '@elementor/editor-v1-adapters';\n\nexport function useBreakpoints() {\n\treturn useListenTo( v1ReadyEvent(), getBreakpoints );\n}\n\nfunction getBreakpoints() {\n\tconst { breakpoints } = ( window as unknown as ExtendedWindow ).elementor?.config?.responsive || {};\n\n\tif ( ! breakpoints || Object.entries( breakpoints ).length === 0 ) {\n\t\treturn [];\n\t}\n\n\tconst minWidth: Breakpoint[] = [];\n\tconst maxWidth: Breakpoint[] = [];\n\n\tconst defaults: Breakpoint[] = [\n\t\t// Desktop breakpoint is not included in V1 config.\n\t\t{ id: 'desktop', label: __( 'Desktop', 'elementor' ) },\n\t];\n\n\tObject.entries( breakpoints ).forEach( ( [ id, v1Breakpoint ] ) => {\n\t\tif ( ! v1Breakpoint.is_enabled ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst breakpoint: Breakpoint = {\n\t\t\tid: id as BreakpointId,\n\t\t\tlabel: v1Breakpoint.label,\n\t\t\twidth: v1Breakpoint.value,\n\t\t\ttype: v1Breakpoint.direction === 'min' ? 'min-width' : 'max-width',\n\t\t};\n\n\t\tif ( ! breakpoint.width ) {\n\t\t\tdefaults.push( breakpoint );\n\t\t} else if ( breakpoint.type === 'min-width' ) {\n\t\t\tminWidth.push( breakpoint );\n\t\t} else if ( breakpoint.type === 'max-width' ) {\n\t\t\tmaxWidth.push( breakpoint );\n\t\t}\n\t} );\n\n\tconst byWidth = ( a: Breakpoint, b: Breakpoint ) => {\n\t\treturn a.width && b.width ? b.width - a.width : 0;\n\t};\n\n\treturn [ ...minWidth.sort( byWidth ), ...defaults, ...maxWidth.sort( byWidth ) ];\n}\n","import { __privateUseListenTo as useListenTo, windowEvent } from '@elementor/editor-v1-adapters';\nimport { BreakpointId, ExtendedWindow } from '../types';\n\nexport function useActiveBreakpoint(): BreakpointId | null {\n\treturn useListenTo( windowEvent( 'elementor/device-mode/change' ), getActiveBreakpoint );\n}\n\nfunction getActiveBreakpoint() {\n\tconst extendedWindow = window as unknown as ExtendedWindow;\n\n\treturn extendedWindow.elementor?.channels?.deviceMode?.request?.( 'currentMode' ) || null;\n}\n","import { useCallback } from 'react';\nimport { BreakpointId } from '../types';\nimport { __privateRunCommand as runCommand } from '@elementor/editor-v1-adapters';\n\nexport function useActivateBreakpoint() {\n\treturn useCallback( ( breakpoint: BreakpointId ) => {\n\t\treturn runCommand( 'panel/change-device-mode', { device: breakpoint } );\n\t}, [] );\n}\n"],"mappings":";AAAA,SAAS,UAAU;AAEnB,SAAS,cAAc,wBAAwB,mBAAmB;AAE3D,SAAS,iBAAiB;AAChC,SAAO,YAAa,aAAa,GAAG,cAAe;AACpD;AAEA,SAAS,iBAAiB;AACzB,QAAM,EAAE,YAAY,IAAM,OAAsC,WAAW,QAAQ,cAAc,CAAC;AAElG,MAAK,CAAE,eAAe,OAAO,QAAS,WAAY,EAAE,WAAW,GAAI;AAClE,WAAO,CAAC;AAAA,EACT;AAEA,QAAM,WAAyB,CAAC;AAChC,QAAM,WAAyB,CAAC;AAEhC,QAAM,WAAyB;AAAA;AAAA,IAE9B,EAAE,IAAI,WAAW,OAAO,GAAI,WAAW,WAAY,EAAE;AAAA,EACtD;AAEA,SAAO,QAAS,WAAY,EAAE,QAAS,CAAE,CAAE,IAAI,YAAa,MAAO;AAClE,QAAK,CAAE,aAAa,YAAa;AAChC;AAAA,IACD;AAEA,UAAM,aAAyB;AAAA,MAC9B;AAAA,MACA,OAAO,aAAa;AAAA,MACpB,OAAO,aAAa;AAAA,MACpB,MAAM,aAAa,cAAc,QAAQ,cAAc;AAAA,IACxD;AAEA,QAAK,CAAE,WAAW,OAAQ;AACzB,eAAS,KAAM,UAAW;AAAA,IAC3B,WAAY,WAAW,SAAS,aAAc;AAC7C,eAAS,KAAM,UAAW;AAAA,IAC3B,WAAY,WAAW,SAAS,aAAc;AAC7C,eAAS,KAAM,UAAW;AAAA,IAC3B;AAAA,EACD,CAAE;AAEF,QAAM,UAAU,CAAE,GAAe,MAAmB;AACnD,WAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ;AAAA,EACjD;AAEA,SAAO,CAAE,GAAG,SAAS,KAAM,OAAQ,GAAG,GAAG,UAAU,GAAG,SAAS,KAAM,OAAQ,CAAE;AAChF;;;ACjDA,SAAS,wBAAwBA,cAAa,mBAAmB;AAG1D,SAAS,sBAA2C;AAC1D,SAAOA,aAAa,YAAa,8BAA+B,GAAG,mBAAoB;AACxF;AAEA,SAAS,sBAAsB;AAC9B,QAAM,iBAAiB;AAEvB,SAAO,eAAe,WAAW,UAAU,YAAY,UAAW,aAAc,KAAK;AACtF;;;ACXA,SAAS,mBAAmB;AAE5B,SAAS,uBAAuB,kBAAkB;AAE3C,SAAS,wBAAwB;AACvC,SAAO,YAAa,CAAE,eAA8B;AACnD,WAAO,WAAY,4BAA4B,EAAE,QAAQ,WAAW,CAAE;AAAA,EACvE,GAAG,CAAC,CAAE;AACP;","names":["useListenTo"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elementor/editor-responsive",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"author": "Elementor Team",
|
|
6
6
|
"homepage": "https://elementor.com/",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"repository": {
|
|
20
20
|
"type": "git",
|
|
21
21
|
"url": "https://github.com/elementor/elementor-packages.git",
|
|
22
|
-
"directory": "packages/
|
|
22
|
+
"directory": "packages/libs/editor-responsive"
|
|
23
23
|
},
|
|
24
24
|
"bugs": {
|
|
25
25
|
"url": "https://github.com/elementor/elementor-packages/issues"
|
|
@@ -32,15 +32,11 @@
|
|
|
32
32
|
"dev": "tsup --config=../../tsup.dev.ts"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@elementor/editor-app-bar": "^0.14.6",
|
|
36
35
|
"@elementor/editor-v1-adapters": "^0.8.0",
|
|
37
|
-
"@elementor/icons": "^0.8.2",
|
|
38
|
-
"@elementor/store": "^0.8.4",
|
|
39
|
-
"@elementor/ui": "^1.4.61",
|
|
40
36
|
"@wordpress/i18n": "^4.45.0"
|
|
41
37
|
},
|
|
42
38
|
"peerDependencies": {
|
|
43
39
|
"react": "^18.3.1"
|
|
44
40
|
},
|
|
45
|
-
"gitHead": "
|
|
41
|
+
"gitHead": "7d626115b07f3425b679f7508230f7776f3fe17b"
|
|
46
42
|
}
|
package/src/hooks/__tests__/{use-breakpoints-actions.test.tsx → use-activate-breakpoint.test.ts}
RENAMED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { __privateRunCommand as runCommand } from '@elementor/editor-v1-adapters';
|
|
2
1
|
import { renderHook } from '@testing-library/react';
|
|
3
|
-
import
|
|
2
|
+
import { useActivateBreakpoint } from '../use-activate-breakpoint';
|
|
3
|
+
import { __privateRunCommand as runCommand } from '@elementor/editor-v1-adapters';
|
|
4
4
|
|
|
5
5
|
jest.mock( '@elementor/editor-v1-adapters', () => ( {
|
|
6
6
|
__privateRunCommand: jest.fn(),
|
|
7
7
|
} ) );
|
|
8
8
|
|
|
9
|
-
describe( '
|
|
9
|
+
describe( 'useActivateBreakpoints', () => {
|
|
10
10
|
it( 'should activate a breakpoint', () => {
|
|
11
11
|
// Act.
|
|
12
|
-
const { result } = renderHook(
|
|
12
|
+
const { result } = renderHook( useActivateBreakpoint );
|
|
13
13
|
|
|
14
|
-
result.current
|
|
14
|
+
result.current( 'tablet' );
|
|
15
15
|
|
|
16
16
|
// Assert.
|
|
17
17
|
expect( jest.mocked( runCommand ) ).toHaveBeenCalledTimes( 1 );
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { act, renderHook } from '@testing-library/react';
|
|
2
|
+
import { useActiveBreakpoint } from '../use-active-breakpoint';
|
|
3
|
+
import { BreakpointId, ExtendedWindow } from '../../types';
|
|
4
|
+
import { dispatchWindowEvent } from 'test-utils';
|
|
5
|
+
|
|
6
|
+
describe( 'useActiveBreakpoint', () => {
|
|
7
|
+
function setActiveBreakpoint( active: BreakpointId ) {
|
|
8
|
+
const extendedWindow = window as unknown as ExtendedWindow;
|
|
9
|
+
|
|
10
|
+
extendedWindow.elementor = {
|
|
11
|
+
channels: {
|
|
12
|
+
deviceMode: {
|
|
13
|
+
request: () => {
|
|
14
|
+
return active;
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
dispatchWindowEvent( 'elementor/device-mode/change' );
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
it( 'should return null when no breakpoint is active', () => {
|
|
24
|
+
// Arrange.
|
|
25
|
+
setActiveBreakpoint( undefined as never );
|
|
26
|
+
|
|
27
|
+
// Act.
|
|
28
|
+
const { result } = renderHook( useActiveBreakpoint );
|
|
29
|
+
|
|
30
|
+
// Assert.
|
|
31
|
+
expect( result.current ).toEqual( null );
|
|
32
|
+
} );
|
|
33
|
+
|
|
34
|
+
it( 'should return the active breakpoint', () => {
|
|
35
|
+
// Arrange.
|
|
36
|
+
setActiveBreakpoint( 'mobile' );
|
|
37
|
+
|
|
38
|
+
// Act.
|
|
39
|
+
const { result } = renderHook( useActiveBreakpoint );
|
|
40
|
+
|
|
41
|
+
// Assert.
|
|
42
|
+
expect( result.current ).toEqual( 'mobile' );
|
|
43
|
+
|
|
44
|
+
// Act.
|
|
45
|
+
act( () => setActiveBreakpoint( 'tablet' ) );
|
|
46
|
+
|
|
47
|
+
// Assert.
|
|
48
|
+
expect( result.current ).toEqual( 'tablet' );
|
|
49
|
+
} );
|
|
50
|
+
} );
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { useBreakpoints } from '../use-breakpoints';
|
|
2
|
+
import { renderHook } from '@testing-library/react';
|
|
3
|
+
import { ExtendedWindow, V1Breakpoints } from '../../types';
|
|
4
|
+
|
|
5
|
+
describe( 'useBreakpoints', () => {
|
|
6
|
+
function setBreakpoints( breakpoints: Partial< V1Breakpoints > ) {
|
|
7
|
+
const extendedWindow = window as unknown as ExtendedWindow;
|
|
8
|
+
|
|
9
|
+
extendedWindow.elementor = {
|
|
10
|
+
config: {
|
|
11
|
+
responsive: {
|
|
12
|
+
breakpoints: breakpoints as V1Breakpoints,
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
it( 'should return an empty array if no breakpoints are available', () => {
|
|
19
|
+
// Arrange.
|
|
20
|
+
setBreakpoints( {} as never );
|
|
21
|
+
|
|
22
|
+
// Act.
|
|
23
|
+
const { result } = renderHook( useBreakpoints );
|
|
24
|
+
|
|
25
|
+
// Assert.
|
|
26
|
+
expect( result.current ).toEqual( [] );
|
|
27
|
+
} );
|
|
28
|
+
|
|
29
|
+
it( 'should filter out inactive breakpoints', () => {
|
|
30
|
+
// Arrange.
|
|
31
|
+
setBreakpoints( {
|
|
32
|
+
tablet: {
|
|
33
|
+
is_enabled: false,
|
|
34
|
+
value: 1024,
|
|
35
|
+
label: 'Tablet Portrait',
|
|
36
|
+
direction: 'max',
|
|
37
|
+
},
|
|
38
|
+
mobile: {
|
|
39
|
+
is_enabled: true,
|
|
40
|
+
value: 767,
|
|
41
|
+
label: 'Mobile Portrait',
|
|
42
|
+
direction: 'max',
|
|
43
|
+
},
|
|
44
|
+
} );
|
|
45
|
+
|
|
46
|
+
// Act.
|
|
47
|
+
const { result } = renderHook( useBreakpoints );
|
|
48
|
+
|
|
49
|
+
// Assert.
|
|
50
|
+
expect( result.current ).toEqual( [
|
|
51
|
+
{ id: 'desktop', label: 'Desktop' },
|
|
52
|
+
{ id: 'mobile', label: 'Mobile Portrait', width: 767, type: 'max-width' },
|
|
53
|
+
] );
|
|
54
|
+
} );
|
|
55
|
+
|
|
56
|
+
it( 'should return all breakpoints sorted by size', () => {
|
|
57
|
+
// Arrange.
|
|
58
|
+
setBreakpoints( {
|
|
59
|
+
tablet: {
|
|
60
|
+
is_enabled: true,
|
|
61
|
+
value: 1024,
|
|
62
|
+
label: 'Tablet Portrait',
|
|
63
|
+
direction: 'max',
|
|
64
|
+
},
|
|
65
|
+
mobile: {
|
|
66
|
+
is_enabled: true,
|
|
67
|
+
value: 767,
|
|
68
|
+
label: 'Mobile Portrait',
|
|
69
|
+
direction: 'max',
|
|
70
|
+
},
|
|
71
|
+
widescreen: {
|
|
72
|
+
is_enabled: true,
|
|
73
|
+
value: 2400,
|
|
74
|
+
label: 'Widescreen',
|
|
75
|
+
direction: 'min',
|
|
76
|
+
},
|
|
77
|
+
} );
|
|
78
|
+
|
|
79
|
+
// Act.
|
|
80
|
+
const { result } = renderHook( useBreakpoints );
|
|
81
|
+
|
|
82
|
+
// Assert.
|
|
83
|
+
expect( result.current ).toEqual( [
|
|
84
|
+
{ id: 'widescreen', label: 'Widescreen', width: 2400, type: 'min-width' },
|
|
85
|
+
{ id: 'desktop', label: 'Desktop' },
|
|
86
|
+
{ id: 'tablet', label: 'Tablet Portrait', width: 1024, type: 'max-width' },
|
|
87
|
+
{ id: 'mobile', label: 'Mobile Portrait', width: 767, type: 'max-width' },
|
|
88
|
+
] );
|
|
89
|
+
} );
|
|
90
|
+
} );
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { useCallback } from 'react';
|
|
2
|
+
import { BreakpointId } from '../types';
|
|
3
|
+
import { __privateRunCommand as runCommand } from '@elementor/editor-v1-adapters';
|
|
4
|
+
|
|
5
|
+
export function useActivateBreakpoint() {
|
|
6
|
+
return useCallback( ( breakpoint: BreakpointId ) => {
|
|
7
|
+
return runCommand( 'panel/change-device-mode', { device: breakpoint } );
|
|
8
|
+
}, [] );
|
|
9
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { __privateUseListenTo as useListenTo, windowEvent } from '@elementor/editor-v1-adapters';
|
|
2
|
+
import { BreakpointId, ExtendedWindow } from '../types';
|
|
3
|
+
|
|
4
|
+
export function useActiveBreakpoint(): BreakpointId | null {
|
|
5
|
+
return useListenTo( windowEvent( 'elementor/device-mode/change' ), getActiveBreakpoint );
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function getActiveBreakpoint() {
|
|
9
|
+
const extendedWindow = window as unknown as ExtendedWindow;
|
|
10
|
+
|
|
11
|
+
return extendedWindow.elementor?.channels?.deviceMode?.request?.( 'currentMode' ) || null;
|
|
12
|
+
}
|
|
@@ -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';
|