@elementor/editor-global-classes 0.3.0 → 0.5.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 +93 -0
- package/dist/index.js +480 -89
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +514 -86
- package/dist/index.mjs.map +1 -1
- package/package.json +16 -8
- package/src/api.ts +6 -12
- package/src/components/class-manager/class-manager-button.tsx +8 -5
- package/src/components/class-manager/class-manager-panel.tsx +16 -9
- package/src/components/class-manager/delete-confirmation-dialog.tsx +96 -0
- package/src/components/class-manager/global-classes-list.tsx +261 -0
- package/src/components/class-manager/sortable.tsx +90 -0
- package/src/components/{logic-hooks.tsx → populate-store.tsx} +1 -1
- package/src/errors.ts +11 -0
- package/src/global-classes-styles-provider.ts +51 -25
- package/src/init.ts +10 -4
- package/src/store.ts +87 -14
- package/src/sync-with-document-save.ts +44 -0
package/dist/index.mjs
CHANGED
|
@@ -2,16 +2,18 @@
|
|
|
2
2
|
import { injectIntoLogic } from "@elementor/editor";
|
|
3
3
|
import { injectIntoClassSelectorActions } from "@elementor/editor-editing-panel";
|
|
4
4
|
import { __registerPanel as registerPanel } from "@elementor/editor-panels";
|
|
5
|
-
import { stylesRepository } from "@elementor/editor-styles-repository";
|
|
5
|
+
import { stylesRepository as stylesRepository2 } from "@elementor/editor-styles-repository";
|
|
6
|
+
import { __privateListenTo as listenTo, v1ReadyEvent } from "@elementor/editor-v1-adapters";
|
|
6
7
|
import { __registerSlice as registerSlice } from "@elementor/store";
|
|
7
8
|
|
|
8
9
|
// src/components/class-manager/class-manager-button.tsx
|
|
9
|
-
import * as
|
|
10
|
-
import {
|
|
11
|
-
import { IconButton as
|
|
10
|
+
import * as React5 from "react";
|
|
11
|
+
import { ColorSwatchIcon as ColorSwatchIcon2 } from "@elementor/icons";
|
|
12
|
+
import { IconButton as IconButton3, Tooltip as Tooltip2 } from "@elementor/ui";
|
|
13
|
+
import { __ as __5 } from "@wordpress/i18n";
|
|
12
14
|
|
|
13
15
|
// src/components/class-manager/class-manager-panel.tsx
|
|
14
|
-
import * as
|
|
16
|
+
import * as React4 from "react";
|
|
15
17
|
import {
|
|
16
18
|
__createPanel as createPanel,
|
|
17
19
|
Panel,
|
|
@@ -19,55 +21,68 @@ import {
|
|
|
19
21
|
PanelHeader,
|
|
20
22
|
PanelHeaderTitle
|
|
21
23
|
} from "@elementor/editor-panels";
|
|
22
|
-
import { XIcon } from "@elementor/icons";
|
|
23
|
-
import { Alert, Box, ErrorBoundary, IconButton, Stack } from "@elementor/ui";
|
|
24
|
-
import { __ } from "@wordpress/i18n";
|
|
25
|
-
var { panel, usePanelActions, usePanelStatus } = createPanel({
|
|
26
|
-
id: "class-manager-panel",
|
|
27
|
-
component: ClassManagerPanel
|
|
28
|
-
});
|
|
29
|
-
function ClassManagerPanel() {
|
|
30
|
-
return /* @__PURE__ */ React.createElement(ErrorBoundary, { fallback: /* @__PURE__ */ React.createElement(ErrorBoundaryFallback, null) }, /* @__PURE__ */ React.createElement(Panel, null, /* @__PURE__ */ React.createElement(PanelHeader, null, /* @__PURE__ */ React.createElement(Stack, { p: 1, width: "100%", direction: "row", justifyContent: "space-between", alignItems: "center" }, /* @__PURE__ */ React.createElement(PanelHeaderTitle, null, __("CSS Class manager")), /* @__PURE__ */ React.createElement(CloseButton, null))), /* @__PURE__ */ React.createElement(PanelBody, null)));
|
|
31
|
-
}
|
|
32
|
-
var CloseButton = () => {
|
|
33
|
-
const { close } = usePanelActions();
|
|
34
|
-
return /* @__PURE__ */ React.createElement(IconButton, { size: "small", color: "secondary", onClick: close }, /* @__PURE__ */ React.createElement(XIcon, { fontSize: "small" }));
|
|
35
|
-
};
|
|
36
|
-
var ErrorBoundaryFallback = () => /* @__PURE__ */ React.createElement(Box, { role: "alert", sx: { minHeight: "100%", p: 2 } }, /* @__PURE__ */ React.createElement(Alert, { severity: "error", sx: { mb: 2, maxWidth: 400, textAlign: "center" } }, /* @__PURE__ */ React.createElement("strong", null, __("Something went wrong", "elementor"))));
|
|
24
|
+
import { ColorSwatchIcon, XIcon } from "@elementor/icons";
|
|
25
|
+
import { Alert, Box as Box3, ErrorBoundary, IconButton as IconButton2, Stack as Stack2 } from "@elementor/ui";
|
|
26
|
+
import { __ as __4 } from "@wordpress/i18n";
|
|
37
27
|
|
|
38
|
-
// src/components/class-manager/
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
};
|
|
28
|
+
// src/components/class-manager/global-classes-list.tsx
|
|
29
|
+
import * as React3 from "react";
|
|
30
|
+
import { stylesRepository } from "@elementor/editor-styles-repository";
|
|
31
|
+
import { EditableField, EllipsisWithTooltip, useEditable } from "@elementor/editor-ui";
|
|
32
|
+
import { DotsVerticalIcon, PhotoIcon } from "@elementor/icons";
|
|
33
|
+
import {
|
|
34
|
+
bindMenu,
|
|
35
|
+
bindTrigger,
|
|
36
|
+
Box as Box2,
|
|
37
|
+
IconButton,
|
|
38
|
+
List,
|
|
39
|
+
ListItem,
|
|
40
|
+
ListItemButton,
|
|
41
|
+
ListItemText,
|
|
42
|
+
Menu,
|
|
43
|
+
MenuItem,
|
|
44
|
+
Stack,
|
|
45
|
+
styled as styled2,
|
|
46
|
+
Tooltip,
|
|
47
|
+
Typography as Typography2,
|
|
48
|
+
usePopupState
|
|
49
|
+
} from "@elementor/ui";
|
|
50
|
+
import { __ as __3 } from "@wordpress/i18n";
|
|
43
51
|
|
|
44
|
-
// src/
|
|
45
|
-
import {
|
|
46
|
-
import {
|
|
52
|
+
// src/global-classes-styles-provider.ts
|
|
53
|
+
import { generateId } from "@elementor/editor-styles";
|
|
54
|
+
import {
|
|
55
|
+
__dispatch as dispatch,
|
|
56
|
+
__getState as getState,
|
|
57
|
+
__subscribeWithSelector as subscribeWithSelector
|
|
58
|
+
} from "@elementor/store";
|
|
59
|
+
import { __ } from "@wordpress/i18n";
|
|
47
60
|
|
|
48
|
-
// src/
|
|
49
|
-
import {
|
|
50
|
-
var
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
put: async (id, data) => {
|
|
59
|
-
return httpService().put(`${RESOURCE_URL}/${id}`, data);
|
|
60
|
-
}
|
|
61
|
-
};
|
|
61
|
+
// src/errors.ts
|
|
62
|
+
import { createError } from "@elementor/utils";
|
|
63
|
+
var GlobalClassNotFoundError = createError({
|
|
64
|
+
code: "global_class_not_found",
|
|
65
|
+
message: "Global class not found."
|
|
66
|
+
});
|
|
67
|
+
var GlobalClassLabelAlreadyExistsError = createError({
|
|
68
|
+
code: "global_class_label_already_exists",
|
|
69
|
+
message: "Class with this name already exists."
|
|
70
|
+
});
|
|
62
71
|
|
|
63
72
|
// src/store.ts
|
|
73
|
+
import { mergeProps } from "@elementor/editor-props";
|
|
74
|
+
import {
|
|
75
|
+
getVariantByMeta
|
|
76
|
+
} from "@elementor/editor-styles";
|
|
64
77
|
import {
|
|
65
78
|
__createSelector as createSelector,
|
|
66
|
-
__createSlice as createSlice
|
|
79
|
+
__createSlice as createSlice,
|
|
80
|
+
__useSelector as useSelector
|
|
67
81
|
} from "@elementor/store";
|
|
68
82
|
var initialState = {
|
|
69
83
|
items: {},
|
|
70
|
-
order: []
|
|
84
|
+
order: [],
|
|
85
|
+
isDirty: false
|
|
71
86
|
};
|
|
72
87
|
var SLICE_NAME = "globalClasses";
|
|
73
88
|
var slice = createSlice({
|
|
@@ -77,91 +92,504 @@ var slice = createSlice({
|
|
|
77
92
|
init(state, { payload }) {
|
|
78
93
|
state.items = payload.items;
|
|
79
94
|
state.order = payload.order;
|
|
95
|
+
state.isDirty = false;
|
|
80
96
|
},
|
|
81
97
|
add(state, { payload }) {
|
|
82
|
-
state.items[payload.
|
|
83
|
-
state.order
|
|
98
|
+
state.items[payload.id] = payload;
|
|
99
|
+
state.order.push(payload.id);
|
|
100
|
+
state.isDirty = true;
|
|
101
|
+
},
|
|
102
|
+
delete(state, { payload }) {
|
|
103
|
+
state.items = Object.fromEntries(Object.entries(state.items).filter(([id]) => id !== payload));
|
|
104
|
+
state.order = state.order.filter((id) => id !== payload);
|
|
105
|
+
state.isDirty = true;
|
|
106
|
+
},
|
|
107
|
+
setOrder(state, { payload }) {
|
|
108
|
+
state.order = payload;
|
|
84
109
|
},
|
|
85
110
|
update(state, { payload }) {
|
|
86
|
-
state.items[payload.style.id]
|
|
87
|
-
|
|
111
|
+
const style = state.items[payload.style.id];
|
|
112
|
+
const mergedData = {
|
|
113
|
+
...style,
|
|
114
|
+
...payload.style
|
|
115
|
+
};
|
|
116
|
+
state.items[payload.style.id] = mergedData;
|
|
117
|
+
state.isDirty = true;
|
|
118
|
+
},
|
|
119
|
+
updateProps(state, {
|
|
120
|
+
payload
|
|
121
|
+
}) {
|
|
122
|
+
const style = state.items[payload.id];
|
|
123
|
+
if (!style) {
|
|
124
|
+
throw new GlobalClassNotFoundError({ context: { styleId: payload.id } });
|
|
125
|
+
}
|
|
126
|
+
const variant = getVariantByMeta(style, payload.meta);
|
|
127
|
+
if (variant) {
|
|
128
|
+
variant.props = mergeProps(variant.props, payload.props);
|
|
129
|
+
} else {
|
|
130
|
+
style.variants.push({ meta: payload.meta, props: payload.props });
|
|
131
|
+
}
|
|
132
|
+
state.isDirty = true;
|
|
133
|
+
},
|
|
134
|
+
setPristine(state) {
|
|
135
|
+
state.isDirty = false;
|
|
88
136
|
}
|
|
89
137
|
}
|
|
90
138
|
});
|
|
91
|
-
var selectItems = (state) => state[SLICE_NAME].items;
|
|
92
139
|
var selectOrder = (state) => state[SLICE_NAME].order;
|
|
140
|
+
var selectGlobalClasses = (state) => state[SLICE_NAME].items;
|
|
93
141
|
var selectOrderedGlobalClasses = createSelector(
|
|
94
|
-
|
|
142
|
+
selectGlobalClasses,
|
|
95
143
|
selectOrder,
|
|
96
144
|
(items, order) => order.map((id) => items[id])
|
|
97
145
|
);
|
|
98
|
-
var selectClass = (state, id) => state[SLICE_NAME].items[id];
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
const { data, meta } = res.data;
|
|
106
|
-
dispatch2(slice.actions.init({ items: data, order: meta.order }));
|
|
107
|
-
});
|
|
108
|
-
}, [dispatch2]);
|
|
109
|
-
return null;
|
|
110
|
-
}
|
|
146
|
+
var selectClass = (state, id) => state[SLICE_NAME].items[id] ?? null;
|
|
147
|
+
var selectIsDirty = (state) => state.globalClasses.isDirty;
|
|
148
|
+
var useOrderedGlobalClasses = () => {
|
|
149
|
+
const items = useSelector(selectOrderedGlobalClasses);
|
|
150
|
+
return items;
|
|
151
|
+
};
|
|
152
|
+
var useGlobalClassesOrder = () => useSelector(selectOrder);
|
|
111
153
|
|
|
112
154
|
// src/global-classes-styles-provider.ts
|
|
113
|
-
import { __dispatch as dispatch, __getState as getState, __subscribe as subscribe } from "@elementor/store";
|
|
114
|
-
import { __ as __2 } from "@wordpress/i18n";
|
|
115
155
|
var globalClassesStylesProvider = {
|
|
116
156
|
key: "global-classes",
|
|
117
157
|
priority: 30,
|
|
118
158
|
actions: {
|
|
119
159
|
get: () => selectOrderedGlobalClasses(getState()),
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
const
|
|
160
|
+
getById: (id) => selectClass(getState(), id),
|
|
161
|
+
create: (label) => {
|
|
162
|
+
const classes = selectGlobalClasses(getState());
|
|
163
|
+
const existingLabels = Object.values(classes).map((style) => style.label);
|
|
164
|
+
if (existingLabels.includes(label)) {
|
|
165
|
+
throw new GlobalClassLabelAlreadyExistsError({ context: { label } });
|
|
166
|
+
}
|
|
167
|
+
const existingIds = Object.keys(classes);
|
|
168
|
+
const id = generateId("g-", existingIds);
|
|
123
169
|
dispatch(
|
|
124
170
|
slice.actions.add({
|
|
125
|
-
|
|
126
|
-
|
|
171
|
+
id,
|
|
172
|
+
type: "class",
|
|
173
|
+
label,
|
|
174
|
+
variants: []
|
|
127
175
|
})
|
|
128
176
|
);
|
|
129
|
-
return
|
|
177
|
+
return id;
|
|
130
178
|
},
|
|
131
|
-
update:
|
|
132
|
-
const style = selectClass(getState(), payload.id);
|
|
133
|
-
const mergedData = { ...style, ...payload };
|
|
134
|
-
const res = await apiClient.put(payload.id, mergedData);
|
|
135
|
-
const { data, meta } = res.data;
|
|
179
|
+
update: (payload) => {
|
|
136
180
|
dispatch(
|
|
137
181
|
slice.actions.update({
|
|
138
|
-
style:
|
|
139
|
-
|
|
182
|
+
style: payload
|
|
183
|
+
})
|
|
184
|
+
);
|
|
185
|
+
},
|
|
186
|
+
delete: (id) => {
|
|
187
|
+
dispatch(slice.actions.delete(id));
|
|
188
|
+
},
|
|
189
|
+
setOrder: (order) => {
|
|
190
|
+
dispatch(slice.actions.setOrder(order));
|
|
191
|
+
},
|
|
192
|
+
updateProps: (args) => {
|
|
193
|
+
dispatch(
|
|
194
|
+
slice.actions.updateProps({
|
|
195
|
+
id: args.id,
|
|
196
|
+
meta: args.meta,
|
|
197
|
+
props: args.props
|
|
140
198
|
})
|
|
141
199
|
);
|
|
142
|
-
return data;
|
|
143
200
|
}
|
|
144
201
|
},
|
|
145
|
-
subscribe: (cb) =>
|
|
202
|
+
subscribe: (cb) => subscribeWithSelector((state) => state.globalClasses, cb),
|
|
146
203
|
labels: {
|
|
147
|
-
singular:
|
|
148
|
-
plural:
|
|
204
|
+
singular: __("Global class", "elementor"),
|
|
205
|
+
plural: __("Global CSS Classes", "elementor")
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
// src/components/class-manager/delete-confirmation-dialog.tsx
|
|
210
|
+
import * as React from "react";
|
|
211
|
+
import { createContext, useContext, useState } from "react";
|
|
212
|
+
import { AlertOctagonFilledIcon } from "@elementor/icons";
|
|
213
|
+
import {
|
|
214
|
+
Button,
|
|
215
|
+
Dialog,
|
|
216
|
+
DialogActions,
|
|
217
|
+
DialogContent,
|
|
218
|
+
DialogContentText,
|
|
219
|
+
DialogTitle,
|
|
220
|
+
Typography
|
|
221
|
+
} from "@elementor/ui";
|
|
222
|
+
import { __ as __2 } from "@wordpress/i18n";
|
|
223
|
+
var context = createContext(null);
|
|
224
|
+
var DeleteConfirmationProvider = ({ children }) => {
|
|
225
|
+
const [dialogProps, setDialogProps] = useState(null);
|
|
226
|
+
const openDialog = (props) => {
|
|
227
|
+
setDialogProps(props);
|
|
228
|
+
};
|
|
229
|
+
const closeDialog = () => {
|
|
230
|
+
setDialogProps(null);
|
|
231
|
+
};
|
|
232
|
+
return /* @__PURE__ */ React.createElement(context.Provider, { value: { openDialog, closeDialog, dialogProps } }, children, !!dialogProps && /* @__PURE__ */ React.createElement(DeleteConfirmationDialog, { ...dialogProps }));
|
|
233
|
+
};
|
|
234
|
+
var TITLE_ID = "delete-class-dialog";
|
|
235
|
+
var DeleteConfirmationDialog = ({ label, id }) => {
|
|
236
|
+
const { closeDialog } = useDeleteConfirmation();
|
|
237
|
+
const onConfirm = () => {
|
|
238
|
+
globalClassesStylesProvider.actions.delete(id);
|
|
239
|
+
closeDialog();
|
|
240
|
+
};
|
|
241
|
+
return /* @__PURE__ */ React.createElement(Dialog, { open: true, onClose: closeDialog, "aria-labelledby": TITLE_ID, maxWidth: "xs" }, /* @__PURE__ */ React.createElement(DialogTitle, { id: TITLE_ID, display: "flex", alignItems: "center", gap: 1, sx: { lineHeight: 1 } }, /* @__PURE__ */ React.createElement(AlertOctagonFilledIcon, { color: "error" }), __2("Delete global class", "elementor")), /* @__PURE__ */ React.createElement(DialogContent, null, /* @__PURE__ */ React.createElement(DialogContentText, { variant: "body2", color: "textPrimary" }, __2("Deleting", "elementor"), /* @__PURE__ */ React.createElement(Typography, { variant: "subtitle2", component: "span" }, "\xA0", label, "\xA0"), __2(
|
|
242
|
+
"will permanently remove it from your project and may affect the design across all elements using it. This action cannot be undone.",
|
|
243
|
+
"elementor"
|
|
244
|
+
))), /* @__PURE__ */ React.createElement(DialogActions, null, /* @__PURE__ */ React.createElement(Button, { color: "secondary", onClick: closeDialog }, __2("Cancel", "elementor")), /* @__PURE__ */ React.createElement(Button, { variant: "contained", color: "error", onClick: onConfirm }, __2("Delete", "elementor"))));
|
|
245
|
+
};
|
|
246
|
+
var useDeleteConfirmation = () => {
|
|
247
|
+
const contextValue = useContext(context);
|
|
248
|
+
if (!contextValue) {
|
|
249
|
+
throw new Error("useDeleteConfirmation must be used within a DeleteConfirmationProvider");
|
|
250
|
+
}
|
|
251
|
+
return contextValue;
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
// src/components/class-manager/sortable.tsx
|
|
255
|
+
import * as React2 from "react";
|
|
256
|
+
import { GripVerticalIcon } from "@elementor/icons";
|
|
257
|
+
import {
|
|
258
|
+
Box,
|
|
259
|
+
Paper,
|
|
260
|
+
styled,
|
|
261
|
+
UnstableSortableItem,
|
|
262
|
+
UnstableSortableProvider
|
|
263
|
+
} from "@elementor/ui";
|
|
264
|
+
var SortableProvider = (props) => /* @__PURE__ */ React2.createElement(UnstableSortableProvider, { restrictAxis: true, variant: "static", dragPlaceholderStyle: { opacity: "1" }, ...props });
|
|
265
|
+
var SortableTrigger = (props) => /* @__PURE__ */ React2.createElement("div", { ...props, role: "button", className: "class-item-sortable-trigger" }, /* @__PURE__ */ React2.createElement(GripVerticalIcon, { fontSize: "tiny" }));
|
|
266
|
+
var SortableItem = ({ children, id }) => {
|
|
267
|
+
return /* @__PURE__ */ React2.createElement(
|
|
268
|
+
UnstableSortableItem,
|
|
269
|
+
{
|
|
270
|
+
id,
|
|
271
|
+
render: ({
|
|
272
|
+
itemProps,
|
|
273
|
+
isDragged,
|
|
274
|
+
triggerProps,
|
|
275
|
+
itemStyle,
|
|
276
|
+
triggerStyle,
|
|
277
|
+
dropIndicationStyle,
|
|
278
|
+
showDropIndication
|
|
279
|
+
}) => {
|
|
280
|
+
return /* @__PURE__ */ React2.createElement(StyledSortableItem, { ...itemProps, elevation: 0, sx: itemStyle, role: "listitem" }, /* @__PURE__ */ React2.createElement(SortableTrigger, { ...triggerProps, style: triggerStyle }), children({
|
|
281
|
+
itemProps,
|
|
282
|
+
isDragged,
|
|
283
|
+
triggerProps,
|
|
284
|
+
itemStyle,
|
|
285
|
+
triggerStyle,
|
|
286
|
+
dropIndicationStyle,
|
|
287
|
+
showDropIndication
|
|
288
|
+
}));
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
);
|
|
292
|
+
};
|
|
293
|
+
var StyledSortableItem = styled(Paper)`
|
|
294
|
+
position: relative;
|
|
295
|
+
|
|
296
|
+
&:hover {
|
|
297
|
+
& .class-item-sortable-trigger {
|
|
298
|
+
visibility: visible;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
& .class-item-sortable-trigger {
|
|
303
|
+
visibility: hidden;
|
|
304
|
+
position: absolute;
|
|
305
|
+
left: 0;
|
|
306
|
+
top: 50%;
|
|
307
|
+
transform: translate( -75%, -50% );
|
|
308
|
+
}
|
|
309
|
+
`;
|
|
310
|
+
var SortableItemIndicator = styled(Box)`
|
|
311
|
+
width: 100%;
|
|
312
|
+
height: 3px;
|
|
313
|
+
border-radius: ${({ theme }) => theme.spacing(0.5)};
|
|
314
|
+
background-color: ${({ theme }) => theme.palette.text.primary};
|
|
315
|
+
`;
|
|
316
|
+
|
|
317
|
+
// src/components/class-manager/global-classes-list.tsx
|
|
318
|
+
var GlobalClassesList = () => {
|
|
319
|
+
const cssClasses = useOrderedGlobalClasses();
|
|
320
|
+
const [classesOrder, reorderClasses] = useClassesOrder();
|
|
321
|
+
if (!cssClasses?.length) {
|
|
322
|
+
return /* @__PURE__ */ React3.createElement(EmptyState, null);
|
|
323
|
+
}
|
|
324
|
+
return /* @__PURE__ */ React3.createElement(DeleteConfirmationProvider, null, /* @__PURE__ */ React3.createElement(List, { sx: { display: "flex", flexDirection: "column", gap: 0.5 } }, /* @__PURE__ */ React3.createElement(SortableProvider, { value: classesOrder, onChange: reorderClasses }, cssClasses?.map(({ id, label }) => {
|
|
325
|
+
const renameClass = (newLabel) => {
|
|
326
|
+
globalClassesStylesProvider.actions.update({ label: newLabel, id });
|
|
327
|
+
};
|
|
328
|
+
return /* @__PURE__ */ React3.createElement(SortableItem, { key: id, id }, ({ isDragged, showDropIndication, dropIndicationStyle }) => /* @__PURE__ */ React3.createElement(
|
|
329
|
+
ClassItem,
|
|
330
|
+
{
|
|
331
|
+
id,
|
|
332
|
+
label,
|
|
333
|
+
renameClass,
|
|
334
|
+
selected: isDragged
|
|
335
|
+
},
|
|
336
|
+
showDropIndication && /* @__PURE__ */ React3.createElement(SortableItemIndicator, { style: dropIndicationStyle })
|
|
337
|
+
));
|
|
338
|
+
}))));
|
|
339
|
+
};
|
|
340
|
+
var useClassesOrder = () => {
|
|
341
|
+
const order = useGlobalClassesOrder();
|
|
342
|
+
const reorder = (newIds) => {
|
|
343
|
+
globalClassesStylesProvider.actions.setOrder(newIds);
|
|
344
|
+
};
|
|
345
|
+
return [order, reorder];
|
|
346
|
+
};
|
|
347
|
+
var ClassItem = ({
|
|
348
|
+
id,
|
|
349
|
+
label,
|
|
350
|
+
renameClass,
|
|
351
|
+
selected,
|
|
352
|
+
children
|
|
353
|
+
}) => {
|
|
354
|
+
const {
|
|
355
|
+
ref: editableRef,
|
|
356
|
+
openEditMode,
|
|
357
|
+
isEditing,
|
|
358
|
+
error,
|
|
359
|
+
getProps: getEditableProps
|
|
360
|
+
} = useEditable({
|
|
361
|
+
value: label,
|
|
362
|
+
onSubmit: renameClass,
|
|
363
|
+
validation: validateLabel
|
|
364
|
+
});
|
|
365
|
+
const { openDialog } = useDeleteConfirmation();
|
|
366
|
+
const popupState = usePopupState({
|
|
367
|
+
variant: "popover",
|
|
368
|
+
disableAutoFocus: true
|
|
369
|
+
});
|
|
370
|
+
return /* @__PURE__ */ React3.createElement(Stack, { direction: "row", alignItems: "center", gap: 1, flexGrow: 1, flexShrink: 0 }, /* @__PURE__ */ React3.createElement(
|
|
371
|
+
StyledListItem,
|
|
372
|
+
{
|
|
373
|
+
component: "div",
|
|
374
|
+
disablePadding: true,
|
|
375
|
+
disableGutters: true,
|
|
376
|
+
secondaryAction: /* @__PURE__ */ React3.createElement(
|
|
377
|
+
Tooltip,
|
|
378
|
+
{
|
|
379
|
+
placement: "top",
|
|
380
|
+
className: "class-item-more-actions",
|
|
381
|
+
title: __3("More actions", "elementor")
|
|
382
|
+
},
|
|
383
|
+
/* @__PURE__ */ React3.createElement(IconButton, { size: "tiny", ...bindTrigger(popupState), "aria-label": "More actions" }, /* @__PURE__ */ React3.createElement(DotsVerticalIcon, { fontSize: "tiny" }))
|
|
384
|
+
)
|
|
385
|
+
},
|
|
386
|
+
/* @__PURE__ */ React3.createElement(
|
|
387
|
+
ListItemButton,
|
|
388
|
+
{
|
|
389
|
+
dense: true,
|
|
390
|
+
disableGutters: true,
|
|
391
|
+
shape: "rounded",
|
|
392
|
+
onDoubleClick: openEditMode,
|
|
393
|
+
selected: selected || popupState.isOpen,
|
|
394
|
+
focusVisibleClassName: "visible-class-item",
|
|
395
|
+
sx: {
|
|
396
|
+
minHeight: "36px",
|
|
397
|
+
display: "flex",
|
|
398
|
+
"&.visible-class-item": {
|
|
399
|
+
boxShadow: "none !important"
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
},
|
|
403
|
+
/* @__PURE__ */ React3.createElement(Indicator, { isActive: isEditing, isError: !!error }, isEditing ? /* @__PURE__ */ React3.createElement(
|
|
404
|
+
EditableField,
|
|
405
|
+
{
|
|
406
|
+
ref: editableRef,
|
|
407
|
+
error,
|
|
408
|
+
as: Typography2,
|
|
409
|
+
variant: "caption",
|
|
410
|
+
...getEditableProps()
|
|
411
|
+
}
|
|
412
|
+
) : /* @__PURE__ */ React3.createElement(EllipsisWithTooltip, { title: label, as: Typography2, variant: "caption" }))
|
|
413
|
+
),
|
|
414
|
+
children,
|
|
415
|
+
/* @__PURE__ */ React3.createElement(
|
|
416
|
+
Menu,
|
|
417
|
+
{
|
|
418
|
+
...bindMenu(popupState),
|
|
419
|
+
anchorOrigin: {
|
|
420
|
+
vertical: "bottom",
|
|
421
|
+
horizontal: "right"
|
|
422
|
+
},
|
|
423
|
+
transformOrigin: {
|
|
424
|
+
vertical: "top",
|
|
425
|
+
horizontal: "right"
|
|
426
|
+
}
|
|
427
|
+
},
|
|
428
|
+
/* @__PURE__ */ React3.createElement(
|
|
429
|
+
MenuItem,
|
|
430
|
+
{
|
|
431
|
+
sx: { minWidth: "160px" },
|
|
432
|
+
onClick: () => {
|
|
433
|
+
popupState.close();
|
|
434
|
+
openEditMode();
|
|
435
|
+
}
|
|
436
|
+
},
|
|
437
|
+
/* @__PURE__ */ React3.createElement(ListItemText, { primary: __3("Rename", "elementor") })
|
|
438
|
+
),
|
|
439
|
+
/* @__PURE__ */ React3.createElement(
|
|
440
|
+
MenuItem,
|
|
441
|
+
{
|
|
442
|
+
onClick: () => {
|
|
443
|
+
popupState.close();
|
|
444
|
+
openDialog({ id, label });
|
|
445
|
+
}
|
|
446
|
+
},
|
|
447
|
+
/* @__PURE__ */ React3.createElement(ListItemText, { primary: __3("Delete", "elementor"), sx: { color: "error.light" } })
|
|
448
|
+
)
|
|
449
|
+
)
|
|
450
|
+
));
|
|
451
|
+
};
|
|
452
|
+
var StyledListItem = styled2(ListItem)`
|
|
453
|
+
.class-item-more-actions {
|
|
454
|
+
visibility: hidden;
|
|
455
|
+
}
|
|
456
|
+
&:hover {
|
|
457
|
+
.class-item-more-actions {
|
|
458
|
+
visibility: visible;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
`;
|
|
462
|
+
var EmptyState = () => /* @__PURE__ */ React3.createElement(Stack, { alignItems: "center", gap: 3, pt: 4, px: 0.5 }, /* @__PURE__ */ React3.createElement(PhotoIcon, { fontSize: "large" }), /* @__PURE__ */ React3.createElement(StyledHeader, { variant: "subtitle2", component: "h2", color: "text.secondary" }, __3("No CSS classes created yet", "elementor")), /* @__PURE__ */ React3.createElement(Typography2, { align: "center", variant: "caption", color: "text.secondary" }, __3(
|
|
463
|
+
"CSS classes created in the editor panel will appear here. Once they are available, you can arrange their hierarchy, rename them, or delete them as needed.",
|
|
464
|
+
"elementor"
|
|
465
|
+
)));
|
|
466
|
+
var StyledHeader = styled2(Typography2)(({ theme, variant }) => ({
|
|
467
|
+
"&.MuiTypography-root": {
|
|
468
|
+
...theme.typography[variant]
|
|
469
|
+
}
|
|
470
|
+
}));
|
|
471
|
+
var Indicator = styled2(Box2, {
|
|
472
|
+
shouldForwardProp: (prop) => !["isActive", "isError"].includes(prop)
|
|
473
|
+
})(({ theme, isActive, isError }) => ({
|
|
474
|
+
display: "flex",
|
|
475
|
+
width: "100%",
|
|
476
|
+
flexGrow: 1,
|
|
477
|
+
borderRadius: theme.spacing(0.5),
|
|
478
|
+
border: getIndicatorBorder({ isActive, isError, theme }),
|
|
479
|
+
padding: `0 ${theme.spacing(1)}`,
|
|
480
|
+
marginLeft: isActive ? theme.spacing(1) : 0
|
|
481
|
+
}));
|
|
482
|
+
var getIndicatorBorder = ({ isActive, isError, theme }) => {
|
|
483
|
+
if (isError) {
|
|
484
|
+
return `2px solid ${theme.palette.error.main}`;
|
|
485
|
+
}
|
|
486
|
+
if (isActive) {
|
|
487
|
+
return `2px solid ${theme.palette.secondary.main}`;
|
|
488
|
+
}
|
|
489
|
+
return "none";
|
|
490
|
+
};
|
|
491
|
+
var validateLabel = (newLabel) => {
|
|
492
|
+
if (!stylesRepository.isLabelValid(newLabel)) {
|
|
493
|
+
return __3("Format is not valid", "elementor");
|
|
494
|
+
}
|
|
495
|
+
if (stylesRepository.isLabelExist(newLabel)) {
|
|
496
|
+
return __3("Existing name", "elementor");
|
|
149
497
|
}
|
|
150
498
|
};
|
|
151
499
|
|
|
500
|
+
// src/components/class-manager/class-manager-panel.tsx
|
|
501
|
+
var { panel, usePanelActions } = createPanel({
|
|
502
|
+
id: "class-manager-panel",
|
|
503
|
+
component: ClassManagerPanel
|
|
504
|
+
});
|
|
505
|
+
function ClassManagerPanel() {
|
|
506
|
+
return /* @__PURE__ */ React4.createElement(ErrorBoundary, { fallback: /* @__PURE__ */ React4.createElement(ErrorBoundaryFallback, null) }, /* @__PURE__ */ React4.createElement(Panel, null, /* @__PURE__ */ React4.createElement(PanelHeader, null, /* @__PURE__ */ React4.createElement(Stack2, { p: 1, pl: 2, width: "100%", direction: "row", alignItems: "center" }, /* @__PURE__ */ React4.createElement(PanelHeaderTitle, { sx: { display: "flex", alignItems: "center", gap: 0.5 } }, /* @__PURE__ */ React4.createElement(ColorSwatchIcon, { fontSize: "inherit", sx: { transform: "rotate(90deg)" } }), __4("CSS Class manager")), /* @__PURE__ */ React4.createElement(CloseButton, { sx: { marginLeft: "auto" } }))), /* @__PURE__ */ React4.createElement(PanelBody, { px: 2 }, /* @__PURE__ */ React4.createElement(GlobalClassesList, null))));
|
|
507
|
+
}
|
|
508
|
+
var CloseButton = (props) => {
|
|
509
|
+
const { close } = usePanelActions();
|
|
510
|
+
return /* @__PURE__ */ React4.createElement(IconButton2, { size: "small", color: "secondary", onClick: close, ...props }, /* @__PURE__ */ React4.createElement(XIcon, { fontSize: "small" }));
|
|
511
|
+
};
|
|
512
|
+
var ErrorBoundaryFallback = () => /* @__PURE__ */ React4.createElement(Box3, { role: "alert", sx: { minHeight: "100%", p: 2 } }, /* @__PURE__ */ React4.createElement(Alert, { severity: "error", sx: { mb: 2, maxWidth: 400, textAlign: "center" } }, /* @__PURE__ */ React4.createElement("strong", null, __4("Something went wrong", "elementor"))));
|
|
513
|
+
|
|
514
|
+
// src/components/class-manager/class-manager-button.tsx
|
|
515
|
+
var ClassManagerButton = () => {
|
|
516
|
+
const { open } = usePanelActions();
|
|
517
|
+
return /* @__PURE__ */ React5.createElement(Tooltip2, { title: __5("Class manager"), placement: "top" }, /* @__PURE__ */ React5.createElement(IconButton3, { onClick: open }, /* @__PURE__ */ React5.createElement(ColorSwatchIcon2, { fontSize: "tiny" })));
|
|
518
|
+
};
|
|
519
|
+
|
|
520
|
+
// src/components/populate-store.tsx
|
|
521
|
+
import { useEffect } from "react";
|
|
522
|
+
import { __useDispatch as useDispatch } from "@elementor/store";
|
|
523
|
+
|
|
524
|
+
// src/api.ts
|
|
525
|
+
import { httpService } from "@elementor/http";
|
|
526
|
+
var RESOURCE_URL = "/global-classes";
|
|
527
|
+
var apiClient = {
|
|
528
|
+
all: () => httpService().get("elementor/v1" + RESOURCE_URL),
|
|
529
|
+
update: (payload) => httpService().put("elementor/v1" + RESOURCE_URL, payload)
|
|
530
|
+
};
|
|
531
|
+
|
|
532
|
+
// src/components/populate-store.tsx
|
|
533
|
+
function PopulateStore() {
|
|
534
|
+
const dispatch2 = useDispatch();
|
|
535
|
+
useEffect(() => {
|
|
536
|
+
apiClient.all().then((res) => {
|
|
537
|
+
const { data, meta } = res.data;
|
|
538
|
+
dispatch2(slice.actions.init({ items: data, order: meta.order }));
|
|
539
|
+
});
|
|
540
|
+
}, [dispatch2]);
|
|
541
|
+
return null;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// src/sync-with-document-save.ts
|
|
545
|
+
import { __privateRunCommandSync as runCommandSync, registerDataHook } from "@elementor/editor-v1-adapters";
|
|
546
|
+
import { __dispatch, __getState as getState2, __subscribeWithSelector as subscribeWithSelector2 } from "@elementor/store";
|
|
547
|
+
function syncWithDocumentSave() {
|
|
548
|
+
const unsubscribe = syncDirtyState();
|
|
549
|
+
bindSaveAction();
|
|
550
|
+
return unsubscribe;
|
|
551
|
+
}
|
|
552
|
+
function syncDirtyState() {
|
|
553
|
+
return subscribeWithSelector2(selectIsDirty, () => {
|
|
554
|
+
if (!isDirty()) {
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
runCommandSync("document/save/set-is-modified", { status: true }, { internal: true });
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
function bindSaveAction() {
|
|
561
|
+
registerDataHook("after", "document/save/save", async () => {
|
|
562
|
+
if (!isDirty()) {
|
|
563
|
+
return;
|
|
564
|
+
}
|
|
565
|
+
const state = getState2().globalClasses;
|
|
566
|
+
await apiClient.update({
|
|
567
|
+
items: state.items,
|
|
568
|
+
order: state.order
|
|
569
|
+
});
|
|
570
|
+
__dispatch(slice.actions.setPristine());
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
function isDirty() {
|
|
574
|
+
return selectIsDirty(getState2());
|
|
575
|
+
}
|
|
576
|
+
|
|
152
577
|
// src/init.ts
|
|
153
578
|
function init() {
|
|
154
579
|
registerSlice(slice);
|
|
155
580
|
registerPanel(panel);
|
|
156
|
-
|
|
581
|
+
stylesRepository2.register(globalClassesStylesProvider);
|
|
157
582
|
injectIntoLogic({
|
|
158
|
-
id: "global-classes-
|
|
159
|
-
component:
|
|
583
|
+
id: "global-classes-populate-store",
|
|
584
|
+
component: PopulateStore
|
|
160
585
|
});
|
|
161
586
|
injectIntoClassSelectorActions({
|
|
162
|
-
id: "global-classes",
|
|
587
|
+
id: "global-classes-manager-button",
|
|
163
588
|
component: ClassManagerButton
|
|
164
589
|
});
|
|
590
|
+
listenTo(v1ReadyEvent(), () => {
|
|
591
|
+
syncWithDocumentSave();
|
|
592
|
+
});
|
|
165
593
|
}
|
|
166
594
|
|
|
167
595
|
// src/index.ts
|