@elementor/editor-components 3.33.0-99 → 3.34.2
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/dist/index.js +1860 -123
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1863 -110
- package/dist/index.mjs.map +1 -1
- package/package.json +21 -11
- package/src/api.ts +57 -11
- package/src/component-instance-transformer.ts +24 -0
- package/src/component-overridable-transformer.ts +28 -0
- package/src/components/components-tab/component-search.tsx +32 -0
- package/src/components/components-tab/components-item.tsx +67 -0
- package/src/components/components-tab/components-list.tsx +141 -0
- package/src/components/components-tab/components.tsx +17 -0
- package/src/components/components-tab/loading-components.tsx +43 -0
- package/src/components/components-tab/search-provider.tsx +38 -0
- package/src/components/consts.ts +1 -0
- package/src/components/create-component-form/create-component-form.tsx +109 -100
- package/src/components/create-component-form/utils/get-component-event-data.ts +54 -0
- package/src/components/create-component-form/utils/replace-element-with-component.ts +28 -10
- package/src/components/edit-component/component-modal.tsx +134 -0
- package/src/components/edit-component/edit-component.tsx +134 -0
- package/src/components/in-edit-mode.tsx +43 -0
- package/src/components/overridable-props/indicator.tsx +81 -0
- package/src/components/overridable-props/overridable-prop-form.tsx +98 -0
- package/src/components/overridable-props/overridable-prop-indicator.tsx +128 -0
- package/src/components/overridable-props/utils/get-overridable-prop.ts +20 -0
- package/src/create-component-type.ts +194 -0
- package/src/hooks/use-canvas-document.ts +6 -0
- package/src/hooks/use-components.ts +6 -9
- package/src/hooks/use-element-rect.ts +81 -0
- package/src/init.ts +82 -3
- package/src/mcp/index.ts +14 -0
- package/src/mcp/save-as-component-tool.ts +92 -0
- package/src/populate-store.ts +12 -0
- package/src/prop-types/component-overridable-prop-type.ts +17 -0
- package/src/store/actions.ts +21 -0
- package/src/store/components-styles-provider.ts +24 -0
- package/src/store/create-unpublished-component.ts +40 -0
- package/src/store/load-components-assets.ts +26 -0
- package/src/store/load-components-styles.ts +44 -0
- package/src/store/remove-component-styles.ts +9 -0
- package/src/store/set-overridable-prop.ts +161 -0
- package/src/store/store.ts +168 -0
- package/src/store/thunks.ts +10 -0
- package/src/sync/before-save.ts +15 -0
- package/src/sync/create-components-before-save.ts +108 -0
- package/src/sync/update-components-before-save.ts +36 -0
- package/src/types.ts +91 -0
- package/src/utils/component-document-data.ts +19 -0
- package/src/utils/get-component-ids.ts +36 -0
- package/src/utils/get-container-for-new-element.ts +49 -0
- package/src/utils/tracking.ts +47 -0
- package/src/components/components-tab.tsx +0 -6
- package/src/hooks/use-create-component.ts +0 -13
package/dist/index.mjs
CHANGED
|
@@ -1,54 +1,864 @@
|
|
|
1
1
|
// src/init.ts
|
|
2
|
-
import { injectIntoTop } from "@elementor/editor";
|
|
2
|
+
import { injectIntoLogic, injectIntoTop } from "@elementor/editor";
|
|
3
|
+
import {
|
|
4
|
+
registerElementType,
|
|
5
|
+
settingsTransformersRegistry as settingsTransformersRegistry2
|
|
6
|
+
} from "@elementor/editor-canvas";
|
|
7
|
+
import { getV1CurrentDocument as getV1CurrentDocument2 } from "@elementor/editor-documents";
|
|
8
|
+
import { FIELD_TYPE, registerFieldIndicator } from "@elementor/editor-editing-panel";
|
|
3
9
|
import { injectTab } from "@elementor/editor-elements-panel";
|
|
4
|
-
import {
|
|
10
|
+
import { stylesRepository } from "@elementor/editor-styles-repository";
|
|
11
|
+
import { registerDataHook } from "@elementor/editor-v1-adapters";
|
|
12
|
+
import { __registerSlice as registerSlice } from "@elementor/store";
|
|
13
|
+
import { __ as __12 } from "@wordpress/i18n";
|
|
5
14
|
|
|
6
|
-
// src/
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
9
|
-
function ComponentsTab() {
|
|
10
|
-
return /* @__PURE__ */ React.createElement(Box, { px: 2 }, "This is the Components tab.");
|
|
11
|
-
}
|
|
15
|
+
// src/component-instance-transformer.ts
|
|
16
|
+
import { createTransformer } from "@elementor/editor-canvas";
|
|
17
|
+
import { __getState as getState } from "@elementor/store";
|
|
12
18
|
|
|
13
|
-
// src/
|
|
14
|
-
import
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
import { StarIcon } from "@elementor/icons";
|
|
19
|
-
import { Alert, Button, FormLabel, Grid, Popover, Snackbar, Stack, TextField, Typography } from "@elementor/ui";
|
|
20
|
-
import { __ as __2 } from "@wordpress/i18n";
|
|
19
|
+
// src/store/store.ts
|
|
20
|
+
import {
|
|
21
|
+
__createSelector as createSelector,
|
|
22
|
+
__createSlice as createSlice
|
|
23
|
+
} from "@elementor/store";
|
|
21
24
|
|
|
22
|
-
// src/
|
|
23
|
-
import {
|
|
25
|
+
// src/store/thunks.ts
|
|
26
|
+
import { __createAsyncThunk as createAsyncThunk } from "@elementor/store";
|
|
24
27
|
|
|
25
28
|
// src/api.ts
|
|
29
|
+
import { ajax } from "@elementor/editor-v1-adapters";
|
|
26
30
|
import { httpService } from "@elementor/http-client";
|
|
27
31
|
var BASE_URL = "elementor/v1/components";
|
|
32
|
+
var LOCK_COMPONENT = `${BASE_URL}/lock`;
|
|
33
|
+
var UNLOCK_COMPONENT = `${BASE_URL}/unlock`;
|
|
34
|
+
var BASE_URL_LOCK_STATUS = `${BASE_URL}/lock-status`;
|
|
35
|
+
var getParams = (id) => ({
|
|
36
|
+
action: "get_document_config",
|
|
37
|
+
unique_id: `document-config-${id}`,
|
|
38
|
+
data: { id }
|
|
39
|
+
});
|
|
28
40
|
var apiClient = {
|
|
29
41
|
get: () => httpService().get(`${BASE_URL}`).then((res) => res.data.data),
|
|
30
|
-
create: (payload) => httpService().post(`${BASE_URL}`, payload).then((res) => res.data.data)
|
|
42
|
+
create: (payload) => httpService().post(`${BASE_URL}`, payload).then((res) => res.data.data),
|
|
43
|
+
updateStatuses: (ids, status) => httpService().put(`${BASE_URL}/status`, {
|
|
44
|
+
ids,
|
|
45
|
+
status
|
|
46
|
+
}),
|
|
47
|
+
getComponentConfig: (id) => ajax.load(getParams(id)),
|
|
48
|
+
invalidateComponentConfigCache: (id) => ajax.invalidateCache(getParams(id)),
|
|
49
|
+
getComponentLockStatus: async (componentId) => await httpService().get(`${BASE_URL_LOCK_STATUS}`, {
|
|
50
|
+
params: {
|
|
51
|
+
componentId
|
|
52
|
+
}
|
|
53
|
+
}).then((res) => {
|
|
54
|
+
const { is_current_user_allow_to_edit: isAllowedToSwitchDocument, locked_by: lockedBy } = res.data.data;
|
|
55
|
+
return { isAllowedToSwitchDocument, lockedBy: lockedBy || "" };
|
|
56
|
+
}),
|
|
57
|
+
lockComponent: async (componentId) => await httpService().post(LOCK_COMPONENT, {
|
|
58
|
+
componentId
|
|
59
|
+
}).then((res) => res.data),
|
|
60
|
+
unlockComponent: async (componentId) => await httpService().post(UNLOCK_COMPONENT, {
|
|
61
|
+
componentId
|
|
62
|
+
}).then((res) => res.data)
|
|
31
63
|
};
|
|
32
64
|
|
|
65
|
+
// src/store/thunks.ts
|
|
66
|
+
var loadComponents = createAsyncThunk("components/load", async () => {
|
|
67
|
+
const response = await apiClient.get();
|
|
68
|
+
return response;
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// src/store/store.ts
|
|
72
|
+
var initialState = {
|
|
73
|
+
data: [],
|
|
74
|
+
unpublishedData: [],
|
|
75
|
+
loadStatus: "idle",
|
|
76
|
+
styles: {},
|
|
77
|
+
createdThisSession: [],
|
|
78
|
+
path: [],
|
|
79
|
+
currentComponentId: null
|
|
80
|
+
};
|
|
81
|
+
var SLICE_NAME = "components";
|
|
82
|
+
var slice = createSlice({
|
|
83
|
+
name: SLICE_NAME,
|
|
84
|
+
initialState,
|
|
85
|
+
reducers: {
|
|
86
|
+
add: (state, { payload }) => {
|
|
87
|
+
if (Array.isArray(payload)) {
|
|
88
|
+
state.data = [...state.data, ...payload];
|
|
89
|
+
} else {
|
|
90
|
+
state.data.unshift(payload);
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
load: (state, { payload }) => {
|
|
94
|
+
state.data = payload;
|
|
95
|
+
},
|
|
96
|
+
addUnpublished: (state, { payload }) => {
|
|
97
|
+
state.unpublishedData.unshift(payload);
|
|
98
|
+
},
|
|
99
|
+
resetUnpublished: (state) => {
|
|
100
|
+
state.unpublishedData = [];
|
|
101
|
+
},
|
|
102
|
+
removeStyles(state, { payload }) {
|
|
103
|
+
const { [payload.id]: _, ...rest } = state.styles;
|
|
104
|
+
state.styles = rest;
|
|
105
|
+
},
|
|
106
|
+
addStyles: (state, { payload }) => {
|
|
107
|
+
state.styles = { ...state.styles, ...payload };
|
|
108
|
+
},
|
|
109
|
+
addCreatedThisSession: (state, { payload }) => {
|
|
110
|
+
state.createdThisSession.push(payload);
|
|
111
|
+
},
|
|
112
|
+
setCurrentComponentId: (state, { payload }) => {
|
|
113
|
+
state.currentComponentId = payload;
|
|
114
|
+
},
|
|
115
|
+
setPath: (state, { payload }) => {
|
|
116
|
+
state.path = payload;
|
|
117
|
+
},
|
|
118
|
+
setOverridableProps: (state, { payload }) => {
|
|
119
|
+
const component = state.data.find((comp) => comp.id === payload.componentId);
|
|
120
|
+
if (!component) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
component.overridableProps = payload.overridableProps;
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
extraReducers: (builder) => {
|
|
127
|
+
builder.addCase(loadComponents.fulfilled, (state, { payload }) => {
|
|
128
|
+
state.data = payload;
|
|
129
|
+
state.loadStatus = "idle";
|
|
130
|
+
});
|
|
131
|
+
builder.addCase(loadComponents.pending, (state) => {
|
|
132
|
+
state.loadStatus = "pending";
|
|
133
|
+
});
|
|
134
|
+
builder.addCase(loadComponents.rejected, (state) => {
|
|
135
|
+
state.loadStatus = "error";
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
var selectData = (state) => state[SLICE_NAME].data;
|
|
140
|
+
var selectLoadStatus = (state) => state[SLICE_NAME].loadStatus;
|
|
141
|
+
var selectStylesDefinitions = (state) => state[SLICE_NAME].styles ?? {};
|
|
142
|
+
var selectUnpublishedData = (state) => state[SLICE_NAME].unpublishedData;
|
|
143
|
+
var getCreatedThisSession = (state) => state[SLICE_NAME].createdThisSession;
|
|
144
|
+
var getPath = (state) => state[SLICE_NAME].path;
|
|
145
|
+
var getCurrentComponentId = (state) => state[SLICE_NAME].currentComponentId;
|
|
146
|
+
var selectComponent = (state, componentId) => state[SLICE_NAME].data.find((component) => component.id === componentId);
|
|
147
|
+
var selectComponents = createSelector(
|
|
148
|
+
selectData,
|
|
149
|
+
selectUnpublishedData,
|
|
150
|
+
(data, unpublishedData) => [
|
|
151
|
+
...unpublishedData.map((item) => ({ uid: item.uid, name: item.name })),
|
|
152
|
+
...data
|
|
153
|
+
]
|
|
154
|
+
);
|
|
155
|
+
var selectUnpublishedComponents = createSelector(
|
|
156
|
+
selectUnpublishedData,
|
|
157
|
+
(unpublishedData) => unpublishedData
|
|
158
|
+
);
|
|
159
|
+
var selectLoadIsPending = createSelector(selectLoadStatus, (status) => status === "pending");
|
|
160
|
+
var selectLoadIsError = createSelector(selectLoadStatus, (status) => status === "error");
|
|
161
|
+
var selectStyles = (state) => state[SLICE_NAME].styles ?? {};
|
|
162
|
+
var selectFlatStyles = createSelector(selectStylesDefinitions, (data) => Object.values(data).flat());
|
|
163
|
+
var selectCreatedThisSession = createSelector(
|
|
164
|
+
getCreatedThisSession,
|
|
165
|
+
(createdThisSession) => createdThisSession
|
|
166
|
+
);
|
|
167
|
+
var DEFAULT_OVERRIDABLE_PROPS = {
|
|
168
|
+
props: {},
|
|
169
|
+
groups: {
|
|
170
|
+
items: {},
|
|
171
|
+
order: []
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
var selectOverridableProps = createSelector(
|
|
175
|
+
selectComponent,
|
|
176
|
+
(component) => {
|
|
177
|
+
if (!component) {
|
|
178
|
+
return void 0;
|
|
179
|
+
}
|
|
180
|
+
return component.overridableProps ?? DEFAULT_OVERRIDABLE_PROPS;
|
|
181
|
+
}
|
|
182
|
+
);
|
|
183
|
+
var selectPath = createSelector(getPath, (path) => path);
|
|
184
|
+
var selectCurrentComponentId = createSelector(
|
|
185
|
+
getCurrentComponentId,
|
|
186
|
+
(currentComponentId) => currentComponentId
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
// src/utils/component-document-data.ts
|
|
190
|
+
import { getV1DocumentsManager } from "@elementor/editor-documents";
|
|
191
|
+
var getComponentDocumentData = async (id) => {
|
|
192
|
+
const documentManager = getV1DocumentsManager();
|
|
193
|
+
try {
|
|
194
|
+
return await documentManager.request(id);
|
|
195
|
+
} catch {
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
var invalidateComponentDocumentData = (id) => {
|
|
200
|
+
const documentManager = getV1DocumentsManager();
|
|
201
|
+
documentManager.invalidateCache(id);
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
// src/component-instance-transformer.ts
|
|
205
|
+
var componentInstanceTransformer = createTransformer(
|
|
206
|
+
async ({ component_id: id }) => {
|
|
207
|
+
const unpublishedComponents = selectUnpublishedComponents(getState());
|
|
208
|
+
const unpublishedComponent = unpublishedComponents.find(({ uid }) => uid === id);
|
|
209
|
+
if (unpublishedComponent) {
|
|
210
|
+
return structuredClone(unpublishedComponent.elements);
|
|
211
|
+
}
|
|
212
|
+
if (typeof id !== "number") {
|
|
213
|
+
throw new Error(`Component ID "${id}" not found.`);
|
|
214
|
+
}
|
|
215
|
+
const data = await getComponentDocumentData(id);
|
|
216
|
+
return data?.elements ?? [];
|
|
217
|
+
}
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
// src/component-overridable-transformer.ts
|
|
221
|
+
import { createTransformer as createTransformer2, settingsTransformersRegistry } from "@elementor/editor-canvas";
|
|
222
|
+
var componentOverridableTransformer = createTransformer2(
|
|
223
|
+
async (value, options) => {
|
|
224
|
+
return await transformOriginValue(value, options);
|
|
225
|
+
}
|
|
226
|
+
);
|
|
227
|
+
async function transformOriginValue(value, options) {
|
|
228
|
+
if (!value.origin_value || !value.origin_value.value || !value.origin_value.$$type) {
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
const transformer = settingsTransformersRegistry.get(value.origin_value.$$type);
|
|
232
|
+
if (!transformer) {
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
try {
|
|
236
|
+
return await transformer(value.origin_value.value, options);
|
|
237
|
+
} catch {
|
|
238
|
+
return null;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// src/components/components-tab/components.tsx
|
|
243
|
+
import * as React6 from "react";
|
|
244
|
+
import { ThemeProvider } from "@elementor/editor-ui";
|
|
245
|
+
|
|
246
|
+
// src/components/components-tab/component-search.tsx
|
|
247
|
+
import * as React2 from "react";
|
|
248
|
+
import { SearchIcon } from "@elementor/icons";
|
|
249
|
+
import { Box, InputAdornment, Stack, TextField } from "@elementor/ui";
|
|
250
|
+
import { __ } from "@wordpress/i18n";
|
|
251
|
+
|
|
252
|
+
// src/components/components-tab/search-provider.tsx
|
|
253
|
+
import * as React from "react";
|
|
254
|
+
import { createContext, useContext } from "react";
|
|
255
|
+
import { useSearchState } from "@elementor/utils";
|
|
256
|
+
var SearchContext = createContext(void 0);
|
|
257
|
+
var SearchProvider = ({
|
|
258
|
+
children,
|
|
259
|
+
localStorageKey
|
|
260
|
+
}) => {
|
|
261
|
+
const { debouncedValue, handleChange, inputValue } = useSearchState({ localStorageKey });
|
|
262
|
+
const clearSearch = () => {
|
|
263
|
+
handleChange("");
|
|
264
|
+
};
|
|
265
|
+
return /* @__PURE__ */ React.createElement(SearchContext.Provider, { value: { handleChange, clearSearch, searchValue: debouncedValue, inputValue } }, children);
|
|
266
|
+
};
|
|
267
|
+
var useSearch = () => {
|
|
268
|
+
const context = useContext(SearchContext);
|
|
269
|
+
if (!context) {
|
|
270
|
+
throw new Error("useSearch must be used within a SearchProvider");
|
|
271
|
+
}
|
|
272
|
+
return context;
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
// src/components/components-tab/component-search.tsx
|
|
276
|
+
var ComponentSearch = () => {
|
|
277
|
+
const { inputValue, handleChange } = useSearch();
|
|
278
|
+
return /* @__PURE__ */ React2.createElement(Stack, { direction: "row", gap: 0.5, sx: { width: "100%", px: 2, py: 1.5 } }, /* @__PURE__ */ React2.createElement(Box, { sx: { flexGrow: 1 } }, /* @__PURE__ */ React2.createElement(
|
|
279
|
+
TextField,
|
|
280
|
+
{
|
|
281
|
+
role: "search",
|
|
282
|
+
fullWidth: true,
|
|
283
|
+
size: "tiny",
|
|
284
|
+
value: inputValue,
|
|
285
|
+
placeholder: __("Search", "elementor"),
|
|
286
|
+
onChange: (e) => handleChange(e.target.value),
|
|
287
|
+
InputProps: {
|
|
288
|
+
startAdornment: /* @__PURE__ */ React2.createElement(InputAdornment, { position: "start" }, /* @__PURE__ */ React2.createElement(SearchIcon, { fontSize: "tiny" }))
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
)));
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
// src/components/components-tab/components-list.tsx
|
|
295
|
+
import * as React5 from "react";
|
|
296
|
+
import { ComponentsIcon as ComponentsIcon2, EyeIcon } from "@elementor/icons";
|
|
297
|
+
import { Box as Box4, Divider, Icon, Link, List, Stack as Stack3, Typography as Typography2 } from "@elementor/ui";
|
|
298
|
+
import { __ as __3 } from "@wordpress/i18n";
|
|
299
|
+
|
|
33
300
|
// src/hooks/use-components.ts
|
|
34
|
-
|
|
301
|
+
import { __useSelector as useSelector } from "@elementor/store";
|
|
35
302
|
var useComponents = () => {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
303
|
+
const components = useSelector(selectComponents);
|
|
304
|
+
const isLoading = useSelector(selectLoadIsPending);
|
|
305
|
+
return { components, isLoading };
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
// src/components/components-tab/components-item.tsx
|
|
309
|
+
import * as React3 from "react";
|
|
310
|
+
import { endDragElementFromPanel, startDragElementFromPanel } from "@elementor/editor-canvas";
|
|
311
|
+
import { dropElement } from "@elementor/editor-elements";
|
|
312
|
+
import { ComponentsIcon } from "@elementor/icons";
|
|
313
|
+
import { Box as Box2, ListItemButton, ListItemIcon, ListItemText, Typography } from "@elementor/ui";
|
|
314
|
+
|
|
315
|
+
// src/store/load-components-assets.ts
|
|
316
|
+
import { isDocumentDirty, setDocumentModifiedStatus } from "@elementor/editor-documents";
|
|
317
|
+
|
|
318
|
+
// src/create-component-type.ts
|
|
319
|
+
import {
|
|
320
|
+
createTemplatedElementView
|
|
321
|
+
} from "@elementor/editor-canvas";
|
|
322
|
+
import { getCurrentDocument } from "@elementor/editor-documents";
|
|
323
|
+
import { __privateRunCommand as runCommand } from "@elementor/editor-v1-adapters";
|
|
324
|
+
import { __ as __2 } from "@wordpress/i18n";
|
|
325
|
+
|
|
326
|
+
// src/utils/tracking.ts
|
|
327
|
+
import { getMixpanel } from "@elementor/mixpanel";
|
|
328
|
+
import { __getState as getState2 } from "@elementor/store";
|
|
329
|
+
var trackComponentEvent = ({ action, ...data }) => {
|
|
330
|
+
const { dispatchEvent, config } = getMixpanel();
|
|
331
|
+
if (!config?.names?.components?.[action]) {
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
const name = config.names.components[action];
|
|
335
|
+
dispatchEvent?.(name, data);
|
|
336
|
+
};
|
|
337
|
+
var onElementDrop = (_args, element) => {
|
|
338
|
+
if (!(element.model.get("widgetType") === "e-component")) {
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
const editorSettings = element.model.get("editor_settings");
|
|
342
|
+
const componentName = editorSettings?.title;
|
|
343
|
+
const componentUID = editorSettings?.component_uid;
|
|
344
|
+
const instanceId = element.id;
|
|
345
|
+
const createdThisSession = selectCreatedThisSession(getState2());
|
|
346
|
+
const isSameSessionReuse = componentUID && createdThisSession.includes(componentUID);
|
|
347
|
+
const eventsManagerConfig = window.elementorCommon.eventsManager.config;
|
|
348
|
+
const { locations, secondaryLocations } = eventsManagerConfig;
|
|
349
|
+
trackComponentEvent({
|
|
350
|
+
action: "instanceAdded",
|
|
351
|
+
instance_id: instanceId,
|
|
352
|
+
component_uid: componentUID,
|
|
353
|
+
component_name: componentName,
|
|
354
|
+
is_same_session_reuse: isSameSessionReuse,
|
|
355
|
+
location: locations.widgetPanel,
|
|
356
|
+
secondary_location: secondaryLocations.componentsTab
|
|
357
|
+
});
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
// src/create-component-type.ts
|
|
361
|
+
var TYPE = "e-component";
|
|
362
|
+
function createComponentType(options) {
|
|
363
|
+
const legacyWindow = window;
|
|
364
|
+
return class extends legacyWindow.elementor.modules.elements.types.Widget {
|
|
365
|
+
getType() {
|
|
366
|
+
return options.type;
|
|
367
|
+
}
|
|
368
|
+
getView() {
|
|
369
|
+
return createComponentView(options);
|
|
370
|
+
}
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
function createComponentView(options) {
|
|
374
|
+
return class extends createTemplatedElementView(options) {
|
|
375
|
+
legacyWindow = window;
|
|
376
|
+
eventsManagerConfig = this.legacyWindow.elementorCommon.eventsManager.config;
|
|
377
|
+
isComponentCurrentlyEdited() {
|
|
378
|
+
const currentDocument = getCurrentDocument();
|
|
379
|
+
return currentDocument?.id === this.getComponentId();
|
|
380
|
+
}
|
|
381
|
+
afterSettingsResolve(settings) {
|
|
382
|
+
if (settings.component_instance) {
|
|
383
|
+
this.collection = this.legacyWindow.elementor.createBackboneElementsCollection(
|
|
384
|
+
settings.component_instance
|
|
385
|
+
);
|
|
386
|
+
this.collection.models.forEach(setInactiveRecursively);
|
|
387
|
+
settings.component_instance = "<template data-children-placeholder></template>";
|
|
388
|
+
}
|
|
389
|
+
return settings;
|
|
390
|
+
}
|
|
391
|
+
getDomElement() {
|
|
392
|
+
return this.children.findByIndex(0)?.getDomElement() ?? this.$el;
|
|
393
|
+
}
|
|
394
|
+
attachBuffer(collectionView, buffer) {
|
|
395
|
+
const childrenPlaceholder = collectionView.$el.find("[data-children-placeholder]").get(0);
|
|
396
|
+
if (!childrenPlaceholder) {
|
|
397
|
+
super.attachBuffer(collectionView, buffer);
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
childrenPlaceholder.replaceWith(buffer);
|
|
401
|
+
}
|
|
402
|
+
getComponentId() {
|
|
403
|
+
const componentInstance = this.options?.model?.get("settings")?.get("component_instance")?.value;
|
|
404
|
+
return componentInstance.component_id;
|
|
405
|
+
}
|
|
406
|
+
getContextMenuGroups() {
|
|
407
|
+
const filteredGroups = super.getContextMenuGroups().filter((group) => group.name !== "save");
|
|
408
|
+
const componentId = this.getComponentId();
|
|
409
|
+
if (!componentId) {
|
|
410
|
+
return filteredGroups;
|
|
411
|
+
}
|
|
412
|
+
const newGroup = [
|
|
413
|
+
{
|
|
414
|
+
name: "edit component",
|
|
415
|
+
actions: [
|
|
416
|
+
{
|
|
417
|
+
name: "edit component",
|
|
418
|
+
icon: "eicon-edit",
|
|
419
|
+
title: () => __2("Edit Component", "elementor"),
|
|
420
|
+
isEnabled: () => true,
|
|
421
|
+
callback: (_, eventData) => this.editComponent(eventData)
|
|
422
|
+
}
|
|
423
|
+
]
|
|
424
|
+
}
|
|
425
|
+
];
|
|
426
|
+
return [...filteredGroups, ...newGroup];
|
|
427
|
+
}
|
|
428
|
+
async switchDocument() {
|
|
429
|
+
const { isAllowedToSwitchDocument, lockedBy } = await apiClient.getComponentLockStatus(
|
|
430
|
+
this.getComponentId()
|
|
431
|
+
);
|
|
432
|
+
if (!isAllowedToSwitchDocument) {
|
|
433
|
+
options.showLockedByModal?.(lockedBy || "");
|
|
434
|
+
} else {
|
|
435
|
+
runCommand("editor/documents/switch", {
|
|
436
|
+
id: this.getComponentId(),
|
|
437
|
+
mode: "autosave",
|
|
438
|
+
selector: `[data-id="${this.model.get("id")}"]`,
|
|
439
|
+
shouldScroll: false
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
editComponent({ trigger, location, secondaryLocation }) {
|
|
444
|
+
if (this.isComponentCurrentlyEdited()) {
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
this.switchDocument();
|
|
448
|
+
const editorSettings = this.model.get("editor_settings");
|
|
449
|
+
trackComponentEvent({
|
|
450
|
+
action: "edited",
|
|
451
|
+
component_uid: editorSettings?.component_uid,
|
|
452
|
+
component_name: editorSettings?.title,
|
|
453
|
+
location,
|
|
454
|
+
secondary_location: secondaryLocation,
|
|
455
|
+
trigger
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
handleDblClick(e) {
|
|
459
|
+
e.stopPropagation();
|
|
460
|
+
const { triggers, locations, secondaryLocations } = this.eventsManagerConfig;
|
|
461
|
+
this.editComponent({
|
|
462
|
+
trigger: triggers.doubleClick,
|
|
463
|
+
location: locations.canvas,
|
|
464
|
+
secondaryLocation: secondaryLocations.canvasElement
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
events() {
|
|
468
|
+
return {
|
|
469
|
+
...super.events(),
|
|
470
|
+
dblclick: this.handleDblClick
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
attributes() {
|
|
474
|
+
return {
|
|
475
|
+
...super.attributes(),
|
|
476
|
+
"data-elementor-id": this.getComponentId()
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
function setInactiveRecursively(model) {
|
|
482
|
+
const editSettings = model.get("editSettings");
|
|
483
|
+
if (editSettings) {
|
|
484
|
+
editSettings.set("inactive", true);
|
|
485
|
+
}
|
|
486
|
+
const elements = model.get("elements");
|
|
487
|
+
if (elements) {
|
|
488
|
+
elements.forEach((childModel) => {
|
|
489
|
+
setInactiveRecursively(childModel);
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// src/utils/get-component-ids.ts
|
|
495
|
+
var getComponentIds = async (elements) => {
|
|
496
|
+
const components = elements.map(async ({ widgetType, elType, elements: childElements, settings }) => {
|
|
497
|
+
const ids = [];
|
|
498
|
+
const isComponent = [widgetType, elType].includes(TYPE);
|
|
499
|
+
if (isComponent) {
|
|
500
|
+
const componentId = settings?.component_instance?.value?.component_id;
|
|
501
|
+
const document = await getComponentDocumentData(componentId);
|
|
502
|
+
childElements = document?.elements;
|
|
503
|
+
if (Boolean(componentId)) {
|
|
504
|
+
ids.push(componentId);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
if (!!childElements?.length) {
|
|
508
|
+
ids.push(...await getComponentIds(childElements));
|
|
509
|
+
}
|
|
510
|
+
return ids;
|
|
40
511
|
});
|
|
512
|
+
const result = (await Promise.all(components)).flat();
|
|
513
|
+
return Array.from(new Set(result));
|
|
41
514
|
};
|
|
42
515
|
|
|
43
|
-
// src/
|
|
44
|
-
import {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
516
|
+
// src/store/load-components-styles.ts
|
|
517
|
+
import { __dispatch as dispatch, __getState as getState3 } from "@elementor/store";
|
|
518
|
+
async function loadComponentsStyles(componentIds) {
|
|
519
|
+
if (!componentIds.length) {
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
const knownComponents = selectStyles(getState3());
|
|
523
|
+
const unknownComponentIds = componentIds.filter((id) => !knownComponents[id]);
|
|
524
|
+
if (!unknownComponentIds.length) {
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
addComponentStyles(unknownComponentIds);
|
|
528
|
+
}
|
|
529
|
+
async function addComponentStyles(ids) {
|
|
530
|
+
const newComponents = await loadStyles(ids);
|
|
531
|
+
addStyles(newComponents);
|
|
532
|
+
}
|
|
533
|
+
async function loadStyles(ids) {
|
|
534
|
+
return Promise.all(ids.map(async (id) => [id, await apiClient.getComponentConfig(id)]));
|
|
535
|
+
}
|
|
536
|
+
function addStyles(data) {
|
|
537
|
+
const styles = Object.fromEntries(
|
|
538
|
+
data.map(([componentId, componentData]) => [componentId, extractStyles(componentData)])
|
|
539
|
+
);
|
|
540
|
+
dispatch(slice.actions.addStyles(styles));
|
|
541
|
+
}
|
|
542
|
+
function extractStyles(element) {
|
|
543
|
+
return [...Object.values(element.styles ?? {}), ...(element.elements ?? []).flatMap(extractStyles)];
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
// src/store/load-components-assets.ts
|
|
547
|
+
async function loadComponentsAssets(elements) {
|
|
548
|
+
const componentIds = await getComponentIds(elements);
|
|
549
|
+
updateDocumentState(componentIds);
|
|
550
|
+
return loadComponentsStyles(componentIds);
|
|
551
|
+
}
|
|
552
|
+
async function updateDocumentState(componentIds) {
|
|
553
|
+
const components = (await Promise.all(componentIds.map(getComponentDocumentData))).filter(
|
|
554
|
+
(document) => !!document
|
|
555
|
+
);
|
|
556
|
+
const isDrafted = components.some(isDocumentDirty);
|
|
557
|
+
if (isDrafted) {
|
|
558
|
+
setDocumentModifiedStatus(true);
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// src/utils/get-container-for-new-element.ts
|
|
563
|
+
import {
|
|
564
|
+
getContainer,
|
|
565
|
+
getCurrentDocumentContainer,
|
|
566
|
+
getSelectedElements
|
|
567
|
+
} from "@elementor/editor-elements";
|
|
568
|
+
var getContainerForNewElement = () => {
|
|
569
|
+
const currentDocumentContainer = getCurrentDocumentContainer();
|
|
570
|
+
const selectedElement = getSelectedElementContainer();
|
|
571
|
+
let container, options;
|
|
572
|
+
if (selectedElement) {
|
|
573
|
+
switch (selectedElement.model.get("elType")) {
|
|
574
|
+
case "widget": {
|
|
575
|
+
container = selectedElement?.parent;
|
|
576
|
+
const selectedElIndex = selectedElement.view?._index ?? -1;
|
|
577
|
+
if (selectedElIndex > -1) {
|
|
578
|
+
options = { at: selectedElIndex + 1 };
|
|
579
|
+
}
|
|
580
|
+
break;
|
|
581
|
+
}
|
|
582
|
+
case "section": {
|
|
583
|
+
container = selectedElement?.children?.[0];
|
|
584
|
+
break;
|
|
585
|
+
}
|
|
586
|
+
default: {
|
|
587
|
+
container = selectedElement;
|
|
588
|
+
break;
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
return { container: container ?? currentDocumentContainer, options };
|
|
593
|
+
};
|
|
594
|
+
function getSelectedElementContainer() {
|
|
595
|
+
const selectedElements = getSelectedElements();
|
|
596
|
+
if (selectedElements.length !== 1) {
|
|
597
|
+
return void 0;
|
|
598
|
+
}
|
|
599
|
+
return getContainer(selectedElements[0].id);
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
// src/components/create-component-form/utils/replace-element-with-component.ts
|
|
603
|
+
import { replaceElement } from "@elementor/editor-elements";
|
|
604
|
+
var replaceElementWithComponent = (element, component) => {
|
|
605
|
+
replaceElement({
|
|
606
|
+
currentElement: element,
|
|
607
|
+
newElement: createComponentModel(component),
|
|
608
|
+
withHistory: false
|
|
50
609
|
});
|
|
51
610
|
};
|
|
611
|
+
var createComponentModel = (component) => {
|
|
612
|
+
return {
|
|
613
|
+
elType: "widget",
|
|
614
|
+
widgetType: "e-component",
|
|
615
|
+
settings: {
|
|
616
|
+
component_instance: {
|
|
617
|
+
$$type: "component-instance",
|
|
618
|
+
value: {
|
|
619
|
+
component_id: component.id ?? component.uid
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
},
|
|
623
|
+
editor_settings: {
|
|
624
|
+
title: component.name,
|
|
625
|
+
component_uid: component.uid
|
|
626
|
+
}
|
|
627
|
+
};
|
|
628
|
+
};
|
|
629
|
+
|
|
630
|
+
// src/components/components-tab/components-item.tsx
|
|
631
|
+
var ComponentItem = ({ component }) => {
|
|
632
|
+
const componentModel = createComponentModel(component);
|
|
633
|
+
const handleClick = () => {
|
|
634
|
+
addComponentToPage(componentModel);
|
|
635
|
+
};
|
|
636
|
+
const handleDragEnd = () => {
|
|
637
|
+
loadComponentsAssets([componentModel]);
|
|
638
|
+
endDragElementFromPanel();
|
|
639
|
+
};
|
|
640
|
+
return /* @__PURE__ */ React3.createElement(
|
|
641
|
+
ListItemButton,
|
|
642
|
+
{
|
|
643
|
+
draggable: true,
|
|
644
|
+
onDragStart: () => startDragElementFromPanel(componentModel),
|
|
645
|
+
onDragEnd: handleDragEnd,
|
|
646
|
+
shape: "rounded",
|
|
647
|
+
sx: { border: "solid 1px", borderColor: "divider", py: 0.5, px: 1 }
|
|
648
|
+
},
|
|
649
|
+
/* @__PURE__ */ React3.createElement(Box2, { sx: { display: "flex", width: "100%", alignItems: "center", gap: 1 }, onClick: handleClick }, /* @__PURE__ */ React3.createElement(ListItemIcon, { size: "tiny" }, /* @__PURE__ */ React3.createElement(ComponentsIcon, { fontSize: "tiny" })), /* @__PURE__ */ React3.createElement(
|
|
650
|
+
ListItemText,
|
|
651
|
+
{
|
|
652
|
+
primary: /* @__PURE__ */ React3.createElement(Typography, { variant: "caption", sx: { color: "text.primary" } }, component.name)
|
|
653
|
+
}
|
|
654
|
+
))
|
|
655
|
+
);
|
|
656
|
+
};
|
|
657
|
+
var addComponentToPage = (model) => {
|
|
658
|
+
const { container, options } = getContainerForNewElement();
|
|
659
|
+
if (!container) {
|
|
660
|
+
throw new Error(`Can't find container to drop new component instance at`);
|
|
661
|
+
}
|
|
662
|
+
loadComponentsAssets([model]);
|
|
663
|
+
dropElement({
|
|
664
|
+
containerId: container.id,
|
|
665
|
+
model,
|
|
666
|
+
options: { ...options, useHistory: false, scrollIntoView: true }
|
|
667
|
+
});
|
|
668
|
+
};
|
|
669
|
+
|
|
670
|
+
// src/components/components-tab/loading-components.tsx
|
|
671
|
+
import * as React4 from "react";
|
|
672
|
+
import { Box as Box3, ListItemButton as ListItemButton2, Skeleton, Stack as Stack2 } from "@elementor/ui";
|
|
673
|
+
var ROWS_COUNT = 6;
|
|
674
|
+
var rows = Array.from({ length: ROWS_COUNT }, (_, index) => index);
|
|
675
|
+
var LoadingComponents = () => {
|
|
676
|
+
return /* @__PURE__ */ React4.createElement(
|
|
677
|
+
Stack2,
|
|
678
|
+
{
|
|
679
|
+
"aria-label": "Loading components",
|
|
680
|
+
gap: 1,
|
|
681
|
+
sx: {
|
|
682
|
+
pointerEvents: "none",
|
|
683
|
+
position: "relative",
|
|
684
|
+
maxHeight: "300px",
|
|
685
|
+
overflow: "hidden",
|
|
686
|
+
"&:after": {
|
|
687
|
+
position: "absolute",
|
|
688
|
+
top: 0,
|
|
689
|
+
content: '""',
|
|
690
|
+
left: 0,
|
|
691
|
+
width: "100%",
|
|
692
|
+
height: "300px",
|
|
693
|
+
background: "linear-gradient(to top, white, transparent)",
|
|
694
|
+
pointerEvents: "none"
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
},
|
|
698
|
+
rows.map((row) => /* @__PURE__ */ React4.createElement(
|
|
699
|
+
ListItemButton2,
|
|
700
|
+
{
|
|
701
|
+
key: row,
|
|
702
|
+
sx: { border: "solid 1px", borderColor: "divider", py: 0.5, px: 1 },
|
|
703
|
+
shape: "rounded"
|
|
704
|
+
},
|
|
705
|
+
/* @__PURE__ */ React4.createElement(Box3, { display: "flex", gap: 1, width: "100%" }, /* @__PURE__ */ React4.createElement(Skeleton, { variant: "text", width: "24px", height: "36px" }), /* @__PURE__ */ React4.createElement(Skeleton, { variant: "text", width: "100%", height: "36px" }))
|
|
706
|
+
))
|
|
707
|
+
);
|
|
708
|
+
};
|
|
709
|
+
|
|
710
|
+
// src/components/components-tab/components-list.tsx
|
|
711
|
+
function ComponentsList() {
|
|
712
|
+
const { components, isLoading, searchValue } = useFilteredComponents();
|
|
713
|
+
if (isLoading) {
|
|
714
|
+
return /* @__PURE__ */ React5.createElement(LoadingComponents, null);
|
|
715
|
+
}
|
|
716
|
+
const isEmpty = !components || components.length === 0;
|
|
717
|
+
if (isEmpty) {
|
|
718
|
+
if (searchValue.length > 0) {
|
|
719
|
+
return /* @__PURE__ */ React5.createElement(EmptySearchResult, null);
|
|
720
|
+
}
|
|
721
|
+
return /* @__PURE__ */ React5.createElement(EmptyState, null);
|
|
722
|
+
}
|
|
723
|
+
return /* @__PURE__ */ React5.createElement(List, { sx: { display: "flex", flexDirection: "column", gap: 1, px: 2 } }, components.map((component) => /* @__PURE__ */ React5.createElement(ComponentItem, { key: component.uid, component })));
|
|
724
|
+
}
|
|
725
|
+
var EmptyState = () => {
|
|
726
|
+
return /* @__PURE__ */ React5.createElement(
|
|
727
|
+
Stack3,
|
|
728
|
+
{
|
|
729
|
+
alignItems: "center",
|
|
730
|
+
justifyContent: "center",
|
|
731
|
+
height: "100%",
|
|
732
|
+
sx: { px: 2.5, pt: 10 },
|
|
733
|
+
gap: 1.75,
|
|
734
|
+
overflow: "hidden"
|
|
735
|
+
},
|
|
736
|
+
/* @__PURE__ */ React5.createElement(Icon, { fontSize: "large" }, /* @__PURE__ */ React5.createElement(EyeIcon, { fontSize: "large" })),
|
|
737
|
+
/* @__PURE__ */ React5.createElement(Typography2, { align: "center", variant: "subtitle2", color: "text.secondary", fontWeight: "bold" }, __3("Text that explains that there are no Components yet.", "elementor")),
|
|
738
|
+
/* @__PURE__ */ React5.createElement(Typography2, { variant: "caption", align: "center", color: "text.secondary" }, __3(
|
|
739
|
+
"Once you have Components, this is where you can manage them\u2014rearrange, duplicate, rename and delete irrelevant classes.",
|
|
740
|
+
"elementor"
|
|
741
|
+
)),
|
|
742
|
+
/* @__PURE__ */ React5.createElement(Divider, { sx: { width: "100%" }, color: "text.secondary" }),
|
|
743
|
+
/* @__PURE__ */ React5.createElement(Typography2, { align: "left", variant: "caption", color: "text.secondary" }, __3("To create a component, first design it, then choose one of three options:", "elementor")),
|
|
744
|
+
/* @__PURE__ */ React5.createElement(
|
|
745
|
+
Typography2,
|
|
746
|
+
{
|
|
747
|
+
align: "left",
|
|
748
|
+
variant: "caption",
|
|
749
|
+
color: "text.secondary",
|
|
750
|
+
sx: { display: "flex", flexDirection: "column" }
|
|
751
|
+
},
|
|
752
|
+
/* @__PURE__ */ React5.createElement("span", null, __3("1. Right-click and select Create Component", "elementor")),
|
|
753
|
+
/* @__PURE__ */ React5.createElement("span", null, __3("2. Use the component icon in the Structure panel", "elementor")),
|
|
754
|
+
/* @__PURE__ */ React5.createElement("span", null, __3("3. Use the component icon in the Edit panel header", "elementor"))
|
|
755
|
+
)
|
|
756
|
+
);
|
|
757
|
+
};
|
|
758
|
+
var EmptySearchResult = () => {
|
|
759
|
+
const { searchValue, clearSearch } = useSearch();
|
|
760
|
+
return /* @__PURE__ */ React5.createElement(
|
|
761
|
+
Stack3,
|
|
762
|
+
{
|
|
763
|
+
color: "text.secondary",
|
|
764
|
+
pt: 5,
|
|
765
|
+
alignItems: "center",
|
|
766
|
+
gap: 1,
|
|
767
|
+
overflow: "hidden",
|
|
768
|
+
justifySelf: "center"
|
|
769
|
+
},
|
|
770
|
+
/* @__PURE__ */ React5.createElement(ComponentsIcon2, null),
|
|
771
|
+
/* @__PURE__ */ React5.createElement(
|
|
772
|
+
Box4,
|
|
773
|
+
{
|
|
774
|
+
sx: {
|
|
775
|
+
width: "100%"
|
|
776
|
+
}
|
|
777
|
+
},
|
|
778
|
+
/* @__PURE__ */ React5.createElement(Typography2, { align: "center", variant: "subtitle2", color: "inherit" }, __3("Sorry, nothing matched", "elementor")),
|
|
779
|
+
searchValue && /* @__PURE__ */ React5.createElement(
|
|
780
|
+
Typography2,
|
|
781
|
+
{
|
|
782
|
+
variant: "subtitle2",
|
|
783
|
+
color: "inherit",
|
|
784
|
+
sx: {
|
|
785
|
+
display: "flex",
|
|
786
|
+
width: "100%",
|
|
787
|
+
justifyContent: "center"
|
|
788
|
+
}
|
|
789
|
+
},
|
|
790
|
+
/* @__PURE__ */ React5.createElement("span", null, "\u201C"),
|
|
791
|
+
/* @__PURE__ */ React5.createElement(
|
|
792
|
+
"span",
|
|
793
|
+
{
|
|
794
|
+
style: {
|
|
795
|
+
maxWidth: "80%",
|
|
796
|
+
overflow: "hidden",
|
|
797
|
+
textOverflow: "ellipsis"
|
|
798
|
+
}
|
|
799
|
+
},
|
|
800
|
+
searchValue
|
|
801
|
+
),
|
|
802
|
+
/* @__PURE__ */ React5.createElement("span", null, "\u201D.")
|
|
803
|
+
)
|
|
804
|
+
),
|
|
805
|
+
/* @__PURE__ */ React5.createElement(Typography2, { align: "center", variant: "caption", color: "inherit" }, __3("Try something else.", "elementor")),
|
|
806
|
+
/* @__PURE__ */ React5.createElement(Typography2, { align: "center", variant: "caption", color: "inherit" }, /* @__PURE__ */ React5.createElement(Link, { color: "secondary", variant: "caption", component: "button", onClick: clearSearch }, __3("Clear & try again", "elementor")))
|
|
807
|
+
);
|
|
808
|
+
};
|
|
809
|
+
var useFilteredComponents = () => {
|
|
810
|
+
const { components, isLoading } = useComponents();
|
|
811
|
+
const { searchValue } = useSearch();
|
|
812
|
+
return {
|
|
813
|
+
components: components.filter(
|
|
814
|
+
(component) => component.name.toLowerCase().includes(searchValue.toLowerCase())
|
|
815
|
+
),
|
|
816
|
+
isLoading,
|
|
817
|
+
searchValue
|
|
818
|
+
};
|
|
819
|
+
};
|
|
820
|
+
|
|
821
|
+
// src/components/components-tab/components.tsx
|
|
822
|
+
var Components = () => {
|
|
823
|
+
return /* @__PURE__ */ React6.createElement(ThemeProvider, null, /* @__PURE__ */ React6.createElement(SearchProvider, { localStorageKey: "elementor-components-search" }, /* @__PURE__ */ React6.createElement(ComponentSearch, null), /* @__PURE__ */ React6.createElement(ComponentsList, null)));
|
|
824
|
+
};
|
|
825
|
+
|
|
826
|
+
// src/components/consts.ts
|
|
827
|
+
var COMPONENT_DOCUMENT_TYPE = "elementor_component";
|
|
828
|
+
|
|
829
|
+
// src/components/create-component-form/create-component-form.tsx
|
|
830
|
+
import * as React7 from "react";
|
|
831
|
+
import { useEffect, useMemo as useMemo2, useRef, useState as useState2 } from "react";
|
|
832
|
+
import { getElementLabel } from "@elementor/editor-elements";
|
|
833
|
+
import { Form as FormElement, ThemeProvider as ThemeProvider2 } from "@elementor/editor-ui";
|
|
834
|
+
import { StarIcon } from "@elementor/icons";
|
|
835
|
+
import { Alert, Button, FormLabel, Grid, Popover, Snackbar, Stack as Stack4, TextField as TextField2, Typography as Typography3 } from "@elementor/ui";
|
|
836
|
+
import { __ as __5 } from "@wordpress/i18n";
|
|
837
|
+
|
|
838
|
+
// src/store/create-unpublished-component.ts
|
|
839
|
+
import { __privateRunCommand as runCommand2 } from "@elementor/editor-v1-adapters";
|
|
840
|
+
import { __dispatch as dispatch2 } from "@elementor/store";
|
|
841
|
+
import { generateUniqueId } from "@elementor/utils";
|
|
842
|
+
function createUnpublishedComponent(name, element, eventData) {
|
|
843
|
+
const uid = generateUniqueId("component");
|
|
844
|
+
const componentBase = { uid, name };
|
|
845
|
+
dispatch2(
|
|
846
|
+
slice.actions.addUnpublished({
|
|
847
|
+
...componentBase,
|
|
848
|
+
elements: [element]
|
|
849
|
+
})
|
|
850
|
+
);
|
|
851
|
+
dispatch2(slice.actions.addCreatedThisSession(uid));
|
|
852
|
+
replaceElementWithComponent(element, componentBase);
|
|
853
|
+
trackComponentEvent({
|
|
854
|
+
action: "created",
|
|
855
|
+
component_uid: uid,
|
|
856
|
+
component_name: name,
|
|
857
|
+
...eventData
|
|
858
|
+
});
|
|
859
|
+
runCommand2("document/save/auto");
|
|
860
|
+
return uid;
|
|
861
|
+
}
|
|
52
862
|
|
|
53
863
|
// src/components/create-component-form/hooks/use-form.ts
|
|
54
864
|
import { useMemo, useState } from "react";
|
|
@@ -101,16 +911,16 @@ var validateForm = (values, schema) => {
|
|
|
101
911
|
|
|
102
912
|
// src/components/create-component-form/utils/component-form-schema.ts
|
|
103
913
|
import { z } from "@elementor/schema";
|
|
104
|
-
import { __ } from "@wordpress/i18n";
|
|
914
|
+
import { __ as __4 } from "@wordpress/i18n";
|
|
105
915
|
var MIN_NAME_LENGTH = 2;
|
|
106
916
|
var MAX_NAME_LENGTH = 50;
|
|
107
917
|
var createBaseComponentSchema = (existingNames) => {
|
|
108
918
|
return z.object({
|
|
109
919
|
componentName: z.string().trim().max(
|
|
110
920
|
MAX_NAME_LENGTH,
|
|
111
|
-
|
|
921
|
+
__4("Component name is too long. Please keep it under 50 characters.", "elementor")
|
|
112
922
|
).refine((value) => !existingNames.includes(value), {
|
|
113
|
-
message:
|
|
923
|
+
message: __4("Component name already exists", "elementor")
|
|
114
924
|
})
|
|
115
925
|
});
|
|
116
926
|
};
|
|
@@ -118,103 +928,114 @@ var createSubmitComponentSchema = (existingNames) => {
|
|
|
118
928
|
const baseSchema = createBaseComponentSchema(existingNames);
|
|
119
929
|
return baseSchema.extend({
|
|
120
930
|
componentName: baseSchema.shape.componentName.refine((value) => value.length > 0, {
|
|
121
|
-
message:
|
|
931
|
+
message: __4("Component name is required.", "elementor")
|
|
122
932
|
}).refine((value) => value.length >= MIN_NAME_LENGTH, {
|
|
123
|
-
message:
|
|
933
|
+
message: __4("Component name is too short. Please enter at least 2 characters.", "elementor")
|
|
124
934
|
})
|
|
125
935
|
});
|
|
126
936
|
};
|
|
127
937
|
|
|
128
|
-
// src/components/create-component-form/utils/
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
}
|
|
140
|
-
},
|
|
141
|
-
withHistory: false
|
|
142
|
-
});
|
|
938
|
+
// src/components/create-component-form/utils/get-component-event-data.ts
|
|
939
|
+
var getComponentEventData = (containerElement, options) => {
|
|
940
|
+
const { elementsCount, componentsCount } = countNestedElements(containerElement);
|
|
941
|
+
return {
|
|
942
|
+
nested_elements_count: elementsCount,
|
|
943
|
+
nested_components_count: componentsCount,
|
|
944
|
+
top_element_type: containerElement.elType,
|
|
945
|
+
location: options?.location,
|
|
946
|
+
secondary_location: options?.secondaryLocation,
|
|
947
|
+
trigger: options?.trigger
|
|
948
|
+
};
|
|
143
949
|
};
|
|
950
|
+
function countNestedElements(container) {
|
|
951
|
+
if (!container.elements || container.elements.length === 0) {
|
|
952
|
+
return { elementsCount: 0, componentsCount: 0 };
|
|
953
|
+
}
|
|
954
|
+
let elementsCount = container.elements.length;
|
|
955
|
+
let componentsCount = 0;
|
|
956
|
+
for (const element of container.elements) {
|
|
957
|
+
if (element.widgetType === "e-component") {
|
|
958
|
+
componentsCount++;
|
|
959
|
+
}
|
|
960
|
+
const { elementsCount: nestedElementsCount, componentsCount: nestedComponentsCount } = countNestedElements(element);
|
|
961
|
+
elementsCount += nestedElementsCount;
|
|
962
|
+
componentsCount += nestedComponentsCount;
|
|
963
|
+
}
|
|
964
|
+
return { elementsCount, componentsCount };
|
|
965
|
+
}
|
|
144
966
|
|
|
145
967
|
// src/components/create-component-form/create-component-form.tsx
|
|
146
968
|
function CreateComponentForm() {
|
|
147
969
|
const [element, setElement] = useState2(null);
|
|
148
970
|
const [anchorPosition, setAnchorPosition] = useState2();
|
|
149
971
|
const [resultNotification, setResultNotification] = useState2(null);
|
|
150
|
-
const
|
|
972
|
+
const eventData = useRef(null);
|
|
151
973
|
useEffect(() => {
|
|
152
974
|
const OPEN_SAVE_AS_COMPONENT_FORM_EVENT = "elementor/editor/open-save-as-component-form";
|
|
153
975
|
const openPopup = (event) => {
|
|
154
976
|
setElement({ element: event.detail.element, elementLabel: getElementLabel(event.detail.element.id) });
|
|
155
977
|
setAnchorPosition(event.detail.anchorPosition);
|
|
978
|
+
eventData.current = getComponentEventData(event.detail.element, event.detail.options);
|
|
979
|
+
trackComponentEvent({
|
|
980
|
+
action: "createClicked",
|
|
981
|
+
...eventData.current
|
|
982
|
+
});
|
|
156
983
|
};
|
|
157
984
|
window.addEventListener(OPEN_SAVE_AS_COMPONENT_FORM_EVENT, openPopup);
|
|
158
985
|
return () => {
|
|
159
986
|
window.removeEventListener(OPEN_SAVE_AS_COMPONENT_FORM_EVENT, openPopup);
|
|
160
987
|
};
|
|
161
988
|
}, []);
|
|
162
|
-
const handleSave =
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
createComponent(
|
|
167
|
-
{
|
|
168
|
-
name: values.componentName,
|
|
169
|
-
content: [element.element.model.toJSON({ remove: ["default"] })]
|
|
170
|
-
},
|
|
171
|
-
{
|
|
172
|
-
onSuccess: (result) => {
|
|
173
|
-
if (!element) {
|
|
174
|
-
throw new Error(`Can't replace element with component: element not found`);
|
|
175
|
-
}
|
|
176
|
-
replaceElementWithComponent(element.element, result.component_id);
|
|
177
|
-
setResultNotification({
|
|
178
|
-
show: true,
|
|
179
|
-
// Translators: %1$s: Component name, %2$s: Component ID
|
|
180
|
-
message: __2("Component saved successfully as: %1$s (ID: %2$s)", "elementor").replace("%1$s", values.componentName).replace("%2$s", result.component_id.toString()),
|
|
181
|
-
type: "success"
|
|
182
|
-
});
|
|
183
|
-
resetAndClosePopup();
|
|
184
|
-
},
|
|
185
|
-
onError: () => {
|
|
186
|
-
const errorMessage = __2("Failed to save component. Please try again.", "elementor");
|
|
187
|
-
setResultNotification({
|
|
188
|
-
show: true,
|
|
189
|
-
message: errorMessage,
|
|
190
|
-
type: "error"
|
|
191
|
-
});
|
|
192
|
-
}
|
|
989
|
+
const handleSave = (values) => {
|
|
990
|
+
try {
|
|
991
|
+
if (!element) {
|
|
992
|
+
throw new Error(`Can't save element as component: element not found`);
|
|
193
993
|
}
|
|
194
|
-
|
|
994
|
+
const uid = createUnpublishedComponent(values.componentName, element.element, eventData.current);
|
|
995
|
+
setResultNotification({
|
|
996
|
+
show: true,
|
|
997
|
+
// Translators: %1$s: Component name, %2$s: Component UID
|
|
998
|
+
message: __5("Component saved successfully as: %1$s (UID: %2$s)", "elementor").replace("%1$s", values.componentName).replace("%2$s", uid),
|
|
999
|
+
type: "success"
|
|
1000
|
+
});
|
|
1001
|
+
resetAndClosePopup();
|
|
1002
|
+
} catch {
|
|
1003
|
+
const errorMessage = __5("Failed to save component. Please try again.", "elementor");
|
|
1004
|
+
setResultNotification({
|
|
1005
|
+
show: true,
|
|
1006
|
+
message: errorMessage,
|
|
1007
|
+
type: "error"
|
|
1008
|
+
});
|
|
1009
|
+
}
|
|
195
1010
|
};
|
|
196
1011
|
const resetAndClosePopup = () => {
|
|
197
1012
|
setElement(null);
|
|
198
1013
|
setAnchorPosition(void 0);
|
|
199
1014
|
};
|
|
200
|
-
|
|
1015
|
+
const cancelSave = () => {
|
|
1016
|
+
resetAndClosePopup();
|
|
1017
|
+
trackComponentEvent({
|
|
1018
|
+
action: "createCancelled",
|
|
1019
|
+
...eventData.current
|
|
1020
|
+
});
|
|
1021
|
+
};
|
|
1022
|
+
return /* @__PURE__ */ React7.createElement(ThemeProvider2, null, /* @__PURE__ */ React7.createElement(
|
|
201
1023
|
Popover,
|
|
202
1024
|
{
|
|
203
1025
|
open: element !== null,
|
|
204
|
-
onClose:
|
|
1026
|
+
onClose: cancelSave,
|
|
205
1027
|
anchorReference: "anchorPosition",
|
|
206
1028
|
anchorPosition
|
|
207
1029
|
},
|
|
208
|
-
element !== null && /* @__PURE__ */
|
|
1030
|
+
element !== null && /* @__PURE__ */ React7.createElement(
|
|
209
1031
|
Form,
|
|
210
1032
|
{
|
|
211
1033
|
initialValues: { componentName: element.elementLabel },
|
|
212
1034
|
handleSave,
|
|
213
|
-
|
|
214
|
-
closePopup: resetAndClosePopup
|
|
1035
|
+
closePopup: cancelSave
|
|
215
1036
|
}
|
|
216
1037
|
)
|
|
217
|
-
), /* @__PURE__ */
|
|
1038
|
+
), /* @__PURE__ */ React7.createElement(Snackbar, { open: resultNotification?.show, onClose: () => setResultNotification(null) }, /* @__PURE__ */ React7.createElement(
|
|
218
1039
|
Alert,
|
|
219
1040
|
{
|
|
220
1041
|
onClose: () => setResultNotification(null),
|
|
@@ -228,11 +1049,10 @@ var FONT_SIZE = "tiny";
|
|
|
228
1049
|
var Form = ({
|
|
229
1050
|
initialValues,
|
|
230
1051
|
handleSave,
|
|
231
|
-
isSubmitting,
|
|
232
1052
|
closePopup
|
|
233
1053
|
}) => {
|
|
234
1054
|
const { values, errors, isValid, handleChange, validateForm: validateForm2 } = useForm(initialValues);
|
|
235
|
-
const {
|
|
1055
|
+
const { components } = useComponents();
|
|
236
1056
|
const existingComponentNames = useMemo2(() => {
|
|
237
1057
|
return components?.map((component) => component.name) ?? [];
|
|
238
1058
|
}, [components]);
|
|
@@ -250,8 +1070,15 @@ var Form = ({
|
|
|
250
1070
|
handleSave(parsedValues);
|
|
251
1071
|
}
|
|
252
1072
|
};
|
|
253
|
-
|
|
254
|
-
|
|
1073
|
+
const texts = {
|
|
1074
|
+
heading: __5("Save as a component", "elementor"),
|
|
1075
|
+
name: __5("Name", "elementor"),
|
|
1076
|
+
cancel: __5("Cancel", "elementor"),
|
|
1077
|
+
create: __5("Create", "elementor")
|
|
1078
|
+
};
|
|
1079
|
+
const nameInputId = "component-name";
|
|
1080
|
+
return /* @__PURE__ */ React7.createElement(FormElement, { onSubmit: handleSubmit }, /* @__PURE__ */ React7.createElement(Stack4, { alignItems: "start", width: "268px" }, /* @__PURE__ */ React7.createElement(
|
|
1081
|
+
Stack4,
|
|
255
1082
|
{
|
|
256
1083
|
direction: "row",
|
|
257
1084
|
alignItems: "center",
|
|
@@ -259,12 +1086,12 @@ var Form = ({
|
|
|
259
1086
|
px: 1.5,
|
|
260
1087
|
sx: { columnGap: 0.5, borderBottom: "1px solid", borderColor: "divider", width: "100%" }
|
|
261
1088
|
},
|
|
262
|
-
/* @__PURE__ */
|
|
263
|
-
/* @__PURE__ */
|
|
264
|
-
), /* @__PURE__ */
|
|
265
|
-
|
|
1089
|
+
/* @__PURE__ */ React7.createElement(StarIcon, { fontSize: FONT_SIZE }),
|
|
1090
|
+
/* @__PURE__ */ React7.createElement(Typography3, { variant: "caption", sx: { color: "text.primary", fontWeight: "500", lineHeight: 1 } }, texts.heading)
|
|
1091
|
+
), /* @__PURE__ */ React7.createElement(Grid, { container: true, gap: 0.75, alignItems: "start", p: 1.5 }, /* @__PURE__ */ React7.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React7.createElement(FormLabel, { htmlFor: nameInputId, size: "tiny" }, texts.name)), /* @__PURE__ */ React7.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React7.createElement(
|
|
1092
|
+
TextField2,
|
|
266
1093
|
{
|
|
267
|
-
id:
|
|
1094
|
+
id: nameInputId,
|
|
268
1095
|
size: FONT_SIZE,
|
|
269
1096
|
fullWidth: true,
|
|
270
1097
|
value: values.componentName,
|
|
@@ -273,30 +1100,956 @@ var Form = ({
|
|
|
273
1100
|
error: Boolean(errors.componentName),
|
|
274
1101
|
helperText: errors.componentName
|
|
275
1102
|
}
|
|
276
|
-
))), /* @__PURE__ */
|
|
277
|
-
|
|
1103
|
+
))), /* @__PURE__ */ React7.createElement(Stack4, { direction: "row", justifyContent: "flex-end", alignSelf: "end", py: 1, px: 1.5 }, /* @__PURE__ */ React7.createElement(Button, { onClick: closePopup, color: "secondary", variant: "text", size: "small" }, texts.cancel), /* @__PURE__ */ React7.createElement(Button, { type: "submit", disabled: !isValid, variant: "contained", color: "primary", size: "small" }, texts.create))));
|
|
1104
|
+
};
|
|
1105
|
+
|
|
1106
|
+
// src/components/edit-component/edit-component.tsx
|
|
1107
|
+
import * as React9 from "react";
|
|
1108
|
+
import { useCallback, useEffect as useEffect4 } from "react";
|
|
1109
|
+
import { getV1DocumentsManager as getV1DocumentsManager2 } from "@elementor/editor-documents";
|
|
1110
|
+
import {
|
|
1111
|
+
__privateListenTo as listenTo,
|
|
1112
|
+
__privateRunCommand as runCommand3,
|
|
1113
|
+
commandEndEvent as commandEndEvent2
|
|
1114
|
+
} from "@elementor/editor-v1-adapters";
|
|
1115
|
+
import { __useSelector as useSelector2 } from "@elementor/store";
|
|
1116
|
+
|
|
1117
|
+
// src/store/actions.ts
|
|
1118
|
+
import { __getStore as getStore } from "@elementor/store";
|
|
1119
|
+
function updateCurrentComponent({
|
|
1120
|
+
path,
|
|
1121
|
+
currentComponentId
|
|
1122
|
+
}) {
|
|
1123
|
+
const dispatch7 = getStore()?.dispatch;
|
|
1124
|
+
if (!dispatch7) {
|
|
1125
|
+
return;
|
|
1126
|
+
}
|
|
1127
|
+
dispatch7(slice.actions.setPath(path));
|
|
1128
|
+
dispatch7(slice.actions.setCurrentComponentId(currentComponentId));
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
// src/components/edit-component/component-modal.tsx
|
|
1132
|
+
import * as React8 from "react";
|
|
1133
|
+
import { useEffect as useEffect3 } from "react";
|
|
1134
|
+
import { createPortal } from "react-dom";
|
|
1135
|
+
import { __ as __6 } from "@wordpress/i18n";
|
|
1136
|
+
|
|
1137
|
+
// src/hooks/use-canvas-document.ts
|
|
1138
|
+
import { getCanvasIframeDocument } from "@elementor/editor-canvas";
|
|
1139
|
+
import { __privateUseListenTo as useListenTo, commandEndEvent } from "@elementor/editor-v1-adapters";
|
|
1140
|
+
function useCanvasDocument() {
|
|
1141
|
+
return useListenTo(commandEndEvent("editor/documents/attach-preview"), () => getCanvasIframeDocument());
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
// src/hooks/use-element-rect.ts
|
|
1145
|
+
import { useEffect as useEffect2, useState as useState3 } from "react";
|
|
1146
|
+
import { throttle } from "@elementor/utils";
|
|
1147
|
+
function useElementRect(element) {
|
|
1148
|
+
const [rect, setRect] = useState3(new DOMRect(0, 0, 0, 0));
|
|
1149
|
+
const onChange = throttle(
|
|
1150
|
+
() => {
|
|
1151
|
+
setRect(element?.getBoundingClientRect() ?? new DOMRect(0, 0, 0, 0));
|
|
1152
|
+
},
|
|
1153
|
+
20,
|
|
1154
|
+
true
|
|
1155
|
+
);
|
|
1156
|
+
useScrollListener({ element, onChange });
|
|
1157
|
+
useResizeListener({ element, onChange });
|
|
1158
|
+
useMutationsListener({ element, onChange });
|
|
1159
|
+
useEffect2(
|
|
1160
|
+
() => () => {
|
|
1161
|
+
onChange.cancel();
|
|
1162
|
+
},
|
|
1163
|
+
[onChange]
|
|
1164
|
+
);
|
|
1165
|
+
return rect;
|
|
1166
|
+
}
|
|
1167
|
+
function useScrollListener({ element, onChange }) {
|
|
1168
|
+
useEffect2(() => {
|
|
1169
|
+
if (!element) {
|
|
1170
|
+
return;
|
|
1171
|
+
}
|
|
1172
|
+
const win = element.ownerDocument?.defaultView;
|
|
1173
|
+
win?.addEventListener("scroll", onChange, { passive: true });
|
|
1174
|
+
return () => {
|
|
1175
|
+
win?.removeEventListener("scroll", onChange);
|
|
1176
|
+
};
|
|
1177
|
+
}, [element, onChange]);
|
|
1178
|
+
}
|
|
1179
|
+
function useResizeListener({ element, onChange }) {
|
|
1180
|
+
useEffect2(() => {
|
|
1181
|
+
if (!element) {
|
|
1182
|
+
return;
|
|
1183
|
+
}
|
|
1184
|
+
const resizeObserver = new ResizeObserver(onChange);
|
|
1185
|
+
resizeObserver.observe(element);
|
|
1186
|
+
const win = element.ownerDocument?.defaultView;
|
|
1187
|
+
win?.addEventListener("resize", onChange, { passive: true });
|
|
1188
|
+
return () => {
|
|
1189
|
+
resizeObserver.disconnect();
|
|
1190
|
+
win?.removeEventListener("resize", onChange);
|
|
1191
|
+
};
|
|
1192
|
+
}, [element, onChange]);
|
|
1193
|
+
}
|
|
1194
|
+
function useMutationsListener({ element, onChange }) {
|
|
1195
|
+
useEffect2(() => {
|
|
1196
|
+
if (!element) {
|
|
1197
|
+
return;
|
|
1198
|
+
}
|
|
1199
|
+
const mutationObserver = new MutationObserver(onChange);
|
|
1200
|
+
mutationObserver.observe(element, { childList: true, subtree: true });
|
|
1201
|
+
return () => {
|
|
1202
|
+
mutationObserver.disconnect();
|
|
1203
|
+
};
|
|
1204
|
+
}, [element, onChange]);
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
// src/components/edit-component/component-modal.tsx
|
|
1208
|
+
function ComponentModal({ element, onClose }) {
|
|
1209
|
+
const canvasDocument = useCanvasDocument();
|
|
1210
|
+
useEffect3(() => {
|
|
1211
|
+
const handleEsc = (event) => {
|
|
1212
|
+
if (event.key === "Escape") {
|
|
1213
|
+
onClose();
|
|
1214
|
+
}
|
|
1215
|
+
};
|
|
1216
|
+
canvasDocument?.body.addEventListener("keydown", handleEsc);
|
|
1217
|
+
return () => {
|
|
1218
|
+
canvasDocument?.body.removeEventListener("keydown", handleEsc);
|
|
1219
|
+
};
|
|
1220
|
+
}, [canvasDocument, onClose]);
|
|
1221
|
+
if (!canvasDocument?.body) {
|
|
1222
|
+
return null;
|
|
1223
|
+
}
|
|
1224
|
+
return createPortal(
|
|
1225
|
+
/* @__PURE__ */ React8.createElement(React8.Fragment, null, /* @__PURE__ */ React8.createElement(BlockEditPage, null), /* @__PURE__ */ React8.createElement(Backdrop, { canvas: canvasDocument, element, onClose })),
|
|
1226
|
+
canvasDocument.body
|
|
1227
|
+
);
|
|
1228
|
+
}
|
|
1229
|
+
function Backdrop({ canvas, element, onClose }) {
|
|
1230
|
+
const rect = useElementRect(element);
|
|
1231
|
+
const backdropStyle = {
|
|
1232
|
+
position: "fixed",
|
|
1233
|
+
top: 0,
|
|
1234
|
+
left: 0,
|
|
1235
|
+
width: "100vw",
|
|
1236
|
+
height: "100vh",
|
|
1237
|
+
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
|
1238
|
+
zIndex: 999,
|
|
1239
|
+
pointerEvents: "painted",
|
|
1240
|
+
cursor: "pointer",
|
|
1241
|
+
clipPath: getRoundedRectPath(rect, canvas.defaultView, 5)
|
|
1242
|
+
};
|
|
1243
|
+
const handleKeyDown = (event) => {
|
|
1244
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
1245
|
+
event.preventDefault();
|
|
1246
|
+
onClose();
|
|
1247
|
+
}
|
|
1248
|
+
};
|
|
1249
|
+
return /* @__PURE__ */ React8.createElement(
|
|
1250
|
+
"div",
|
|
278
1251
|
{
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
1252
|
+
style: backdropStyle,
|
|
1253
|
+
onClick: onClose,
|
|
1254
|
+
onKeyDown: handleKeyDown,
|
|
1255
|
+
role: "button",
|
|
1256
|
+
tabIndex: 0,
|
|
1257
|
+
"aria-label": __6("Exit component editing mode", "elementor")
|
|
1258
|
+
}
|
|
1259
|
+
);
|
|
1260
|
+
}
|
|
1261
|
+
function getRoundedRectPath(rect, viewport, borderRadius) {
|
|
1262
|
+
const padding = borderRadius / 2;
|
|
1263
|
+
const { x: originalX, y: originalY, width: originalWidth, height: originalHeight } = rect;
|
|
1264
|
+
const x = originalX - padding;
|
|
1265
|
+
const y = originalY - padding;
|
|
1266
|
+
const width = originalWidth + 2 * padding;
|
|
1267
|
+
const height = originalHeight + 2 * padding;
|
|
1268
|
+
const radius = Math.min(borderRadius, width / 2, height / 2);
|
|
1269
|
+
const { innerWidth: vw, innerHeight: vh } = viewport;
|
|
1270
|
+
const path = `path(evenodd, 'M 0 0
|
|
1271
|
+
L ${vw} 0
|
|
1272
|
+
L ${vw} ${vh}
|
|
1273
|
+
L 0 ${vh}
|
|
1274
|
+
Z
|
|
1275
|
+
M ${x + radius} ${y}
|
|
1276
|
+
L ${x + width - radius} ${y}
|
|
1277
|
+
A ${radius} ${radius} 0 0 1 ${x + width} ${y + radius}
|
|
1278
|
+
L ${x + width} ${y + height - radius}
|
|
1279
|
+
A ${radius} ${radius} 0 0 1 ${x + width - radius} ${y + height}
|
|
1280
|
+
L ${x + radius} ${y + height}
|
|
1281
|
+
A ${radius} ${radius} 0 0 1 ${x} ${y + height - radius}
|
|
1282
|
+
L ${x} ${y + radius}
|
|
1283
|
+
A ${radius} ${radius} 0 0 1 ${x + radius} ${y}
|
|
1284
|
+
Z'
|
|
1285
|
+
)`;
|
|
1286
|
+
return path.replace(/\s{2,}/g, " ");
|
|
1287
|
+
}
|
|
1288
|
+
function BlockEditPage() {
|
|
1289
|
+
const blockV3DocumentHandlesStyles = `
|
|
1290
|
+
.elementor-editor-active {
|
|
1291
|
+
& .elementor-section-wrap.ui-sortable {
|
|
1292
|
+
display: contents;
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
& *[data-editable-elementor-document]:not(.elementor-edit-mode):hover {
|
|
1296
|
+
& .elementor-document-handle:not(.elementor-document-save-back-handle) {
|
|
1297
|
+
display: none;
|
|
1298
|
+
|
|
1299
|
+
&::before,
|
|
1300
|
+
& .elementor-document-handle__inner {
|
|
1301
|
+
display: none;
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
`;
|
|
1307
|
+
return /* @__PURE__ */ React8.createElement("style", { "data-e-style-id": "e-block-v3-document-handles-styles" }, blockV3DocumentHandlesStyles);
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
// src/components/edit-component/edit-component.tsx
|
|
1311
|
+
function EditComponent() {
|
|
1312
|
+
const { path, currentComponentId } = useCurrentComponent();
|
|
1313
|
+
useHandleDocumentSwitches();
|
|
1314
|
+
const onBack = useNavigateBack(path);
|
|
1315
|
+
const elementDom = getComponentDOMElement(currentComponentId ?? void 0);
|
|
1316
|
+
if (!elementDom) {
|
|
1317
|
+
return null;
|
|
1318
|
+
}
|
|
1319
|
+
return /* @__PURE__ */ React9.createElement(ComponentModal, { element: elementDom, onClose: onBack });
|
|
1320
|
+
}
|
|
1321
|
+
function useHandleDocumentSwitches() {
|
|
1322
|
+
const documentsManager = getV1DocumentsManager2();
|
|
1323
|
+
const { path, currentComponentId } = useCurrentComponent();
|
|
1324
|
+
useEffect4(() => {
|
|
1325
|
+
return listenTo(commandEndEvent2("editor/documents/attach-preview"), () => {
|
|
1326
|
+
const nextDocument = documentsManager.getCurrent();
|
|
1327
|
+
if (nextDocument.id === currentComponentId) {
|
|
1328
|
+
return;
|
|
1329
|
+
}
|
|
1330
|
+
if (currentComponentId) {
|
|
1331
|
+
apiClient.unlockComponent(currentComponentId);
|
|
1332
|
+
}
|
|
1333
|
+
const isComponent = nextDocument.config.type === COMPONENT_DOCUMENT_TYPE;
|
|
1334
|
+
if (!isComponent) {
|
|
1335
|
+
updateCurrentComponent({ path: [], currentComponentId: null });
|
|
1336
|
+
return;
|
|
1337
|
+
}
|
|
1338
|
+
updateCurrentComponent({
|
|
1339
|
+
path: getUpdatedComponentPath(path, nextDocument),
|
|
1340
|
+
currentComponentId: nextDocument.id
|
|
1341
|
+
});
|
|
1342
|
+
});
|
|
1343
|
+
}, [path, documentsManager, currentComponentId]);
|
|
1344
|
+
}
|
|
1345
|
+
function getUpdatedComponentPath(path, nextDocument) {
|
|
1346
|
+
const componentIndex = path.findIndex(({ componentId }) => componentId === nextDocument.id);
|
|
1347
|
+
if (componentIndex >= 0) {
|
|
1348
|
+
return path.slice(0, componentIndex + 1);
|
|
1349
|
+
}
|
|
1350
|
+
return [
|
|
1351
|
+
...path,
|
|
1352
|
+
{
|
|
1353
|
+
instanceId: nextDocument?.container.view?.el?.dataset.id,
|
|
1354
|
+
componentId: nextDocument.id
|
|
1355
|
+
}
|
|
1356
|
+
];
|
|
1357
|
+
}
|
|
1358
|
+
function useNavigateBack(path) {
|
|
1359
|
+
const documentsManager = getV1DocumentsManager2();
|
|
1360
|
+
return useCallback(() => {
|
|
1361
|
+
const { componentId: prevComponentId, instanceId: prevComponentInstanceId } = path.at(-2) ?? {};
|
|
1362
|
+
const switchToDocument = (id, selector) => {
|
|
1363
|
+
runCommand3("editor/documents/switch", {
|
|
1364
|
+
id,
|
|
1365
|
+
selector,
|
|
1366
|
+
mode: "autosave",
|
|
1367
|
+
setAsInitial: false,
|
|
1368
|
+
shouldScroll: false
|
|
1369
|
+
});
|
|
1370
|
+
};
|
|
1371
|
+
if (prevComponentId && prevComponentInstanceId) {
|
|
1372
|
+
switchToDocument(prevComponentId, `[data-id="${prevComponentInstanceId}"]`);
|
|
1373
|
+
return;
|
|
1374
|
+
}
|
|
1375
|
+
switchToDocument(documentsManager.getInitialId());
|
|
1376
|
+
}, [path, documentsManager]);
|
|
1377
|
+
}
|
|
1378
|
+
function useCurrentComponent() {
|
|
1379
|
+
const path = useSelector2(selectPath);
|
|
1380
|
+
const currentComponentId = useSelector2(selectCurrentComponentId);
|
|
1381
|
+
return {
|
|
1382
|
+
path,
|
|
1383
|
+
currentComponentId
|
|
1384
|
+
};
|
|
1385
|
+
}
|
|
1386
|
+
function getComponentDOMElement(id) {
|
|
1387
|
+
if (!id) {
|
|
1388
|
+
return null;
|
|
1389
|
+
}
|
|
1390
|
+
const documentsManager = getV1DocumentsManager2();
|
|
1391
|
+
const currentComponent = documentsManager.get(id);
|
|
1392
|
+
const widget = currentComponent?.container;
|
|
1393
|
+
const elementDom = widget?.children?.[0].view?.el;
|
|
1394
|
+
return elementDom ?? null;
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
// src/components/in-edit-mode.tsx
|
|
1398
|
+
import * as React10 from "react";
|
|
1399
|
+
import { closeDialog, openDialog } from "@elementor/editor-ui";
|
|
1400
|
+
import { InfoCircleFilledIcon } from "@elementor/icons";
|
|
1401
|
+
import { Box as Box5, Button as Button2, DialogActions, DialogContent, DialogHeader, Icon as Icon2, Stack as Stack5, Typography as Typography4 } from "@elementor/ui";
|
|
1402
|
+
import { __ as __7 } from "@wordpress/i18n";
|
|
1403
|
+
var openEditModeDialog = (lockedBy) => {
|
|
1404
|
+
openDialog({
|
|
1405
|
+
component: /* @__PURE__ */ React10.createElement(EditModeDialog, { lockedBy })
|
|
1406
|
+
});
|
|
1407
|
+
};
|
|
1408
|
+
var EditModeDialog = ({ lockedBy }) => {
|
|
1409
|
+
const content = __7("%s is currently editing this document", "elementor").replace("%s", lockedBy);
|
|
1410
|
+
return /* @__PURE__ */ React10.createElement(React10.Fragment, null, /* @__PURE__ */ React10.createElement(DialogHeader, { logo: false }, /* @__PURE__ */ React10.createElement(Box5, { display: "flex", alignItems: "center", gap: 1 }, /* @__PURE__ */ React10.createElement(Icon2, { color: "secondary" }, /* @__PURE__ */ React10.createElement(InfoCircleFilledIcon, { fontSize: "medium" })), /* @__PURE__ */ React10.createElement(Typography4, { variant: "subtitle1" }, content))), /* @__PURE__ */ React10.createElement(DialogContent, null, /* @__PURE__ */ React10.createElement(Stack5, { spacing: 2, direction: "column" }, /* @__PURE__ */ React10.createElement(Typography4, { variant: "body2" }, __7(
|
|
1411
|
+
"You can wait for them to finish or reach out to coordinate your changes together.",
|
|
1412
|
+
"elementor"
|
|
1413
|
+
)), /* @__PURE__ */ React10.createElement(DialogActions, null, /* @__PURE__ */ React10.createElement(Button2, { color: "secondary", variant: "contained", onClick: closeDialog }, __7("Close", "elementor"))))));
|
|
1414
|
+
};
|
|
1415
|
+
|
|
1416
|
+
// src/components/overridable-props/overridable-prop-indicator.tsx
|
|
1417
|
+
import * as React13 from "react";
|
|
1418
|
+
import { useBoundProp } from "@elementor/editor-controls";
|
|
1419
|
+
import { getV1CurrentDocument } from "@elementor/editor-documents";
|
|
1420
|
+
import { useElement } from "@elementor/editor-editing-panel";
|
|
1421
|
+
import { getWidgetsCache } from "@elementor/editor-elements";
|
|
1422
|
+
import { __getState as getState6 } from "@elementor/store";
|
|
1423
|
+
import { bindPopover, bindTrigger, Popover as Popover2, Tooltip, usePopupState } from "@elementor/ui";
|
|
1424
|
+
import { __ as __11 } from "@wordpress/i18n";
|
|
1425
|
+
|
|
1426
|
+
// src/prop-types/component-overridable-prop-type.ts
|
|
1427
|
+
import { createPropUtils } from "@elementor/editor-props";
|
|
1428
|
+
import { z as z2 } from "@elementor/schema";
|
|
1429
|
+
var componentOverridablePropTypeUtil = createPropUtils(
|
|
1430
|
+
"overridable",
|
|
1431
|
+
z2.object({
|
|
1432
|
+
override_key: z2.string(),
|
|
1433
|
+
origin_value: z2.object({
|
|
1434
|
+
$$type: z2.string(),
|
|
1435
|
+
value: z2.unknown()
|
|
1436
|
+
}).nullable()
|
|
1437
|
+
})
|
|
1438
|
+
);
|
|
1439
|
+
|
|
1440
|
+
// src/store/set-overridable-prop.ts
|
|
1441
|
+
import { __dispatch as dispatch3, __getState as getState4 } from "@elementor/store";
|
|
1442
|
+
import { generateUniqueId as generateUniqueId2 } from "@elementor/utils";
|
|
1443
|
+
import { __ as __8 } from "@wordpress/i18n";
|
|
1444
|
+
function setOverridableProp({
|
|
1445
|
+
componentId,
|
|
1446
|
+
overrideKey,
|
|
1447
|
+
elementId,
|
|
1448
|
+
label,
|
|
1449
|
+
groupId,
|
|
1450
|
+
propKey,
|
|
1451
|
+
elType,
|
|
1452
|
+
widgetType,
|
|
1453
|
+
originValue
|
|
1454
|
+
}) {
|
|
1455
|
+
const overridableProps = selectOverridableProps(getState4(), componentId);
|
|
1456
|
+
if (!overridableProps) {
|
|
1457
|
+
return;
|
|
1458
|
+
}
|
|
1459
|
+
const existingOverridableProp = overrideKey ? overridableProps.props[overrideKey] : null;
|
|
1460
|
+
const { props: existingProps, groups: existingGroups } = { ...overridableProps };
|
|
1461
|
+
const { groups: updatedGroups, currentGroupId } = getUpdatedGroups(
|
|
1462
|
+
existingGroups,
|
|
1463
|
+
groupId || existingOverridableProp?.groupId
|
|
1464
|
+
);
|
|
1465
|
+
const overridableProp = {
|
|
1466
|
+
overrideKey: existingOverridableProp?.overrideKey || generateUniqueId2("prop"),
|
|
1467
|
+
label,
|
|
1468
|
+
elementId,
|
|
1469
|
+
propKey,
|
|
1470
|
+
widgetType,
|
|
1471
|
+
elType,
|
|
1472
|
+
originValue,
|
|
1473
|
+
groupId: currentGroupId
|
|
1474
|
+
};
|
|
1475
|
+
const props = {
|
|
1476
|
+
...existingProps,
|
|
1477
|
+
[overridableProp.overrideKey]: overridableProp
|
|
1478
|
+
};
|
|
1479
|
+
const groups = {
|
|
1480
|
+
items: {
|
|
1481
|
+
...updatedGroups.items,
|
|
1482
|
+
[currentGroupId]: getGroupWithProp(updatedGroups, currentGroupId, overridableProp)
|
|
284
1483
|
},
|
|
285
|
-
|
|
286
|
-
|
|
1484
|
+
order: updatedGroups.order.includes(currentGroupId) ? updatedGroups.order : [...updatedGroups.order, currentGroupId]
|
|
1485
|
+
};
|
|
1486
|
+
const isChangingGroups = existingOverridableProp && existingOverridableProp.groupId !== currentGroupId;
|
|
1487
|
+
if (isChangingGroups) {
|
|
1488
|
+
groups.items[existingOverridableProp.groupId] = getGroupWithoutProp(
|
|
1489
|
+
updatedGroups,
|
|
1490
|
+
existingOverridableProp.groupId,
|
|
1491
|
+
overridableProp
|
|
1492
|
+
);
|
|
1493
|
+
}
|
|
1494
|
+
dispatch3(
|
|
1495
|
+
slice.actions.setOverridableProps({
|
|
1496
|
+
componentId,
|
|
1497
|
+
overridableProps: {
|
|
1498
|
+
props,
|
|
1499
|
+
groups
|
|
1500
|
+
}
|
|
1501
|
+
})
|
|
1502
|
+
);
|
|
1503
|
+
return overridableProp;
|
|
1504
|
+
}
|
|
1505
|
+
function getUpdatedGroups(groups, groupId) {
|
|
1506
|
+
if (!groupId) {
|
|
1507
|
+
if (groups.order.length > 0) {
|
|
1508
|
+
return { groups, currentGroupId: groups.order[0] };
|
|
1509
|
+
}
|
|
1510
|
+
return addNewGroup(groups);
|
|
1511
|
+
}
|
|
1512
|
+
if (!groups.items[groupId]) {
|
|
1513
|
+
return addNewGroup(groups, groupId);
|
|
1514
|
+
}
|
|
1515
|
+
return { groups, currentGroupId: groupId };
|
|
1516
|
+
}
|
|
1517
|
+
function addNewGroup(groups, groupId) {
|
|
1518
|
+
const currentGroupId = groupId || generateUniqueId2("group");
|
|
1519
|
+
const updatedGroups = {
|
|
1520
|
+
...groups,
|
|
1521
|
+
items: {
|
|
1522
|
+
...groups.items,
|
|
1523
|
+
[currentGroupId]: {
|
|
1524
|
+
id: currentGroupId,
|
|
1525
|
+
label: __8("Default", "elementor"),
|
|
1526
|
+
props: []
|
|
1527
|
+
}
|
|
1528
|
+
},
|
|
1529
|
+
order: [...groups.order, currentGroupId]
|
|
1530
|
+
};
|
|
1531
|
+
return { groups: updatedGroups, currentGroupId };
|
|
1532
|
+
}
|
|
1533
|
+
function getGroupWithProp(groups, groupId, overridableProp) {
|
|
1534
|
+
const group = { ...groups.items[groupId] };
|
|
1535
|
+
if (!group.props.includes(overridableProp.overrideKey)) {
|
|
1536
|
+
group.props = [...group.props, overridableProp.overrideKey];
|
|
1537
|
+
}
|
|
1538
|
+
return group;
|
|
1539
|
+
}
|
|
1540
|
+
function getGroupWithoutProp(groups, groupId, overridableProp) {
|
|
1541
|
+
const group = { ...groups.items[groupId] };
|
|
1542
|
+
if (group) {
|
|
1543
|
+
group.props = group.props.filter((key) => key !== overridableProp.overrideKey);
|
|
1544
|
+
}
|
|
1545
|
+
return group;
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
// src/components/overridable-props/indicator.tsx
|
|
1549
|
+
import * as React11 from "react";
|
|
1550
|
+
import { forwardRef } from "react";
|
|
1551
|
+
import { CheckIcon, PlusIcon } from "@elementor/icons";
|
|
1552
|
+
import { Box as Box6, styled } from "@elementor/ui";
|
|
1553
|
+
import { __ as __9 } from "@wordpress/i18n";
|
|
1554
|
+
var SIZE = "tiny";
|
|
1555
|
+
var IconContainer = styled(Box6)`
|
|
1556
|
+
pointer-events: none;
|
|
1557
|
+
opacity: 0;
|
|
1558
|
+
transition: opacity 0.2s ease-in-out;
|
|
1559
|
+
|
|
1560
|
+
& > svg {
|
|
1561
|
+
position: absolute;
|
|
1562
|
+
top: 50%;
|
|
1563
|
+
left: 50%;
|
|
1564
|
+
transform: translate( -50%, -50% );
|
|
1565
|
+
width: 10px;
|
|
1566
|
+
height: 10px;
|
|
1567
|
+
fill: ${({ theme }) => theme.palette.primary.contrastText};
|
|
1568
|
+
stroke: ${({ theme }) => theme.palette.primary.contrastText};
|
|
1569
|
+
stroke-width: 2px;
|
|
1570
|
+
}
|
|
1571
|
+
`;
|
|
1572
|
+
var Content = styled(Box6)`
|
|
1573
|
+
position: relative;
|
|
1574
|
+
display: flex;
|
|
1575
|
+
align-items: center;
|
|
1576
|
+
justify-content: center;
|
|
1577
|
+
cursor: pointer;
|
|
1578
|
+
width: 16px;
|
|
1579
|
+
height: 16px;
|
|
1580
|
+
margin-inline: ${({ theme }) => theme.spacing(0.5)};
|
|
1581
|
+
|
|
1582
|
+
&:before {
|
|
1583
|
+
content: '';
|
|
1584
|
+
display: block;
|
|
1585
|
+
position: absolute;
|
|
1586
|
+
top: 50%;
|
|
1587
|
+
left: 50%;
|
|
1588
|
+
transform: translate( -50%, -50% ) rotate( 45deg );
|
|
1589
|
+
width: 5px;
|
|
1590
|
+
height: 5px;
|
|
1591
|
+
border-radius: 1px;
|
|
1592
|
+
background-color: ${({ theme }) => theme.palette.primary.main};
|
|
1593
|
+
transition: all 0.1s ease-in-out;
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
&:hover,
|
|
1597
|
+
&.enlarged {
|
|
1598
|
+
&:before {
|
|
1599
|
+
width: 12px;
|
|
1600
|
+
height: 12px;
|
|
1601
|
+
border-radius: 2px;
|
|
1602
|
+
}
|
|
1603
|
+
|
|
1604
|
+
.icon {
|
|
1605
|
+
opacity: 1;
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
`;
|
|
1609
|
+
var Indicator = forwardRef(({ triggerProps, isOpen, isOverridable }, ref) => /* @__PURE__ */ React11.createElement(Content, { ref, ...triggerProps, className: isOpen || isOverridable ? "enlarged" : "" }, /* @__PURE__ */ React11.createElement(
|
|
1610
|
+
IconContainer,
|
|
1611
|
+
{
|
|
1612
|
+
className: "icon",
|
|
1613
|
+
"aria-label": isOverridable ? __9("Overridable property", "elementor") : __9("Make prop overridable", "elementor")
|
|
1614
|
+
},
|
|
1615
|
+
isOverridable ? /* @__PURE__ */ React11.createElement(CheckIcon, { fontSize: SIZE }) : /* @__PURE__ */ React11.createElement(PlusIcon, { fontSize: SIZE })
|
|
1616
|
+
)));
|
|
1617
|
+
|
|
1618
|
+
// src/components/overridable-props/overridable-prop-form.tsx
|
|
1619
|
+
import * as React12 from "react";
|
|
1620
|
+
import { useState as useState4 } from "react";
|
|
1621
|
+
import { Form as Form2, MenuListItem } from "@elementor/editor-ui";
|
|
1622
|
+
import { Button as Button3, FormLabel as FormLabel2, Grid as Grid2, Select, Stack as Stack6, TextField as TextField3, Typography as Typography5 } from "@elementor/ui";
|
|
1623
|
+
import { __ as __10 } from "@wordpress/i18n";
|
|
1624
|
+
var SIZE2 = "tiny";
|
|
1625
|
+
var DEFAULT_GROUP = { value: null, label: __10("Default", "elementor") };
|
|
1626
|
+
function OverridablePropForm({ onSubmit, groups, currentValue }) {
|
|
1627
|
+
const [propLabel, setPropLabel] = useState4(currentValue?.label ?? null);
|
|
1628
|
+
const [group, setGroup] = useState4(currentValue?.groupId ?? groups?.[0]?.value ?? null);
|
|
1629
|
+
const name = __10("Name", "elementor");
|
|
1630
|
+
const groupName = __10("Group Name", "elementor");
|
|
1631
|
+
const isCreate = currentValue === void 0;
|
|
1632
|
+
const title = isCreate ? __10("Create new property", "elementor") : __10("Update property", "elementor");
|
|
1633
|
+
const ctaLabel = isCreate ? __10("Create", "elementor") : __10("Update", "elementor");
|
|
1634
|
+
return /* @__PURE__ */ React12.createElement(Form2, { onSubmit: () => onSubmit({ label: propLabel ?? "", group }) }, /* @__PURE__ */ React12.createElement(Stack6, { alignItems: "start", width: "268px" }, /* @__PURE__ */ React12.createElement(
|
|
1635
|
+
Stack6,
|
|
1636
|
+
{
|
|
1637
|
+
direction: "row",
|
|
1638
|
+
alignItems: "center",
|
|
1639
|
+
py: 1,
|
|
1640
|
+
px: 1.5,
|
|
1641
|
+
sx: { columnGap: 0.5, borderBottom: "1px solid", borderColor: "divider", width: "100%", mb: 1.5 }
|
|
1642
|
+
},
|
|
1643
|
+
/* @__PURE__ */ React12.createElement(Typography5, { variant: "caption", sx: { color: "text.primary", fontWeight: "500", lineHeight: 1 } }, title)
|
|
1644
|
+
), /* @__PURE__ */ React12.createElement(Grid2, { container: true, gap: 0.75, alignItems: "start", px: 1.5, mb: 1.5 }, /* @__PURE__ */ React12.createElement(Grid2, { item: true, xs: 12 }, /* @__PURE__ */ React12.createElement(FormLabel2, { size: "tiny" }, name)), /* @__PURE__ */ React12.createElement(Grid2, { item: true, xs: 12 }, /* @__PURE__ */ React12.createElement(
|
|
1645
|
+
TextField3,
|
|
1646
|
+
{
|
|
1647
|
+
name,
|
|
1648
|
+
size: SIZE2,
|
|
1649
|
+
fullWidth: true,
|
|
1650
|
+
placeholder: __10("Enter value", "elementor"),
|
|
1651
|
+
value: propLabel ?? "",
|
|
1652
|
+
onChange: (e) => setPropLabel(e.target.value)
|
|
1653
|
+
}
|
|
1654
|
+
))), /* @__PURE__ */ React12.createElement(Grid2, { container: true, gap: 0.75, alignItems: "start", px: 1.5, mb: 1.5 }, /* @__PURE__ */ React12.createElement(Grid2, { item: true, xs: 12 }, /* @__PURE__ */ React12.createElement(FormLabel2, { size: "tiny" }, groupName)), /* @__PURE__ */ React12.createElement(Grid2, { item: true, xs: 12 }, /* @__PURE__ */ React12.createElement(
|
|
1655
|
+
Select,
|
|
1656
|
+
{
|
|
1657
|
+
name: groupName,
|
|
1658
|
+
size: SIZE2,
|
|
1659
|
+
fullWidth: true,
|
|
1660
|
+
value: group ?? null,
|
|
1661
|
+
onChange: setGroup,
|
|
1662
|
+
displayEmpty: true,
|
|
1663
|
+
renderValue: (selectedValue) => {
|
|
1664
|
+
if (!selectedValue || selectedValue === "") {
|
|
1665
|
+
const [firstGroup = DEFAULT_GROUP] = groups ?? [];
|
|
1666
|
+
return firstGroup.label;
|
|
1667
|
+
}
|
|
1668
|
+
return groups?.find(({ value }) => value === selectedValue)?.label ?? selectedValue;
|
|
1669
|
+
}
|
|
1670
|
+
},
|
|
1671
|
+
(groups ?? [DEFAULT_GROUP]).map(({ label: groupLabel, ...props }) => /* @__PURE__ */ React12.createElement(MenuListItem, { key: props.value, ...props, value: props.value ?? "" }, groupLabel))
|
|
1672
|
+
))), /* @__PURE__ */ React12.createElement(Stack6, { direction: "row", justifyContent: "flex-end", alignSelf: "end", mt: 1.5, py: 1, px: 1.5 }, /* @__PURE__ */ React12.createElement(Button3, { type: "submit", disabled: !propLabel, variant: "contained", color: "primary", size: "small" }, ctaLabel))));
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
// src/components/overridable-props/utils/get-overridable-prop.ts
|
|
1676
|
+
import { __getState as getState5 } from "@elementor/store";
|
|
1677
|
+
function getOverridableProp({
|
|
1678
|
+
componentId,
|
|
1679
|
+
overrideKey
|
|
1680
|
+
}) {
|
|
1681
|
+
const overridableProps = selectOverridableProps(getState5(), componentId);
|
|
1682
|
+
if (!overridableProps) {
|
|
1683
|
+
return void 0;
|
|
1684
|
+
}
|
|
1685
|
+
return overridableProps.props[overrideKey];
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1688
|
+
// src/components/overridable-props/overridable-prop-indicator.tsx
|
|
1689
|
+
var FORBIDDEN_KEYS = ["_cssid", "attributes"];
|
|
1690
|
+
function OverridablePropIndicator() {
|
|
1691
|
+
const { bind } = useBoundProp();
|
|
1692
|
+
const currentDocument = getV1CurrentDocument();
|
|
1693
|
+
if (currentDocument.config.type !== COMPONENT_DOCUMENT_TYPE || !currentDocument.id) {
|
|
1694
|
+
return null;
|
|
1695
|
+
}
|
|
1696
|
+
if (!isPropAllowed(bind)) {
|
|
1697
|
+
return null;
|
|
1698
|
+
}
|
|
1699
|
+
const overridableProps = selectOverridableProps(getState6(), currentDocument.id);
|
|
1700
|
+
return /* @__PURE__ */ React13.createElement(Content2, { componentId: currentDocument.id, overridableProps });
|
|
1701
|
+
}
|
|
1702
|
+
function Content2({ componentId, overridableProps }) {
|
|
1703
|
+
const {
|
|
1704
|
+
element: { id: elementId },
|
|
1705
|
+
elementType
|
|
1706
|
+
} = useElement();
|
|
1707
|
+
const { value, bind } = useBoundProp();
|
|
1708
|
+
const { value: overridableValue, setValue: setOverridableValue } = useBoundProp(componentOverridablePropTypeUtil);
|
|
1709
|
+
const popupState = usePopupState({
|
|
1710
|
+
variant: "popover"
|
|
1711
|
+
});
|
|
1712
|
+
const triggerProps = bindTrigger(popupState);
|
|
1713
|
+
const popoverProps = bindPopover(popupState);
|
|
1714
|
+
const { elType } = getWidgetsCache()?.[elementType.key] ?? { elType: "widget" };
|
|
1715
|
+
const handleSubmit = ({ label, group }) => {
|
|
1716
|
+
const originValue = !overridableValue ? value : overridableValue?.origin_value ?? {};
|
|
1717
|
+
const overridablePropConfig = setOverridableProp({
|
|
1718
|
+
componentId,
|
|
1719
|
+
overrideKey: overridableValue?.override_key ?? null,
|
|
1720
|
+
elementId,
|
|
1721
|
+
label,
|
|
1722
|
+
groupId: group,
|
|
1723
|
+
propKey: bind,
|
|
1724
|
+
elType: elType ?? "widget",
|
|
1725
|
+
widgetType: elementType.key,
|
|
1726
|
+
originValue
|
|
1727
|
+
});
|
|
1728
|
+
if (!overridableValue && overridablePropConfig) {
|
|
1729
|
+
setOverridableValue({
|
|
1730
|
+
override_key: overridablePropConfig.overrideKey,
|
|
1731
|
+
origin_value: originValue
|
|
1732
|
+
});
|
|
1733
|
+
}
|
|
1734
|
+
popupState.close();
|
|
1735
|
+
};
|
|
1736
|
+
const overridableConfig = overridableValue ? getOverridableProp({ componentId, overrideKey: overridableValue.override_key }) : void 0;
|
|
1737
|
+
return /* @__PURE__ */ React13.createElement(React13.Fragment, null, /* @__PURE__ */ React13.createElement(Tooltip, { placement: "top", title: __11("Override Property", "elementor") }, /* @__PURE__ */ React13.createElement(
|
|
1738
|
+
Indicator,
|
|
1739
|
+
{
|
|
1740
|
+
triggerProps,
|
|
1741
|
+
isOpen: !!popoverProps.open,
|
|
1742
|
+
isOverridable: !!overridableValue
|
|
1743
|
+
}
|
|
1744
|
+
)), /* @__PURE__ */ React13.createElement(
|
|
1745
|
+
Popover2,
|
|
1746
|
+
{
|
|
1747
|
+
disableScrollLock: true,
|
|
1748
|
+
anchorOrigin: {
|
|
1749
|
+
vertical: "bottom",
|
|
1750
|
+
horizontal: "right"
|
|
1751
|
+
},
|
|
1752
|
+
transformOrigin: {
|
|
1753
|
+
vertical: "top",
|
|
1754
|
+
horizontal: "right"
|
|
1755
|
+
},
|
|
1756
|
+
PaperProps: {
|
|
1757
|
+
sx: { my: 2.5 }
|
|
1758
|
+
},
|
|
1759
|
+
...popoverProps
|
|
1760
|
+
},
|
|
1761
|
+
/* @__PURE__ */ React13.createElement(
|
|
1762
|
+
OverridablePropForm,
|
|
1763
|
+
{
|
|
1764
|
+
onSubmit: handleSubmit,
|
|
1765
|
+
groups: overridableProps?.groups.order.map((groupId) => ({
|
|
1766
|
+
value: groupId,
|
|
1767
|
+
label: overridableProps.groups.items[groupId].label
|
|
1768
|
+
})),
|
|
1769
|
+
currentValue: overridableConfig
|
|
1770
|
+
}
|
|
1771
|
+
)
|
|
1772
|
+
));
|
|
1773
|
+
}
|
|
1774
|
+
function isPropAllowed(bind) {
|
|
1775
|
+
return !FORBIDDEN_KEYS.includes(bind);
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
// src/mcp/index.ts
|
|
1779
|
+
import { getMCPByDomain as getMCPByDomain2 } from "@elementor/editor-mcp";
|
|
1780
|
+
|
|
1781
|
+
// src/mcp/save-as-component-tool.ts
|
|
1782
|
+
import { getContainer as getContainer2 } from "@elementor/editor-elements";
|
|
1783
|
+
import { getMCPByDomain } from "@elementor/editor-mcp";
|
|
1784
|
+
import { z as z3 } from "@elementor/schema";
|
|
1785
|
+
var InputSchema = {
|
|
1786
|
+
element_id: z3.string().describe(
|
|
1787
|
+
'The unique identifier of the element to save as a component. Use the "list-elements" tool to find available element IDs in the current document.'
|
|
1788
|
+
),
|
|
1789
|
+
component_name: z3.string().describe("The name for the new component. Should be descriptive and unique among existing components.")
|
|
1790
|
+
};
|
|
1791
|
+
var OutputSchema = {
|
|
1792
|
+
message: z3.string().optional().describe("Additional information about the operation result"),
|
|
1793
|
+
component_uid: z3.string().optional().describe("The unique identifier of the newly created component (only present on success)")
|
|
1794
|
+
};
|
|
1795
|
+
var VALID_ELEMENT_TYPES = ["e-div-block", "e-flexbox", "e-tabs"];
|
|
1796
|
+
var ERROR_MESSAGES = {
|
|
1797
|
+
ELEMENT_NOT_FOUND: "Element not found. Use 'list-elements' to get valid element IDs.",
|
|
1798
|
+
ELEMENT_NOT_ONE_OF_TYPES: `Element is not one of the following types: ${VALID_ELEMENT_TYPES.join(", ")}`,
|
|
1799
|
+
ELEMENT_IS_LOCKED: "Cannot save a locked element as a component."
|
|
1800
|
+
};
|
|
1801
|
+
var handleSaveAsComponent = async (params) => {
|
|
1802
|
+
const { element_id: elementId, component_name: componentName } = params;
|
|
1803
|
+
const container = getContainer2(elementId);
|
|
1804
|
+
if (!container) {
|
|
1805
|
+
throw new Error(ERROR_MESSAGES.ELEMENT_NOT_FOUND);
|
|
1806
|
+
}
|
|
1807
|
+
const elType = container.model.get("elType");
|
|
1808
|
+
if (!VALID_ELEMENT_TYPES.includes(elType)) {
|
|
1809
|
+
throw new Error(ERROR_MESSAGES.ELEMENT_NOT_ONE_OF_TYPES);
|
|
1810
|
+
}
|
|
1811
|
+
const element = container.model.toJSON({ remove: ["default"] });
|
|
1812
|
+
if (element?.isLocked) {
|
|
1813
|
+
throw new Error(ERROR_MESSAGES.ELEMENT_IS_LOCKED);
|
|
1814
|
+
}
|
|
1815
|
+
const uid = createUnpublishedComponent(componentName, element, null);
|
|
1816
|
+
return {
|
|
1817
|
+
status: "ok",
|
|
1818
|
+
message: `Component "${componentName}" created successfully.`,
|
|
1819
|
+
component_uid: uid
|
|
1820
|
+
};
|
|
1821
|
+
};
|
|
1822
|
+
var initSaveAsComponentTool = () => {
|
|
1823
|
+
return getMCPByDomain("components").addTool({
|
|
1824
|
+
name: "save-as-component",
|
|
1825
|
+
schema: InputSchema,
|
|
1826
|
+
outputSchema: OutputSchema,
|
|
1827
|
+
description: `Save an existing element as a reusable component in the Elementor editor.
|
|
1828
|
+
|
|
1829
|
+
## When NOT to use this tool:
|
|
1830
|
+
- Do not use for elements that are already components (widgetType: 'e-component').
|
|
1831
|
+
- Do not use for locked elements.
|
|
1832
|
+
- Do not guess element IDs. Always use "list-elements" first to get valid IDs.
|
|
1833
|
+
|
|
1834
|
+
## Prerequisites:
|
|
1835
|
+
- **Verify element type**: Ensure the element is not already a component (widgetType should not be 'e-component').
|
|
1836
|
+
- **Check if element is unlocked**: Locked elements cannot be saved as components.
|
|
1837
|
+
- **Check that the element is one of the following types**: ${VALID_ELEMENT_TYPES.join(", ")}
|
|
1838
|
+
|
|
1839
|
+
## Required parameters:
|
|
1840
|
+
- **element_id**: The unique ID of the element to save.
|
|
1841
|
+
- **component_name**: A descriptive name for the component (2-50 characters).
|
|
1842
|
+
|
|
1843
|
+
## Example tool call:
|
|
1844
|
+
\`\`\`json
|
|
1845
|
+
{ "element_id": "abc123", "component_name": "Hero Section" }
|
|
1846
|
+
\`\`\`
|
|
1847
|
+
`,
|
|
1848
|
+
handler: handleSaveAsComponent
|
|
1849
|
+
});
|
|
1850
|
+
};
|
|
1851
|
+
|
|
1852
|
+
// src/mcp/index.ts
|
|
1853
|
+
function initMcp() {
|
|
1854
|
+
const { setMCPDescription } = getMCPByDomain2("components");
|
|
1855
|
+
setMCPDescription(
|
|
1856
|
+
`Elementor Editor Components MCP - Tools for creating and managing reusable components.
|
|
1857
|
+
Components are reusable blocks of content that can be used multiple times across the pages, its a widget which contains a set of elements and styles.`
|
|
1858
|
+
);
|
|
1859
|
+
initSaveAsComponentTool();
|
|
1860
|
+
}
|
|
1861
|
+
|
|
1862
|
+
// src/populate-store.ts
|
|
1863
|
+
import { useEffect as useEffect5 } from "react";
|
|
1864
|
+
import { __dispatch as dispatch4 } from "@elementor/store";
|
|
1865
|
+
function PopulateStore() {
|
|
1866
|
+
useEffect5(() => {
|
|
1867
|
+
dispatch4(loadComponents());
|
|
1868
|
+
}, []);
|
|
1869
|
+
return null;
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1872
|
+
// src/store/components-styles-provider.ts
|
|
1873
|
+
import { createStylesProvider } from "@elementor/editor-styles-repository";
|
|
1874
|
+
import { __getState as getState7, __subscribeWithSelector as subscribeWithSelector } from "@elementor/store";
|
|
1875
|
+
var componentsStylesProvider = createStylesProvider({
|
|
1876
|
+
key: "components-styles",
|
|
1877
|
+
priority: 100,
|
|
1878
|
+
subscribe: (cb) => subscribeWithSelector(
|
|
1879
|
+
(state) => state[SLICE_NAME],
|
|
1880
|
+
() => {
|
|
1881
|
+
cb();
|
|
1882
|
+
}
|
|
1883
|
+
),
|
|
1884
|
+
actions: {
|
|
1885
|
+
all: () => {
|
|
1886
|
+
return selectFlatStyles(getState7());
|
|
1887
|
+
},
|
|
1888
|
+
get: (id) => {
|
|
1889
|
+
return selectFlatStyles(getState7()).find((style) => style.id === id) ?? null;
|
|
1890
|
+
}
|
|
1891
|
+
}
|
|
1892
|
+
});
|
|
1893
|
+
|
|
1894
|
+
// src/store/remove-component-styles.ts
|
|
1895
|
+
import { __dispatch as dispatch5 } from "@elementor/store";
|
|
1896
|
+
function removeComponentStyles(id) {
|
|
1897
|
+
apiClient.invalidateComponentConfigCache(id);
|
|
1898
|
+
dispatch5(slice.actions.removeStyles({ id }));
|
|
1899
|
+
}
|
|
1900
|
+
|
|
1901
|
+
// src/sync/create-components-before-save.ts
|
|
1902
|
+
import { updateElementSettings } from "@elementor/editor-elements";
|
|
1903
|
+
import { __dispatch as dispatch6, __getState as getState8 } from "@elementor/store";
|
|
1904
|
+
async function createComponentsBeforeSave({
|
|
1905
|
+
container,
|
|
1906
|
+
status
|
|
1907
|
+
}) {
|
|
1908
|
+
const unpublishedComponents = selectUnpublishedComponents(getState8());
|
|
1909
|
+
if (!unpublishedComponents.length) {
|
|
1910
|
+
return;
|
|
1911
|
+
}
|
|
1912
|
+
try {
|
|
1913
|
+
const uidToComponentId = await createComponents(unpublishedComponents, status);
|
|
1914
|
+
const elements = container.model.get("elements").toJSON();
|
|
1915
|
+
updateComponentInstances(elements, uidToComponentId);
|
|
1916
|
+
dispatch6(
|
|
1917
|
+
slice.actions.add(
|
|
1918
|
+
unpublishedComponents.map((component) => ({
|
|
1919
|
+
id: uidToComponentId.get(component.uid),
|
|
1920
|
+
name: component.name,
|
|
1921
|
+
uid: component.uid
|
|
1922
|
+
}))
|
|
1923
|
+
)
|
|
1924
|
+
);
|
|
1925
|
+
dispatch6(slice.actions.resetUnpublished());
|
|
1926
|
+
} catch (error) {
|
|
1927
|
+
throw new Error(`Failed to publish components and update component instances: ${error}`);
|
|
1928
|
+
}
|
|
1929
|
+
}
|
|
1930
|
+
async function createComponents(components, status) {
|
|
1931
|
+
const response = await apiClient.create({
|
|
1932
|
+
status,
|
|
1933
|
+
items: components.map((component) => ({
|
|
1934
|
+
uid: component.uid,
|
|
1935
|
+
title: component.name,
|
|
1936
|
+
elements: component.elements
|
|
1937
|
+
}))
|
|
1938
|
+
});
|
|
1939
|
+
const map = /* @__PURE__ */ new Map();
|
|
1940
|
+
Object.entries(response).forEach(([key, value]) => {
|
|
1941
|
+
map.set(key, value);
|
|
1942
|
+
});
|
|
1943
|
+
return map;
|
|
1944
|
+
}
|
|
1945
|
+
function updateComponentInstances(elements, uidToComponentId) {
|
|
1946
|
+
elements.forEach((element) => {
|
|
1947
|
+
const { shouldUpdate, newComponentId } = shouldUpdateElement(element, uidToComponentId);
|
|
1948
|
+
if (shouldUpdate) {
|
|
1949
|
+
updateElementComponentId(element.id, newComponentId);
|
|
1950
|
+
}
|
|
1951
|
+
if (element.elements) {
|
|
1952
|
+
updateComponentInstances(element.elements, uidToComponentId);
|
|
1953
|
+
}
|
|
1954
|
+
});
|
|
1955
|
+
}
|
|
1956
|
+
function shouldUpdateElement(element, uidToComponentId) {
|
|
1957
|
+
if (element.widgetType === "e-component") {
|
|
1958
|
+
const currentComponentId = element.settings?.component_instance?.value?.component_id;
|
|
1959
|
+
if (currentComponentId && uidToComponentId.has(currentComponentId)) {
|
|
1960
|
+
return { shouldUpdate: true, newComponentId: uidToComponentId.get(currentComponentId) };
|
|
1961
|
+
}
|
|
1962
|
+
}
|
|
1963
|
+
return { shouldUpdate: false, newComponentId: null };
|
|
1964
|
+
}
|
|
1965
|
+
function updateElementComponentId(elementId, componentId) {
|
|
1966
|
+
updateElementSettings({
|
|
1967
|
+
id: elementId,
|
|
1968
|
+
props: {
|
|
1969
|
+
component_instance: {
|
|
1970
|
+
$$type: "component-instance",
|
|
1971
|
+
value: { component_id: componentId }
|
|
1972
|
+
}
|
|
1973
|
+
},
|
|
1974
|
+
withHistory: false
|
|
1975
|
+
});
|
|
1976
|
+
}
|
|
1977
|
+
|
|
1978
|
+
// src/sync/update-components-before-save.ts
|
|
1979
|
+
import { isDocumentDirty as isDocumentDirty2 } from "@elementor/editor-documents";
|
|
1980
|
+
async function updateComponentsBeforeSave({ status, container }) {
|
|
1981
|
+
if (status !== "publish") {
|
|
1982
|
+
return;
|
|
1983
|
+
}
|
|
1984
|
+
const elements = container.model.get("elements").toJSON();
|
|
1985
|
+
const componentIds = await getComponentIds(elements);
|
|
1986
|
+
const componentDocumentData = await Promise.all(componentIds.map(getComponentDocumentData));
|
|
1987
|
+
const draftIds = componentDocumentData.filter((document) => !!document).filter(isDocumentDirty2).map((document) => document.id);
|
|
1988
|
+
if (draftIds.length === 0) {
|
|
1989
|
+
return;
|
|
1990
|
+
}
|
|
1991
|
+
await apiClient.updateStatuses(draftIds, "publish");
|
|
1992
|
+
draftIds.forEach((id) => invalidateComponentDocumentData(id));
|
|
1993
|
+
}
|
|
1994
|
+
|
|
1995
|
+
// src/sync/before-save.ts
|
|
1996
|
+
var beforeSave = ({ container, status }) => {
|
|
1997
|
+
return Promise.all([
|
|
1998
|
+
createComponentsBeforeSave({ container, status }),
|
|
1999
|
+
updateComponentsBeforeSave({ container, status })
|
|
2000
|
+
]);
|
|
287
2001
|
};
|
|
288
2002
|
|
|
289
2003
|
// src/init.ts
|
|
290
2004
|
function init() {
|
|
2005
|
+
stylesRepository.register(componentsStylesProvider);
|
|
2006
|
+
registerSlice(slice);
|
|
2007
|
+
registerElementType(
|
|
2008
|
+
TYPE,
|
|
2009
|
+
(options) => createComponentType({ ...options, showLockedByModal: openEditModeDialog })
|
|
2010
|
+
);
|
|
2011
|
+
registerDataHook("dependency", "editor/documents/close", (args) => {
|
|
2012
|
+
const document = getV1CurrentDocument2();
|
|
2013
|
+
if (document.config.type === COMPONENT_DOCUMENT_TYPE) {
|
|
2014
|
+
args.mode = "autosave";
|
|
2015
|
+
}
|
|
2016
|
+
return true;
|
|
2017
|
+
});
|
|
2018
|
+
registerDataHook("after", "preview/drop", onElementDrop);
|
|
2019
|
+
window.elementorCommon.__beforeSave = beforeSave;
|
|
291
2020
|
injectTab({
|
|
292
2021
|
id: "components",
|
|
293
|
-
label:
|
|
294
|
-
component:
|
|
2022
|
+
label: __12("Components", "elementor"),
|
|
2023
|
+
component: Components
|
|
295
2024
|
});
|
|
296
2025
|
injectIntoTop({
|
|
297
2026
|
id: "create-component-popup",
|
|
298
2027
|
component: CreateComponentForm
|
|
299
2028
|
});
|
|
2029
|
+
injectIntoLogic({
|
|
2030
|
+
id: "components-populate-store",
|
|
2031
|
+
component: PopulateStore
|
|
2032
|
+
});
|
|
2033
|
+
injectIntoTop({
|
|
2034
|
+
id: "edit-component",
|
|
2035
|
+
component: EditComponent
|
|
2036
|
+
});
|
|
2037
|
+
registerDataHook("after", "editor/documents/attach-preview", async () => {
|
|
2038
|
+
const { id, config } = getV1CurrentDocument2();
|
|
2039
|
+
if (id) {
|
|
2040
|
+
removeComponentStyles(id);
|
|
2041
|
+
}
|
|
2042
|
+
await loadComponentsAssets(config?.elements ?? []);
|
|
2043
|
+
});
|
|
2044
|
+
registerFieldIndicator({
|
|
2045
|
+
fieldType: FIELD_TYPE.SETTINGS,
|
|
2046
|
+
id: "component-overridable-prop",
|
|
2047
|
+
priority: 1,
|
|
2048
|
+
indicator: OverridablePropIndicator
|
|
2049
|
+
});
|
|
2050
|
+
settingsTransformersRegistry2.register("component-instance", componentInstanceTransformer);
|
|
2051
|
+
settingsTransformersRegistry2.register("overridable", componentOverridableTransformer);
|
|
2052
|
+
initMcp();
|
|
300
2053
|
}
|
|
301
2054
|
export {
|
|
302
2055
|
init
|