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