@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,176 +0,0 @@
1
- import * as React from 'react';
2
- import { useMemo, useRef, useState } from 'react';
3
- import { setDocumentModifiedStatus } from '@elementor/editor-documents';
4
- import { PanelBody, PanelHeader, PanelHeaderTitle } from '@elementor/editor-panels';
5
- import { ComponentPropListIcon, FolderPlusIcon, XIcon } from '@elementor/icons';
6
- import { Divider, IconButton, List, Stack, Tooltip } from '@elementor/ui';
7
- import { generateUniqueId } from '@elementor/utils';
8
- import { __ } from '@wordpress/i18n';
9
-
10
- import { useSanitizeOverridableProps } from '../../../hooks/use-sanitize-overridable-props';
11
- import { useCurrentComponentId } from '../../../store/store';
12
- import { addOverridableGroup } from '../../store/actions/add-overridable-group';
13
- import { deleteOverridableGroup } from '../../store/actions/delete-overridable-group';
14
- import { deleteOverridableProp } from '../../store/actions/delete-overridable-prop';
15
- import { reorderGroupProps } from '../../store/actions/reorder-group-props';
16
- import { reorderOverridableGroups } from '../../store/actions/reorder-overridable-groups';
17
- import { updateOverridablePropParams } from '../../store/actions/update-overridable-prop-params';
18
- import { PropertiesEmptyState } from './properties-empty-state';
19
- import { PropertiesGroup } from './properties-group';
20
- import { SortableItem, SortableProvider } from './sortable';
21
- import { useCurrentEditableItem } from './use-current-editable-item';
22
- import { generateUniqueLabel } from './utils/generate-unique-label';
23
-
24
- type Props = {
25
- onClose: () => void;
26
- };
27
-
28
- export function ComponentPropertiesPanelContent( { onClose }: Props ) {
29
- const currentComponentId = useCurrentComponentId();
30
- const overridableProps = useSanitizeOverridableProps( currentComponentId );
31
- const [ isAddingGroup, setIsAddingGroup ] = useState( false );
32
- const introductionRef = useRef< HTMLButtonElement >( null );
33
- const groupLabelEditable = useCurrentEditableItem();
34
-
35
- const groups = useMemo( () => {
36
- if ( ! overridableProps ) {
37
- return [];
38
- }
39
-
40
- return overridableProps.groups.order
41
- .map( ( groupId ) => overridableProps.groups.items[ groupId ] ?? null )
42
- .filter( Boolean );
43
- }, [ overridableProps ] );
44
-
45
- const allGroupsForSelect = useMemo(
46
- () => groups.map( ( group ) => ( { value: group.id, label: group.label } ) ),
47
- [ groups ]
48
- );
49
-
50
- if ( ! currentComponentId || ! overridableProps ) {
51
- return null;
52
- }
53
-
54
- const hasGroups = groups.length > 0;
55
- const showEmptyState = ! hasGroups && ! isAddingGroup;
56
- const groupIds = overridableProps.groups.order;
57
-
58
- const handleAddGroupClick = () => {
59
- if ( isAddingGroup ) {
60
- return;
61
- }
62
-
63
- const newGroupId = generateUniqueId( 'group' );
64
- const newLabel = generateUniqueLabel( groups );
65
-
66
- addOverridableGroup( {
67
- componentId: currentComponentId,
68
- groupId: newGroupId,
69
- label: newLabel,
70
- source: 'user',
71
- } );
72
- setDocumentModifiedStatus( true );
73
- setIsAddingGroup( false );
74
-
75
- groupLabelEditable.setEditingGroupId( newGroupId );
76
- };
77
-
78
- const handleGroupsReorder = ( newOrder: string[] ) => {
79
- reorderOverridableGroups( { componentId: currentComponentId, newOrder } );
80
- setDocumentModifiedStatus( true );
81
- };
82
-
83
- const handlePropsReorder = ( groupId: string, newPropsOrder: string[] ) => {
84
- reorderGroupProps( { componentId: currentComponentId, groupId, newPropsOrder } );
85
- setDocumentModifiedStatus( true );
86
- };
87
-
88
- const handlePropertyDelete = ( propKey: string ) => {
89
- deleteOverridableProp( { componentId: currentComponentId, propKey, source: 'user' } );
90
- setDocumentModifiedStatus( true );
91
- };
92
-
93
- const handlePropertyUpdate = ( overrideKey: string, data: { label: string; group: string | null } ) => {
94
- updateOverridablePropParams( {
95
- componentId: currentComponentId,
96
- overrideKey,
97
- label: data.label,
98
- groupId: data.group,
99
- } );
100
- setDocumentModifiedStatus( true );
101
- };
102
-
103
- const handleGroupDelete = ( groupId: string ) => {
104
- deleteOverridableGroup( { componentId: currentComponentId, groupId } );
105
- setDocumentModifiedStatus( true );
106
- };
107
-
108
- return (
109
- <>
110
- <PanelHeader sx={ { justifyContent: 'start', pl: 1.5, pr: 1, py: 1 } }>
111
- <Stack direction="row" alignItems="center" gap={ 0.5 } flexGrow={ 1 }>
112
- <ComponentPropListIcon fontSize="tiny" />
113
- <PanelHeaderTitle variant="subtitle2">
114
- { __( 'Component properties', 'elementor' ) }
115
- </PanelHeaderTitle>
116
- </Stack>
117
-
118
- { ! showEmptyState && (
119
- <Tooltip title={ __( 'Add new group', 'elementor' ) }>
120
- <IconButton
121
- size="tiny"
122
- aria-label={ __( 'Add new group', 'elementor' ) }
123
- onClick={ handleAddGroupClick }
124
- >
125
- <FolderPlusIcon fontSize="tiny" />
126
- </IconButton>
127
- </Tooltip>
128
- ) }
129
-
130
- <Tooltip title={ __( 'Close panel', 'elementor' ) }>
131
- <IconButton
132
- ref={ introductionRef }
133
- size="tiny"
134
- aria-label={ __( 'Close panel', 'elementor' ) }
135
- onClick={ onClose }
136
- >
137
- <XIcon fontSize="tiny" />
138
- </IconButton>
139
- </Tooltip>
140
- </PanelHeader>
141
-
142
- <Divider />
143
-
144
- <PanelBody>
145
- { showEmptyState ? (
146
- <PropertiesEmptyState introductionRef={ introductionRef } />
147
- ) : (
148
- <List sx={ { p: 2, display: 'flex', flexDirection: 'column', gap: 2 } }>
149
- <SortableProvider value={ groupIds } onChange={ handleGroupsReorder }>
150
- { groups.map( ( group ) => (
151
- <SortableItem key={ group.id } id={ group.id }>
152
- { ( { triggerProps, triggerStyle, isDragPlaceholder } ) => (
153
- <PropertiesGroup
154
- group={ group }
155
- props={ overridableProps.props }
156
- allGroups={ allGroupsForSelect }
157
- allGroupsRecord={ overridableProps.groups.items }
158
- sortableTriggerProps={ { ...triggerProps, style: triggerStyle } }
159
- isDragPlaceholder={ isDragPlaceholder }
160
- setIsAddingGroup={ setIsAddingGroup }
161
- onPropsReorder={ ( newOrder ) => handlePropsReorder( group.id, newOrder ) }
162
- onPropertyDelete={ handlePropertyDelete }
163
- onPropertyUpdate={ handlePropertyUpdate }
164
- editableLabelProps={ groupLabelEditable }
165
- onGroupDelete={ handleGroupDelete }
166
- />
167
- ) }
168
- </SortableItem>
169
- ) ) }
170
- </SortableProvider>
171
- </List>
172
- ) }
173
- </PanelBody>
174
- </>
175
- );
176
- }
@@ -1,43 +0,0 @@
1
- import * as React from 'react';
2
- import { usePanelActions as useEditingPanelActions } from '@elementor/editor-editing-panel';
3
- import { __createPanel as createPanel, Panel } from '@elementor/editor-panels';
4
- import { ThemeProvider } from '@elementor/editor-ui';
5
- import { Alert, Box, ErrorBoundary } from '@elementor/ui';
6
- import { __ } from '@wordpress/i18n';
7
-
8
- import { ComponentPropertiesPanelContent } from './component-properties-panel-content';
9
-
10
- const id = 'component-properties-panel';
11
-
12
- export const { panel, usePanelActions } = createPanel( {
13
- id,
14
- component: ComponentPropertiesPanel,
15
- } );
16
-
17
- function ComponentPropertiesPanel() {
18
- const { close: closePanel } = usePanelActions();
19
- const { open: openEditingPanel } = useEditingPanelActions();
20
-
21
- return (
22
- <ThemeProvider>
23
- <ErrorBoundary fallback={ <ErrorBoundaryFallback /> }>
24
- <Panel>
25
- <ComponentPropertiesPanelContent
26
- onClose={ () => {
27
- closePanel();
28
- openEditingPanel();
29
- } }
30
- />
31
- </Panel>
32
- </ErrorBoundary>
33
- </ThemeProvider>
34
- );
35
- }
36
-
37
- const ErrorBoundaryFallback = () => (
38
- <Box role="alert" sx={ { minHeight: '100%', p: 2 } }>
39
- <Alert severity="error" sx={ { mb: 2, maxWidth: 400, textAlign: 'center' } }>
40
- <strong>{ __( 'Something went wrong', 'elementor' ) }</strong>
41
- </Alert>
42
- </Box>
43
- );
@@ -1,51 +0,0 @@
1
- import * as React from 'react';
2
- import { useState } from 'react';
3
- import { ComponentPropListIcon } from '@elementor/icons';
4
- import { Link, Stack, Typography } from '@elementor/ui';
5
- import { __ } from '@wordpress/i18n';
6
-
7
- import { ComponentIntroduction } from '../component-introduction';
8
-
9
- export function PropertiesEmptyState( { introductionRef }: { introductionRef: React.RefObject< HTMLButtonElement > } ) {
10
- const [ isOpen, setIsOpen ] = useState( false );
11
- return (
12
- <>
13
- <Stack
14
- alignItems="center"
15
- justifyContent="flex-start"
16
- height="100%"
17
- color="text.secondary"
18
- sx={ { px: 2.5, pt: 10, pb: 5.5 } }
19
- gap={ 1 }
20
- >
21
- <ComponentPropListIcon fontSize="large" />
22
-
23
- <Typography align="center" variant="subtitle2">
24
- { __( 'Add your first property', 'elementor' ) }
25
- </Typography>
26
-
27
- <Typography align="center" variant="caption">
28
- { __( 'Make instances flexible while keeping design synced.', 'elementor' ) }
29
- </Typography>
30
-
31
- <Typography align="center" variant="caption">
32
- { __( 'Select any element, then click + next to a setting to expose it.', 'elementor' ) }
33
- </Typography>
34
-
35
- <Link
36
- variant="caption"
37
- color="secondary"
38
- sx={ { textDecorationLine: 'underline' } }
39
- onClick={ () => setIsOpen( true ) }
40
- >
41
- { __( 'Learn more', 'elementor' ) }
42
- </Link>
43
- </Stack>
44
- <ComponentIntroduction
45
- anchorRef={ introductionRef }
46
- shouldShowIntroduction={ isOpen }
47
- onClose={ () => setIsOpen( false ) }
48
- />
49
- </>
50
- );
51
- }
@@ -1,196 +0,0 @@
1
- import * as React from 'react';
2
- import { EditableField, EllipsisWithTooltip, MenuListItem } from '@elementor/editor-ui';
3
- import { DotsVerticalIcon } from '@elementor/icons';
4
- import {
5
- bindMenu,
6
- bindTrigger,
7
- Box,
8
- IconButton,
9
- List,
10
- Menu,
11
- Stack,
12
- Tooltip,
13
- Typography,
14
- usePopupState,
15
- } from '@elementor/ui';
16
- import { __ } from '@wordpress/i18n';
17
-
18
- import { type OverridableProp, type OverridablePropsGroup } from '../../../types';
19
- import { PropertyItem } from './property-item';
20
- import { SortableItem, SortableProvider, SortableTrigger, type SortableTriggerProps } from './sortable';
21
- import { type GroupLabelEditableState } from './use-current-editable-item';
22
-
23
- type Props = {
24
- group: OverridablePropsGroup;
25
- props: Record< string, OverridableProp >;
26
- allGroups: { value: string; label: string }[];
27
- allGroupsRecord: Record< string, OverridablePropsGroup >;
28
- sortableTriggerProps: SortableTriggerProps;
29
- isDragPlaceholder?: boolean;
30
- setIsAddingGroup: ( isAddingGroup: boolean ) => void;
31
- onPropsReorder: ( newOrder: string[] ) => void;
32
- onPropertyDelete: ( propKey: string ) => void;
33
- onPropertyUpdate: ( propKey: string, data: { label: string; group: string | null } ) => void;
34
- onGroupDelete: ( groupId: string ) => void;
35
- editableLabelProps: GroupLabelEditableState;
36
- };
37
-
38
- export function PropertiesGroup( {
39
- group,
40
- props,
41
- allGroups,
42
- sortableTriggerProps,
43
- isDragPlaceholder,
44
- onPropsReorder,
45
- onPropertyDelete,
46
- onPropertyUpdate,
47
- onGroupDelete,
48
- editableLabelProps,
49
- }: Props ) {
50
- const groupProps = group.props
51
- .map( ( propId ) => props[ propId ] )
52
- .filter( ( prop ): prop is OverridableProp => Boolean( prop ) );
53
-
54
- const popupState = usePopupState( {
55
- variant: 'popover',
56
- disableAutoFocus: true,
57
- } );
58
-
59
- const { editableRef, isEditing, error, getEditableProps, setEditingGroupId, editingGroupId } = editableLabelProps;
60
-
61
- const hasProperties = group.props.length > 0;
62
- const isThisGroupEditing = isEditing && editingGroupId === group.id;
63
-
64
- const handleRenameClick = () => {
65
- popupState.close();
66
- setEditingGroupId( group.id );
67
- };
68
-
69
- const handleDeleteClick = () => {
70
- popupState.close();
71
- onGroupDelete( group.id );
72
- };
73
-
74
- return (
75
- <Box
76
- sx={ {
77
- opacity: isDragPlaceholder ? 0.5 : 1,
78
- } }
79
- >
80
- <Stack gap={ 1 }>
81
- <Box
82
- className="group-header"
83
- sx={ {
84
- position: 'relative',
85
- '&:hover .group-sortable-trigger': {
86
- visibility: 'visible',
87
- },
88
- '& .group-sortable-trigger': {
89
- visibility: 'hidden',
90
- },
91
- '&:hover .group-menu': {
92
- visibility: 'visible',
93
- },
94
- '& .group-menu': {
95
- visibility: 'hidden',
96
- },
97
- } }
98
- >
99
- <SortableTrigger triggerClassName="group-sortable-trigger" { ...sortableTriggerProps } />
100
- <Stack direction="row" alignItems="center" justifyContent="space-between" gap={ 2 }>
101
- { isThisGroupEditing ? (
102
- <Box
103
- sx={ {
104
- height: 28,
105
- display: 'flex',
106
- alignItems: 'center',
107
- border: 2,
108
- borderColor: 'text.secondary',
109
- borderRadius: 1,
110
- pl: 0.5,
111
- flexGrow: 1,
112
- overflow: 'hidden',
113
- textOverflow: 'ellipsis',
114
- whiteSpace: 'nowrap',
115
- width: '100%',
116
- } }
117
- >
118
- <EditableField
119
- ref={ editableRef }
120
- as={ Typography }
121
- variant="caption"
122
- error={ error ?? undefined }
123
- sx={ { color: 'text.primary', fontWeight: 400, lineHeight: 1.66 } }
124
- { ...getEditableProps() }
125
- />
126
- </Box>
127
- ) : (
128
- <EllipsisWithTooltip
129
- title={ group.label }
130
- as={ Typography }
131
- variant="caption"
132
- sx={ { color: 'text.primary', fontWeight: 400, lineHeight: 1.66 } }
133
- />
134
- ) }
135
- <IconButton
136
- className="group-menu"
137
- size="tiny"
138
- sx={ { p: 0.25, visibility: isThisGroupEditing ? 'visible' : undefined } }
139
- aria-label={ __( 'Group actions', 'elementor' ) }
140
- { ...bindTrigger( popupState ) }
141
- >
142
- <DotsVerticalIcon fontSize="tiny" />
143
- </IconButton>
144
- </Stack>
145
- </Box>
146
- <List sx={ { p: 0, display: 'flex', flexDirection: 'column', gap: 1 } }>
147
- <SortableProvider value={ group.props } onChange={ onPropsReorder }>
148
- { groupProps.map( ( prop ) => (
149
- <SortableItem key={ prop.overrideKey } id={ prop.overrideKey }>
150
- { ( { triggerProps, triggerStyle, isDragPlaceholder: isItemDragPlaceholder } ) => (
151
- <PropertyItem
152
- prop={ prop }
153
- sortableTriggerProps={ { ...triggerProps, style: triggerStyle } }
154
- isDragPlaceholder={ isItemDragPlaceholder }
155
- groups={ allGroups }
156
- existingLabels={ Object.values( props ).map( ( p ) => p.label ) }
157
- onDelete={ onPropertyDelete }
158
- onUpdate={ ( data ) => onPropertyUpdate( prop.overrideKey, data ) }
159
- />
160
- ) }
161
- </SortableItem>
162
- ) ) }
163
- </SortableProvider>
164
- </List>
165
- </Stack>
166
- <Menu
167
- { ...bindMenu( popupState ) }
168
- anchorOrigin={ { vertical: 'bottom', horizontal: 'right' } }
169
- transformOrigin={ { vertical: 'top', horizontal: 'right' } }
170
- >
171
- <MenuListItem sx={ { minWidth: '160px' } } onClick={ handleRenameClick }>
172
- <Typography variant="caption" sx={ { color: 'text.primary' } }>
173
- { __( 'Rename', 'elementor' ) }
174
- </Typography>
175
- </MenuListItem>
176
- <Tooltip
177
- title={
178
- hasProperties ? __( 'To delete the group, first remove all the properties', 'elementor' ) : ''
179
- }
180
- placement="right"
181
- >
182
- <span>
183
- <MenuListItem onClick={ handleDeleteClick } disabled={ hasProperties }>
184
- <Typography
185
- variant="caption"
186
- sx={ { color: hasProperties ? 'text.disabled' : 'error.light' } }
187
- >
188
- { __( 'Delete', 'elementor' ) }
189
- </Typography>
190
- </MenuListItem>
191
- </span>
192
- </Tooltip>
193
- </Menu>
194
- </Box>
195
- );
196
- }
@@ -1,124 +0,0 @@
1
- import * as React from 'react';
2
- import { getWidgetsCache } from '@elementor/editor-elements';
3
- import { XIcon } from '@elementor/icons';
4
- import { bindPopover, bindTrigger, Box, IconButton, Popover, Typography, usePopupState } from '@elementor/ui';
5
-
6
- import { type OverridableProp } from '../../../types';
7
- import { OverridablePropForm } from '../overridable-props/overridable-prop-form';
8
- import { SortableTrigger, type SortableTriggerProps } from './sortable';
9
-
10
- type PropertyItemProps = {
11
- prop: OverridableProp;
12
- sortableTriggerProps: SortableTriggerProps;
13
- isDragPlaceholder?: boolean;
14
- groups: { value: string; label: string }[];
15
- existingLabels: string[];
16
- onDelete: ( propKey: string ) => void;
17
- onUpdate: ( data: { label: string; group: string | null } ) => void;
18
- };
19
-
20
- export function PropertyItem( {
21
- prop,
22
- sortableTriggerProps,
23
- isDragPlaceholder,
24
- groups,
25
- existingLabels,
26
- onDelete,
27
- onUpdate,
28
- }: PropertyItemProps ) {
29
- const popoverState = usePopupState( {
30
- variant: 'popover',
31
- } );
32
- const icon = getElementIcon( prop );
33
- const popoverProps = bindPopover( popoverState );
34
-
35
- const handleSubmit = ( data: { label: string; group: string | null } ) => {
36
- onUpdate( data );
37
- popoverState.close();
38
- };
39
-
40
- const handleDelete = ( event: React.MouseEvent ) => {
41
- event.stopPropagation();
42
- onDelete( prop.overrideKey );
43
- };
44
-
45
- return (
46
- <>
47
- <Box
48
- { ...bindTrigger( popoverState ) }
49
- sx={ {
50
- position: 'relative',
51
- pl: 0.5,
52
- pr: 1,
53
- py: 0.25,
54
- minHeight: 28,
55
- borderRadius: 1,
56
- border: '1px solid',
57
- borderColor: 'divider',
58
- display: 'flex',
59
- alignItems: 'center',
60
- gap: 0.5,
61
- opacity: isDragPlaceholder ? 0.5 : 1,
62
- cursor: 'pointer',
63
- '&:hover': {
64
- backgroundColor: 'action.hover',
65
- },
66
- '&:hover .sortable-trigger': {
67
- visibility: 'visible',
68
- },
69
- '& .sortable-trigger': {
70
- visibility: 'hidden',
71
- },
72
- '&:hover .delete-button': {
73
- visibility: 'visible',
74
- },
75
- '& .delete-button': {
76
- visibility: 'hidden',
77
- },
78
- } }
79
- >
80
- <SortableTrigger { ...sortableTriggerProps } />
81
- <Box
82
- sx={ { display: 'flex', alignItems: 'center', color: 'text.primary', fontSize: 12, padding: 0.25 } }
83
- >
84
- <i className={ icon } />
85
- </Box>
86
- <Typography variant="caption" sx={ { color: 'text.primary', flexGrow: 1, fontSize: 10 } }>
87
- { prop.label }
88
- </Typography>
89
- <IconButton size="tiny" onClick={ handleDelete } aria-label="Delete property" sx={ { p: 0.25 } }>
90
- <XIcon fontSize="tiny" />
91
- </IconButton>
92
- </Box>
93
-
94
- <Popover
95
- { ...popoverProps }
96
- anchorOrigin={ { vertical: 'bottom', horizontal: 'left' } }
97
- transformOrigin={ { vertical: 'top', horizontal: 'left' } }
98
- PaperProps={ { sx: { width: popoverState.anchorEl?.getBoundingClientRect().width } } }
99
- >
100
- <OverridablePropForm
101
- onSubmit={ handleSubmit }
102
- currentValue={ prop }
103
- groups={ groups }
104
- existingLabels={ existingLabels }
105
- sx={ { width: '100%' } }
106
- />
107
- </Popover>
108
- </>
109
- );
110
- }
111
-
112
- function getElementIcon( prop: OverridableProp ): string {
113
- const elType = prop.elType === 'widget' ? prop.widgetType : prop.elType;
114
-
115
- const widgetsCache = getWidgetsCache();
116
-
117
- if ( ! widgetsCache ) {
118
- return 'eicon-apps';
119
- }
120
-
121
- const widgetConfig = widgetsCache[ elType ];
122
-
123
- return widgetConfig?.icon || 'eicon-apps';
124
- }
@@ -1,92 +0,0 @@
1
- import * as React from 'react';
2
- import { GripVerticalIcon } from '@elementor/icons';
3
- import {
4
- Box,
5
- styled,
6
- UnstableSortableItem,
7
- type UnstableSortableItemProps,
8
- type UnstableSortableItemRenderProps,
9
- UnstableSortableProvider,
10
- type UnstableSortableProviderProps,
11
- } from '@elementor/ui';
12
-
13
- export const SortableProvider = < T extends string >( props: UnstableSortableProviderProps< T > ) => (
14
- <UnstableSortableProvider restrictAxis variant="static" dragPlaceholderStyle={ { opacity: '1' } } { ...props } />
15
- );
16
-
17
- export type SortableTriggerProps = React.HTMLAttributes< HTMLDivElement > & {
18
- triggerClassName?: string;
19
- };
20
-
21
- export const SortableTrigger = ( { triggerClassName, ...props }: SortableTriggerProps ) => (
22
- <StyledSortableTrigger
23
- { ...props }
24
- role="button"
25
- className={ `sortable-trigger ${ triggerClassName ?? '' }`.trim() }
26
- aria-label="sort"
27
- >
28
- <GripVerticalIcon fontSize="tiny" />
29
- </StyledSortableTrigger>
30
- );
31
-
32
- type SortableItemProps = {
33
- id: UnstableSortableItemProps[ 'id' ];
34
- children: ( props: SortableItemRenderData ) => React.ReactNode;
35
- };
36
-
37
- export type SortableItemRenderData = {
38
- isDragged: boolean;
39
- isDragPlaceholder: boolean;
40
- triggerProps: React.HTMLAttributes< HTMLElement >;
41
- triggerStyle: React.CSSProperties;
42
- };
43
-
44
- export const SortableItem = ( { children, id }: SortableItemProps ) => (
45
- <UnstableSortableItem
46
- id={ id }
47
- render={ ( {
48
- itemProps,
49
- isDragged,
50
- triggerProps,
51
- itemStyle,
52
- triggerStyle,
53
- dropIndicationStyle,
54
- showDropIndication,
55
- isDragOverlay,
56
- isDragPlaceholder,
57
- }: UnstableSortableItemRenderProps ) => (
58
- <Box
59
- { ...itemProps }
60
- style={ itemStyle }
61
- component="div"
62
- role="listitem"
63
- sx={ {
64
- backgroundColor: isDragOverlay ? 'background.paper' : undefined,
65
- } }
66
- >
67
- { children( {
68
- isDragged,
69
- isDragPlaceholder,
70
- triggerProps,
71
- triggerStyle,
72
- } ) }
73
- { showDropIndication && <SortableItemIndicator style={ dropIndicationStyle } /> }
74
- </Box>
75
- ) }
76
- />
77
- );
78
-
79
- const StyledSortableTrigger = styled( 'div' )( ( { theme } ) => ( {
80
- position: 'absolute',
81
- left: '-2px',
82
- top: '50%',
83
- transform: `translate( -${ theme.spacing( 1.5 ) }, -50% )`,
84
- color: theme.palette.action.active,
85
- cursor: 'grab',
86
- } ) );
87
-
88
- const SortableItemIndicator = styled( Box )`
89
- width: 100%;
90
- height: 1px;
91
- background-color: ${ ( { theme } ) => theme.palette.text.primary };
92
- `;