@elementor/editor-components 4.0.0-manual → 4.0.1

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 (106) hide show
  1. package/dist/index.d.mts +1422 -1
  2. package/dist/index.d.ts +1422 -1
  3. package/dist/index.js +2096 -4814
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.mjs +2028 -4837
  6. package/dist/index.mjs.map +1 -1
  7. package/package.json +23 -23
  8. package/src/components/components-tab/components-list.tsx +92 -4
  9. package/src/components/components-tab/components-pro-notification.tsx +9 -15
  10. package/src/components/components-tab/components-update-notification.tsx +13 -0
  11. package/src/components/components-tab/components.tsx +52 -3
  12. package/src/components/components-tab/loading-components.tsx +26 -14
  13. package/src/components/components-update-alert.tsx +40 -0
  14. package/src/components/components-upgrade-alert.tsx +39 -0
  15. package/src/components/detach-instance-confirmation-dialog.tsx +50 -0
  16. package/src/components/instance-editing-panel/detach-action.tsx +76 -0
  17. package/src/components/instance-editing-panel/empty-state.tsx +9 -2
  18. package/src/components/instance-editing-panel/instance-editing-panel.tsx +34 -6
  19. package/src/components/instance-editing-panel/override-prop-control.tsx +14 -6
  20. package/src/components/instance-editing-panel/use-instance-panel-data.ts +2 -2
  21. package/src/components/instance-editing-panel/utils/correct-exposed-empty-override.ts +28 -0
  22. package/src/consts.ts +1 -0
  23. package/src/create-component-type.ts +130 -29
  24. package/src/index.ts +92 -0
  25. package/src/init.ts +6 -4
  26. package/src/store/actions/update-overridable-prop.ts +4 -10
  27. package/src/store/dispatchers.ts +63 -0
  28. package/src/store/extensible-slice.ts +168 -0
  29. package/src/store/selectors.ts +53 -0
  30. package/src/store/store-types.ts +48 -0
  31. package/src/store/store.ts +7 -169
  32. package/src/sync/publish-draft-components-in-page-before-save.ts +42 -1
  33. package/src/types.ts +1 -1
  34. package/src/utils/detach-component-instance/detach-component-instance.ts +172 -0
  35. package/src/utils/detach-component-instance/index.ts +1 -0
  36. package/src/utils/detach-component-instance/regenerate-local-style-ids.ts +53 -0
  37. package/src/utils/detach-component-instance/resolve-detached-instance.ts +94 -0
  38. package/src/utils/detach-component-instance/resolve-overridable-settings.ts +121 -0
  39. package/src/utils/is-component-instance.ts +1 -1
  40. package/src/utils/is-pro-components-supported.ts +11 -0
  41. package/src/utils/tracking.ts +2 -1
  42. package/src/extended/components/component-introduction.tsx +0 -77
  43. package/src/extended/components/component-panel-header/component-badge.tsx +0 -73
  44. package/src/extended/components/component-panel-header/component-panel-header.tsx +0 -98
  45. package/src/extended/components/component-properties-panel/component-properties-panel-content.tsx +0 -176
  46. package/src/extended/components/component-properties-panel/component-properties-panel.tsx +0 -43
  47. package/src/extended/components/component-properties-panel/properties-empty-state.tsx +0 -51
  48. package/src/extended/components/component-properties-panel/properties-group.tsx +0 -196
  49. package/src/extended/components/component-properties-panel/property-item.tsx +0 -124
  50. package/src/extended/components/component-properties-panel/sortable.tsx +0 -92
  51. package/src/extended/components/component-properties-panel/use-current-editable-item.ts +0 -73
  52. package/src/extended/components/component-properties-panel/utils/generate-unique-label.ts +0 -21
  53. package/src/extended/components/component-properties-panel/utils/validate-group-label.ts +0 -24
  54. package/src/extended/components/components-tab/component-item.tsx +0 -180
  55. package/src/extended/components/components-tab/components.tsx +0 -58
  56. package/src/extended/components/components-tab/delete-confirmation-dialog.tsx +0 -26
  57. package/src/extended/components/create-component-form/create-component-form.tsx +0 -282
  58. package/src/extended/components/create-component-form/hooks/use-form.ts +0 -72
  59. package/src/extended/components/create-component-form/utils/get-component-event-data.ts +0 -54
  60. package/src/extended/components/edit-component/component-modal.tsx +0 -133
  61. package/src/extended/components/edit-component/edit-component.tsx +0 -166
  62. package/src/extended/components/edit-component/use-canvas-document.ts +0 -9
  63. package/src/extended/components/edit-component/use-element-rect.ts +0 -81
  64. package/src/extended/components/instance-editing-panel/instance-editing-panel.tsx +0 -60
  65. package/src/extended/components/overridable-props/indicator.tsx +0 -83
  66. package/src/extended/components/overridable-props/overridable-prop-control.tsx +0 -127
  67. package/src/extended/components/overridable-props/overridable-prop-form.tsx +0 -135
  68. package/src/extended/components/overridable-props/overridable-prop-indicator.tsx +0 -138
  69. package/src/extended/components/overridable-props/utils/validate-prop-label.ts +0 -38
  70. package/src/extended/consts.ts +0 -3
  71. package/src/extended/hooks/use-navigate-back.ts +0 -24
  72. package/src/extended/init.ts +0 -104
  73. package/src/extended/mcp/index.ts +0 -14
  74. package/src/extended/mcp/save-as-component-tool.ts +0 -436
  75. package/src/extended/store/actions/add-overridable-group.ts +0 -59
  76. package/src/extended/store/actions/archive-component.ts +0 -19
  77. package/src/extended/store/actions/create-unpublished-component.ts +0 -102
  78. package/src/extended/store/actions/delete-overridable-group.ts +0 -38
  79. package/src/extended/store/actions/delete-overridable-prop.ts +0 -70
  80. package/src/extended/store/actions/rename-component.ts +0 -49
  81. package/src/extended/store/actions/rename-overridable-group.ts +0 -39
  82. package/src/extended/store/actions/reorder-group-props.ts +0 -43
  83. package/src/extended/store/actions/reorder-overridable-groups.ts +0 -30
  84. package/src/extended/store/actions/reset-sanitized-components.ts +0 -7
  85. package/src/extended/store/actions/set-overridable-prop.ts +0 -117
  86. package/src/extended/store/actions/update-component-sanitized-attribute.ts +0 -8
  87. package/src/extended/store/actions/update-current-component.ts +0 -21
  88. package/src/extended/store/actions/update-overridable-prop-params.ts +0 -58
  89. package/src/extended/store/utils/groups-transformers.ts +0 -187
  90. package/src/extended/sync/before-save.ts +0 -52
  91. package/src/extended/sync/cleanup-overridable-props-on-delete.ts +0 -85
  92. package/src/extended/sync/create-components-before-save.ts +0 -113
  93. package/src/extended/sync/handle-component-edit-mode-container.ts +0 -114
  94. package/src/extended/sync/prevent-non-atomic-nesting.ts +0 -198
  95. package/src/extended/sync/revert-overridables-on-copy-or-duplicate.ts +0 -66
  96. package/src/extended/sync/sanitize-overridable-props.ts +0 -32
  97. package/src/extended/sync/set-component-overridable-props-settings-before-save.ts +0 -23
  98. package/src/extended/sync/update-archived-component-before-save.ts +0 -32
  99. package/src/extended/sync/update-component-title-before-save.ts +0 -19
  100. package/src/extended/utils/component-form-schema.ts +0 -32
  101. package/src/extended/utils/component-name-validation.ts +0 -27
  102. package/src/extended/utils/create-component-model.ts +0 -28
  103. package/src/extended/utils/get-container-for-new-element.ts +0 -49
  104. package/src/extended/utils/is-editing-component.ts +0 -13
  105. package/src/extended/utils/replace-element-with-component.ts +0 -11
  106. package/src/extended/utils/revert-overridable-settings.ts +0 -207
@@ -1,72 +0,0 @@
1
- import { useMemo, useState } from 'react';
2
- import { type z } from '@elementor/schema';
3
-
4
- export const useForm = < TValues extends Record< string, unknown > >( initialValues: TValues ) => {
5
- const [ values, setValues ] = useState< TValues >( initialValues );
6
- const [ errors, setErrors ] = useState< Partial< Record< keyof TValues, string > > >( {} );
7
-
8
- const isValid = useMemo( () => {
9
- return ! Object.values( errors ).some( ( error ) => error );
10
- }, [ errors ] );
11
-
12
- const handleChange = (
13
- e: React.ChangeEvent< HTMLInputElement >,
14
- field: keyof TValues,
15
- validationSchema: z.ZodType< TValues >
16
- ) => {
17
- const updated = { ...values, [ field ]: e.target.value };
18
- setValues( updated );
19
-
20
- const { success, errors: validationErrors } = validateForm( updated, validationSchema );
21
-
22
- if ( ! success ) {
23
- setErrors( validationErrors );
24
- } else {
25
- setErrors( {} );
26
- }
27
- };
28
-
29
- const validate = (
30
- validationSchema: z.ZodType< TValues >
31
- ): { success: true; parsedValues: TValues } | { success: false; parsedValues?: never } => {
32
- const { success, errors: validationErrors, parsedValues } = validateForm( values, validationSchema );
33
-
34
- if ( ! success ) {
35
- setErrors( validationErrors );
36
- return { success };
37
- }
38
- setErrors( {} );
39
- return { success, parsedValues };
40
- };
41
-
42
- return {
43
- values,
44
- errors,
45
- isValid,
46
- handleChange,
47
- validateForm: validate,
48
- };
49
- };
50
-
51
- const validateForm = < TValues extends Record< string, unknown > >(
52
- values: TValues,
53
- schema: z.ZodType< TValues >
54
- ):
55
- | { success: false; parsedValues?: never; errors: Partial< Record< keyof TValues, string > > }
56
- | { success: true; parsedValues: TValues; errors?: never } => {
57
- const result = schema.safeParse( values );
58
-
59
- if ( result.success ) {
60
- return { success: true, parsedValues: result.data };
61
- }
62
-
63
- const errors = {} as Partial< Record< keyof TValues, string > >;
64
-
65
- ( Object.entries( result.error.formErrors.fieldErrors ) as Array< [ keyof TValues, string[] ] > ).forEach(
66
- ( [ field, error ] ) => {
67
- errors[ field ] = error[ 0 ];
68
- }
69
- );
70
-
71
- return { success: false, errors };
72
- };
@@ -1,54 +0,0 @@
1
- import { type V1ElementData } from '@elementor/editor-elements';
2
-
3
- export type ComponentEventData = {
4
- nested_elements_count: number;
5
- nested_components_count: number;
6
- top_element_type: string;
7
- location?: string;
8
- secondary_location?: string;
9
- trigger?: string;
10
- };
11
-
12
- export type ContextMenuEventOptions = Record< string, unknown > & {
13
- location: string;
14
- secondaryLocation: string;
15
- trigger: string;
16
- };
17
-
18
- export const getComponentEventData = (
19
- containerElement: V1ElementData,
20
- options?: ContextMenuEventOptions
21
- ): ComponentEventData => {
22
- const { elementsCount, componentsCount } = countNestedElements( containerElement );
23
-
24
- return {
25
- nested_elements_count: elementsCount,
26
- nested_components_count: componentsCount,
27
- top_element_type: containerElement.elType,
28
- location: options?.location,
29
- secondary_location: options?.secondaryLocation,
30
- trigger: options?.trigger,
31
- };
32
- };
33
-
34
- function countNestedElements( container: V1ElementData ): { elementsCount: number; componentsCount: number } {
35
- if ( ! container.elements || container.elements.length === 0 ) {
36
- return { elementsCount: 0, componentsCount: 0 };
37
- }
38
-
39
- let elementsCount = container.elements.length;
40
- let componentsCount = 0;
41
-
42
- for ( const element of container.elements ) {
43
- if ( element.widgetType === 'e-component' ) {
44
- componentsCount++;
45
- }
46
-
47
- const { elementsCount: nestedElementsCount, componentsCount: nestedComponentsCount } =
48
- countNestedElements( element );
49
- elementsCount += nestedElementsCount;
50
- componentsCount += nestedComponentsCount;
51
- }
52
-
53
- return { elementsCount, componentsCount };
54
- }
@@ -1,133 +0,0 @@
1
- import * as React from 'react';
2
- import { type CSSProperties, useEffect } from 'react';
3
- import { createPortal } from 'react-dom';
4
- import { __ } from '@wordpress/i18n';
5
-
6
- import { useCanvasDocument } from './use-canvas-document';
7
- import { useElementRect } from './use-element-rect';
8
-
9
- type ModalProps = {
10
- topLevelElementDom: HTMLElement | null;
11
- onClose: () => void;
12
- };
13
-
14
- export function ComponentModal( { topLevelElementDom, onClose }: ModalProps ) {
15
- const canvasDocument = useCanvasDocument();
16
-
17
- useEffect( () => {
18
- const handleEsc = ( event: KeyboardEvent ) => {
19
- if ( event.key === 'Escape' ) {
20
- onClose();
21
- }
22
- };
23
-
24
- canvasDocument?.body.addEventListener( 'keydown', handleEsc );
25
-
26
- return () => {
27
- canvasDocument?.body.removeEventListener( 'keydown', handleEsc );
28
- };
29
- }, [ canvasDocument, onClose ] );
30
-
31
- if ( ! canvasDocument?.body ) {
32
- return null;
33
- }
34
-
35
- return createPortal(
36
- <>
37
- <BlockEditPage />
38
- <Backdrop canvas={ canvasDocument } element={ topLevelElementDom } onClose={ onClose } />
39
- </>,
40
- canvasDocument.body
41
- );
42
- }
43
-
44
- function Backdrop( {
45
- canvas,
46
- element,
47
- onClose,
48
- }: {
49
- canvas: HTMLDocument;
50
- element: HTMLElement | null;
51
- onClose: () => void;
52
- } ) {
53
- const rect = useElementRect( element );
54
- const clipPath = element ? getRectPath( rect, canvas.defaultView as Window ) : undefined;
55
- const backdropStyle: CSSProperties = {
56
- position: 'fixed',
57
- top: 0,
58
- left: 0,
59
- width: '100vw',
60
- height: '100vh',
61
- backgroundColor: 'rgba(0, 0, 0, 0.5)',
62
- zIndex: 999,
63
- pointerEvents: 'painted',
64
- cursor: 'pointer',
65
- clipPath,
66
- };
67
-
68
- const handleKeyDown = ( event: React.KeyboardEvent ) => {
69
- if ( event.key === 'Enter' || event.key === ' ' ) {
70
- event.preventDefault();
71
- onClose();
72
- }
73
- };
74
-
75
- return (
76
- <div
77
- style={ backdropStyle }
78
- onClick={ onClose }
79
- onKeyDown={ handleKeyDown }
80
- role="button"
81
- tabIndex={ 0 }
82
- aria-label={ __( 'Exit component editing mode', 'elementor' ) }
83
- />
84
- );
85
- }
86
-
87
- function getRectPath( rect: DOMRect, viewport: Window ) {
88
- const { x, y, width, height } = rect;
89
- const { innerWidth: vw, innerHeight: vh } = viewport;
90
-
91
- const path = `path(evenodd, 'M 0 0
92
- L ${ vw } 0
93
- L ${ vw } ${ vh }
94
- L 0 ${ vh }
95
- Z
96
- M ${ x } ${ y }
97
- L ${ x + width } ${ y }
98
- L ${ x + width } ${ y + height }
99
- L ${ x } ${ y + height }
100
- L ${ x } ${ y }
101
- Z'
102
- )`;
103
-
104
- return path.replace( /\s{2,}/g, ' ' );
105
- }
106
-
107
- /**
108
- * when switching to another document id, we get a document handler when hovering
109
- * this functionality originates in Pro, and is intended for editing templates, e.g. header/footer
110
- * in components we don't want that, so the easy way out is to prevent it of being displayed via a CSS rule
111
- */
112
- function BlockEditPage() {
113
- const blockV3DocumentHandlesStyles = `
114
- .elementor-editor-active {
115
- & .elementor-section-wrap.ui-sortable {
116
- display: contents;
117
- }
118
-
119
- & *[data-editable-elementor-document]:not(.elementor-edit-mode):hover {
120
- & .elementor-document-handle:not(.elementor-document-save-back-handle) {
121
- display: none;
122
-
123
- &::before,
124
- & .elementor-document-handle__inner {
125
- display: none;
126
- }
127
- }
128
- }
129
- }
130
- `;
131
-
132
- return <style data-e-style-id="e-block-v3-document-handles-styles">{ blockV3DocumentHandlesStyles }</style>;
133
- }
@@ -1,166 +0,0 @@
1
- import * as React from 'react';
2
- import { useEffect, useState } from 'react';
3
- import { getV1DocumentsManager, type V1Document } from '@elementor/editor-documents';
4
- import { type V1Element } from '@elementor/editor-elements';
5
- import { __privateListenTo as listenTo, commandEndEvent } from '@elementor/editor-v1-adapters';
6
- import { __useSelector as useSelector } from '@elementor/store';
7
- import { throttle } from '@elementor/utils';
8
-
9
- import { apiClient } from '../../../api';
10
- import { type ComponentsPathItem, selectPath, useCurrentComponentId } from '../../../store/store';
11
- import { COMPONENT_DOCUMENT_TYPE } from '../../consts';
12
- import { useNavigateBack } from '../../hooks/use-navigate-back';
13
- import { resetSanitizedComponents } from '../../store/actions/reset-sanitized-components';
14
- import { updateCurrentComponent } from '../../store/actions/update-current-component';
15
- import { ComponentModal } from './component-modal';
16
-
17
- export function EditComponent() {
18
- const currentComponentId = useCurrentComponentId();
19
-
20
- useHandleDocumentSwitches();
21
-
22
- const navigateBack = useNavigateBack();
23
-
24
- const onClose = throttle( navigateBack, 100 );
25
-
26
- const topLevelElementDom = useComponentDOMElement( currentComponentId ?? undefined );
27
-
28
- if ( ! currentComponentId ) {
29
- return null;
30
- }
31
-
32
- return <ComponentModal topLevelElementDom={ topLevelElementDom } onClose={ onClose } />;
33
- }
34
-
35
- function useHandleDocumentSwitches() {
36
- const documentsManager = getV1DocumentsManager();
37
- const currentComponentId = useCurrentComponentId();
38
- const path = useSelector( selectPath );
39
-
40
- useEffect( () => {
41
- return listenTo( commandEndEvent( 'editor/documents/open' ), () => {
42
- const nextDocument = documentsManager.getCurrent();
43
-
44
- if ( nextDocument.id === currentComponentId ) {
45
- return;
46
- }
47
-
48
- if ( currentComponentId ) {
49
- apiClient.unlockComponent( currentComponentId );
50
- }
51
-
52
- resetSanitizedComponents();
53
-
54
- const isComponent = nextDocument.config.type === COMPONENT_DOCUMENT_TYPE;
55
-
56
- if ( ! isComponent ) {
57
- updateCurrentComponent( { path: [], currentComponentId: null } );
58
- return;
59
- }
60
-
61
- updateCurrentComponent( {
62
- path: getUpdatedComponentPath( path, nextDocument ),
63
- currentComponentId: nextDocument.id,
64
- } );
65
- } );
66
- }, [ path, documentsManager, currentComponentId ] );
67
- }
68
-
69
- function getUpdatedComponentPath( path: ComponentsPathItem[], nextDocument: V1Document ): ComponentsPathItem[] {
70
- const componentIndex = path.findIndex( ( { componentId } ) => componentId === nextDocument.id );
71
-
72
- if ( componentIndex >= 0 ) {
73
- // When exiting the editing of a nested component - we in fact go back a step
74
- // so we need to make sure the path is cleaned up of any newer items
75
- // By doing it with the slice and not a simple pop() - we could jump to any component in the path and make sure it becomes the current one
76
- return path.slice( 0, componentIndex + 1 );
77
- }
78
-
79
- const instanceId = nextDocument?.container.view?.el?.dataset.id;
80
- const instanceTitle = getInstanceTitle( instanceId, path );
81
-
82
- return [
83
- ...path,
84
- {
85
- instanceId,
86
- instanceTitle,
87
- componentId: nextDocument.id,
88
- },
89
- ];
90
- }
91
-
92
- function getInstanceTitle( instanceId: string | undefined, path: ComponentsPathItem[] ): string | undefined {
93
- if ( ! instanceId ) {
94
- return undefined;
95
- }
96
-
97
- const documentsManager = getV1DocumentsManager();
98
- const parentDocId = path.at( -1 )?.componentId ?? documentsManager.getInitialId();
99
- const parentDoc = documentsManager.get( parentDocId );
100
-
101
- type EditorSettings = { title?: string };
102
- type ContainerWithChildren = V1Element & {
103
- children?: {
104
- findRecursive?: ( predicate: ( child: V1Element ) => boolean ) => V1Element | undefined;
105
- };
106
- };
107
-
108
- const parentContainer = parentDoc?.container as unknown as ContainerWithChildren | undefined;
109
- const widget = parentContainer?.children?.findRecursive?.(
110
- ( container: V1Element ) => container.id === instanceId
111
- );
112
-
113
- const editorSettings = widget?.model?.get?.( 'editor_settings' ) as EditorSettings | undefined;
114
-
115
- return editorSettings?.title;
116
- }
117
-
118
- function useComponentDOMElement( id: V1Document[ 'id' ] | undefined ) {
119
- const { componentContainerDomElement, topLevelElementDom } = getComponentDOMElements( id );
120
-
121
- const [ currentElementDom, setCurrentElementDom ] = useState< HTMLElement | null >( topLevelElementDom );
122
-
123
- useEffect( () => {
124
- setCurrentElementDom( topLevelElementDom );
125
- }, [ topLevelElementDom ] );
126
-
127
- useEffect( () => {
128
- if ( ! componentContainerDomElement ) {
129
- return;
130
- }
131
-
132
- const mutationObserver = new MutationObserver( () => {
133
- const newElementDom = componentContainerDomElement.children[ 0 ] as HTMLElement | null;
134
- setCurrentElementDom( newElementDom );
135
- } );
136
-
137
- mutationObserver.observe( componentContainerDomElement, { childList: true } );
138
-
139
- return () => {
140
- mutationObserver.disconnect();
141
- };
142
- }, [ componentContainerDomElement ] );
143
-
144
- return currentElementDom;
145
- }
146
-
147
- type ComponentDOMElements = {
148
- componentContainerDomElement: HTMLElement | null;
149
- topLevelElementDom: HTMLElement | null;
150
- };
151
-
152
- function getComponentDOMElements( id: V1Document[ 'id' ] | undefined ): ComponentDOMElements {
153
- if ( ! id ) {
154
- return { componentContainerDomElement: null, topLevelElementDom: null };
155
- }
156
-
157
- const documentsManager = getV1DocumentsManager();
158
-
159
- const currentComponent = documentsManager.get( id );
160
-
161
- const componentContainer = currentComponent?.container as V1Element;
162
- const componentContainerDomElement = ( componentContainer?.view?.el?.children?.[ 0 ] as HTMLElement ) ?? null;
163
- const topLevelElementDom = ( componentContainerDomElement?.children[ 0 ] as HTMLElement ) ?? null;
164
-
165
- return { componentContainerDomElement, topLevelElementDom };
166
- }
@@ -1,9 +0,0 @@
1
- import {
2
- __privateUseListenTo as useListenTo,
3
- commandEndEvent,
4
- getCanvasIframeDocument,
5
- } from '@elementor/editor-v1-adapters';
6
-
7
- export function useCanvasDocument() {
8
- return useListenTo( commandEndEvent( 'editor/documents/attach-preview' ), () => getCanvasIframeDocument() );
9
- }
@@ -1,81 +0,0 @@
1
- import { useEffect, useState } from 'react';
2
- import { throttle } from '@elementor/utils';
3
-
4
- export function useElementRect( element: HTMLElement | null ) {
5
- const [ rect, setRect ] = useState< DOMRect >( new DOMRect( 0, 0, 0, 0 ) );
6
-
7
- const onChange = throttle(
8
- () => {
9
- setRect( element?.getBoundingClientRect() ?? new DOMRect( 0, 0, 0, 0 ) );
10
- },
11
- 20,
12
- true
13
- );
14
-
15
- useScrollListener( { element, onChange } );
16
- useResizeListener( { element, onChange } );
17
- useMutationsListener( { element, onChange } );
18
-
19
- useEffect(
20
- () => () => {
21
- onChange.cancel();
22
- },
23
- [ onChange ]
24
- );
25
-
26
- return rect;
27
- }
28
-
29
- type ListenerProps = {
30
- element: HTMLElement | null;
31
- onChange: () => void;
32
- };
33
-
34
- function useScrollListener( { element, onChange }: ListenerProps ) {
35
- useEffect( () => {
36
- if ( ! element ) {
37
- return;
38
- }
39
-
40
- const win = element.ownerDocument?.defaultView;
41
- win?.addEventListener( 'scroll', onChange, { passive: true } );
42
-
43
- return () => {
44
- win?.removeEventListener( 'scroll', onChange );
45
- };
46
- }, [ element, onChange ] );
47
- }
48
-
49
- function useResizeListener( { element, onChange }: ListenerProps ) {
50
- useEffect( () => {
51
- if ( ! element ) {
52
- return;
53
- }
54
-
55
- const resizeObserver = new ResizeObserver( onChange );
56
- resizeObserver.observe( element );
57
-
58
- const win = element.ownerDocument?.defaultView;
59
- win?.addEventListener( 'resize', onChange, { passive: true } );
60
-
61
- return () => {
62
- resizeObserver.disconnect();
63
- win?.removeEventListener( 'resize', onChange );
64
- };
65
- }, [ element, onChange ] );
66
- }
67
-
68
- function useMutationsListener( { element, onChange }: ListenerProps ) {
69
- useEffect( () => {
70
- if ( ! element ) {
71
- return;
72
- }
73
-
74
- const mutationObserver = new MutationObserver( onChange );
75
- mutationObserver.observe( element, { childList: true, subtree: true } );
76
-
77
- return () => {
78
- mutationObserver.disconnect();
79
- };
80
- }, [ element, onChange ] );
81
- }
@@ -1,60 +0,0 @@
1
- import * as React from 'react';
2
- import { PencilIcon } from '@elementor/icons';
3
- import { Box } from '@elementor/ui';
4
- import { __ } from '@wordpress/i18n';
5
-
6
- import { EmptyState } from '../../../components/instance-editing-panel/empty-state';
7
- import { InstancePanelBody } from '../../../components/instance-editing-panel/instance-panel-body';
8
- import {
9
- EditComponentAction,
10
- InstancePanelHeader,
11
- } from '../../../components/instance-editing-panel/instance-panel-header';
12
- import { useInstancePanelData } from '../../../components/instance-editing-panel/use-instance-panel-data';
13
- import { useComponentsPermissions } from '../../../hooks/use-components-permissions';
14
- import { ComponentInstanceProvider } from '../../../provider/component-instance-context';
15
- import { switchToComponent } from '../../../utils/switch-to-component';
16
-
17
- export function ExtendedInstanceEditingPanel() {
18
- const { canEdit } = useComponentsPermissions();
19
- const data = useInstancePanelData();
20
-
21
- if ( ! data ) {
22
- return null;
23
- }
24
-
25
- const { componentId, component, overrides, overridableProps, groups, isEmpty, componentInstanceId } = data;
26
-
27
- /* translators: %s: component name. */
28
- const panelTitle = __( 'Edit %s', 'elementor' ).replace( '%s', component.name );
29
-
30
- const handleEditComponent = () => switchToComponent( componentId, componentInstanceId );
31
-
32
- return (
33
- <Box data-testid="instance-editing-panel">
34
- <ComponentInstanceProvider
35
- componentId={ componentId }
36
- overrides={ overrides }
37
- overridableProps={ overridableProps }
38
- >
39
- <InstancePanelHeader
40
- componentName={ component.name }
41
- actions={
42
- canEdit ? (
43
- <EditComponentAction
44
- label={ panelTitle }
45
- onClick={ handleEditComponent }
46
- icon={ PencilIcon }
47
- />
48
- ) : undefined
49
- }
50
- />
51
- <InstancePanelBody
52
- groups={ groups }
53
- isEmpty={ isEmpty }
54
- emptyState={ <EmptyState onEditComponent={ canEdit ? handleEditComponent : undefined } /> }
55
- componentInstanceId={ componentInstanceId }
56
- />
57
- </ComponentInstanceProvider>
58
- </Box>
59
- );
60
- }
@@ -1,83 +0,0 @@
1
- import * as React from 'react';
2
- import { forwardRef } from 'react';
3
- import { CheckIcon, PlusIcon } from '@elementor/icons';
4
- import { Box, styled } from '@elementor/ui';
5
- import { __ } from '@wordpress/i18n';
6
-
7
- const SIZE = 'tiny';
8
-
9
- const IconContainer = styled( Box )`
10
- pointer-events: none;
11
- opacity: 0;
12
- transition: opacity 0.2s ease-in-out;
13
-
14
- & > svg {
15
- position: absolute;
16
- top: 50%;
17
- left: 50%;
18
- transform: translate( -50%, -50% );
19
- width: 10px;
20
- height: 10px;
21
- fill: ${ ( { theme } ) => theme.palette.primary.contrastText };
22
- stroke: ${ ( { theme } ) => theme.palette.primary.contrastText };
23
- stroke-width: 2px;
24
- }
25
- `;
26
-
27
- const Content = styled( Box )`
28
- position: relative;
29
- display: flex;
30
- align-items: center;
31
- justify-content: center;
32
- cursor: pointer;
33
- width: 16px;
34
- height: 16px;
35
- margin-inline: ${ ( { theme } ) => theme.spacing( 0.5 ) };
36
-
37
- &:before {
38
- content: '';
39
- display: block;
40
- position: absolute;
41
- top: 50%;
42
- left: 50%;
43
- transform: translate( -50%, -50% ) rotate( 45deg );
44
- width: 5px;
45
- height: 5px;
46
- border-radius: 1px;
47
- background-color: ${ ( { theme } ) => theme.palette.primary.main };
48
- transition: all 0.1s ease-in-out;
49
- }
50
-
51
- &:hover,
52
- &.enlarged {
53
- &:before {
54
- width: 12px;
55
- height: 12px;
56
- border-radius: 2px;
57
- }
58
-
59
- .icon {
60
- opacity: 1;
61
- }
62
- }
63
- `;
64
-
65
- type Props = {
66
- isOverridable: boolean;
67
- isOpen: boolean;
68
- };
69
- export const Indicator = forwardRef< HTMLDivElement, Props >( ( { isOpen, isOverridable, ...props }, ref ) => (
70
- <Content
71
- role="button"
72
- ref={ ref }
73
- { ...props }
74
- className={ isOpen || isOverridable ? 'enlarged' : '' }
75
- aria-label={
76
- isOverridable ? __( 'Overridable property', 'elementor' ) : __( 'Make prop overridable', 'elementor' )
77
- }
78
- >
79
- <IconContainer className="icon">
80
- { isOverridable ? <CheckIcon fontSize={ SIZE } /> : <PlusIcon fontSize={ SIZE } /> }
81
- </IconContainer>
82
- </Content>
83
- ) );