@elementor/editor-global-classes 3.33.0-99 → 3.34.2
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.
- package/dist/index.js +1000 -430
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +940 -366
- package/dist/index.mjs.map +1 -1
- package/package.json +21 -18
- package/src/api.ts +4 -0
- package/src/components/class-manager/class-manager-button.tsx +15 -1
- package/src/components/class-manager/class-manager-panel.tsx +2 -2
- package/src/components/class-manager/delete-class.ts +9 -3
- package/src/components/class-manager/delete-confirmation-dialog.tsx +2 -2
- package/src/components/class-manager/duplicate-label-dialog.tsx +159 -0
- package/src/components/class-manager/global-classes-list.tsx +53 -22
- package/src/components/convert-local-class-to-global-class.tsx +7 -0
- package/src/components/css-class-usage/components/css-class-usage-popover.tsx +10 -1
- package/src/components/css-class-usage/components/css-class-usage-trigger.tsx +22 -7
- package/src/components/search-and-filter/components/filter/active-filters.tsx +8 -0
- package/src/components/search-and-filter/components/filter/clear-icon-button.tsx +12 -3
- package/src/components/search-and-filter/components/filter/css-class-filter.tsx +10 -0
- package/src/components/search-and-filter/components/filter/filter-list.tsx +7 -0
- package/src/components/search-and-filter/components/search/class-manager-search.tsx +6 -0
- package/src/components/search-and-filter/context.tsx +12 -2
- package/src/errors.ts +5 -0
- package/src/global-classes-styles-provider.ts +13 -3
- package/src/hooks/use-css-class-by-id.ts +8 -0
- package/src/hooks/use-prefetch-css-class-usage.ts +6 -0
- package/src/init.ts +14 -5
- package/src/mcp-integration/classes-resource.ts +20 -0
- package/src/mcp-integration/index.ts +15 -0
- package/src/mcp-integration/mcp-apply-unapply-global-classes.ts +117 -0
- package/src/mcp-integration/mcp-get-global-class-usages.ts +72 -0
- package/src/save-global-classes.tsx +55 -0
- package/src/store.ts +32 -1
- package/src/sync-with-document-save.ts +9 -6
- package/src/sync-with-document.tsx +19 -0
- package/src/utils/tracking.ts +204 -0
- package/src/components/class-manager/save-changes-dialog.tsx +0 -92
- package/src/save-global-classes.ts +0 -42
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elementor/editor-global-classes",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.34.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"author": "Elementor Team",
|
|
6
6
|
"homepage": "https://elementor.com/",
|
|
@@ -39,23 +39,26 @@
|
|
|
39
39
|
"dev": "tsup --config=../../tsup.dev.ts"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@elementor/editor": "3.
|
|
43
|
-
"@elementor/editor-current-user": "3.
|
|
44
|
-
"@elementor/editor-documents": "3.
|
|
45
|
-
"@elementor/editor-editing-panel": "3.
|
|
46
|
-
"@elementor/editor-
|
|
47
|
-
"@elementor/editor-
|
|
48
|
-
"@elementor/editor-
|
|
49
|
-
"@elementor/editor-styles
|
|
50
|
-
"@elementor/editor-
|
|
51
|
-
"@elementor/editor-
|
|
52
|
-
"@elementor/
|
|
53
|
-
"@elementor/
|
|
54
|
-
"@elementor/
|
|
55
|
-
"@elementor/
|
|
56
|
-
"@elementor/
|
|
57
|
-
"@elementor/
|
|
58
|
-
"@
|
|
42
|
+
"@elementor/editor": "3.34.2",
|
|
43
|
+
"@elementor/editor-current-user": "3.34.2",
|
|
44
|
+
"@elementor/editor-documents": "3.34.2",
|
|
45
|
+
"@elementor/editor-editing-panel": "3.34.2",
|
|
46
|
+
"@elementor/editor-mcp": "3.34.2",
|
|
47
|
+
"@elementor/editor-panels": "3.34.2",
|
|
48
|
+
"@elementor/editor-props": "3.34.2",
|
|
49
|
+
"@elementor/editor-styles": "3.34.2",
|
|
50
|
+
"@elementor/editor-styles-repository": "3.34.2",
|
|
51
|
+
"@elementor/editor-ui": "3.34.2",
|
|
52
|
+
"@elementor/editor-v1-adapters": "3.34.2",
|
|
53
|
+
"@elementor/http-client": "3.34.2",
|
|
54
|
+
"@elementor/icons": "^1.61.0",
|
|
55
|
+
"@elementor/query": "3.34.2",
|
|
56
|
+
"@elementor/schema": "3.34.2",
|
|
57
|
+
"@elementor/store": "3.34.2",
|
|
58
|
+
"@elementor/ui": "1.36.17",
|
|
59
|
+
"@elementor/utils": "3.34.2",
|
|
60
|
+
"@wordpress/i18n": "^5.13.0",
|
|
61
|
+
"@elementor/mixpanel": "3.34.2"
|
|
59
62
|
},
|
|
60
63
|
"peerDependencies": {
|
|
61
64
|
"react": "^18.3.1",
|
package/src/api.ts
CHANGED
|
@@ -4,14 +4,22 @@ import {
|
|
|
4
4
|
__useActiveDocumentActions as useActiveDocumentActions,
|
|
5
5
|
} from '@elementor/editor-documents';
|
|
6
6
|
import { useUserStylesCapability } from '@elementor/editor-styles-repository';
|
|
7
|
+
import { SaveChangesDialog, useDialog } from '@elementor/editor-ui';
|
|
7
8
|
import { IconButton, Tooltip } from '@elementor/ui';
|
|
8
9
|
import { __ } from '@wordpress/i18n';
|
|
9
10
|
|
|
10
11
|
import { globalClassesStylesProvider } from '../../global-classes-styles-provider';
|
|
11
12
|
import { usePrefetchCssClassUsage } from '../../hooks/use-prefetch-css-class-usage';
|
|
13
|
+
import { trackGlobalClasses } from '../../utils/tracking';
|
|
12
14
|
import { usePanelActions } from './class-manager-panel';
|
|
13
15
|
import { FlippedColorSwatchIcon } from './flipped-color-swatch-icon';
|
|
14
|
-
|
|
16
|
+
|
|
17
|
+
const trackGlobalClassesButton = () => {
|
|
18
|
+
trackGlobalClasses( {
|
|
19
|
+
event: 'classManagerOpened',
|
|
20
|
+
source: 'style-panel',
|
|
21
|
+
} );
|
|
22
|
+
};
|
|
15
23
|
|
|
16
24
|
export const ClassManagerButton = () => {
|
|
17
25
|
const document = useActiveDocument();
|
|
@@ -35,6 +43,11 @@ export const ClassManagerButton = () => {
|
|
|
35
43
|
}
|
|
36
44
|
|
|
37
45
|
openPanel();
|
|
46
|
+
trackGlobalClassesButton();
|
|
47
|
+
trackGlobalClasses( {
|
|
48
|
+
event: 'classManagerOpened',
|
|
49
|
+
source: 'style-panel',
|
|
50
|
+
} );
|
|
38
51
|
prefetchClassesUsage();
|
|
39
52
|
};
|
|
40
53
|
|
|
@@ -68,6 +81,7 @@ export const ClassManagerButton = () => {
|
|
|
68
81
|
await saveDocument();
|
|
69
82
|
closeSaveChangesDialog();
|
|
70
83
|
openPanel();
|
|
84
|
+
trackGlobalClassesButton();
|
|
71
85
|
prefetchClassesUsage();
|
|
72
86
|
},
|
|
73
87
|
},
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
PanelHeader,
|
|
10
10
|
PanelHeaderTitle,
|
|
11
11
|
} from '@elementor/editor-panels';
|
|
12
|
-
import { ThemeProvider } from '@elementor/editor-ui';
|
|
12
|
+
import { SaveChangesDialog, ThemeProvider, useDialog } from '@elementor/editor-ui';
|
|
13
13
|
import { changeEditMode } from '@elementor/editor-v1-adapters';
|
|
14
14
|
import { XIcon } from '@elementor/icons';
|
|
15
15
|
import { useMutation } from '@elementor/query';
|
|
@@ -42,7 +42,6 @@ import { hasDeletedItems, onDelete } from './delete-class';
|
|
|
42
42
|
import { FlippedColorSwatchIcon } from './flipped-color-swatch-icon';
|
|
43
43
|
import { GlobalClassesList } from './global-classes-list';
|
|
44
44
|
import { blockPanelInteractions, unblockPanelInteractions } from './panel-interactions';
|
|
45
|
-
import { SaveChangesDialog, useDialog } from './save-changes-dialog';
|
|
46
45
|
|
|
47
46
|
const id = 'global-classes-manager';
|
|
48
47
|
|
|
@@ -64,6 +63,7 @@ export const { panel, usePanelActions } = createPanel( {
|
|
|
64
63
|
|
|
65
64
|
unblockPanelInteractions();
|
|
66
65
|
},
|
|
66
|
+
isOpenPreviousElement: true,
|
|
67
67
|
} );
|
|
68
68
|
|
|
69
69
|
export function ClassManagerPanel() {
|
|
@@ -3,13 +3,19 @@ import { __privateRunCommand as runCommand } from '@elementor/editor-v1-adapters
|
|
|
3
3
|
import { __dispatch as dispatch } from '@elementor/store';
|
|
4
4
|
|
|
5
5
|
import { slice } from '../../store';
|
|
6
|
+
import { trackGlobalClasses } from '../../utils/tracking';
|
|
6
7
|
|
|
7
8
|
let isDeleted = false;
|
|
8
9
|
|
|
9
10
|
export const deleteClass = ( id: string ) => {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
trackGlobalClasses( {
|
|
12
|
+
event: 'classDeleted',
|
|
13
|
+
classId: id,
|
|
14
|
+
runAction: () => {
|
|
15
|
+
dispatch( slice.actions.delete( id ) );
|
|
16
|
+
isDeleted = true;
|
|
17
|
+
},
|
|
18
|
+
} );
|
|
13
19
|
};
|
|
14
20
|
|
|
15
21
|
export const onDelete = async () => {
|
|
@@ -53,9 +53,9 @@ const DeleteConfirmationDialog = ( { label, id }: DeleteConfirmationDialogProps
|
|
|
53
53
|
data: { total, content },
|
|
54
54
|
} = useCssClassUsageByID( id );
|
|
55
55
|
const onConfirm = () => {
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
//
|
|
58
57
|
closeDialog();
|
|
58
|
+
deleteClass( id );
|
|
59
59
|
};
|
|
60
60
|
// translators: %1: total usage count, %2: number of pages
|
|
61
61
|
const text =
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { closeDialog, EllipsisWithTooltip } from '@elementor/editor-ui';
|
|
3
|
+
import { InfoCircleFilledIcon } from '@elementor/icons';
|
|
4
|
+
import {
|
|
5
|
+
Alert,
|
|
6
|
+
Box,
|
|
7
|
+
Button,
|
|
8
|
+
DialogActions,
|
|
9
|
+
DialogContent,
|
|
10
|
+
DialogHeader,
|
|
11
|
+
Divider,
|
|
12
|
+
Icon,
|
|
13
|
+
Stack,
|
|
14
|
+
Typography,
|
|
15
|
+
} from '@elementor/ui';
|
|
16
|
+
import { __ } from '@wordpress/i18n';
|
|
17
|
+
|
|
18
|
+
import { type ModifiedLabels } from '../../store';
|
|
19
|
+
|
|
20
|
+
const DUP_PREFIX = 'DUP_';
|
|
21
|
+
|
|
22
|
+
export const DuplicateLabelDialog = ( {
|
|
23
|
+
modifiedLabels,
|
|
24
|
+
onApprove,
|
|
25
|
+
}: {
|
|
26
|
+
modifiedLabels: ModifiedLabels;
|
|
27
|
+
onApprove?: () => void;
|
|
28
|
+
} ) => {
|
|
29
|
+
const handleButtonClick = () => {
|
|
30
|
+
localStorage.setItem( 'elementor-global-classes-search', DUP_PREFIX );
|
|
31
|
+
onApprove?.();
|
|
32
|
+
closeDialog();
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<>
|
|
37
|
+
<DialogHeader logo={ false }>
|
|
38
|
+
<Box display="flex" alignItems="center" gap={ 1 }>
|
|
39
|
+
<Icon color="secondary">
|
|
40
|
+
<InfoCircleFilledIcon fontSize="medium" />
|
|
41
|
+
</Icon>
|
|
42
|
+
<Typography variant="subtitle1">
|
|
43
|
+
{ __( "We've published your page and updated class names.", 'elementor' ) }
|
|
44
|
+
</Typography>
|
|
45
|
+
</Box>
|
|
46
|
+
</DialogHeader>
|
|
47
|
+
<DialogContent>
|
|
48
|
+
<Stack spacing={ 2 } direction="column">
|
|
49
|
+
<Typography variant="body2">
|
|
50
|
+
{ __(
|
|
51
|
+
'Some new classes used the same names as existing ones. To prevent conflicts, we added the prefix',
|
|
52
|
+
'elementor'
|
|
53
|
+
) }
|
|
54
|
+
<strong> { DUP_PREFIX }</strong>
|
|
55
|
+
</Typography>
|
|
56
|
+
|
|
57
|
+
<Box>
|
|
58
|
+
<Box
|
|
59
|
+
sx={ {
|
|
60
|
+
width: '100%',
|
|
61
|
+
display: 'flex',
|
|
62
|
+
gap: 2,
|
|
63
|
+
alignItems: 'flex-start',
|
|
64
|
+
} }
|
|
65
|
+
>
|
|
66
|
+
<Typography
|
|
67
|
+
variant="subtitle2"
|
|
68
|
+
sx={ {
|
|
69
|
+
fontWeight: 'bold',
|
|
70
|
+
flex: 1,
|
|
71
|
+
flexShrink: 1,
|
|
72
|
+
flexGrow: 1,
|
|
73
|
+
minWidth: 0,
|
|
74
|
+
} }
|
|
75
|
+
>
|
|
76
|
+
{ __( 'Before', 'elementor' ) }
|
|
77
|
+
</Typography>
|
|
78
|
+
<Typography
|
|
79
|
+
variant="subtitle2"
|
|
80
|
+
sx={ {
|
|
81
|
+
minWidth: '200px',
|
|
82
|
+
fontWeight: 'bold',
|
|
83
|
+
flexShrink: 0,
|
|
84
|
+
flexGrow: 0,
|
|
85
|
+
width: '200px',
|
|
86
|
+
maxWidth: '200px',
|
|
87
|
+
} }
|
|
88
|
+
>
|
|
89
|
+
{ __( 'After', 'elementor' ) }
|
|
90
|
+
</Typography>
|
|
91
|
+
</Box>
|
|
92
|
+
<Divider sx={ { mt: 0.5, mb: 0.5 } } />
|
|
93
|
+
<Stack direction="column" gap={ 0.5 } sx={ { pb: 2 } }>
|
|
94
|
+
{ Object.values( modifiedLabels ).map( ( { original, modified }, index ) => (
|
|
95
|
+
<Box
|
|
96
|
+
key={ index }
|
|
97
|
+
sx={ {
|
|
98
|
+
width: '100%',
|
|
99
|
+
display: 'flex',
|
|
100
|
+
gap: 2,
|
|
101
|
+
alignItems: 'flex-start',
|
|
102
|
+
} }
|
|
103
|
+
>
|
|
104
|
+
<Box
|
|
105
|
+
sx={ {
|
|
106
|
+
flex: 1,
|
|
107
|
+
flexShrink: 1,
|
|
108
|
+
flexGrow: 1,
|
|
109
|
+
minWidth: 0,
|
|
110
|
+
} }
|
|
111
|
+
>
|
|
112
|
+
<EllipsisWithTooltip title={ original }>
|
|
113
|
+
<Typography variant="body2" sx={ { color: 'text.secondary' } }>
|
|
114
|
+
{ original }
|
|
115
|
+
</Typography>
|
|
116
|
+
</EllipsisWithTooltip>
|
|
117
|
+
</Box>
|
|
118
|
+
<Box
|
|
119
|
+
sx={ {
|
|
120
|
+
minWidth: '200px',
|
|
121
|
+
flexShrink: 0,
|
|
122
|
+
flexGrow: 0,
|
|
123
|
+
width: '200px',
|
|
124
|
+
maxWidth: '200px',
|
|
125
|
+
} }
|
|
126
|
+
>
|
|
127
|
+
<EllipsisWithTooltip title={ modified }>
|
|
128
|
+
<Typography variant="body2" sx={ { color: 'text.primary' } }>
|
|
129
|
+
{ modified }
|
|
130
|
+
</Typography>
|
|
131
|
+
</EllipsisWithTooltip>
|
|
132
|
+
</Box>
|
|
133
|
+
</Box>
|
|
134
|
+
) ) }
|
|
135
|
+
</Stack>
|
|
136
|
+
<Box>
|
|
137
|
+
<Alert severity="info" size="small" color="secondary">
|
|
138
|
+
<strong>{ __( 'Your designs and classes are safe.', 'elementor' ) }</strong>
|
|
139
|
+
{ __(
|
|
140
|
+
'Only the prefixes were added. Find them in Class Manager by searching',
|
|
141
|
+
'elementor'
|
|
142
|
+
) }
|
|
143
|
+
<strong>{ DUP_PREFIX }</strong>
|
|
144
|
+
</Alert>
|
|
145
|
+
</Box>
|
|
146
|
+
</Box>
|
|
147
|
+
</Stack>
|
|
148
|
+
</DialogContent>
|
|
149
|
+
<DialogActions>
|
|
150
|
+
<Button color="secondary" variant="text" onClick={ handleButtonClick }>
|
|
151
|
+
{ __( 'Go to Class Manager', 'elementor' ) }
|
|
152
|
+
</Button>
|
|
153
|
+
<Button color="secondary" variant="contained" onClick={ closeDialog }>
|
|
154
|
+
{ __( 'Done', 'elementor' ) }
|
|
155
|
+
</Button>
|
|
156
|
+
</DialogActions>
|
|
157
|
+
</>
|
|
158
|
+
);
|
|
159
|
+
};
|
|
@@ -9,6 +9,7 @@ import { useClassesOrder } from '../../hooks/use-classes-order';
|
|
|
9
9
|
import { useFilters } from '../../hooks/use-filters';
|
|
10
10
|
import { useOrderedClasses } from '../../hooks/use-ordered-classes';
|
|
11
11
|
import { slice } from '../../store';
|
|
12
|
+
import { trackGlobalClasses } from '../../utils/tracking';
|
|
12
13
|
import { useSearchAndFilters } from '../search-and-filter/context';
|
|
13
14
|
import { ClassItem } from './class-item';
|
|
14
15
|
import { DeleteConfirmationProvider } from './delete-confirmation-dialog';
|
|
@@ -27,7 +28,9 @@ export const GlobalClassesList = ( { disabled }: GlobalClassesListProps ) => {
|
|
|
27
28
|
const cssClasses = useOrderedClasses();
|
|
28
29
|
const dispatch = useDispatch();
|
|
29
30
|
const filters = useFilters();
|
|
30
|
-
const [
|
|
31
|
+
const [ draggedItemId, setDraggedItemId ] = React.useState< StyleDefinitionID | null >( null );
|
|
32
|
+
const draggedItemLabel = cssClasses.find( ( cssClass ) => cssClass.id === draggedItemId )?.label ?? '';
|
|
33
|
+
const [ classesOrder, reorderClasses ] = useReorder( draggedItemId, setDraggedItemId, draggedItemLabel ?? '' );
|
|
31
34
|
const filteredCssClasses = useFilteredCssClasses();
|
|
32
35
|
|
|
33
36
|
useEffect( () => {
|
|
@@ -72,26 +75,41 @@ export const GlobalClassesList = ( { disabled }: GlobalClassesListProps ) => {
|
|
|
72
75
|
>
|
|
73
76
|
{ filteredCssClasses?.map( ( { id, label } ) => (
|
|
74
77
|
<SortableItem key={ id } id={ id }>
|
|
75
|
-
{ ( { isDragged, isDragPlaceholder, triggerProps, triggerStyle } ) =>
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
78
|
+
{ ( { isDragged, isDragPlaceholder, triggerProps, triggerStyle } ) => {
|
|
79
|
+
if ( isDragged && ! draggedItemId ) {
|
|
80
|
+
setDraggedItemId( id );
|
|
81
|
+
}
|
|
82
|
+
return (
|
|
83
|
+
<ClassItem
|
|
84
|
+
id={ id }
|
|
85
|
+
label={ label }
|
|
86
|
+
renameClass={ ( newLabel: string ) => {
|
|
87
|
+
trackGlobalClasses( {
|
|
88
|
+
event: 'classRenamed',
|
|
89
|
+
classId: id,
|
|
90
|
+
oldValue: label,
|
|
91
|
+
newValue: newLabel,
|
|
92
|
+
source: 'class-manager',
|
|
93
|
+
} );
|
|
94
|
+
dispatch(
|
|
95
|
+
slice.actions.update( {
|
|
96
|
+
style: {
|
|
97
|
+
id,
|
|
98
|
+
label: newLabel,
|
|
99
|
+
},
|
|
100
|
+
} )
|
|
101
|
+
);
|
|
102
|
+
} }
|
|
103
|
+
selected={ isDragged }
|
|
104
|
+
disabled={ disabled || isDragPlaceholder }
|
|
105
|
+
sortableTriggerProps={ {
|
|
106
|
+
...triggerProps,
|
|
107
|
+
style: triggerStyle,
|
|
108
|
+
} }
|
|
109
|
+
showSortIndicator={ allowSorting }
|
|
110
|
+
/>
|
|
111
|
+
);
|
|
112
|
+
} }
|
|
95
113
|
</SortableItem>
|
|
96
114
|
) ) }
|
|
97
115
|
</SortableProvider>
|
|
@@ -122,12 +140,25 @@ const StyledHeader = styled( Typography )< TypographyProps >( ( { theme, variant
|
|
|
122
140
|
},
|
|
123
141
|
} ) );
|
|
124
142
|
|
|
125
|
-
const useReorder = (
|
|
143
|
+
const useReorder = (
|
|
144
|
+
draggedItemId: StyleDefinitionID | null,
|
|
145
|
+
setDraggedItemId: React.Dispatch< React.SetStateAction< StyleDefinitionID | null > >,
|
|
146
|
+
draggedItemLabel: string
|
|
147
|
+
) => {
|
|
126
148
|
const dispatch = useDispatch();
|
|
127
149
|
const order = useClassesOrder();
|
|
128
150
|
|
|
129
151
|
const reorder = ( newIds: StyleDefinitionID[] ) => {
|
|
130
152
|
dispatch( slice.actions.setOrder( newIds ) );
|
|
153
|
+
|
|
154
|
+
if ( draggedItemId ) {
|
|
155
|
+
trackGlobalClasses( {
|
|
156
|
+
event: 'classManagerReorder',
|
|
157
|
+
classId: draggedItemId,
|
|
158
|
+
classTitle: draggedItemLabel,
|
|
159
|
+
} );
|
|
160
|
+
setDraggedItemId( null ); // Reset after tracking
|
|
161
|
+
}
|
|
131
162
|
};
|
|
132
163
|
|
|
133
164
|
return [ order, reorder ] as const;
|
|
@@ -6,6 +6,7 @@ import { Divider } from '@elementor/ui';
|
|
|
6
6
|
import { __ } from '@wordpress/i18n';
|
|
7
7
|
|
|
8
8
|
import { globalClassesStylesProvider } from '../global-classes-styles-provider';
|
|
9
|
+
import { trackGlobalClasses } from '../utils/tracking';
|
|
9
10
|
|
|
10
11
|
type OwnProps = {
|
|
11
12
|
successCallback: ( _: string ) => void;
|
|
@@ -26,6 +27,12 @@ export const ConvertLocalClassToGlobalClass = ( props: OwnProps ) => {
|
|
|
26
27
|
const newId = globalClassesStylesProvider.actions.create?.( newClassName, localStyleData.variants );
|
|
27
28
|
if ( newId ) {
|
|
28
29
|
props.successCallback( newId );
|
|
30
|
+
trackGlobalClasses( {
|
|
31
|
+
classId: newId,
|
|
32
|
+
event: 'classCreated',
|
|
33
|
+
source: 'converted',
|
|
34
|
+
classTitle: newClassName,
|
|
35
|
+
} );
|
|
29
36
|
}
|
|
30
37
|
};
|
|
31
38
|
|
|
@@ -20,6 +20,7 @@ import { Box, Chip, Divider, Icon, MenuList, Stack, styled, Tooltip, Typography
|
|
|
20
20
|
import { __ } from '@wordpress/i18n';
|
|
21
21
|
|
|
22
22
|
import { useCssClassUsageByID } from '../../../hooks/use-css-class-usage-by-id';
|
|
23
|
+
import { trackGlobalClasses } from '../../../utils/tracking';
|
|
23
24
|
import { type ContentType } from '../types';
|
|
24
25
|
|
|
25
26
|
type CssClassUsageRecord = VirtualizedItem< 'item', string > & { docType: ContentType };
|
|
@@ -69,6 +70,14 @@ export const CssClassUsagePopover = ( {
|
|
|
69
70
|
} ) as CssClassUsageRecord
|
|
70
71
|
) ?? [];
|
|
71
72
|
|
|
73
|
+
const handleSelect = ( value: string ) => {
|
|
74
|
+
onNavigate( +value );
|
|
75
|
+
trackGlobalClasses( {
|
|
76
|
+
event: 'classUsageLocate',
|
|
77
|
+
classId: cssClassID,
|
|
78
|
+
} );
|
|
79
|
+
};
|
|
80
|
+
|
|
72
81
|
return (
|
|
73
82
|
<>
|
|
74
83
|
<PopoverHeader
|
|
@@ -86,7 +95,7 @@ export const CssClassUsagePopover = ( {
|
|
|
86
95
|
<Divider />
|
|
87
96
|
<PopoverBody width={ 300 }>
|
|
88
97
|
<PopoverMenuList
|
|
89
|
-
onSelect={
|
|
98
|
+
onSelect={ handleSelect }
|
|
90
99
|
items={ cssClassUsageRecords }
|
|
91
100
|
onClose={ () => {} }
|
|
92
101
|
menuListTemplate={ StyledCssClassUsageItem }
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
import { __ } from '@wordpress/i18n';
|
|
17
17
|
|
|
18
18
|
import { useCssClassUsageByID } from '../../../hooks/use-css-class-usage-by-id';
|
|
19
|
+
import { trackGlobalClasses } from '../../../utils/tracking';
|
|
19
20
|
import { type CssClassID } from '../types';
|
|
20
21
|
import { CssClassUsagePopover } from './css-class-usage-popover';
|
|
21
22
|
|
|
@@ -32,20 +33,34 @@ export const CssClassUsageTrigger = ( { id, onClick }: { id: CssClassID; onClick
|
|
|
32
33
|
|
|
33
34
|
const WrapperComponent = total !== 0 ? TooltipWrapper : InfoAlertMessage;
|
|
34
35
|
|
|
36
|
+
const handleMouseEnter = () => {
|
|
37
|
+
trackGlobalClasses( {
|
|
38
|
+
event: 'classUsageHovered',
|
|
39
|
+
classId: id,
|
|
40
|
+
usage: total,
|
|
41
|
+
} );
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const handleClick = ( e: MouseEvent ) => {
|
|
45
|
+
if ( total !== 0 ) {
|
|
46
|
+
bindTrigger( cssClassUsagePopover ).onClick( e );
|
|
47
|
+
onClick( id );
|
|
48
|
+
trackGlobalClasses( {
|
|
49
|
+
event: 'classUsageClicked',
|
|
50
|
+
classId: id,
|
|
51
|
+
} );
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
35
55
|
return (
|
|
36
56
|
<>
|
|
37
|
-
<Box position={ 'relative' }>
|
|
57
|
+
<Box position={ 'relative' } onMouseEnter={ handleMouseEnter }>
|
|
38
58
|
<WrapperComponent total={ total }>
|
|
39
59
|
<CustomIconButton
|
|
40
60
|
disabled={ total === 0 }
|
|
41
61
|
size={ 'tiny' }
|
|
42
62
|
{ ...bindTrigger( cssClassUsagePopover ) }
|
|
43
|
-
onClick={
|
|
44
|
-
if ( total !== 0 ) {
|
|
45
|
-
bindTrigger( cssClassUsagePopover ).onClick( e );
|
|
46
|
-
onClick( id );
|
|
47
|
-
}
|
|
48
|
-
} }
|
|
63
|
+
onClick={ handleClick }
|
|
49
64
|
>
|
|
50
65
|
<CurrentLocationIcon fontSize={ 'tiny' } />
|
|
51
66
|
</CustomIconButton>
|
|
@@ -3,6 +3,7 @@ import { Chip, Stack } from '@elementor/ui';
|
|
|
3
3
|
import { __ } from '@wordpress/i18n';
|
|
4
4
|
|
|
5
5
|
import type { FilterKey } from '../../../../hooks/use-filtered-css-class-usage';
|
|
6
|
+
import { trackGlobalClasses } from '../../../../utils/tracking';
|
|
6
7
|
import { useSearchAndFilters } from '../../context';
|
|
7
8
|
import { ClearIconButton } from './clear-icon-button';
|
|
8
9
|
import { filterConfig } from './filter-list';
|
|
@@ -14,6 +15,12 @@ export const ActiveFilters = () => {
|
|
|
14
15
|
|
|
15
16
|
const handleRemove = ( key: FilterKey ) => {
|
|
16
17
|
setFilters( ( prev ) => ( { ...prev, [ key ]: false } ) );
|
|
18
|
+
trackGlobalClasses( {
|
|
19
|
+
event: 'classManagerFilterUsed',
|
|
20
|
+
action: 'remove',
|
|
21
|
+
type: key,
|
|
22
|
+
trigger: 'header',
|
|
23
|
+
} );
|
|
17
24
|
};
|
|
18
25
|
|
|
19
26
|
const activeKeys = Object.keys( filters ).filter( ( key ): key is FilterKey => filters[ key as FilterKey ] );
|
|
@@ -35,6 +42,7 @@ export const ActiveFilters = () => {
|
|
|
35
42
|
</Stack>
|
|
36
43
|
{ showClearIcon && (
|
|
37
44
|
<ClearIconButton
|
|
45
|
+
trigger="header"
|
|
38
46
|
tooltipText={ __( 'Clear Filters', 'elementor' ) }
|
|
39
47
|
sx={ { margin: '0 0 auto auto' } }
|
|
40
48
|
/>
|
|
@@ -2,19 +2,28 @@ import * as React from 'react';
|
|
|
2
2
|
import { BrushBigIcon } from '@elementor/icons';
|
|
3
3
|
import { Box, IconButton, styled, type SxProps, type Theme, Tooltip } from '@elementor/ui';
|
|
4
4
|
|
|
5
|
+
import { trackGlobalClasses } from '../../../../utils/tracking';
|
|
5
6
|
import { useSearchAndFilters } from '../../context';
|
|
6
7
|
|
|
7
|
-
type ClearIconButtonProps = { tooltipText: React.ReactNode; sx?: SxProps< Theme
|
|
8
|
+
type ClearIconButtonProps = { tooltipText: React.ReactNode; sx?: SxProps< Theme >; trigger: 'menu' | 'header' };
|
|
8
9
|
|
|
9
|
-
export const ClearIconButton = ( { tooltipText, sx }: ClearIconButtonProps ) => {
|
|
10
|
+
export const ClearIconButton = ( { tooltipText, sx, trigger }: ClearIconButtonProps ) => {
|
|
10
11
|
const {
|
|
11
12
|
filters: { onClearFilter },
|
|
12
13
|
} = useSearchAndFilters();
|
|
13
14
|
|
|
15
|
+
const handleClearFilters = () => {
|
|
16
|
+
onClearFilter( trigger );
|
|
17
|
+
trackGlobalClasses( {
|
|
18
|
+
event: 'classManagerFilterCleared',
|
|
19
|
+
trigger,
|
|
20
|
+
} );
|
|
21
|
+
};
|
|
22
|
+
|
|
14
23
|
return (
|
|
15
24
|
<Tooltip title={ tooltipText } placement="top" disableInteractive>
|
|
16
25
|
<Box>
|
|
17
|
-
<CustomIconButton aria-label={ tooltipText } size="tiny" onClick={
|
|
26
|
+
<CustomIconButton aria-label={ tooltipText } size="tiny" onClick={ handleClearFilters } sx={ sx }>
|
|
18
27
|
<BrushBigIcon fontSize="tiny" />
|
|
19
28
|
</CustomIconButton>
|
|
20
29
|
</Box>
|
|
@@ -4,6 +4,7 @@ import { FilterIcon } from '@elementor/icons';
|
|
|
4
4
|
import { bindPopover, bindToggle, Divider, Popover, ToggleButton, Tooltip, usePopupState } from '@elementor/ui';
|
|
5
5
|
import { __ } from '@wordpress/i18n';
|
|
6
6
|
|
|
7
|
+
import { trackGlobalClasses, type TrackingEvent } from '../../../../utils/tracking';
|
|
7
8
|
import { useSearchAndFilters } from '../../context';
|
|
8
9
|
import { ClearIconButton } from './clear-icon-button';
|
|
9
10
|
import { FilterList } from './filter-list';
|
|
@@ -17,6 +18,14 @@ export const CssClassFilter = () => {
|
|
|
17
18
|
disableAutoFocus: true,
|
|
18
19
|
} );
|
|
19
20
|
|
|
21
|
+
React.useEffect( () => {
|
|
22
|
+
if ( popupState.isOpen ) {
|
|
23
|
+
trackGlobalClasses( {
|
|
24
|
+
event: 'classManagerFiltersOpened',
|
|
25
|
+
} as TrackingEvent );
|
|
26
|
+
}
|
|
27
|
+
}, [ popupState.isOpen ] );
|
|
28
|
+
|
|
20
29
|
const showCleanIcon = Object.values( filters ).some( ( value ) => value );
|
|
21
30
|
|
|
22
31
|
return (
|
|
@@ -50,6 +59,7 @@ export const CssClassFilter = () => {
|
|
|
50
59
|
showCleanIcon
|
|
51
60
|
? [
|
|
52
61
|
<ClearIconButton
|
|
62
|
+
trigger="menu"
|
|
53
63
|
key="clear-all-button"
|
|
54
64
|
tooltipText={ __( 'Clear all', 'elementor' ) }
|
|
55
65
|
/>,
|
|
@@ -3,6 +3,7 @@ import { Checkbox, Chip, MenuItem, MenuList, Stack, Typography } from '@elemento
|
|
|
3
3
|
import { __ } from '@wordpress/i18n';
|
|
4
4
|
|
|
5
5
|
import { type FilterKey, useFilteredCssClassUsage } from '../../../../hooks/use-filtered-css-class-usage';
|
|
6
|
+
import { trackGlobalClasses } from '../../../../utils/tracking';
|
|
6
7
|
import { useSearchAndFilters } from '../../context';
|
|
7
8
|
|
|
8
9
|
export const filterConfig: Record< FilterKey, string > = {
|
|
@@ -19,6 +20,12 @@ export const FilterList = () => {
|
|
|
19
20
|
|
|
20
21
|
const handleOnClick = ( value: FilterKey ) => {
|
|
21
22
|
setFilters( ( prev ) => ( { ...prev, [ value ]: ! prev[ value ] } ) );
|
|
23
|
+
trackGlobalClasses( {
|
|
24
|
+
event: 'classManagerFilterUsed',
|
|
25
|
+
action: filters[ value ] ? 'remove' : 'apply',
|
|
26
|
+
type: value,
|
|
27
|
+
trigger: 'menu',
|
|
28
|
+
} );
|
|
22
29
|
};
|
|
23
30
|
|
|
24
31
|
return (
|
|
@@ -3,6 +3,7 @@ import { SearchIcon } from '@elementor/icons';
|
|
|
3
3
|
import { Box, InputAdornment, Stack, TextField } from '@elementor/ui';
|
|
4
4
|
import { __ } from '@wordpress/i18n';
|
|
5
5
|
|
|
6
|
+
import { trackGlobalClasses, type TrackingEvent } from '../../../../utils/tracking';
|
|
6
7
|
import { useSearchAndFilters } from '../../context';
|
|
7
8
|
|
|
8
9
|
export const ClassManagerSearch = () => {
|
|
@@ -18,6 +19,11 @@ export const ClassManagerSearch = () => {
|
|
|
18
19
|
fullWidth
|
|
19
20
|
size={ 'tiny' }
|
|
20
21
|
value={ inputValue }
|
|
22
|
+
onFocus={ () => {
|
|
23
|
+
trackGlobalClasses( {
|
|
24
|
+
event: 'classManagerSearched',
|
|
25
|
+
} as TrackingEvent );
|
|
26
|
+
} }
|
|
21
27
|
placeholder={ __( 'Search', 'elementor' ) }
|
|
22
28
|
onChange={ ( e: React.ChangeEvent< HTMLInputElement > ) => handleChange( e.target.value ) }
|
|
23
29
|
InputProps={ {
|