@elementor/editor-variables 0.16.0 → 3.32.0-20

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 (67) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/index.d.mts +19 -1
  3. package/dist/index.d.ts +19 -1
  4. package/dist/index.js +1397 -885
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +1399 -871
  7. package/dist/index.mjs.map +1 -1
  8. package/package.json +16 -14
  9. package/src/api.ts +18 -2
  10. package/src/components/fields/color-field.tsx +3 -3
  11. package/src/components/fields/font-field.tsx +21 -10
  12. package/src/components/fields/label-field.tsx +31 -5
  13. package/src/components/ui/delete-confirmation-dialog.tsx +4 -7
  14. package/src/components/ui/deleted-variable-alert.tsx +47 -0
  15. package/src/components/ui/edit-confirmation-dialog.tsx +75 -0
  16. package/src/components/ui/missing-variable-alert.tsx +39 -0
  17. package/src/components/ui/no-variables.tsx +59 -26
  18. package/src/components/ui/tags/assigned-tag.tsx +21 -19
  19. package/src/components/ui/tags/deleted-tag.tsx +29 -18
  20. package/src/components/ui/tags/missing-tag.tsx +25 -0
  21. package/src/components/ui/variable/assigned-variable.tsx +11 -14
  22. package/src/components/ui/variable/deleted-variable.tsx +115 -7
  23. package/src/components/ui/variable/missing-variable.tsx +44 -0
  24. package/src/components/variable-creation.tsx +135 -0
  25. package/src/components/variable-edit.tsx +221 -0
  26. package/src/components/variable-restore.tsx +117 -0
  27. package/src/components/variable-selection-popover.tsx +91 -92
  28. package/src/components/variables-manager/variables-manager-panel.tsx +115 -0
  29. package/src/components/variables-selection.tsx +148 -0
  30. package/src/context/variable-selection-popover.context.tsx +19 -0
  31. package/src/context/variable-type-context.tsx +23 -0
  32. package/src/controls/variable-control.tsx +26 -0
  33. package/src/create-style-variables-repository.ts +44 -5
  34. package/src/hooks/use-initial-value.ts +22 -0
  35. package/src/hooks/use-permissions.ts +15 -0
  36. package/src/hooks/use-prop-variable-action.tsx +53 -0
  37. package/src/hooks/use-prop-variables.ts +6 -0
  38. package/src/index.ts +1 -0
  39. package/src/init.ts +33 -4
  40. package/src/register-variable-types.tsx +29 -0
  41. package/src/renderers/style-variables-renderer.tsx +10 -4
  42. package/src/repeater-injections.ts +5 -1
  43. package/src/service.ts +8 -4
  44. package/src/sync/enqueue-font.ts +7 -0
  45. package/src/sync/types.ts +5 -0
  46. package/src/transformers/inheritance-transformer.tsx +30 -0
  47. package/src/transformers/utils/resolve-css-variable.ts +24 -0
  48. package/src/transformers/variable-transformer.ts +8 -3
  49. package/src/types.ts +1 -1
  50. package/src/utils/tracking.ts +39 -0
  51. package/src/utils/validations.ts +40 -6
  52. package/src/variables-registry/create-variable-type-registry.ts +77 -0
  53. package/src/variables-registry/variable-type-registry.ts +3 -0
  54. package/src/components/color-variable-creation.tsx +0 -86
  55. package/src/components/color-variable-edit.tsx +0 -138
  56. package/src/components/color-variables-selection.tsx +0 -130
  57. package/src/components/font-variable-creation.tsx +0 -86
  58. package/src/components/font-variable-edit.tsx +0 -138
  59. package/src/components/font-variables-selection.tsx +0 -129
  60. package/src/components/variable-selection-popover.context.ts +0 -7
  61. package/src/controls/color-variable-control.tsx +0 -33
  62. package/src/controls/font-variable-control.tsx +0 -31
  63. package/src/hooks/use-prop-color-variable-action.tsx +0 -25
  64. package/src/hooks/use-prop-font-variable-action.tsx +0 -25
  65. package/src/init-color-variables.ts +0 -27
  66. package/src/init-font-variables.ts +0 -24
  67. package/src/utils.ts +0 -20
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elementor/editor-variables",
3
- "version": "0.16.0",
3
+ "version": "3.32.0-20",
4
4
  "private": false,
5
5
  "author": "Elementor Team",
6
6
  "homepage": "https://elementor.com/",
@@ -18,11 +18,11 @@
18
18
  },
19
19
  "repository": {
20
20
  "type": "git",
21
- "url": "git+https://github.com/elementor/elementor-packages.git",
21
+ "url": "git+https://github.com/elementor/elementor.git",
22
22
  "directory": "packages/core/editor-variables"
23
23
  },
24
24
  "bugs": {
25
- "url": "https://github.com/elementor/elementor-packages/issues"
25
+ "url": "https://github.com/elementor/elementor/issues"
26
26
  },
27
27
  "publishConfig": {
28
28
  "access": "public"
@@ -39,18 +39,20 @@
39
39
  "dev": "tsup --config=../../tsup.dev.ts"
40
40
  },
41
41
  "dependencies": {
42
- "@elementor/editor": "0.21.0",
43
- "@elementor/editor-editing-panel": "1.48.0",
44
- "@elementor/editor-canvas": "0.26.0",
45
- "@elementor/editor-props": "0.16.0",
46
- "@elementor/schema": "0.1.2",
47
- "@elementor/editor-controls": "1.3.0",
42
+ "@elementor/editor": "3.32.0-20",
43
+ "@elementor/editor-canvas": "3.32.0-20",
44
+ "@elementor/editor-controls": "3.32.0-20",
45
+ "@elementor/editor-current-user": "3.32.0-20",
46
+ "@elementor/editor-editing-panel": "3.32.0-20",
47
+ "@elementor/editor-panels": "3.32.0-20",
48
+ "@elementor/editor-props": "3.32.0-20",
49
+ "@elementor/editor-ui": "3.32.0-20",
50
+ "@elementor/editor-v1-adapters": "3.32.0-20",
51
+ "@elementor/http-client": "3.32.0-20",
48
52
  "@elementor/icons": "1.46.0",
49
- "@wordpress/i18n": "^5.13.0",
50
- "@elementor/ui": "1.36.0",
51
- "@elementor/editor-v1-adapters": "0.12.1",
52
- "@elementor/http-client": "0.3.0",
53
- "@elementor/editor-ui": "0.14.0"
53
+ "@elementor/schema": "3.32.0-20",
54
+ "@elementor/ui": "1.36.2",
55
+ "@wordpress/i18n": "^5.13.0"
54
56
  },
55
57
  "peerDependencies": {
56
58
  "react": "^18.3.1",
package/src/api.ts CHANGED
@@ -2,6 +2,12 @@ import { httpService } from '@elementor/http-client';
2
2
 
3
3
  const BASE_PATH = 'elementor/v1/variables';
4
4
 
5
+ type RestoreVariablePayload = {
6
+ id: string;
7
+ label?: string;
8
+ value?: string;
9
+ };
10
+
5
11
  export const apiClient = {
6
12
  list: () => {
7
13
  return httpService().get( BASE_PATH + '/list' );
@@ -27,7 +33,17 @@ export const apiClient = {
27
33
  return httpService().post( BASE_PATH + '/delete', { id } );
28
34
  },
29
35
 
30
- restore: ( id: string ) => {
31
- return httpService().post( BASE_PATH + '/restore', { id } );
36
+ restore: ( id: string, label?: string, value?: string ) => {
37
+ const payload: RestoreVariablePayload = { id };
38
+
39
+ if ( label ) {
40
+ payload.label = label;
41
+ }
42
+
43
+ if ( value ) {
44
+ payload.value = value;
45
+ }
46
+
47
+ return httpService().post( BASE_PATH + '/restore', payload );
32
48
  },
33
49
  };
@@ -3,8 +3,8 @@ import { useRef, useState } from 'react';
3
3
  import { FormHelperText, FormLabel, Grid, UnstableColorField } from '@elementor/ui';
4
4
  import { __ } from '@wordpress/i18n';
5
5
 
6
+ import { usePopoverContentRef } from '../../context/variable-selection-popover.context';
6
7
  import { validateValue } from '../../utils/validations';
7
- import { usePopoverContentRef } from '../variable-selection-popover.context';
8
8
 
9
9
  type ColorFieldProps = {
10
10
  value: string;
@@ -16,7 +16,7 @@ export const ColorField = ( { value, onChange }: ColorFieldProps ) => {
16
16
  const [ errorMessage, setErrorMessage ] = useState( '' );
17
17
 
18
18
  const defaultRef = useRef< HTMLDivElement >( null );
19
- const anchorRef = usePopoverContentRef() ?? defaultRef;
19
+ const anchorRef = usePopoverContentRef() ?? defaultRef.current;
20
20
 
21
21
  const handleChange = ( newValue: string ) => {
22
22
  setColor( newValue );
@@ -41,7 +41,7 @@ export const ColorField = ( { value, onChange }: ColorFieldProps ) => {
41
41
  error={ errorMessage ?? undefined }
42
42
  slotProps={ {
43
43
  colorPicker: {
44
- anchorEl: anchorRef.current,
44
+ anchorEl: anchorRef,
45
45
  anchorOrigin: { vertical: 'top', horizontal: 'right' },
46
46
  transformOrigin: { vertical: 'top', horizontal: -10 },
47
47
  },
@@ -1,8 +1,8 @@
1
1
  import * as React from 'react';
2
2
  import { useRef, useState } from 'react';
3
- import { FontFamilySelector } from '@elementor/editor-controls';
3
+ import { enqueueFont, ItemSelector } from '@elementor/editor-controls';
4
4
  import { useFontFamilies, useSectionWidth } from '@elementor/editor-editing-panel';
5
- import { ChevronDownIcon } from '@elementor/icons';
5
+ import { ChevronDownIcon, TextIcon } from '@elementor/icons';
6
6
  import {
7
7
  bindPopover,
8
8
  bindTrigger,
@@ -15,8 +15,8 @@ import {
15
15
  } from '@elementor/ui';
16
16
  import { __ } from '@wordpress/i18n';
17
17
 
18
+ import { usePopoverContentRef } from '../../context/variable-selection-popover.context';
18
19
  import { validateValue } from '../../utils/validations';
19
- import { usePopoverContentRef } from '../variable-selection-popover.context';
20
20
 
21
21
  type FontFieldProps = {
22
22
  value: string;
@@ -28,13 +28,20 @@ export const FontField = ( { value, onChange }: FontFieldProps ) => {
28
28
  const [ errorMessage, setErrorMessage ] = useState( '' );
29
29
 
30
30
  const defaultRef = useRef< HTMLDivElement >( null );
31
- const anchorRef = usePopoverContentRef() ?? defaultRef;
31
+ const anchorRef = usePopoverContentRef() ?? defaultRef.current;
32
32
 
33
33
  const fontPopoverState = usePopupState( { variant: 'popover' } );
34
34
 
35
35
  const fontFamilies = useFontFamilies();
36
36
  const sectionWidth = useSectionWidth();
37
37
 
38
+ const mapFontSubs = React.useMemo( () => {
39
+ return fontFamilies.map( ( { label, fonts } ) => ( {
40
+ label,
41
+ items: fonts,
42
+ } ) );
43
+ }, [ fontFamilies ] );
44
+
38
45
  const handleChange = ( newValue: string ) => {
39
46
  setFontFamily( newValue );
40
47
 
@@ -65,17 +72,21 @@ export const FontField = ( { value, onChange }: FontFieldProps ) => {
65
72
  <Popover
66
73
  disablePortal
67
74
  disableScrollLock
68
- anchorEl={ anchorRef.current }
75
+ anchorEl={ anchorRef }
69
76
  anchorOrigin={ { vertical: 'top', horizontal: 'right' } }
70
- transformOrigin={ { vertical: 'top', horizontal: -20 } }
77
+ transformOrigin={ { vertical: 'top', horizontal: -28 } }
71
78
  { ...bindPopover( fontPopoverState ) }
72
79
  >
73
- <FontFamilySelector
74
- fontFamilies={ fontFamilies }
75
- fontFamily={ fontFamily }
76
- onFontFamilyChange={ handleFontFamilyChange }
80
+ <ItemSelector
81
+ itemsList={ mapFontSubs }
82
+ selectedItem={ fontFamily }
83
+ onItemChange={ handleFontFamilyChange }
77
84
  onClose={ fontPopoverState.close }
78
85
  sectionWidth={ sectionWidth }
86
+ title={ __( 'Font Family', 'elementor' ) }
87
+ itemStyle={ ( item ) => ( { fontFamily: item.value } ) }
88
+ onDebounce={ enqueueFont }
89
+ icon={ TextIcon as React.ElementType< { fontSize: string } > }
79
90
  />
80
91
  </Popover>
81
92
  { errorMessage && <FormHelperText error>{ errorMessage }</FormHelperText> }
@@ -5,12 +5,31 @@ import { __ } from '@wordpress/i18n';
5
5
 
6
6
  import { labelHint, validateLabel, VARIABLE_LABEL_MAX_LENGTH } from '../../utils/validations';
7
7
 
8
+ function isLabelEqual( a: string, b: string ) {
9
+ return a.trim().toLowerCase() === b.trim().toLowerCase();
10
+ }
11
+
12
+ type LabelErrorProps = {
13
+ value: string;
14
+ message: string;
15
+ };
16
+
17
+ export const useLabelError = ( initialError?: LabelErrorProps ) => {
18
+ const [ error, setError ] = useState< LabelErrorProps >( initialError ?? { value: '', message: '' } );
19
+
20
+ return {
21
+ labelFieldError: error,
22
+ setLabelFieldError: setError,
23
+ };
24
+ };
25
+
8
26
  type LabelFieldProps = {
9
27
  value: string;
28
+ error?: LabelErrorProps;
10
29
  onChange: ( value: string ) => void;
11
30
  };
12
31
 
13
- export const LabelField = ( { value, onChange }: LabelFieldProps ) => {
32
+ export const LabelField = ( { value, error, onChange }: LabelFieldProps ) => {
14
33
  const [ label, setLabel ] = useState( value );
15
34
  const [ errorMessage, setErrorMessage ] = useState( '' );
16
35
  const [ noticeMessage, setNoticeMessage ] = useState( () => labelHint( value ) );
@@ -24,11 +43,18 @@ export const LabelField = ( { value, onChange }: LabelFieldProps ) => {
24
43
  setErrorMessage( errorMsg );
25
44
  setNoticeMessage( errorMsg ? '' : hintMsg );
26
45
 
27
- onChange( errorMsg ? '' : newValue );
46
+ onChange( isLabelEqual( newValue, error?.value ?? '' ) || errorMsg ? '' : newValue );
28
47
  };
29
48
 
30
49
  const id = useId();
31
50
 
51
+ let errorMsg = errorMessage;
52
+ if ( isLabelEqual( label, error?.value ?? '' ) && error?.message ) {
53
+ errorMsg = error.message;
54
+ }
55
+
56
+ const noticeMsg = errorMsg ? '' : noticeMessage;
57
+
32
58
  return (
33
59
  <Grid container gap={ 0.75 } alignItems="center">
34
60
  <Grid item xs={ 12 }>
@@ -42,12 +68,12 @@ export const LabelField = ( { value, onChange }: LabelFieldProps ) => {
42
68
  size="tiny"
43
69
  fullWidth
44
70
  value={ label }
45
- error={ !! errorMessage }
71
+ error={ !! errorMsg }
46
72
  onChange={ ( e: React.ChangeEvent< HTMLInputElement > ) => handleChange( e.target.value ) }
47
73
  inputProps={ { maxLength: VARIABLE_LABEL_MAX_LENGTH } }
48
74
  />
49
- { errorMessage && <FormHelperText error>{ errorMessage }</FormHelperText> }
50
- { noticeMessage && <FormHelperText>{ noticeMessage }</FormHelperText> }
75
+ { errorMsg && <FormHelperText error>{ errorMsg }</FormHelperText> }
76
+ { noticeMsg && <FormHelperText>{ noticeMsg }</FormHelperText> }
51
77
  </Grid>
52
78
  </Grid>
53
79
  );
@@ -28,23 +28,20 @@ export const DeleteConfirmationDialog = ( {
28
28
  <Dialog open={ open } onClose={ closeDialog } aria-labelledby={ TITLE_ID } maxWidth="xs">
29
29
  <DialogTitle id={ TITLE_ID } display="flex" alignItems="center" gap={ 1 } sx={ { lineHeight: 1 } }>
30
30
  <AlertOctagonFilledIcon color="error" />
31
- { __( 'Delete Variable', 'elementor' ) }
31
+ { __( 'Delete this variable?', 'elementor' ) }
32
32
  </DialogTitle>
33
33
  <DialogContent>
34
34
  <DialogContentText variant="body2" color="textPrimary">
35
- { __( 'You are about to delete', 'elementor' ) }
35
+ { __( 'All elements using', 'elementor' ) }
36
36
  <Typography variant="subtitle2" component="span">
37
37
  &nbsp;{ label }&nbsp;
38
38
  </Typography>
39
- { __(
40
- 'Variable. Note that its value is still being used anywhere on your site where it was connected to the variable.',
41
- 'elementor'
42
- ) }
39
+ { __( 'will keep their current values, but the variable itself will be removed.', 'elementor' ) }
43
40
  </DialogContentText>
44
41
  </DialogContent>
45
42
  <DialogActions>
46
43
  <Button color="secondary" onClick={ closeDialog }>
47
- { __( 'Cancel', 'elementor' ) }
44
+ { __( 'Not now', 'elementor' ) }
48
45
  </Button>
49
46
  <Button variant="contained" color="error" onClick={ onConfirm }>
50
47
  { __( 'Delete', 'elementor' ) }
@@ -0,0 +1,47 @@
1
+ import * as React from 'react';
2
+ import { useSectionWidth } from '@elementor/editor-editing-panel';
3
+ import { Alert, AlertAction, AlertTitle, ClickAwayListener } from '@elementor/ui';
4
+ import { __ } from '@wordpress/i18n';
5
+
6
+ type DeletedVariableAlertProps = {
7
+ onClose: () => void;
8
+ onUnlink?: () => void;
9
+ onRestore?: () => void;
10
+ label: string;
11
+ };
12
+
13
+ export const DeletedVariableAlert = ( { onClose, onUnlink, onRestore, label }: DeletedVariableAlertProps ) => {
14
+ const sectionWidth = useSectionWidth();
15
+
16
+ return (
17
+ <ClickAwayListener onClickAway={ onClose }>
18
+ <Alert
19
+ variant="standard"
20
+ severity="warning"
21
+ onClose={ onClose }
22
+ action={
23
+ <>
24
+ { onUnlink && (
25
+ <AlertAction variant="contained" onClick={ onUnlink }>
26
+ { __( 'Unlink', 'elementor' ) }
27
+ </AlertAction>
28
+ ) }
29
+ { onRestore && (
30
+ <AlertAction variant="outlined" onClick={ onRestore }>
31
+ { __( 'Restore', 'elementor' ) }
32
+ </AlertAction>
33
+ ) }
34
+ </>
35
+ }
36
+ sx={ { width: sectionWidth } }
37
+ >
38
+ <AlertTitle>{ __( 'Deleted variable', 'elementor' ) }</AlertTitle>
39
+ { __( 'The variable', 'elementor' ) } &apos;{ label }&apos;{ ' ' }
40
+ { __(
41
+ 'has been deleted, but it is still referenced in this location. You may restore the variable or unlink it to assign a different value.',
42
+ 'elementor'
43
+ ) }
44
+ </Alert>
45
+ </ClickAwayListener>
46
+ );
47
+ };
@@ -0,0 +1,75 @@
1
+ import * as React from 'react';
2
+ import { useState } from 'react';
3
+ import { AlertTriangleFilledIcon } from '@elementor/icons';
4
+ import {
5
+ Button,
6
+ Checkbox,
7
+ Dialog,
8
+ DialogActions,
9
+ DialogContent,
10
+ DialogContentText,
11
+ DialogTitle,
12
+ FormControlLabel,
13
+ Typography,
14
+ } from '@elementor/ui';
15
+ import { __ } from '@wordpress/i18n';
16
+
17
+ export const EDIT_CONFIRMATION_DIALOG_ID = 'edit-confirmation-dialog';
18
+
19
+ export const EditConfirmationDialog = ( {
20
+ closeDialog,
21
+ onConfirm,
22
+ onSuppressMessage,
23
+ }: {
24
+ closeDialog: () => void;
25
+ onConfirm?: () => void;
26
+ onSuppressMessage?: () => void;
27
+ } ) => {
28
+ const [ dontShowAgain, setDontShowAgain ] = useState( false );
29
+
30
+ const handleSave = () => {
31
+ if ( dontShowAgain ) {
32
+ onSuppressMessage?.();
33
+ }
34
+ onConfirm?.();
35
+ };
36
+
37
+ return (
38
+ <Dialog open onClose={ closeDialog } maxWidth="xs">
39
+ <DialogTitle display="flex" alignItems="center" gap={ 1 }>
40
+ <AlertTriangleFilledIcon color="secondary" />
41
+ { __( 'Changes to variables go live right away.', 'elementor' ) }
42
+ </DialogTitle>
43
+ <DialogContent>
44
+ <DialogContentText variant="body2" color="textPrimary">
45
+ { __(
46
+ "Don't worry - all other changes you make will wait until you publish your site.",
47
+ 'elementor'
48
+ ) }
49
+ </DialogContentText>
50
+ </DialogContent>
51
+ <DialogActions sx={ { justifyContent: 'space-between', alignItems: 'center' } }>
52
+ <FormControlLabel
53
+ control={
54
+ <Checkbox
55
+ checked={ dontShowAgain }
56
+ onChange={ ( event: React.ChangeEvent< HTMLInputElement > ) =>
57
+ setDontShowAgain( event.target.checked )
58
+ }
59
+ size="small"
60
+ />
61
+ }
62
+ label={ <Typography variant="body2">{ __( "Don't show me again", 'elementor' ) }</Typography> }
63
+ />
64
+ <div>
65
+ <Button color="secondary" onClick={ closeDialog }>
66
+ { __( 'Keep editing', 'elementor' ) }
67
+ </Button>
68
+ <Button variant="contained" color="secondary" onClick={ handleSave } sx={ { ml: 1 } }>
69
+ { __( 'Save', 'elementor' ) }
70
+ </Button>
71
+ </div>
72
+ </DialogActions>
73
+ </Dialog>
74
+ );
75
+ };
@@ -0,0 +1,39 @@
1
+ import * as React from 'react';
2
+ import { useSectionWidth } from '@elementor/editor-editing-panel';
3
+ import { Alert, AlertAction, AlertTitle, ClickAwayListener } from '@elementor/ui';
4
+ import { __ } from '@wordpress/i18n';
5
+
6
+ type MissingVariableAlertProps = {
7
+ onClose: () => void;
8
+ onClear?: () => void;
9
+ };
10
+
11
+ export const MissingVariableAlert = ( { onClose, onClear }: MissingVariableAlertProps ) => {
12
+ const sectionWidth = useSectionWidth();
13
+
14
+ return (
15
+ <ClickAwayListener onClickAway={ onClose }>
16
+ <Alert
17
+ variant="standard"
18
+ severity="warning"
19
+ onClose={ onClose }
20
+ action={
21
+ <>
22
+ { onClear && (
23
+ <AlertAction variant="contained" onClick={ onClear }>
24
+ { __( 'Clear', 'elementor' ) }
25
+ </AlertAction>
26
+ ) }
27
+ </>
28
+ }
29
+ sx={ { width: sectionWidth } }
30
+ >
31
+ <AlertTitle>{ __( 'This variable is missing', 'elementor' ) }</AlertTitle>
32
+ { __(
33
+ 'It may have been deleted. Try clearing this field and select a different value or variable.',
34
+ 'elementor'
35
+ ) }
36
+ </Alert>
37
+ </ClickAwayListener>
38
+ );
39
+ };
@@ -2,35 +2,68 @@ import * as React from 'react';
2
2
  import { Button, Stack, Typography } from '@elementor/ui';
3
3
  import { __ } from '@wordpress/i18n';
4
4
 
5
+ import { usePermissions } from '../../hooks/use-permissions';
6
+
5
7
  type Props = {
6
8
  icon?: React.ReactNode;
7
9
  title?: string;
8
10
  onAdd?: () => void;
9
11
  };
10
12
 
11
- export const NoVariables = ( { icon, title, onAdd }: Props ) => (
12
- <Stack
13
- gap={ 1 }
14
- alignItems="center"
15
- justifyContent="center"
16
- height="100%"
17
- color="text.secondary"
18
- sx={ { p: 2.5, pb: 5.5 } }
19
- >
20
- { icon }
21
-
22
- <Typography align="center" variant="subtitle2">
23
- { title }
24
- </Typography>
25
-
26
- <Typography align="center" variant="caption" maxWidth="180px">
27
- { __( 'Variables are saved attributes that you can apply anywhere on your site.', 'elementor' ) }
28
- </Typography>
29
-
30
- { onAdd && (
31
- <Button variant="outlined" color="secondary" size="small" onClick={ onAdd }>
32
- { __( 'Create a variable', 'elementor' ) }
33
- </Button>
34
- ) }
35
- </Stack>
36
- );
13
+ export const NoVariables = ( { icon, title, onAdd }: Props ) => {
14
+ const canAdd = usePermissions().canAdd();
15
+
16
+ return (
17
+ <Stack
18
+ gap={ 1 }
19
+ alignItems="center"
20
+ justifyContent="center"
21
+ height="100%"
22
+ color="text.secondary"
23
+ sx={ { p: 2.5, pb: 5.5 } }
24
+ >
25
+ { icon }
26
+
27
+ { canAdd ? (
28
+ <>
29
+ <NoVariablesContent
30
+ title={ title || __( 'Create your first variable', 'elementor' ) }
31
+ message={ __(
32
+ 'Variables are saved attributes that you can apply anywhere on your site.',
33
+ 'elementor'
34
+ ) }
35
+ />
36
+ { onAdd && (
37
+ <Button variant="outlined" color="secondary" size="small" onClick={ onAdd }>
38
+ { __( 'Create a variable', 'elementor' ) }
39
+ </Button>
40
+ ) }
41
+ </>
42
+ ) : (
43
+ <NoVariablesContent
44
+ title={ __( 'There are no variables', 'elementor' ) }
45
+ message={ __( 'With your current role, you can only connect and detach variables.', 'elementor' ) }
46
+ />
47
+ ) }
48
+ </Stack>
49
+ );
50
+ };
51
+
52
+ type NoVariablesContentProps = {
53
+ title: string;
54
+ message: string;
55
+ };
56
+
57
+ function NoVariablesContent( { title, message }: NoVariablesContentProps ) {
58
+ return (
59
+ <>
60
+ <Typography align="center" variant="subtitle2">
61
+ { title }
62
+ </Typography>
63
+
64
+ <Typography align="center" variant="caption" maxWidth="180px">
65
+ { message }
66
+ </Typography>
67
+ </>
68
+ );
69
+ }
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { DetachIcon } from '@elementor/icons';
3
- import { Box, IconButton, Stack, Typography, UnstableTag as Tag, type UnstableTagProps } from '@elementor/ui';
3
+ import { Box, IconButton, Stack, Tooltip, Typography, UnstableTag as Tag, type UnstableTagProps } from '@elementor/ui';
4
4
  import { __ } from '@wordpress/i18n';
5
5
 
6
6
  export const SIZE = 'tiny';
@@ -21,23 +21,25 @@ export const AssignedTag = ( { startIcon, label, onUnlink, ...props }: VariableT
21
21
  }
22
22
 
23
23
  return (
24
- <Tag
25
- fullWidth
26
- showActionsOnHover
27
- startIcon={
28
- <Stack gap={ 0.5 } direction="row" alignItems="center">
29
- { startIcon }
30
- </Stack>
31
- }
32
- label={
33
- <Box sx={ { display: 'inline-grid', minWidth: 0 } }>
34
- <Typography sx={ { lineHeight: 1.34 } } variant="caption" noWrap>
35
- { label }
36
- </Typography>
37
- </Box>
38
- }
39
- actions={ actions }
40
- { ...props }
41
- />
24
+ <Tooltip title={ label } placement="top">
25
+ <Tag
26
+ fullWidth
27
+ showActionsOnHover
28
+ startIcon={
29
+ <Stack gap={ 0.5 } direction="row" alignItems="center">
30
+ { startIcon }
31
+ </Stack>
32
+ }
33
+ label={
34
+ <Box sx={ { display: 'inline-grid', minWidth: 0 } }>
35
+ <Typography sx={ { lineHeight: 1.34 } } variant="caption" noWrap>
36
+ { label }
37
+ </Typography>
38
+ </Box>
39
+ }
40
+ actions={ actions }
41
+ { ...props }
42
+ />
43
+ </Tooltip>
42
44
  );
43
45
  };
@@ -1,26 +1,37 @@
1
1
  import * as React from 'react';
2
- import { ColorFilterIcon } from '@elementor/icons';
3
- import { Box, Typography, UnstableTag as Tag, type UnstableTagProps } from '@elementor/ui';
2
+ import { AlertTriangleFilledIcon } from '@elementor/icons';
3
+ import { Box, Chip, type ChipProps, type Theme, Tooltip, Typography } from '@elementor/ui';
4
4
  import { __ } from '@wordpress/i18n';
5
5
 
6
- export const DeletedTag = ( { label }: UnstableTagProps ) => {
6
+ export const DeletedTag = React.forwardRef< HTMLDivElement, ChipProps >( ( { label, onClick, ...props }, ref ) => {
7
7
  return (
8
- <Tag
9
- showActionsOnHover
10
- fullWidth
8
+ <Chip
9
+ ref={ ref }
10
+ size="tiny"
11
+ color="warning"
12
+ shape="rounded"
13
+ variant="standard"
14
+ onClick={ onClick }
15
+ icon={ <AlertTriangleFilledIcon /> }
11
16
  label={
12
- <Box sx={ { display: 'inline-grid', minWidth: 0 } }>
13
- <Typography sx={ { lineHeight: 1.34 } } variant="caption" noWrap>
14
- { label }
15
- </Typography>
16
- </Box>
17
- }
18
- startIcon={ <ColorFilterIcon fontSize="tiny" /> }
19
- endAdornment={
20
- <Typography sx={ { lineHeight: 1.34 } } variant="caption" noWrap>
21
- ({ __( 'deleted', 'elementor' ) })
22
- </Typography>
17
+ <Tooltip title={ label } placement="top">
18
+ <Box sx={ { display: 'flex', gap: 0.5, alignItems: 'center' } }>
19
+ <Typography variant="caption" noWrap>
20
+ { label }
21
+ </Typography>
22
+ <Typography variant="caption" noWrap sx={ { textOverflow: 'initial', overflow: 'visible' } }>
23
+ ({ __( 'deleted', 'elementor' ) })
24
+ </Typography>
25
+ </Box>
26
+ </Tooltip>
23
27
  }
28
+ sx={ {
29
+ height: ( theme: Theme ) => theme.spacing( 3.5 ),
30
+ borderRadius: ( theme: Theme ) => theme.spacing( 1 ),
31
+ justifyContent: 'flex-start',
32
+ width: '100%',
33
+ } }
34
+ { ...props }
24
35
  />
25
36
  );
26
- };
37
+ } );