@elementor/editor-variables 3.33.0-156 → 3.33.0-158

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elementor/editor-variables",
3
- "version": "3.33.0-156",
3
+ "version": "3.33.0-158",
4
4
  "private": false,
5
5
  "author": "Elementor Team",
6
6
  "homepage": "https://elementor.com/",
@@ -39,19 +39,19 @@
39
39
  "dev": "tsup --config=../../tsup.dev.ts"
40
40
  },
41
41
  "dependencies": {
42
- "@elementor/editor": "3.33.0-156",
43
- "@elementor/editor-canvas": "3.33.0-156",
44
- "@elementor/editor-controls": "3.33.0-156",
45
- "@elementor/editor-current-user": "3.33.0-156",
46
- "@elementor/editor-editing-panel": "3.33.0-156",
47
- "@elementor/editor-panels": "3.33.0-156",
48
- "@elementor/editor-props": "3.33.0-156",
49
- "@elementor/editor-ui": "3.33.0-156",
50
- "@elementor/editor-v1-adapters": "3.33.0-156",
51
- "@elementor/http-client": "3.33.0-156",
42
+ "@elementor/editor": "3.33.0-158",
43
+ "@elementor/editor-canvas": "3.33.0-158",
44
+ "@elementor/editor-controls": "3.33.0-158",
45
+ "@elementor/editor-current-user": "3.33.0-158",
46
+ "@elementor/editor-editing-panel": "3.33.0-158",
47
+ "@elementor/editor-panels": "3.33.0-158",
48
+ "@elementor/editor-props": "3.33.0-158",
49
+ "@elementor/editor-ui": "3.33.0-158",
50
+ "@elementor/editor-v1-adapters": "3.33.0-158",
51
+ "@elementor/http-client": "3.33.0-158",
52
52
  "@elementor/icons": "1.46.0",
53
- "@elementor/mixpanel": "3.33.0-156",
54
- "@elementor/schema": "3.33.0-156",
53
+ "@elementor/mixpanel": "3.33.0-158",
54
+ "@elementor/schema": "3.33.0-158",
55
55
  "@elementor/ui": "1.36.12",
56
56
  "@wordpress/i18n": "^5.13.0"
57
57
  },
@@ -14,10 +14,9 @@ export const NoSearchResults = ( { searchValue, onClear, icon }: Props ) => {
14
14
  gap={ 1 }
15
15
  alignItems="center"
16
16
  justifyContent="center"
17
- height="100%"
18
17
  p={ 2.5 }
19
18
  color="text.secondary"
20
- sx={ { pb: 3.5 } }
19
+ sx={ { pb: 3.5, pt: 5 } }
21
20
  >
22
21
  { icon }
23
22
  <Typography align="center" variant="subtitle2">
@@ -5,20 +5,24 @@ import { generateTempId } from '../../../batch-operations';
5
5
  import { getVariables } from '../../../hooks/use-prop-variables';
6
6
  import { service } from '../../../service';
7
7
  import { type TVariablesList } from '../../../storage';
8
+ import { filterBySearch } from '../../../utils/filter-by-search';
8
9
  import { ERROR_MESSAGES } from '../../../utils/validations';
9
10
 
10
11
  export const useVariablesManagerState = () => {
11
12
  const [ variables, setVariables ] = useState( () => getVariables( false ) );
12
13
  const [ deletedVariables, setDeletedVariables ] = useState< string[] >( [] );
13
- const [ ids, setIds ] = useState< string[] >( () => Object.keys( getVariables( false ) ) );
14
14
  const [ isDirty, setIsDirty ] = useState( false );
15
15
  const [ hasValidationErrors, setHasValidationErrors ] = useState( false );
16
16
  const [ isSaving, setIsSaving ] = useState( false );
17
+ const [ searchValue, setSearchValue ] = useState( '' );
17
18
 
18
- const handleOnChange = useCallback( ( newVariables: TVariablesList ) => {
19
- setVariables( newVariables );
20
- setIsDirty( true );
21
- }, [] );
19
+ const handleOnChange = useCallback(
20
+ ( newVariables: TVariablesList ) => {
21
+ setVariables( { ...variables, ...newVariables } );
22
+ setIsDirty( true );
23
+ },
24
+ [ variables ]
25
+ );
22
26
 
23
27
  const createVariable = useCallback( ( type: string, defaultName: string, defaultValue: string ) => {
24
28
  const newId = generateTempId();
@@ -30,7 +34,6 @@ export const useVariablesManagerState = () => {
30
34
  };
31
35
 
32
36
  setVariables( ( prev ) => ( { ...prev, [ newId ]: newVariable } ) );
33
- setIds( ( prev ) => [ ...prev, newId ] );
34
37
  setIsDirty( true );
35
38
 
36
39
  return newId;
@@ -42,6 +45,10 @@ export const useVariablesManagerState = () => {
42
45
  setIsDirty( true );
43
46
  }, [] );
44
47
 
48
+ const handleSearch = ( searchTerm: string ) => {
49
+ setSearchValue( searchTerm );
50
+ };
51
+
45
52
  const handleSave = useCallback( async (): Promise< { success: boolean; error?: string } > => {
46
53
  try {
47
54
  const originalVariables = getVariables( false );
@@ -53,7 +60,6 @@ export const useVariablesManagerState = () => {
53
60
  const updatedVariables = service.variables();
54
61
 
55
62
  setVariables( updatedVariables );
56
- setIds( Object.keys( updatedVariables ) );
57
63
  setDeletedVariables( [] );
58
64
  setIsDirty( false );
59
65
  setIsSaving( false );
@@ -67,18 +73,25 @@ export const useVariablesManagerState = () => {
67
73
  }
68
74
  }, [ variables ] );
69
75
 
76
+ const filteredVariables = () => {
77
+ const list = Object.entries( variables ).map( ( [ id, value ] ) => ( { ...value, id } ) );
78
+ const filtered = filterBySearch( list, searchValue );
79
+
80
+ return Object.fromEntries( filtered.map( ( { id, ...rest } ) => [ id, rest ] ) );
81
+ };
82
+
70
83
  return {
71
- variables,
84
+ variables: filteredVariables(),
72
85
  deletedVariables,
73
- ids,
74
86
  isDirty,
75
87
  hasValidationErrors,
76
- setIds,
77
88
  handleOnChange,
78
89
  createVariable,
79
90
  handleDeleteVariable,
80
91
  handleSave,
81
92
  isSaving,
93
+ handleSearch,
94
+ searchValue,
82
95
  setHasValidationErrors,
83
96
  };
84
97
  };
@@ -8,13 +8,14 @@ import {
8
8
  PanelHeader,
9
9
  PanelHeaderTitle,
10
10
  } from '@elementor/editor-panels';
11
- import { SaveChangesDialog, ThemeProvider, useDialog } from '@elementor/editor-ui';
11
+ import { SaveChangesDialog, SearchField, ThemeProvider, useDialog } from '@elementor/editor-ui';
12
12
  import { changeEditMode } from '@elementor/editor-v1-adapters';
13
13
  import { ColorFilterIcon, TrashIcon } from '@elementor/icons';
14
14
  import { Alert, Box, Button, CloseButton, Divider, ErrorBoundary, Stack } from '@elementor/ui';
15
15
  import { __ } from '@wordpress/i18n';
16
16
 
17
17
  import { DeleteConfirmationDialog } from '../ui/delete-confirmation-dialog';
18
+ import { NoSearchResults } from '../ui/no-search-results';
18
19
  import { useAutoEdit } from './hooks/use-auto-edit';
19
20
  import { useVariablesManagerState } from './hooks/use-variables-manager-state';
20
21
  import { SIZE, VariableManagerCreateMenu } from './variables-manager-create-menu';
@@ -40,15 +41,15 @@ export function VariablesManagerPanel() {
40
41
 
41
42
  const {
42
43
  variables,
43
- ids,
44
44
  isDirty,
45
45
  hasValidationErrors,
46
- setIds,
46
+ searchValue,
47
47
  handleOnChange,
48
48
  createVariable,
49
49
  handleDeleteVariable,
50
50
  handleSave,
51
51
  isSaving,
52
+ handleSearch,
52
53
  setHasValidationErrors,
53
54
  } = useVariablesManagerState();
54
55
 
@@ -98,6 +99,8 @@ export function VariablesManagerPanel() {
98
99
  },
99
100
  ];
100
101
 
102
+ const hasVariables = Object.keys( variables ).length !== 0;
103
+
101
104
  return (
102
105
  <ThemeProvider>
103
106
  <ErrorBoundary fallback={ <ErrorBoundaryFallback /> }>
@@ -125,7 +128,6 @@ export function VariablesManagerPanel() {
125
128
  />
126
129
  </Stack>
127
130
  </Stack>
128
- <Divider sx={ { width: '100%' } } />
129
131
  </Stack>
130
132
  </PanelHeader>
131
133
  <PanelBody
@@ -135,16 +137,30 @@ export function VariablesManagerPanel() {
135
137
  height: '100%',
136
138
  } }
137
139
  >
138
- <VariablesManagerTable
139
- menuActions={ menuActions }
140
- variables={ variables }
141
- onChange={ handleOnChange }
142
- ids={ ids }
143
- onIdsChange={ setIds }
144
- autoEditVariableId={ autoEditVariableId }
145
- onAutoEditComplete={ handleAutoEditComplete }
146
- onFieldError={ setHasValidationErrors }
140
+ <SearchField
141
+ placeholder={ __( 'Search', 'elementor' ) }
142
+ value={ searchValue }
143
+ onSearch={ handleSearch }
147
144
  />
145
+ <Divider sx={ { width: '100%' } } />
146
+ { hasVariables && (
147
+ <VariablesManagerTable
148
+ menuActions={ menuActions }
149
+ variables={ variables }
150
+ onChange={ handleOnChange }
151
+ autoEditVariableId={ autoEditVariableId }
152
+ onAutoEditComplete={ handleAutoEditComplete }
153
+ onFieldError={ setHasValidationErrors }
154
+ />
155
+ ) }
156
+
157
+ { ! hasVariables && (
158
+ <NoSearchResults
159
+ searchValue={ searchValue }
160
+ onClear={ () => handleSearch( '' ) }
161
+ icon={ <ColorFilterIcon fontSize="large" /> }
162
+ />
163
+ ) }
148
164
  </PanelBody>
149
165
 
150
166
  <PanelFooter>
@@ -28,8 +28,6 @@ type Props = {
28
28
  menuActions: VariableManagerMenuAction[];
29
29
  variables: TVariablesList;
30
30
  onChange: ( variables: TVariablesList ) => void;
31
- ids: string[];
32
- onIdsChange: ( ids: string[] ) => void;
33
31
  autoEditVariableId?: string;
34
32
  onAutoEditComplete?: () => void;
35
33
  onFieldError?: ( hasError: boolean ) => void;
@@ -39,8 +37,6 @@ export const VariablesManagerTable = ( {
39
37
  menuActions,
40
38
  variables,
41
39
  onChange: handleOnChange,
42
- ids,
43
- onIdsChange: setIds,
44
40
  autoEditVariableId,
45
41
  onAutoEditComplete,
46
42
  onFieldError,
@@ -71,17 +67,9 @@ export const VariablesManagerTable = ( {
71
67
  }
72
68
  };
73
69
 
74
- useEffect( () => {
75
- const sortedIds = [ ...ids ].sort( sortVariablesOrder( variables ) );
76
-
77
- if ( JSON.stringify( sortedIds ) !== JSON.stringify( ids ) ) {
78
- setIds( sortedIds );
79
- }
80
- }, [ ids, variables, setIds ] );
81
-
70
+ const ids = Object.keys( variables ).sort( sortVariablesOrder( variables ) );
82
71
  const rows = ids
83
72
  .filter( ( id ) => ! variables[ id ].deleted )
84
- .sort( sortVariablesOrder( variables ) )
85
73
  .map( ( id ) => {
86
74
  const variable = variables[ id ];
87
75
  const variableType = getVariableType( variable.type );
@@ -100,6 +88,22 @@ export const VariablesManagerTable = ( {
100
88
  tableLayout: 'fixed',
101
89
  };
102
90
 
91
+ const handleReorder = ( newIds: string[] ) => {
92
+ const updatedVariables = { ...variables };
93
+
94
+ newIds.forEach( ( id, index ) => {
95
+ const current = updatedVariables[ id ];
96
+
97
+ if ( ! current ) {
98
+ return;
99
+ }
100
+
101
+ updatedVariables[ id ] = Object.assign( {}, current, { order: index + 1 } );
102
+ } );
103
+
104
+ handleOnChange( updatedVariables );
105
+ };
106
+
103
107
  return (
104
108
  <TableContainer ref={ tableContainerRef } sx={ { overflow: 'initial' } }>
105
109
  <Table sx={ tableSX } aria-label="Variables manager list with drag and drop reordering" stickyHeader>
@@ -114,19 +118,7 @@ export const VariablesManagerTable = ( {
114
118
  <TableBody>
115
119
  <UnstableSortableProvider
116
120
  value={ ids }
117
- onChange={ ( newIds ) => {
118
- const updatedVariables = { ...variables };
119
- newIds.forEach( ( id, index ) => {
120
- if ( updatedVariables[ id ] ) {
121
- updatedVariables[ id ] = {
122
- ...updatedVariables[ id ],
123
- order: index + 1,
124
- };
125
- }
126
- } );
127
- handleOnChange( updatedVariables );
128
- setIds( newIds );
129
- } }
121
+ onChange={ handleReorder }
130
122
  variant="static"
131
123
  restrictAxis
132
124
  dragOverlay={ ( { children: dragOverlayChildren, ...dragOverlayProps } ) => (
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import { useState } from 'react';
3
3
  import { PopoverBody } from '@elementor/editor-editing-panel';
4
- import { PopoverHeader, PopoverMenuList, PopoverSearch, type VirtualizedItem } from '@elementor/editor-ui';
4
+ import { PopoverHeader, PopoverMenuList, SearchField, type VirtualizedItem } from '@elementor/editor-ui';
5
5
  import { ColorFilterIcon, PlusIcon, SettingsIcon } from '@elementor/icons';
6
6
  import { Divider, IconButton } from '@elementor/ui';
7
7
  import { __, sprintf } from '@wordpress/i18n';
@@ -110,7 +110,7 @@ export const VariablesSelection = ( { closePopover, onAdd, onEdit, onSettings }:
110
110
  />
111
111
 
112
112
  { hasVariables && (
113
- <PopoverSearch
113
+ <SearchField
114
114
  value={ searchValue }
115
115
  onSearch={ handleSearch }
116
116
  placeholder={ __( 'Search', 'elementor' ) }
@@ -5,6 +5,7 @@ import { type PropKey } from '@elementor/editor-props';
5
5
  import { useVariableType } from '../context/variable-type-context';
6
6
  import { service } from '../service';
7
7
  import { type NormalizedVariable, type Variable } from '../types';
8
+ import { filterBySearch } from '../utils/filter-by-search';
8
9
 
9
10
  export const getVariables = ( includeDeleted = true ) => {
10
11
  const variables = service.variables();
@@ -33,7 +34,7 @@ export const useFilteredVariables = ( searchValue: string, propTypeKey: string )
33
34
  const baseVariables = usePropVariables( propTypeKey );
34
35
 
35
36
  const typeFilteredVariables = useVariableSelectionFilter( baseVariables );
36
- const searchFilteredVariables = filterVariablesBySearchValue( typeFilteredVariables, searchValue );
37
+ const searchFilteredVariables = filterBySearch( typeFilteredVariables, searchValue );
37
38
  const sortedVariables = searchFilteredVariables.sort( ( a, b ) => {
38
39
  const orderA = a.order ?? Number.MAX_SAFE_INTEGER;
39
40
  const orderB = b.order ?? Number.MAX_SAFE_INTEGER;
@@ -55,11 +56,6 @@ const useVariableSelectionFilter = ( variables: NormalizedVariable[] ): Normaliz
55
56
  return selectionFilter ? selectionFilter( variables, propType ) : variables;
56
57
  };
57
58
 
58
- const filterVariablesBySearchValue = ( variables: NormalizedVariable[], searchValue: string ): NormalizedVariable[] => {
59
- const lowerSearchValue = searchValue.toLowerCase();
60
- return variables.filter( ( { label } ) => label.toLowerCase().includes( lowerSearchValue ) );
61
- };
62
-
63
59
  const usePropVariables = ( propKey: PropKey ): NormalizedVariable[] => {
64
60
  return useMemo( () => normalizeVariables( propKey ), [ propKey ] );
65
61
  };
@@ -0,0 +1,5 @@
1
+ export function filterBySearch< T extends { label: string } >( variables: T[], searchValue: string ): T[] {
2
+ const lowerSearchValue = searchValue.toLowerCase();
3
+
4
+ return variables.filter( ( variable ) => variable.label.toLowerCase().includes( lowerSearchValue ) );
5
+ }