@elementor/editor-components 4.0.0-manual → 4.1.0-684

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 (101) hide show
  1. package/dist/index.d.mts +1422 -1
  2. package/dist/index.d.ts +1422 -1
  3. package/dist/index.js +1964 -4820
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.mjs +1901 -4849
  6. package/dist/index.mjs.map +1 -1
  7. package/package.json +23 -23
  8. package/src/components/components-tab/components-list.tsx +47 -4
  9. package/src/components/components-tab/components-pro-notification.tsx +9 -15
  10. package/src/components/components-tab/components.tsx +51 -3
  11. package/src/components/components-tab/loading-components.tsx +26 -14
  12. package/src/components/components-upgrade-alert.tsx +39 -0
  13. package/src/components/detach-instance-confirmation-dialog.tsx +50 -0
  14. package/src/components/instance-editing-panel/detach-action.tsx +76 -0
  15. package/src/components/instance-editing-panel/empty-state.tsx +9 -2
  16. package/src/components/instance-editing-panel/instance-editing-panel.tsx +25 -6
  17. package/src/components/instance-editing-panel/use-instance-panel-data.ts +2 -2
  18. package/src/consts.ts +1 -0
  19. package/src/create-component-type.ts +89 -26
  20. package/src/index.ts +92 -0
  21. package/src/init.ts +6 -4
  22. package/src/store/actions/update-overridable-prop.ts +4 -10
  23. package/src/store/dispatchers.ts +63 -0
  24. package/src/store/extensible-slice.ts +168 -0
  25. package/src/store/selectors.ts +53 -0
  26. package/src/store/store-types.ts +48 -0
  27. package/src/store/store.ts +7 -169
  28. package/src/sync/publish-draft-components-in-page-before-save.ts +42 -1
  29. package/src/types.ts +1 -1
  30. package/src/utils/detach-component-instance/detach-component-instance.ts +172 -0
  31. package/src/utils/detach-component-instance/index.ts +1 -0
  32. package/src/utils/detach-component-instance/regenerate-local-style-ids.ts +53 -0
  33. package/src/utils/detach-component-instance/resolve-detached-instance.ts +94 -0
  34. package/src/utils/detach-component-instance/resolve-overridable-settings.ts +121 -0
  35. package/src/utils/is-component-instance.ts +1 -1
  36. package/src/utils/tracking.ts +2 -1
  37. package/src/extended/components/component-introduction.tsx +0 -77
  38. package/src/extended/components/component-panel-header/component-badge.tsx +0 -73
  39. package/src/extended/components/component-panel-header/component-panel-header.tsx +0 -98
  40. package/src/extended/components/component-properties-panel/component-properties-panel-content.tsx +0 -176
  41. package/src/extended/components/component-properties-panel/component-properties-panel.tsx +0 -43
  42. package/src/extended/components/component-properties-panel/properties-empty-state.tsx +0 -51
  43. package/src/extended/components/component-properties-panel/properties-group.tsx +0 -196
  44. package/src/extended/components/component-properties-panel/property-item.tsx +0 -124
  45. package/src/extended/components/component-properties-panel/sortable.tsx +0 -92
  46. package/src/extended/components/component-properties-panel/use-current-editable-item.ts +0 -73
  47. package/src/extended/components/component-properties-panel/utils/generate-unique-label.ts +0 -21
  48. package/src/extended/components/component-properties-panel/utils/validate-group-label.ts +0 -24
  49. package/src/extended/components/components-tab/component-item.tsx +0 -180
  50. package/src/extended/components/components-tab/components.tsx +0 -58
  51. package/src/extended/components/components-tab/delete-confirmation-dialog.tsx +0 -26
  52. package/src/extended/components/create-component-form/create-component-form.tsx +0 -282
  53. package/src/extended/components/create-component-form/hooks/use-form.ts +0 -72
  54. package/src/extended/components/create-component-form/utils/get-component-event-data.ts +0 -54
  55. package/src/extended/components/edit-component/component-modal.tsx +0 -133
  56. package/src/extended/components/edit-component/edit-component.tsx +0 -166
  57. package/src/extended/components/edit-component/use-canvas-document.ts +0 -9
  58. package/src/extended/components/edit-component/use-element-rect.ts +0 -81
  59. package/src/extended/components/instance-editing-panel/instance-editing-panel.tsx +0 -60
  60. package/src/extended/components/overridable-props/indicator.tsx +0 -83
  61. package/src/extended/components/overridable-props/overridable-prop-control.tsx +0 -127
  62. package/src/extended/components/overridable-props/overridable-prop-form.tsx +0 -135
  63. package/src/extended/components/overridable-props/overridable-prop-indicator.tsx +0 -138
  64. package/src/extended/components/overridable-props/utils/validate-prop-label.ts +0 -38
  65. package/src/extended/consts.ts +0 -3
  66. package/src/extended/hooks/use-navigate-back.ts +0 -24
  67. package/src/extended/init.ts +0 -104
  68. package/src/extended/mcp/index.ts +0 -14
  69. package/src/extended/mcp/save-as-component-tool.ts +0 -436
  70. package/src/extended/store/actions/add-overridable-group.ts +0 -59
  71. package/src/extended/store/actions/archive-component.ts +0 -19
  72. package/src/extended/store/actions/create-unpublished-component.ts +0 -102
  73. package/src/extended/store/actions/delete-overridable-group.ts +0 -38
  74. package/src/extended/store/actions/delete-overridable-prop.ts +0 -70
  75. package/src/extended/store/actions/rename-component.ts +0 -49
  76. package/src/extended/store/actions/rename-overridable-group.ts +0 -39
  77. package/src/extended/store/actions/reorder-group-props.ts +0 -43
  78. package/src/extended/store/actions/reorder-overridable-groups.ts +0 -30
  79. package/src/extended/store/actions/reset-sanitized-components.ts +0 -7
  80. package/src/extended/store/actions/set-overridable-prop.ts +0 -117
  81. package/src/extended/store/actions/update-component-sanitized-attribute.ts +0 -8
  82. package/src/extended/store/actions/update-current-component.ts +0 -21
  83. package/src/extended/store/actions/update-overridable-prop-params.ts +0 -58
  84. package/src/extended/store/utils/groups-transformers.ts +0 -187
  85. package/src/extended/sync/before-save.ts +0 -52
  86. package/src/extended/sync/cleanup-overridable-props-on-delete.ts +0 -85
  87. package/src/extended/sync/create-components-before-save.ts +0 -113
  88. package/src/extended/sync/handle-component-edit-mode-container.ts +0 -114
  89. package/src/extended/sync/prevent-non-atomic-nesting.ts +0 -198
  90. package/src/extended/sync/revert-overridables-on-copy-or-duplicate.ts +0 -66
  91. package/src/extended/sync/sanitize-overridable-props.ts +0 -32
  92. package/src/extended/sync/set-component-overridable-props-settings-before-save.ts +0 -23
  93. package/src/extended/sync/update-archived-component-before-save.ts +0 -32
  94. package/src/extended/sync/update-component-title-before-save.ts +0 -19
  95. package/src/extended/utils/component-form-schema.ts +0 -32
  96. package/src/extended/utils/component-name-validation.ts +0 -27
  97. package/src/extended/utils/create-component-model.ts +0 -28
  98. package/src/extended/utils/get-container-for-new-element.ts +0 -49
  99. package/src/extended/utils/is-editing-component.ts +0 -13
  100. package/src/extended/utils/replace-element-with-component.ts +0 -11
  101. package/src/extended/utils/revert-overridable-settings.ts +0 -207
@@ -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
- `;
@@ -1,73 +0,0 @@
1
- import { useState } from 'react';
2
- import type * as React from 'react';
3
- import { setDocumentModifiedStatus } from '@elementor/editor-documents';
4
- import { useEditable } from '@elementor/editor-ui';
5
- import { __ } from '@wordpress/i18n';
6
-
7
- import { useCurrentComponentId, useOverridableProps } from '../../../store/store';
8
- import { renameOverridableGroup } from '../../store/actions/rename-overridable-group';
9
- import { validateGroupLabel } from './utils/validate-group-label';
10
-
11
- export type GroupLabelEditableState = {
12
- editableRef: React.RefObject< HTMLElement | null >;
13
- isEditing: boolean;
14
- error: string | null;
15
- getEditableProps: () => { value: string };
16
- setEditingGroupId: ( groupId: string ) => void;
17
- editingGroupId: string | null;
18
- };
19
-
20
- export function useCurrentEditableItem(): GroupLabelEditableState {
21
- const [ editingGroupId, setEditingGroupId ] = useState< string | null >( null );
22
- const currentComponentId = useCurrentComponentId();
23
- const overridableProps = useOverridableProps( currentComponentId );
24
-
25
- const allGroupsRecord = overridableProps?.groups?.items ?? {};
26
- const currentGroup = editingGroupId ? allGroupsRecord[ editingGroupId ] : null;
27
-
28
- const validateLabel = ( newLabel: string ): string | null => {
29
- const otherGroups = Object.fromEntries(
30
- Object.entries( allGroupsRecord ).filter( ( [ id ] ) => id !== editingGroupId )
31
- );
32
-
33
- return validateGroupLabel( newLabel, otherGroups ) || null;
34
- };
35
-
36
- const handleSubmit = ( newLabel: string ) => {
37
- if ( ! editingGroupId || ! currentComponentId ) {
38
- throw new Error( __( 'Group ID or component ID is missing', 'elementor' ) );
39
- }
40
-
41
- renameOverridableGroup( {
42
- componentId: currentComponentId,
43
- groupId: editingGroupId,
44
- label: newLabel,
45
- } );
46
-
47
- setDocumentModifiedStatus( true );
48
- };
49
-
50
- const {
51
- ref: editableRef,
52
- openEditMode,
53
- isEditing,
54
- error,
55
- getProps: getEditableProps,
56
- } = useEditable( {
57
- value: currentGroup?.label ?? '',
58
- onSubmit: handleSubmit,
59
- validation: validateLabel,
60
- } );
61
-
62
- return {
63
- editableRef,
64
- isEditing,
65
- error,
66
- getEditableProps,
67
- setEditingGroupId: ( groupId ) => {
68
- setEditingGroupId( groupId );
69
- openEditMode();
70
- },
71
- editingGroupId,
72
- };
73
- }
@@ -1,21 +0,0 @@
1
- import { type OverridablePropsGroup } from '../../../../types';
2
-
3
- const DEFAULT_NEW_GROUP_LABEL = 'New group';
4
-
5
- export function generateUniqueLabel( groups: OverridablePropsGroup[] ): string {
6
- const existingLabels = new Set( groups.map( ( group ) => group.label ) );
7
-
8
- if ( ! existingLabels.has( DEFAULT_NEW_GROUP_LABEL ) ) {
9
- return DEFAULT_NEW_GROUP_LABEL;
10
- }
11
-
12
- let index = 1;
13
- let newLabel = `${ DEFAULT_NEW_GROUP_LABEL }-${ index }`;
14
-
15
- while ( existingLabels.has( newLabel ) ) {
16
- index++;
17
- newLabel = `${ DEFAULT_NEW_GROUP_LABEL }-${ index }`;
18
- }
19
-
20
- return newLabel;
21
- }
@@ -1,24 +0,0 @@
1
- import { __ } from '@wordpress/i18n';
2
-
3
- import { type OverridablePropsGroup } from '../../../../types';
4
-
5
- export const ERROR_MESSAGES = {
6
- EMPTY_NAME: __( 'Group name is required', 'elementor' ),
7
- DUPLICATE_NAME: __( 'Group name already exists', 'elementor' ),
8
- } as const;
9
-
10
- export function validateGroupLabel( label: string, existingGroups: Record< string, OverridablePropsGroup > ): string {
11
- const trimmedLabel = label.trim();
12
-
13
- if ( ! trimmedLabel ) {
14
- return ERROR_MESSAGES.EMPTY_NAME;
15
- }
16
-
17
- const isDuplicate = Object.values( existingGroups ).some( ( group ) => group.label === trimmedLabel );
18
-
19
- if ( isDuplicate ) {
20
- return ERROR_MESSAGES.DUPLICATE_NAME;
21
- }
22
-
23
- return '';
24
- }