@elementor/editor-components 4.0.0-666 → 4.0.0-667

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 (72) hide show
  1. package/dist/index.js +191 -3870
  2. package/dist/index.js.map +1 -1
  3. package/dist/index.mjs +184 -3904
  4. package/dist/index.mjs.map +1 -1
  5. package/package.json +23 -23
  6. package/src/init.ts +0 -13
  7. package/src/extended/components/component-introduction.tsx +0 -77
  8. package/src/extended/components/component-panel-header/component-badge.tsx +0 -73
  9. package/src/extended/components/component-panel-header/component-panel-header.tsx +0 -98
  10. package/src/extended/components/component-properties-panel/component-properties-panel-content.tsx +0 -176
  11. package/src/extended/components/component-properties-panel/component-properties-panel.tsx +0 -43
  12. package/src/extended/components/component-properties-panel/properties-empty-state.tsx +0 -51
  13. package/src/extended/components/component-properties-panel/properties-group.tsx +0 -196
  14. package/src/extended/components/component-properties-panel/property-item.tsx +0 -124
  15. package/src/extended/components/component-properties-panel/sortable.tsx +0 -92
  16. package/src/extended/components/component-properties-panel/use-current-editable-item.ts +0 -73
  17. package/src/extended/components/component-properties-panel/utils/generate-unique-label.ts +0 -21
  18. package/src/extended/components/component-properties-panel/utils/validate-group-label.ts +0 -24
  19. package/src/extended/components/components-tab/component-item.tsx +0 -180
  20. package/src/extended/components/components-tab/components.tsx +0 -58
  21. package/src/extended/components/components-tab/delete-confirmation-dialog.tsx +0 -26
  22. package/src/extended/components/create-component-form/create-component-form.tsx +0 -281
  23. package/src/extended/components/create-component-form/hooks/use-form.ts +0 -72
  24. package/src/extended/components/create-component-form/utils/get-component-event-data.ts +0 -54
  25. package/src/extended/components/edit-component/component-modal.tsx +0 -133
  26. package/src/extended/components/edit-component/edit-component.tsx +0 -166
  27. package/src/extended/components/edit-component/use-canvas-document.ts +0 -9
  28. package/src/extended/components/edit-component/use-element-rect.ts +0 -81
  29. package/src/extended/components/instance-editing-panel/instance-editing-panel.tsx +0 -60
  30. package/src/extended/components/overridable-props/indicator.tsx +0 -83
  31. package/src/extended/components/overridable-props/overridable-prop-control.tsx +0 -127
  32. package/src/extended/components/overridable-props/overridable-prop-form.tsx +0 -135
  33. package/src/extended/components/overridable-props/overridable-prop-indicator.tsx +0 -138
  34. package/src/extended/components/overridable-props/utils/validate-prop-label.ts +0 -38
  35. package/src/extended/consts.ts +0 -3
  36. package/src/extended/hooks/use-navigate-back.ts +0 -24
  37. package/src/extended/init.ts +0 -108
  38. package/src/extended/mcp/index.ts +0 -14
  39. package/src/extended/mcp/save-as-component-tool.ts +0 -436
  40. package/src/extended/shortcuts/create-component-shortcut.ts +0 -121
  41. package/src/extended/store/actions/add-overridable-group.ts +0 -53
  42. package/src/extended/store/actions/archive-component.ts +0 -18
  43. package/src/extended/store/actions/create-unpublished-component.ts +0 -99
  44. package/src/extended/store/actions/delete-overridable-group.ts +0 -32
  45. package/src/extended/store/actions/delete-overridable-prop.ts +0 -64
  46. package/src/extended/store/actions/rename-component.ts +0 -48
  47. package/src/extended/store/actions/rename-overridable-group.ts +0 -33
  48. package/src/extended/store/actions/reorder-group-props.ts +0 -37
  49. package/src/extended/store/actions/reorder-overridable-groups.ts +0 -24
  50. package/src/extended/store/actions/reset-sanitized-components.ts +0 -5
  51. package/src/extended/store/actions/set-overridable-prop.ts +0 -109
  52. package/src/extended/store/actions/update-component-sanitized-attribute.ts +0 -7
  53. package/src/extended/store/actions/update-current-component.ts +0 -12
  54. package/src/extended/store/actions/update-overridable-prop-params.ts +0 -52
  55. package/src/extended/store/utils/groups-transformers.ts +0 -187
  56. package/src/extended/sync/before-save.ts +0 -52
  57. package/src/extended/sync/cleanup-overridable-props-on-delete.ts +0 -78
  58. package/src/extended/sync/create-components-before-save.ts +0 -111
  59. package/src/extended/sync/handle-component-edit-mode-container.ts +0 -114
  60. package/src/extended/sync/prevent-non-atomic-nesting.ts +0 -198
  61. package/src/extended/sync/revert-overridables-on-copy-or-duplicate.ts +0 -66
  62. package/src/extended/sync/sanitize-overridable-props.ts +0 -32
  63. package/src/extended/sync/set-component-overridable-props-settings-before-save.ts +0 -22
  64. package/src/extended/sync/update-archived-component-before-save.ts +0 -31
  65. package/src/extended/sync/update-component-title-before-save.ts +0 -18
  66. package/src/extended/utils/component-form-schema.ts +0 -32
  67. package/src/extended/utils/component-name-validation.ts +0 -25
  68. package/src/extended/utils/create-component-model.ts +0 -28
  69. package/src/extended/utils/get-container-for-new-element.ts +0 -49
  70. package/src/extended/utils/is-editing-component.ts +0 -5
  71. package/src/extended/utils/replace-element-with-component.ts +0 -11
  72. 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
- }