@elementor/editor-editing-panel 0.19.0 → 1.1.0

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 (139) hide show
  1. package/CHANGELOG.md +97 -0
  2. package/dist/index.d.mts +10 -36
  3. package/dist/index.d.ts +10 -36
  4. package/dist/index.js +1256 -1445
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +1311 -1482
  7. package/dist/index.mjs.map +1 -1
  8. package/package.json +15 -14
  9. package/src/components/add-or-remove-content.tsx +42 -0
  10. package/src/components/collapse-icon.tsx +12 -0
  11. package/src/components/collapsible-content.tsx +5 -14
  12. package/src/components/collapsible-field.tsx +36 -0
  13. package/src/components/css-class-selector-section.tsx +76 -0
  14. package/src/components/editing-panel-hooks.tsx +2 -0
  15. package/src/components/editing-panel-tabs.tsx +23 -13
  16. package/src/components/editing-panel.tsx +21 -21
  17. package/src/components/multi-combobox/index.ts +3 -0
  18. package/src/components/multi-combobox/multi-combobox.tsx +120 -0
  19. package/src/components/multi-combobox/types.ts +26 -0
  20. package/src/components/multi-combobox/use-combobox-actions.ts +62 -0
  21. package/src/components/section.tsx +37 -0
  22. package/src/components/sections-list.tsx +6 -0
  23. package/src/components/settings-tab.tsx +17 -16
  24. package/src/components/style-sections/background-section/background-color-field.tsx +21 -0
  25. package/src/components/style-sections/background-section/background-section.tsx +10 -8
  26. package/src/components/style-sections/border-section/border-color-field.tsx +21 -0
  27. package/src/components/style-sections/border-section/border-field.tsx +48 -0
  28. package/src/components/style-sections/border-section/border-radius-field.tsx +49 -0
  29. package/src/components/style-sections/border-section/border-section.tsx +13 -0
  30. package/src/components/style-sections/border-section/border-style-field.tsx +32 -0
  31. package/src/components/style-sections/border-section/border-width-field.tsx +43 -0
  32. package/src/components/style-sections/effects-section/effects-section.tsx +8 -11
  33. package/src/components/style-sections/layout-section/display-field.tsx +32 -0
  34. package/src/components/style-sections/layout-section/justify-content-field.tsx +82 -0
  35. package/src/components/style-sections/layout-section/layout-section.tsx +17 -0
  36. package/src/components/style-sections/layout-section/utils/rotate-flex-icon.ts +12 -0
  37. package/src/components/style-sections/position-section/dimensions-field.tsx +46 -0
  38. package/src/components/style-sections/position-section/position-field.tsx +28 -0
  39. package/src/components/style-sections/position-section/position-section.tsx +51 -8
  40. package/src/components/style-sections/position-section/z-index-field.tsx +21 -0
  41. package/src/components/style-sections/size-section/overflow-field.tsx +45 -0
  42. package/src/components/style-sections/size-section/size-section.tsx +62 -0
  43. package/src/components/style-sections/spacing-section/spacing-section.tsx +12 -14
  44. package/src/components/style-sections/typography-section/font-family-field.tsx +40 -0
  45. package/src/components/style-sections/typography-section/font-size-field.tsx +21 -0
  46. package/src/components/style-sections/typography-section/{font-weight-control.tsx → font-weight-field.tsx} +9 -8
  47. package/src/components/style-sections/typography-section/letter-spacing-field.tsx +21 -0
  48. package/src/components/style-sections/typography-section/text-alignment-field.tsx +47 -0
  49. package/src/components/style-sections/typography-section/text-color-field.tsx +21 -0
  50. package/src/components/style-sections/typography-section/{text-direction-control.tsx → text-direction-field.tsx} +12 -12
  51. package/src/components/style-sections/typography-section/text-stroke-field.tsx +16 -0
  52. package/src/components/style-sections/typography-section/{text-style-control.tsx → text-style-field.tsx} +9 -8
  53. package/src/components/style-sections/typography-section/transform-field.tsx +40 -0
  54. package/src/components/style-sections/typography-section/typography-section.tsx +31 -30
  55. package/src/components/style-sections/typography-section/word-spacing-field.tsx +21 -0
  56. package/src/components/style-tab.tsx +82 -29
  57. package/src/contexts/classes-prop-context.tsx +24 -0
  58. package/src/{controls/providers/element-provider.tsx → contexts/element-context.tsx} +3 -7
  59. package/src/contexts/style-context.tsx +10 -23
  60. package/src/control-replacement.tsx +1 -1
  61. package/src/{controls/control-actions/control-actions-menu.ts → controls-actions.ts} +2 -1
  62. package/src/{controls/components → controls-registry}/control-type-container.tsx +3 -2
  63. package/src/{controls → controls-registry}/control.tsx +2 -1
  64. package/src/{controls → controls-registry}/controls-registry.tsx +8 -6
  65. package/src/controls-registry/settings-field.tsx +36 -0
  66. package/src/controls-registry/styles-field.tsx +20 -0
  67. package/src/dynamics/components/dynamic-selection-control.tsx +18 -17
  68. package/src/dynamics/components/dynamic-selection.tsx +10 -9
  69. package/src/dynamics/dynamic-control.tsx +7 -6
  70. package/src/dynamics/hooks/use-dynamic-tag.ts +3 -2
  71. package/src/dynamics/hooks/use-prop-dynamic-action.tsx +7 -6
  72. package/src/dynamics/hooks/use-prop-dynamic-tags.ts +3 -2
  73. package/src/dynamics/init.ts +3 -3
  74. package/src/dynamics/sync/get-elementor-config.ts +1 -1
  75. package/src/dynamics/types.ts +2 -2
  76. package/src/dynamics/utils.ts +3 -3
  77. package/src/hooks/use-close-editor-panel.ts +23 -0
  78. package/src/hooks/use-direction.ts +13 -0
  79. package/src/hooks/use-open-editor-panel.ts +4 -3
  80. package/src/hooks/use-prop-value-history.ts +45 -0
  81. package/src/hooks/use-style-prop-history.ts +75 -0
  82. package/src/hooks/use-styles-field.ts +51 -0
  83. package/src/index.ts +2 -3
  84. package/src/init.ts +5 -4
  85. package/src/panel.ts +1 -0
  86. package/src/{controls/control-actions/actions/popover-action.tsx → popover-action.tsx} +2 -2
  87. package/src/sync/enqueue-font.ts +7 -0
  88. package/src/sync/get-elementor-config.ts +7 -0
  89. package/src/sync/{should-use-v2-panel.ts → is-atomic-widget-selected.ts} +2 -3
  90. package/src/sync/types.ts +20 -21
  91. package/src/components/accordion-section.tsx +0 -25
  92. package/src/components/control-label.tsx +0 -10
  93. package/src/components/style-sections/background-section/background-color-control.tsx +0 -20
  94. package/src/components/style-sections/effects-section/box-shadow-repeater.tsx +0 -224
  95. package/src/components/style-sections/position-section/z-index-control.tsx +0 -20
  96. package/src/components/style-sections/size-section.tsx +0 -49
  97. package/src/components/style-sections/spacing-section/linked-dimensions-control.tsx +0 -155
  98. package/src/components/style-sections/typography-section/font-size-control.tsx +0 -20
  99. package/src/components/style-sections/typography-section/letter-spacing-control.tsx +0 -20
  100. package/src/components/style-sections/typography-section/text-alignment-control.tsx +0 -47
  101. package/src/components/style-sections/typography-section/text-color-control.tsx +0 -20
  102. package/src/components/style-sections/typography-section/transform-control.tsx +0 -25
  103. package/src/components/style-sections/typography-section/word-spacing-control.tsx +0 -20
  104. package/src/controls/components/control-toggle-button-group.tsx +0 -59
  105. package/src/controls/components/repeater.tsx +0 -197
  106. package/src/controls/components/text-field-inner-selection.tsx +0 -79
  107. package/src/controls/control-actions/control-actions.tsx +0 -43
  108. package/src/controls/control-context.tsx +0 -22
  109. package/src/controls/control-replacement.ts +0 -34
  110. package/src/controls/control-types/color-control.tsx +0 -27
  111. package/src/controls/control-types/image-control.tsx +0 -66
  112. package/src/controls/control-types/image-media-control.tsx +0 -73
  113. package/src/controls/control-types/number-control.tsx +0 -29
  114. package/src/controls/control-types/select-control.tsx +0 -30
  115. package/src/controls/control-types/size-control.tsx +0 -71
  116. package/src/controls/control-types/text-area-control.tsx +0 -31
  117. package/src/controls/control-types/text-control.tsx +0 -17
  118. package/src/controls/control-types/toggle-control.tsx +0 -26
  119. package/src/controls/create-control-replacement.tsx +0 -53
  120. package/src/controls/create-control.tsx +0 -40
  121. package/src/controls/hooks/use-style-control.ts +0 -29
  122. package/src/controls/hooks/use-sync-external-state.tsx +0 -51
  123. package/src/controls/hooks/use-widget-settings.ts +0 -16
  124. package/src/controls/props/is-transformable.ts +0 -13
  125. package/src/controls/props/types.ts +0 -51
  126. package/src/controls/settings-control.tsx +0 -37
  127. package/src/controls/style-control.tsx +0 -20
  128. package/src/controls/sync/get-container.ts +0 -8
  129. package/src/controls/sync/update-settings.ts +0 -14
  130. package/src/controls/types.ts +0 -39
  131. package/src/dynamics/hooks/use-prop-value-history.ts +0 -26
  132. package/src/hooks/use-element-style-prop.ts +0 -46
  133. package/src/hooks/use-element-styles.ts +0 -13
  134. package/src/hooks/use-element-type.ts +0 -33
  135. package/src/hooks/use-selected-elements.ts +0 -9
  136. package/src/sync/get-element-styles.ts +0 -9
  137. package/src/sync/get-selected-elements.ts +0 -21
  138. package/src/sync/get-widgets-cache.ts +0 -7
  139. package/src/sync/update-style.ts +0 -25
@@ -1,155 +0,0 @@
1
- import * as React from 'react';
2
- import { __ } from '@wordpress/i18n';
3
- import { Grid, Stack, ToggleButton } from '@elementor/ui';
4
- import { DetachIcon, LinkIcon, SideBottomIcon, SideLeftIcon, SideRightIcon, SideTopIcon } from '@elementor/icons';
5
- import { PropValue, TransformablePropValue } from '../../../controls/props/types';
6
- import { SizeControl } from '../../../controls/control-types/size-control';
7
- import { ControlLabel } from '../../control-label';
8
- import { ControlContext, useControl } from '../../../controls/control-context';
9
-
10
- export type Position = 'top' | 'right' | 'bottom' | 'left';
11
-
12
- export type LinkedDimensionsValue = TransformablePropValue<
13
- 'linked-dimensions',
14
- {
15
- isLinked: boolean;
16
- top: PropValue;
17
- right: PropValue;
18
- bottom: PropValue;
19
- left: PropValue;
20
- }
21
- >;
22
-
23
- export const LinkedDimensionsControl = ( { label }: { label: string } ) => {
24
- const { value, setValue } = useControl< LinkedDimensionsValue >();
25
- const { top, right, bottom, left, isLinked = true } = value?.value || {};
26
-
27
- const setLinkedValue = ( position: Position, newValue: PropValue ) => {
28
- const updatedValue = {
29
- isLinked,
30
- top: isLinked ? newValue : top,
31
- right: isLinked ? newValue : right,
32
- bottom: isLinked ? newValue : bottom,
33
- left: isLinked ? newValue : left,
34
- [ position ]: newValue,
35
- };
36
-
37
- setValue( {
38
- $$type: 'linked-dimensions',
39
- value: updatedValue,
40
- } );
41
- };
42
-
43
- const toggleLinked = () => {
44
- const updatedValue = {
45
- isLinked: ! isLinked,
46
- top,
47
- right: ! isLinked ? top : right,
48
- bottom: ! isLinked ? top : bottom,
49
- left: ! isLinked ? top : left,
50
- };
51
-
52
- setValue( {
53
- $$type: 'linked-dimensions',
54
- value: updatedValue,
55
- } );
56
- };
57
-
58
- const LinkedIcon = isLinked ? LinkIcon : DetachIcon;
59
-
60
- return (
61
- <>
62
- <Stack direction="row" gap={ 2 }>
63
- <ControlLabel>{ label }</ControlLabel>
64
- <ToggleButton
65
- aria-label={ __( 'Link Inputs', 'elementor' ) }
66
- size={ 'tiny' }
67
- value={ 'check' }
68
- selected={ isLinked }
69
- sx={ { marginLeft: 'auto' } }
70
- onChange={ toggleLinked }
71
- >
72
- <LinkedIcon fontSize={ 'tiny' } />
73
- </ToggleButton>
74
- </Stack>
75
- <Stack direction="row" gap={ 2 }>
76
- <Grid container spacing={ 1 } alignItems="center">
77
- <Grid item xs={ 12 }>
78
- <ControlLabel>{ __( 'Top', 'elementor' ) }</ControlLabel>
79
- </Grid>
80
- <Grid item xs={ 12 }>
81
- <Control
82
- bind={ 'top' }
83
- value={ top }
84
- setValue={ setLinkedValue }
85
- startIcon={ <SideTopIcon fontSize={ 'tiny' } /> }
86
- />
87
- </Grid>
88
- </Grid>
89
- <Grid container spacing={ 1 } alignItems="center">
90
- <Grid item xs={ 12 }>
91
- <ControlLabel>{ __( 'Right', 'elementor' ) }</ControlLabel>
92
- </Grid>
93
- <Grid item xs={ 12 }>
94
- <Control
95
- bind={ 'right' }
96
- value={ right }
97
- setValue={ setLinkedValue }
98
- startIcon={ <SideRightIcon fontSize={ 'tiny' } /> }
99
- />
100
- </Grid>
101
- </Grid>
102
- </Stack>
103
- <Stack direction="row" gap={ 2 }>
104
- <Grid container spacing={ 1 } alignItems="center">
105
- <Grid item xs={ 12 }>
106
- <ControlLabel>{ __( 'Bottom', 'elementor' ) }</ControlLabel>
107
- </Grid>
108
- <Grid item xs={ 12 }>
109
- <Control
110
- bind={ 'bottom' }
111
- value={ bottom }
112
- setValue={ setLinkedValue }
113
- startIcon={ <SideBottomIcon fontSize={ 'tiny' } /> }
114
- />
115
- </Grid>
116
- </Grid>
117
- <Grid container spacing={ 1 } alignItems="center">
118
- <Grid item xs={ 12 }>
119
- <ControlLabel>{ __( 'Left', 'elementor' ) }</ControlLabel>
120
- </Grid>
121
- <Grid item xs={ 12 }>
122
- <Control
123
- bind={ 'left' }
124
- value={ left }
125
- setValue={ setLinkedValue }
126
- startIcon={ <SideLeftIcon fontSize={ 'tiny' } /> }
127
- />
128
- </Grid>
129
- </Grid>
130
- </Stack>
131
- </>
132
- );
133
- };
134
-
135
- const Control = ( {
136
- bind,
137
- startIcon,
138
- value,
139
- setValue,
140
- }: {
141
- bind: Position;
142
- value: PropValue;
143
- startIcon: React.ReactNode;
144
- setValue: ( bind: Position, newValue: PropValue ) => void;
145
- } ) => (
146
- <ControlContext.Provider
147
- value={ {
148
- bind,
149
- setValue: ( newValue ) => setValue( bind, newValue ),
150
- value,
151
- } }
152
- >
153
- <SizeControl startIcon={ startIcon } />
154
- </ControlContext.Provider>
155
- );
@@ -1,20 +0,0 @@
1
- import * as React from 'react';
2
- import { __ } from '@wordpress/i18n';
3
- import { Grid } from '@elementor/ui';
4
- import { StyleControl } from '../../../controls/style-control';
5
- import { SizeControl } from '../../../controls/control-types/size-control';
6
-
7
- export const FontSizeControl = () => {
8
- return (
9
- <StyleControl bind="font-size">
10
- <Grid container spacing={ 1 } alignItems="center">
11
- <Grid item xs={ 6 }>
12
- <StyleControl.Label>{ __( 'Font Size', 'elementor' ) }</StyleControl.Label>
13
- </Grid>
14
- <Grid item xs={ 6 }>
15
- <SizeControl />
16
- </Grid>
17
- </Grid>
18
- </StyleControl>
19
- );
20
- };
@@ -1,20 +0,0 @@
1
- import * as React from 'react';
2
- import { __ } from '@wordpress/i18n';
3
- import { Grid } from '@elementor/ui';
4
- import { StyleControl } from '../../../controls/style-control';
5
- import { SizeControl } from '../../../controls/control-types/size-control';
6
-
7
- export const LetterSpacingControl = () => {
8
- return (
9
- <StyleControl bind="letter-spacing">
10
- <Grid container spacing={ 1 } alignItems="center">
11
- <Grid item xs={ 6 }>
12
- <StyleControl.Label>{ __( 'Letter Spacing', 'elementor' ) }</StyleControl.Label>
13
- </Grid>
14
- <Grid item xs={ 6 }>
15
- <SizeControl />
16
- </Grid>
17
- </Grid>
18
- </StyleControl>
19
- );
20
- };
@@ -1,47 +0,0 @@
1
- import * as React from 'react';
2
- import { __ } from '@wordpress/i18n';
3
- import { Grid } from '@elementor/ui';
4
- import { AlignLeftIcon, AlignCenterIcon, AlignRightIcon, AlignJustifiedIcon } from '@elementor/icons';
5
- import { ToggleButtonGroupItem } from '../../../controls/components/control-toggle-button-group';
6
- import { StyleControl } from '../../../controls/style-control';
7
- import { ToggleControl } from '../../../controls/control-types/toggle-control';
8
-
9
- type Alignments = 'left' | 'center' | 'right' | 'justify';
10
-
11
- const options: ToggleButtonGroupItem< Alignments >[] = [
12
- {
13
- value: 'left',
14
- label: __( 'Left', 'elementor' ),
15
- icon: AlignLeftIcon,
16
- },
17
- {
18
- value: 'center',
19
- label: __( 'Center', 'elementor' ),
20
- icon: AlignCenterIcon,
21
- },
22
- {
23
- value: 'right',
24
- label: __( 'Right', 'elementor' ),
25
- icon: AlignRightIcon,
26
- },
27
- {
28
- value: 'justify',
29
- label: __( 'Justify', 'elementor' ),
30
- icon: AlignJustifiedIcon,
31
- },
32
- ];
33
-
34
- export const TextAlignmentControl = () => {
35
- return (
36
- <StyleControl bind={ 'text-align' }>
37
- <Grid container spacing={ 1 } alignItems="center">
38
- <Grid item xs={ 6 }>
39
- <StyleControl.Label>{ __( 'Alignment', 'elementor' ) }</StyleControl.Label>
40
- </Grid>
41
- <Grid item xs={ 6 } display="flex" justifyContent="end">
42
- <ToggleControl options={ options } />
43
- </Grid>
44
- </Grid>
45
- </StyleControl>
46
- );
47
- };
@@ -1,20 +0,0 @@
1
- import * as React from 'react';
2
- import { __ } from '@wordpress/i18n';
3
- import { Grid } from '@elementor/ui';
4
- import { StyleControl } from '../../../controls/style-control';
5
- import { ColorControl } from '../../../controls/control-types/color-control';
6
-
7
- export const TextColorControl = () => {
8
- return (
9
- <StyleControl bind="color">
10
- <Grid container spacing={ 1 } alignItems="center">
11
- <Grid item xs={ 6 }>
12
- <StyleControl.Label>{ __( 'Text Color', 'elementor' ) }</StyleControl.Label>
13
- </Grid>
14
- <Grid item xs={ 6 }>
15
- <ColorControl />
16
- </Grid>
17
- </Grid>
18
- </StyleControl>
19
- );
20
- };
@@ -1,25 +0,0 @@
1
- import * as React from 'react';
2
- import { __ } from '@wordpress/i18n';
3
- import { Grid } from '@elementor/ui';
4
- import { LetterCaseIcon, LetterCaseLowerIcon, LetterCaseUpperIcon } from '@elementor/icons';
5
- import { StyleControl } from '../../../controls/style-control';
6
- import { ToggleControl } from '../../../controls/control-types/toggle-control';
7
-
8
- const options = [
9
- { value: 'capitalize', label: __( 'Capitalize', 'elementor' ), icon: LetterCaseIcon },
10
- { value: 'uppercase', label: __( 'Uppercase', 'elementor' ), icon: LetterCaseUpperIcon },
11
- { value: 'lowercase', label: __( 'Lowercase', 'elementor' ), icon: LetterCaseLowerIcon },
12
- ];
13
-
14
- export const TransformControl = () => (
15
- <StyleControl bind={ 'text-transform' }>
16
- <Grid container spacing={ 1 } alignItems="center">
17
- <Grid item xs={ 6 }>
18
- <StyleControl.Label>{ __( 'Transform', 'elementor' ) }</StyleControl.Label>
19
- </Grid>
20
- <Grid item xs={ 6 } display="flex" justifyContent="end">
21
- <ToggleControl options={ options } />
22
- </Grid>
23
- </Grid>
24
- </StyleControl>
25
- );
@@ -1,20 +0,0 @@
1
- import * as React from 'react';
2
- import { __ } from '@wordpress/i18n';
3
- import { Grid } from '@elementor/ui';
4
- import { StyleControl } from '../../../controls/style-control';
5
- import { SizeControl } from '../../../controls/control-types/size-control';
6
-
7
- export const WordSpacingControl = () => {
8
- return (
9
- <StyleControl bind="word-spacing">
10
- <Grid container spacing={ 1 } alignItems="center">
11
- <Grid item xs={ 6 }>
12
- <StyleControl.Label>{ __( 'Word Spacing', 'elementor' ) }</StyleControl.Label>
13
- </Grid>
14
- <Grid item xs={ 6 }>
15
- <SizeControl />
16
- </Grid>
17
- </Grid>
18
- </StyleControl>
19
- );
20
- };
@@ -1,59 +0,0 @@
1
- import * as React from 'react';
2
- import { JSX } from 'react';
3
- import { StackProps, styled, ToggleButton, ToggleButtonGroup } from '@elementor/ui';
4
-
5
- export type ToggleButtonGroupItem< TValue > = {
6
- value: TValue;
7
- label: string;
8
- icon: JSX.ElementType;
9
- };
10
-
11
- const StyledToggleButtonGroup = styled( ToggleButtonGroup )`
12
- ${ ( { justify } ) => `justify-content: ${ justify };` }
13
- `;
14
-
15
- type ExclusiveValue< TValue > = TValue | null;
16
- type NonExclusiveValue< TValue > = TValue[];
17
-
18
- type Props< TValue > = {
19
- justify?: StackProps[ 'justifyContent' ];
20
- size?: 'tiny' | 'small' | 'medium' | 'large';
21
- items: ToggleButtonGroupItem< TValue >[];
22
- } & (
23
- | {
24
- exclusive?: false;
25
- value: NonExclusiveValue< TValue >;
26
- onChange: ( value: NonExclusiveValue< TValue > ) => void;
27
- }
28
- | {
29
- exclusive: true;
30
- value: ExclusiveValue< TValue >;
31
- onChange: ( value: ExclusiveValue< TValue > ) => void;
32
- }
33
- );
34
-
35
- export const ControlToggleButtonGroup = < TValue, >( {
36
- justify = 'end',
37
- size = 'tiny',
38
- value,
39
- onChange,
40
- items,
41
- exclusive = false,
42
- }: Props< TValue > ) => {
43
- const handleChange = (
44
- _: React.MouseEvent< HTMLElement >,
45
- newValue: typeof exclusive extends true ? ExclusiveValue< TValue > : NonExclusiveValue< TValue >
46
- ) => {
47
- onChange( newValue as never );
48
- };
49
-
50
- return (
51
- <StyledToggleButtonGroup justify={ justify } value={ value } onChange={ handleChange } exclusive={ exclusive }>
52
- { items.map( ( { label, value: buttonValue, icon: Icon } ) => (
53
- <ToggleButton key={ buttonValue } value={ buttonValue } aria-label={ label } size={ size }>
54
- <Icon fontSize={ size } />
55
- </ToggleButton>
56
- ) ) }
57
- </StyledToggleButtonGroup>
58
- );
59
- };
@@ -1,197 +0,0 @@
1
- import * as React from 'react';
2
- import { useId, useRef, useState } from 'react';
3
- import { __ } from '@wordpress/i18n';
4
- import { PlusIcon, XIcon, CopyIcon, EyeIcon, EyeOffIcon } from '@elementor/icons';
5
- import {
6
- Box,
7
- Stack,
8
- Popover,
9
- IconButton,
10
- bindTrigger,
11
- bindPopover,
12
- usePopupState,
13
- UnstableTagProps,
14
- UnstableTag,
15
- Typography,
16
- } from '@elementor/ui';
17
-
18
- const SIZE = 'tiny';
19
-
20
- type AnchorEl = HTMLElement | null;
21
-
22
- type Item< T > = {
23
- disabled?: boolean;
24
- } & T;
25
-
26
- export type RepeaterProps< T > = {
27
- label: string;
28
- values?: T[];
29
- setValues: ( newValue: T[] ) => void;
30
- itemSettings: {
31
- initialValues: T;
32
- Label: React.ComponentType< { value: T } >;
33
- Icon: React.ComponentType< { value: T } >;
34
- Content: React.ComponentType< {
35
- value: T;
36
- setValue: ( newValue: T ) => void;
37
- anchorEl: AnchorEl;
38
- } >;
39
- };
40
- };
41
-
42
- export const Repeater = < T, >( {
43
- label,
44
- itemSettings,
45
- values: repeaterValues = [],
46
- setValues: setRepeaterValues,
47
- }: RepeaterProps< Item< T > > ) => {
48
- const addRepeaterItem = () => {
49
- const newItem = structuredClone( itemSettings.initialValues );
50
-
51
- setRepeaterValues( [ ...repeaterValues, newItem ] );
52
- };
53
-
54
- const duplicateRepeaterItem = ( index: number ) => {
55
- setRepeaterValues( [
56
- ...repeaterValues.slice( 0, index ),
57
- structuredClone( repeaterValues[ index ] ),
58
- ...repeaterValues.slice( index ),
59
- ] );
60
- };
61
-
62
- const removeRepeaterItem = ( index: number ) => {
63
- setRepeaterValues( repeaterValues.filter( ( _, i ) => i !== index ) );
64
- };
65
-
66
- const toggleDisableRepeaterItem = ( index: number ) => {
67
- setRepeaterValues(
68
- repeaterValues.map( ( value, i ) => {
69
- if ( i === index ) {
70
- const { disabled, ...rest } = value;
71
-
72
- // If the items should not be disabled, remove the disabled property.
73
- return { ...rest, ...( disabled ? {} : { disabled: true } ) } as Item< T >;
74
- }
75
-
76
- return value;
77
- } )
78
- );
79
- };
80
-
81
- return (
82
- <Stack>
83
- <Stack direction="row" justifyContent="space-between" sx={ { py: 0.5 } }>
84
- <Typography component="label" variant="caption" color="text.secondary">
85
- { label }
86
- </Typography>
87
- <IconButton size={ SIZE } onClick={ addRepeaterItem } aria-label={ __( 'Add item', 'elementor' ) }>
88
- <PlusIcon fontSize={ SIZE } />
89
- </IconButton>
90
- </Stack>
91
- <Stack gap={ 1 }>
92
- { repeaterValues.map( ( value, index ) => (
93
- <RepeaterItem
94
- key={ index }
95
- disabled={ value.disabled }
96
- label={ <itemSettings.Label value={ value } /> }
97
- startIcon={ <itemSettings.Icon value={ value } /> }
98
- removeItem={ () => removeRepeaterItem( index ) }
99
- duplicateItem={ () => duplicateRepeaterItem( index ) }
100
- toggleDisableItem={ () => toggleDisableRepeaterItem( index ) }
101
- >
102
- { ( props ) => (
103
- <itemSettings.Content
104
- { ...props }
105
- value={ value }
106
- setValue={ ( newValue ) =>
107
- setRepeaterValues(
108
- repeaterValues.map( ( item, i ) => ( i === index ? newValue : item ) )
109
- )
110
- }
111
- />
112
- ) }
113
- </RepeaterItem>
114
- ) ) }
115
- </Stack>
116
- </Stack>
117
- );
118
- };
119
-
120
- type RepeaterItemProps = {
121
- label: React.ReactNode;
122
- disabled?: boolean;
123
- startIcon: UnstableTagProps[ 'startIcon' ];
124
- removeItem: () => void;
125
- duplicateItem: () => void;
126
- toggleDisableItem: () => void;
127
- children: ( { anchorEl }: { anchorEl: AnchorEl } ) => React.ReactNode;
128
- };
129
-
130
- const RepeaterItem = ( {
131
- label,
132
- disabled,
133
- startIcon,
134
- children,
135
- removeItem,
136
- duplicateItem,
137
- toggleDisableItem,
138
- }: RepeaterItemProps ) => {
139
- const popupId = useId();
140
- const tagRef = useRef< HTMLElement >( null );
141
- const [ anchorEl, setAnchorEl ] = useState< AnchorEl >( null );
142
-
143
- const popoverState = usePopupState( { popupId, variant: 'popover' } );
144
-
145
- const popoverProps = bindPopover( popoverState );
146
-
147
- return (
148
- <>
149
- <UnstableTag
150
- ref={ tagRef }
151
- label={ label }
152
- showActionsOnHover
153
- variant="outlined"
154
- aria-label={ __( 'Open item', 'elementor' ) }
155
- { ...bindTrigger( popoverState ) }
156
- startIcon={ startIcon }
157
- actions={
158
- <>
159
- <IconButton
160
- size={ SIZE }
161
- onClick={ duplicateItem }
162
- aria-label={ __( 'Duplicate item', 'elementor' ) }
163
- >
164
- <CopyIcon fontSize={ SIZE } />
165
- </IconButton>
166
- <IconButton
167
- size={ SIZE }
168
- onClick={ toggleDisableItem }
169
- aria-label={
170
- disabled ? __( 'Enable item', 'elementor' ) : __( 'Disable item', 'elementor' )
171
- }
172
- >
173
- { disabled ? <EyeOffIcon fontSize={ SIZE } /> : <EyeIcon fontSize={ SIZE } /> }
174
- </IconButton>
175
- <IconButton
176
- size={ SIZE }
177
- onClick={ removeItem }
178
- aria-label={ __( 'Remove item', 'elementor' ) }
179
- >
180
- <XIcon fontSize={ SIZE } />
181
- </IconButton>
182
- </>
183
- }
184
- />
185
- <Popover
186
- disablePortal
187
- slotProps={ {
188
- paper: { ref: setAnchorEl, sx: { width: tagRef.current?.getBoundingClientRect().width } },
189
- } }
190
- anchorOrigin={ { vertical: 'bottom', horizontal: 'left' } }
191
- { ...popoverProps }
192
- >
193
- <Box p={ 2 }>{ children( { anchorEl } ) }</Box>
194
- </Popover>
195
- </>
196
- );
197
- };
@@ -1,79 +0,0 @@
1
- import * as React from 'react';
2
- import { useId } from 'react';
3
- import { bindMenu, bindTrigger, Button, InputAdornment, Menu, MenuItem, TextField, usePopupState } from '@elementor/ui';
4
- import { PropValue } from '../props/types';
5
-
6
- export type TextFieldInnerSelectionProps = {
7
- placeholder?: string;
8
- type: string;
9
- value: PropValue;
10
- onChange: ( event: React.ChangeEvent< HTMLInputElement > ) => void;
11
- endAdornment: React.ReactNode;
12
- startAdornment?: React.ReactNode;
13
- };
14
-
15
- export const TextFieldInnerSelection = ( {
16
- placeholder,
17
- type,
18
- value,
19
- onChange,
20
- endAdornment,
21
- startAdornment,
22
- }: TextFieldInnerSelectionProps ) => {
23
- return (
24
- <TextField
25
- size="tiny"
26
- type={ type }
27
- value={ value }
28
- onChange={ onChange }
29
- placeholder={ placeholder }
30
- InputProps={ {
31
- endAdornment,
32
- startAdornment,
33
- } }
34
- />
35
- );
36
- };
37
-
38
- export type SelectionEndAdornmentProps< T extends string > = {
39
- options: T[];
40
- onClick: ( value: T ) => void;
41
- value: T;
42
- };
43
-
44
- export const SelectionEndAdornment = < T extends string >( {
45
- options,
46
- onClick,
47
- value,
48
- }: SelectionEndAdornmentProps< T > ) => {
49
- const popupState = usePopupState( {
50
- variant: 'popover',
51
- popupId: useId(),
52
- } );
53
-
54
- const handleMenuItemClick = ( index: number ) => {
55
- onClick( options[ index ] );
56
- popupState.close();
57
- };
58
-
59
- return (
60
- <InputAdornment position="end">
61
- <Button
62
- size="small"
63
- color="inherit"
64
- sx={ { font: 'inherit', minWidth: 'initial' } }
65
- { ...bindTrigger( popupState ) }
66
- >
67
- { value.toUpperCase() }
68
- </Button>
69
-
70
- <Menu MenuListProps={ { dense: true } } { ...bindMenu( popupState ) }>
71
- { options.map( ( option, index ) => (
72
- <MenuItem key={ option } onClick={ () => handleMenuItemClick( index ) }>
73
- { option.toUpperCase() }
74
- </MenuItem>
75
- ) ) }
76
- </Menu>
77
- </InputAdornment>
78
- );
79
- };
@@ -1,43 +0,0 @@
1
- import * as React from 'react';
2
- import { styled, UnstableFloatingActionBar } from '@elementor/ui';
3
- import { PropsWithChildren } from 'react';
4
- import { controlActionsMenu } from './control-actions-menu';
5
-
6
- const { useMenuItems } = controlActionsMenu;
7
-
8
- // CSS hack to hide empty floating bars.
9
- const FloatingBar = styled( UnstableFloatingActionBar )`
10
- & .MuiPaper-root:empty {
11
- display: none;
12
- }
13
-
14
- // this is for a fix which would be added later on - to force the width externally
15
- width: 100%;
16
- & > :first-of-type {
17
- width: 100%;
18
- }
19
- `;
20
-
21
- export type ControlActionsProps = PropsWithChildren< {
22
- fullWidth?: boolean;
23
- } >;
24
-
25
- export default function ControlActions( { fullWidth = false, children }: ControlActionsProps ) {
26
- const items = useMenuItems().default;
27
-
28
- if ( items.length === 0 ) {
29
- return children;
30
- }
31
-
32
- return (
33
- <FloatingBar
34
- actions={ items.map( ( { MenuItem, id } ) => (
35
- <MenuItem key={ id } />
36
- ) ) }
37
- // TODO - work on a general layouting solution instead
38
- sx={ fullWidth ? { width: '100%' } : undefined }
39
- >
40
- { children }
41
- </FloatingBar>
42
- );
43
- }