@elementor/editor-global-classes 0.10.0 → 0.11.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.
@@ -2,15 +2,15 @@ import * as React from 'react';
2
2
  import { type StyleDefinitionID } from '@elementor/editor-styles';
3
3
  import { stylesRepository } from '@elementor/editor-styles-repository';
4
4
  import { EditableField, EllipsisWithTooltip, useEditable } from '@elementor/editor-ui';
5
- import { DotsVerticalIcon, PhotoIcon } from '@elementor/icons';
5
+ import { DotsVerticalIcon } from '@elementor/icons';
6
6
  import {
7
7
  bindMenu,
8
8
  bindTrigger,
9
9
  Box,
10
10
  IconButton,
11
11
  List,
12
- ListItem,
13
12
  ListItemButton,
13
+ type ListItemButtonProps,
14
14
  ListItemText,
15
15
  Menu,
16
16
  MenuItem,
@@ -28,7 +28,8 @@ import { globalClassesStylesProvider } from '../../global-classes-styles-provide
28
28
  import { useClassesOrder } from '../../hooks/use-classes-order';
29
29
  import { useOrderedClasses } from '../../hooks/use-ordered-classes';
30
30
  import { DeleteConfirmationProvider, useDeleteConfirmation } from './delete-confirmation-dialog';
31
- import { SortableItem, SortableItemIndicator, SortableProvider } from './sortable';
31
+ import { FlippedColorSwatchIcon } from './flipped-color-swatch-icon';
32
+ import { SortableItem, SortableProvider, SortableTrigger, type SortableTriggerProps } from './sortable';
32
33
 
33
34
  export const GlobalClassesList = () => {
34
35
  const cssClasses = useOrderedClasses();
@@ -50,17 +51,15 @@ export const GlobalClassesList = () => {
50
51
 
51
52
  return (
52
53
  <SortableItem key={ id } id={ id }>
53
- { ( { isDragged, showDropIndication, dropIndicationStyle } ) => (
54
+ { ( { isDragged, isDragPlaceholder, triggerProps, triggerStyle } ) => (
54
55
  <ClassItem
55
56
  id={ id }
56
57
  label={ label }
57
58
  renameClass={ renameClass }
58
59
  selected={ isDragged }
59
- >
60
- { showDropIndication && (
61
- <SortableItemIndicator style={ dropIndicationStyle } />
62
- ) }
63
- </ClassItem>
60
+ disabled={ isDragPlaceholder }
61
+ sortableTriggerProps={ { ...triggerProps, style: triggerStyle } }
62
+ />
64
63
  ) }
65
64
  </SortableItem>
66
65
  );
@@ -81,18 +80,16 @@ const useReorder = () => {
81
80
  return [ order, reorder ] as const;
82
81
  };
83
82
 
84
- const ClassItem = ( {
85
- id,
86
- label,
87
- renameClass,
88
- selected,
89
- children,
90
- }: React.PropsWithChildren< {
83
+ type ClassItemProps = React.PropsWithChildren< {
91
84
  id: string;
92
85
  label: string;
93
86
  renameClass: ( newLabel: string ) => void;
94
- selected: boolean;
95
- } > ) => {
87
+ selected?: boolean;
88
+ disabled?: boolean;
89
+ sortableTriggerProps: SortableTriggerProps;
90
+ } >;
91
+
92
+ const ClassItem = ( { id, label, renameClass, selected, disabled, sortableTriggerProps }: ClassItemProps ) => {
96
93
  const {
97
94
  ref: editableRef,
98
95
  openEditMode,
@@ -112,104 +109,109 @@ const ClassItem = ( {
112
109
  disableAutoFocus: true,
113
110
  } );
114
111
 
112
+ const isSelected = ( selected || popupState.isOpen ) && ! disabled;
113
+
115
114
  return (
116
- <Stack direction="row" alignItems="center" gap={ 1 } flexGrow={ 1 } flexShrink={ 0 }>
117
- <StyledListItem
118
- component={ 'div' }
119
- disablePadding
115
+ <>
116
+ <StyledListItemButton
117
+ dense
120
118
  disableGutters
121
- secondaryAction={
122
- <Tooltip
123
- placement="top"
124
- className="class-item-more-actions"
125
- title={ __( 'More actions', 'elementor' ) }
126
- >
127
- <IconButton size="tiny" { ...bindTrigger( popupState ) } aria-label="More actions">
128
- <DotsVerticalIcon fontSize="tiny" />
129
- </IconButton>
130
- </Tooltip>
131
- }
119
+ showActions={ isSelected || isEditing }
120
+ shape="rounded"
121
+ onDoubleClick={ openEditMode }
122
+ selected={ isSelected }
123
+ disabled={ disabled }
124
+ focusVisibleClassName="visible-class-item"
132
125
  >
133
- <ListItemButton
134
- dense
135
- disableGutters
136
- shape="rounded"
137
- onDoubleClick={ openEditMode }
138
- selected={ selected || popupState.isOpen }
139
- focusVisibleClassName="visible-class-item"
140
- sx={ {
141
- minHeight: '36px',
142
- display: 'flex',
143
- '&.visible-class-item': {
144
- boxShadow: 'none !important',
145
- },
146
- } }
126
+ <SortableTrigger { ...sortableTriggerProps } />
127
+ <Indicator isActive={ isEditing } isError={ !! error }>
128
+ { isEditing ? (
129
+ <EditableField
130
+ ref={ editableRef }
131
+ error={ error }
132
+ as={ Typography }
133
+ variant="caption"
134
+ { ...getEditableProps() }
135
+ />
136
+ ) : (
137
+ <EllipsisWithTooltip title={ label } as={ Typography } variant="caption" />
138
+ ) }
139
+ </Indicator>
140
+ <Tooltip
141
+ placement="top"
142
+ className={ 'class-item-more-actions' }
143
+ title={ __( 'More actions', 'elementor' ) }
147
144
  >
148
- <Indicator isActive={ isEditing } isError={ !! error }>
149
- { isEditing ? (
150
- <EditableField
151
- ref={ editableRef }
152
- error={ error }
153
- as={ Typography }
154
- variant="caption"
155
- { ...getEditableProps() }
156
- />
157
- ) : (
158
- <EllipsisWithTooltip title={ label } as={ Typography } variant="caption" />
159
- ) }
160
- </Indicator>
161
- </ListItemButton>
162
- { children }
163
- <Menu
164
- { ...bindMenu( popupState ) }
165
- anchorOrigin={ {
166
- vertical: 'bottom',
167
- horizontal: 'right',
145
+ <IconButton size="tiny" { ...bindTrigger( popupState ) } aria-label="More actions">
146
+ <DotsVerticalIcon fontSize="tiny" />
147
+ </IconButton>
148
+ </Tooltip>
149
+ </StyledListItemButton>
150
+ <Menu
151
+ { ...bindMenu( popupState ) }
152
+ anchorOrigin={ {
153
+ vertical: 'bottom',
154
+ horizontal: 'right',
155
+ } }
156
+ transformOrigin={ {
157
+ vertical: 'top',
158
+ horizontal: 'right',
159
+ } }
160
+ >
161
+ <MenuItem
162
+ sx={ { minWidth: '160px' } }
163
+ onClick={ () => {
164
+ popupState.close();
165
+ openEditMode();
168
166
  } }
169
- transformOrigin={ {
170
- vertical: 'top',
171
- horizontal: 'right',
167
+ >
168
+ <ListItemText primary={ __( 'Rename', 'elementor' ) } />
169
+ </MenuItem>
170
+ <MenuItem
171
+ onClick={ () => {
172
+ popupState.close();
173
+ openDialog( { id, label } );
172
174
  } }
173
175
  >
174
- <MenuItem
175
- sx={ { minWidth: '160px' } }
176
- onClick={ () => {
177
- popupState.close();
178
- openEditMode();
179
- } }
180
- >
181
- <ListItemText primary={ __( 'Rename', 'elementor' ) } />
182
- </MenuItem>
183
- <MenuItem
184
- onClick={ () => {
185
- popupState.close();
186
- openDialog( { id, label } );
187
- } }
188
- >
189
- <ListItemText primary={ __( 'Delete', 'elementor' ) } sx={ { color: 'error.light' } } />
190
- </MenuItem>
191
- </Menu>
192
- </StyledListItem>
193
- </Stack>
176
+ <ListItemText primary={ __( 'Delete', 'elementor' ) } sx={ { color: 'error.light' } } />
177
+ </MenuItem>
178
+ </Menu>
179
+ </>
194
180
  );
195
181
  };
196
182
 
197
- const StyledListItem = styled( ListItem )`
198
- .class-item-more-actions {
199
- visibility: hidden;
183
+ // Custom styles for sortable list item, until the component is available in the UI package.
184
+ const StyledListItemButton = styled( ListItemButton, {
185
+ shouldForwardProp: ( prop: string ) => ! [ 'showActions' ].includes( prop ),
186
+ } )< ListItemButtonProps & { showActions: boolean } >(
187
+ ( { showActions } ) => `
188
+ min-height: 36px;
189
+
190
+ &.visible-class-item {
191
+ box-shadow: none !important;
200
192
  }
201
- &:hover {
202
- .class-item-more-actions {
193
+
194
+ .class-item-more-actions, .class-item-sortable-trigger {
195
+ visibility: ${ showActions ? 'visible' : 'hidden' };
196
+ }
197
+
198
+ .class-item-sortable-trigger {
199
+ visibility: ${ showActions ? 'visible' : 'hidden' };
200
+ }
201
+
202
+ &:hover&:not(:disabled) {
203
+ .class-item-more-actions, .class-item-sortable-trigger {
203
204
  visibility: visible;
204
205
  }
205
206
  }
206
- `;
207
+ `
208
+ );
207
209
 
208
210
  const EmptyState = () => (
209
- <Stack alignItems="center" gap={ 3 } pt={ 4 } px={ 0.5 }>
210
- <PhotoIcon fontSize="large" />
211
+ <Stack alignItems="center" gap={ 1.5 } pt={ 10 } px={ 0.5 } maxWidth="260px" margin="auto">
212
+ <FlippedColorSwatchIcon fontSize="large" />
211
213
  <StyledHeader variant="subtitle2" component="h2" color="text.secondary">
212
- { __( 'No CSS classes created yet', 'elementor' ) }
214
+ { __( 'There are no global classes yet.', 'elementor' ) }
213
215
  </StyledHeader>
214
216
  <Typography align="center" variant="caption" color="text.secondary">
215
217
  { __(
@@ -237,6 +239,7 @@ const Indicator = styled( Box, {
237
239
  border: getIndicatorBorder( { isActive, isError, theme } ),
238
240
  padding: `0 ${ theme.spacing( 1 ) }`,
239
241
  marginLeft: isActive ? theme.spacing( 1 ) : 0,
242
+ minWidth: 0,
240
243
  } ) );
241
244
 
242
245
  const getIndicatorBorder = ( { isActive, isError, theme }: { isActive: boolean; isError: boolean; theme: Theme } ) => {
@@ -2,7 +2,6 @@ import * as React from 'react';
2
2
  import { GripVerticalIcon } from '@elementor/icons';
3
3
  import {
4
4
  Box,
5
- Paper,
6
5
  styled,
7
6
  UnstableSortableItem,
8
7
  type UnstableSortableItemProps,
@@ -15,26 +14,23 @@ export const SortableProvider = < T extends string >( props: UnstableSortablePro
15
14
  <UnstableSortableProvider restrictAxis variant="static" dragPlaceholderStyle={ { opacity: '1' } } { ...props } />
16
15
  );
17
16
 
18
- const SortableTrigger = ( props: React.HTMLAttributes< HTMLDivElement > ) => (
19
- <div { ...props } role="button" className="class-item-sortable-trigger">
17
+ export type SortableTriggerProps = React.HTMLAttributes< HTMLDivElement >;
18
+
19
+ export const SortableTrigger = ( props: SortableTriggerProps ) => (
20
+ <StyledSortableTrigger { ...props } role="button" className="class-item-sortable-trigger">
20
21
  <GripVerticalIcon fontSize="tiny" />
21
- </div>
22
+ </StyledSortableTrigger>
22
23
  );
23
24
 
24
- type ItemRenderProps = Record< string, unknown > & {
25
- isDragged: boolean;
26
- showDropIndication: boolean;
27
- dropIndicationStyle: React.CSSProperties;
28
- };
29
-
30
25
  type SortableItemProps = {
31
26
  id: UnstableSortableItemProps[ 'id' ];
32
- children: ( props: ItemRenderProps ) => React.ReactNode;
27
+ children: ( props: Partial< UnstableSortableItemRenderProps > ) => React.ReactNode;
33
28
  };
34
29
 
35
- export const SortableItem = ( { children, id }: SortableItemProps ) => {
30
+ export const SortableItem = ( { children, id, ...props }: SortableItemProps ) => {
36
31
  return (
37
32
  <UnstableSortableItem
33
+ { ...props }
38
34
  id={ id }
39
35
  render={ ( {
40
36
  itemProps,
@@ -44,47 +40,45 @@ export const SortableItem = ( { children, id }: SortableItemProps ) => {
44
40
  triggerStyle,
45
41
  dropIndicationStyle,
46
42
  showDropIndication,
43
+ isDragOverlay,
44
+ isDragPlaceholder,
47
45
  }: UnstableSortableItemRenderProps ) => {
48
46
  return (
49
- <StyledSortableItem { ...itemProps } elevation={ 0 } sx={ itemStyle } role="listitem">
50
- <SortableTrigger { ...triggerProps } style={ triggerStyle } />
47
+ <Box
48
+ { ...itemProps }
49
+ style={ itemStyle }
50
+ component={ 'li' }
51
+ role="listitem"
52
+ sx={ {
53
+ backgroundColor: isDragOverlay ? 'background.paper' : undefined,
54
+ } }
55
+ >
51
56
  { children( {
52
57
  itemProps,
53
58
  isDragged,
54
59
  triggerProps,
55
60
  itemStyle,
56
61
  triggerStyle,
57
- dropIndicationStyle,
58
- showDropIndication,
62
+ isDragPlaceholder,
59
63
  } ) }
60
- </StyledSortableItem>
64
+ { showDropIndication && <SortableItemIndicator style={ dropIndicationStyle } /> }
65
+ </Box>
61
66
  );
62
67
  } }
63
68
  />
64
69
  );
65
70
  };
66
71
 
67
- const StyledSortableItem = styled( Paper )`
68
- position: relative;
69
-
70
- &:hover {
71
- & .class-item-sortable-trigger {
72
- visibility: visible;
73
- }
74
- }
75
-
76
- & .class-item-sortable-trigger {
77
- visibility: hidden;
78
- position: absolute;
79
- left: 0;
80
- top: 50%;
81
- transform: translate( -75%, -50% );
82
- }
83
- `;
72
+ const StyledSortableTrigger = styled( 'div' )( ( { theme } ) => ( {
73
+ position: 'absolute',
74
+ left: 0,
75
+ top: '50%',
76
+ transform: `translate( -${ theme.spacing( 1.5 ) }, -50% )`,
77
+ color: theme.palette.action.active,
78
+ } ) );
84
79
 
85
- export const SortableItemIndicator = styled( Box )`
80
+ const SortableItemIndicator = styled( Box )`
86
81
  width: 100%;
87
- height: 3px;
88
- border-radius: ${ ( { theme } ) => theme.spacing( 0.5 ) };
82
+ height: 1px;
89
83
  background-color: ${ ( { theme } ) => theme.palette.text.primary };
90
84
  `;