@elementor/editor-controls 4.0.0-607 → 4.0.0-619
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.d.mts +17 -4
- package/dist/index.d.ts +17 -4
- package/dist/index.js +904 -759
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +682 -539
- package/dist/index.mjs.map +1 -1
- package/package.json +15 -15
- package/src/components/size-control/size-input.tsx +20 -13
- package/src/components/text-field-popover.tsx +7 -0
- package/src/controls/aspect-ratio-control.tsx +12 -1
- package/src/controls/number-control.tsx +10 -2
- package/src/controls/svg-media-control.tsx +1 -1
- package/src/controls/transform-control/transform-repeater-control.tsx +19 -19
- package/src/controls/video-media-control.tsx +102 -0
- package/src/hooks/use-typing-buffer.ts +52 -0
- package/src/index.ts +10 -2
- package/src/hooks/use-element-can-have-children.ts +0 -17
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elementor/editor-controls",
|
|
3
3
|
"description": "This package contains the controls model and utils for the Elementor editor",
|
|
4
|
-
"version": "4.0.0-
|
|
4
|
+
"version": "4.0.0-619",
|
|
5
5
|
"private": false,
|
|
6
6
|
"author": "Elementor Team",
|
|
7
7
|
"homepage": "https://elementor.com/",
|
|
@@ -40,22 +40,22 @@
|
|
|
40
40
|
"dev": "tsup --config=../../tsup.dev.ts"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@elementor/editor-current-user": "4.0.0-
|
|
44
|
-
"@elementor/editor-elements": "4.0.0-
|
|
45
|
-
"@elementor/editor-props": "4.0.0-
|
|
46
|
-
"@elementor/editor-responsive": "4.0.0-
|
|
47
|
-
"@elementor/editor-ui": "4.0.0-
|
|
48
|
-
"@elementor/editor-v1-adapters": "4.0.0-
|
|
49
|
-
"@elementor/env": "4.0.0-
|
|
50
|
-
"@elementor/http-client": "4.0.0-
|
|
43
|
+
"@elementor/editor-current-user": "4.0.0-619",
|
|
44
|
+
"@elementor/editor-elements": "4.0.0-619",
|
|
45
|
+
"@elementor/editor-props": "4.0.0-619",
|
|
46
|
+
"@elementor/editor-responsive": "4.0.0-619",
|
|
47
|
+
"@elementor/editor-ui": "4.0.0-619",
|
|
48
|
+
"@elementor/editor-v1-adapters": "4.0.0-619",
|
|
49
|
+
"@elementor/env": "4.0.0-619",
|
|
50
|
+
"@elementor/http-client": "4.0.0-619",
|
|
51
51
|
"@elementor/icons": "^1.68.0",
|
|
52
|
-
"@elementor/locations": "4.0.0-
|
|
53
|
-
"@elementor/events": "4.0.0-
|
|
54
|
-
"@elementor/query": "4.0.0-
|
|
55
|
-
"@elementor/session": "4.0.0-
|
|
52
|
+
"@elementor/locations": "4.0.0-619",
|
|
53
|
+
"@elementor/events": "4.0.0-619",
|
|
54
|
+
"@elementor/query": "4.0.0-619",
|
|
55
|
+
"@elementor/session": "4.0.0-619",
|
|
56
56
|
"@elementor/ui": "1.36.17",
|
|
57
|
-
"@elementor/utils": "4.0.0-
|
|
58
|
-
"@elementor/wp-media": "4.0.0-
|
|
57
|
+
"@elementor/utils": "4.0.0-619",
|
|
58
|
+
"@elementor/wp-media": "4.0.0-619",
|
|
59
59
|
"@wordpress/i18n": "^5.13.0",
|
|
60
60
|
"@monaco-editor/react": "^4.7.0",
|
|
61
61
|
"dayjs": "^1.11.18",
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { useRef } from 'react';
|
|
3
2
|
import { MathFunctionIcon } from '@elementor/icons';
|
|
4
3
|
import { Box, InputAdornment, type PopupState } from '@elementor/ui';
|
|
5
4
|
|
|
6
5
|
import ControlActions from '../../control-actions/control-actions';
|
|
6
|
+
import { useTypingBuffer } from '../../hooks/use-typing-buffer';
|
|
7
7
|
import { type ExtendedOption, isUnitExtendedOption, type Unit } from '../../utils/size-control';
|
|
8
8
|
import { SelectionEndAdornment, TextFieldInnerSelection } from '../size-control/text-field-inner-selection';
|
|
9
9
|
|
|
10
|
-
const RESTRICTED_KEYBOARD_SHORTCUT_UNITS = [ 'auto' ];
|
|
11
|
-
|
|
12
10
|
type SizeInputProps = {
|
|
13
11
|
unit: Unit | ExtendedOption;
|
|
14
12
|
size: number | string;
|
|
@@ -44,12 +42,25 @@ export const SizeInput = ( {
|
|
|
44
42
|
id,
|
|
45
43
|
ariaLabel,
|
|
46
44
|
}: SizeInputProps ) => {
|
|
47
|
-
const
|
|
45
|
+
const { appendKey, startsWith } = useTypingBuffer();
|
|
46
|
+
|
|
48
47
|
const inputType = isUnitExtendedOption( unit ) ? 'text' : 'number';
|
|
49
48
|
const inputValue = ! isUnitExtendedOption( unit ) && Number.isNaN( size ) ? '' : size ?? '';
|
|
50
49
|
|
|
51
|
-
const
|
|
52
|
-
const { key } = event;
|
|
50
|
+
const handleKeyDown = ( event: React.KeyboardEvent< HTMLInputElement > ) => {
|
|
51
|
+
const { key, altKey, ctrlKey, metaKey } = event;
|
|
52
|
+
|
|
53
|
+
if ( altKey || ctrlKey || metaKey ) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if ( isUnitExtendedOption( unit ) && ! isNaN( Number( key ) ) ) {
|
|
58
|
+
const defaultUnit = units?.[ 0 ];
|
|
59
|
+
if ( defaultUnit ) {
|
|
60
|
+
handleUnitChange( defaultUnit );
|
|
61
|
+
}
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
53
64
|
|
|
54
65
|
if ( ! /^[a-zA-Z%]$/.test( key ) ) {
|
|
55
66
|
return;
|
|
@@ -58,13 +69,9 @@ export const SizeInput = ( {
|
|
|
58
69
|
event.preventDefault();
|
|
59
70
|
|
|
60
71
|
const newChar = key.toLowerCase();
|
|
61
|
-
const updatedBuffer = (
|
|
62
|
-
unitInputBufferRef.current = updatedBuffer;
|
|
72
|
+
const updatedBuffer = appendKey( newChar );
|
|
63
73
|
|
|
64
|
-
const matchedUnit =
|
|
65
|
-
units.find( ( u ) => ! RESTRICTED_KEYBOARD_SHORTCUT_UNITS.includes( u ) && u.includes( updatedBuffer ) ) ||
|
|
66
|
-
units.find( ( u ) => ! RESTRICTED_KEYBOARD_SHORTCUT_UNITS.includes( u ) && u.startsWith( newChar ) ) ||
|
|
67
|
-
units.find( ( u ) => ! RESTRICTED_KEYBOARD_SHORTCUT_UNITS.includes( u ) && u.includes( newChar ) );
|
|
74
|
+
const matchedUnit = units.find( ( u ) => startsWith( u, updatedBuffer ) );
|
|
68
75
|
|
|
69
76
|
if ( matchedUnit ) {
|
|
70
77
|
handleUnitChange( matchedUnit );
|
|
@@ -118,7 +125,7 @@ export const SizeInput = ( {
|
|
|
118
125
|
type={ inputType }
|
|
119
126
|
value={ inputValue }
|
|
120
127
|
onChange={ handleSizeChange }
|
|
121
|
-
|
|
128
|
+
onKeyDown={ handleKeyDown }
|
|
122
129
|
onBlur={ onBlur }
|
|
123
130
|
InputProps={ InputProps }
|
|
124
131
|
inputProps={ { min, step: 'any', 'aria-label': ariaLabel } }
|
|
@@ -29,6 +29,12 @@ export const TextFieldPopover = ( props: Props ) => {
|
|
|
29
29
|
}
|
|
30
30
|
}, [ popupState.isOpen ] );
|
|
31
31
|
|
|
32
|
+
const handleKeyPress = ( event: React.KeyboardEvent< HTMLInputElement > ) => {
|
|
33
|
+
if ( event.key.toLowerCase() === 'enter' ) {
|
|
34
|
+
handleClose();
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
32
38
|
const handleClose = () => {
|
|
33
39
|
restoreValue();
|
|
34
40
|
popupState.close();
|
|
@@ -58,6 +64,7 @@ export const TextFieldPopover = ( props: Props ) => {
|
|
|
58
64
|
<TextField
|
|
59
65
|
value={ value }
|
|
60
66
|
onChange={ onChange }
|
|
67
|
+
onKeyPress={ handleKeyPress }
|
|
61
68
|
size="tiny"
|
|
62
69
|
type="text"
|
|
63
70
|
fullWidth
|
|
@@ -25,7 +25,14 @@ const RATIO_OPTIONS = [
|
|
|
25
25
|
const CUSTOM_RATIO = 'custom';
|
|
26
26
|
|
|
27
27
|
export const AspectRatioControl = createControl( ( { label }: { label: string } ) => {
|
|
28
|
-
const {
|
|
28
|
+
const {
|
|
29
|
+
value: currentPropValue,
|
|
30
|
+
setValue: setAspectRatioValue,
|
|
31
|
+
disabled,
|
|
32
|
+
placeholder: externalPlaceholder,
|
|
33
|
+
} = useBoundProp( stringPropTypeUtil );
|
|
34
|
+
|
|
35
|
+
const aspectRatioValue = currentPropValue ?? externalPlaceholder;
|
|
29
36
|
|
|
30
37
|
const isCustomSelected =
|
|
31
38
|
aspectRatioValue && ! RATIO_OPTIONS.some( ( option ) => option.value === aspectRatioValue );
|
|
@@ -87,6 +94,9 @@ export const AspectRatioControl = createControl( ( { label }: { label: string }
|
|
|
87
94
|
}
|
|
88
95
|
};
|
|
89
96
|
|
|
97
|
+
const lookup = currentPropValue ?? externalPlaceholder;
|
|
98
|
+
const selectedOption = RATIO_OPTIONS.find( ( option ) => option.value === lookup );
|
|
99
|
+
|
|
90
100
|
return (
|
|
91
101
|
<ControlActions>
|
|
92
102
|
<Stack direction="column" gap={ 2 }>
|
|
@@ -102,6 +112,7 @@ export const AspectRatioControl = createControl( ( { label }: { label: string }
|
|
|
102
112
|
disabled={ disabled }
|
|
103
113
|
value={ selectedValue }
|
|
104
114
|
onChange={ handleSelectChange }
|
|
115
|
+
renderValue={ isCustomSelected ? undefined : () => selectedOption?.label }
|
|
105
116
|
fullWidth
|
|
106
117
|
>
|
|
107
118
|
{ [ ...RATIO_OPTIONS, { label: __( 'Custom', 'elementor' ), value: CUSTOM_RATIO } ].map(
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { numberPropTypeUtil } from '@elementor/editor-props';
|
|
2
|
+
import { numberPropTypeUtil, type PropType } from '@elementor/editor-props';
|
|
3
3
|
import { InputAdornment } from '@elementor/ui';
|
|
4
4
|
|
|
5
5
|
import { useBoundProp } from '../bound-prop-context';
|
|
@@ -10,6 +10,13 @@ import { createControl } from '../create-control';
|
|
|
10
10
|
const isEmptyOrNaN = ( value?: string | number | null ) =>
|
|
11
11
|
value === null || value === undefined || value === '' || Number.isNaN( Number( value ) );
|
|
12
12
|
|
|
13
|
+
const renderSuffix = ( propType: PropType ) => {
|
|
14
|
+
if ( propType.meta?.suffix ) {
|
|
15
|
+
return <InputAdornment position="end">{ propType.meta.suffix }</InputAdornment>;
|
|
16
|
+
}
|
|
17
|
+
return <></>;
|
|
18
|
+
};
|
|
19
|
+
|
|
13
20
|
export const NumberControl = createControl(
|
|
14
21
|
( {
|
|
15
22
|
placeholder: labelPlaceholder,
|
|
@@ -26,7 +33,7 @@ export const NumberControl = createControl(
|
|
|
26
33
|
shouldForceInt?: boolean;
|
|
27
34
|
startIcon?: React.ReactNode;
|
|
28
35
|
} ) => {
|
|
29
|
-
const { value, setValue, placeholder, disabled, restoreValue } = useBoundProp( numberPropTypeUtil );
|
|
36
|
+
const { value, setValue, placeholder, disabled, restoreValue, propType } = useBoundProp( numberPropTypeUtil );
|
|
30
37
|
|
|
31
38
|
const handleChange = ( event: React.ChangeEvent< HTMLInputElement > ) => {
|
|
32
39
|
const {
|
|
@@ -68,6 +75,7 @@ export const NumberControl = createControl(
|
|
|
68
75
|
{ startIcon }
|
|
69
76
|
</InputAdornment>
|
|
70
77
|
) : undefined,
|
|
78
|
+
endAdornment: renderSuffix( propType ),
|
|
71
79
|
} }
|
|
72
80
|
/>
|
|
73
81
|
</ControlActions>
|
|
@@ -17,7 +17,7 @@ import { useUnfilteredFilesUpload } from '../hooks/use-unfiltered-files-upload';
|
|
|
17
17
|
const TILE_SIZE = 8;
|
|
18
18
|
const TILE_WHITE = 'transparent';
|
|
19
19
|
const TILE_BLACK = '#c1c1c1';
|
|
20
|
-
const TILES_GRADIENT_FORMULA = `linear-gradient(45deg, ${ TILE_BLACK } 25%, ${ TILE_WHITE } 0, ${ TILE_WHITE } 75%, ${ TILE_BLACK } 0, ${ TILE_BLACK })`;
|
|
20
|
+
export const TILES_GRADIENT_FORMULA = `linear-gradient(45deg, ${ TILE_BLACK } 25%, ${ TILE_WHITE } 0, ${ TILE_WHITE } 75%, ${ TILE_BLACK } 0, ${ TILE_BLACK })`;
|
|
21
21
|
|
|
22
22
|
const StyledCard = styled( Card )`
|
|
23
23
|
background-color: white;
|
|
@@ -13,7 +13,6 @@ import { EditItemPopover } from '../../components/control-repeater/items/edit-it
|
|
|
13
13
|
import { RepeaterHeader } from '../../components/repeater/repeater-header';
|
|
14
14
|
import { ControlAdornments } from '../../control-adornments/control-adornments';
|
|
15
15
|
import { createControl } from '../../create-control';
|
|
16
|
-
import { useElementCanHaveChildren } from '../../hooks/use-element-can-have-children';
|
|
17
16
|
import { initialRotateValue, initialScaleValue, initialSkewValue, initialTransformValue } from './initial-values';
|
|
18
17
|
import { TransformContent } from './transform-content';
|
|
19
18
|
import { TransformIcon } from './transform-icon';
|
|
@@ -22,25 +21,26 @@ import { TransformSettingsControl } from './transform-settings-control';
|
|
|
22
21
|
|
|
23
22
|
const SIZE = 'tiny';
|
|
24
23
|
|
|
25
|
-
export const TransformRepeaterControl = createControl(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
export const TransformRepeaterControl = createControl(
|
|
25
|
+
( { showChildrenPerspective }: { showChildrenPerspective: boolean } ) => {
|
|
26
|
+
const context = useBoundProp( transformPropTypeUtil );
|
|
27
|
+
const headerRef = useRef< HTMLDivElement >( null );
|
|
28
|
+
const popupState = usePopupState( { variant: 'popover' } );
|
|
30
29
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
30
|
+
return (
|
|
31
|
+
<PropProvider { ...context }>
|
|
32
|
+
<TransformSettingsControl
|
|
33
|
+
popupState={ popupState }
|
|
34
|
+
anchorRef={ headerRef }
|
|
35
|
+
showChildrenPerspective={ showChildrenPerspective }
|
|
36
|
+
/>
|
|
37
|
+
<PropKeyProvider bind={ 'transform-functions' }>
|
|
38
|
+
<Repeater headerRef={ headerRef } propType={ context.propType } popupState={ popupState } />
|
|
39
|
+
</PropKeyProvider>
|
|
40
|
+
</PropProvider>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
);
|
|
44
44
|
|
|
45
45
|
const ToolTip = (
|
|
46
46
|
<Box
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { videoSrcPropTypeUtil } from '@elementor/editor-props';
|
|
3
|
+
import { UploadIcon } from '@elementor/icons';
|
|
4
|
+
import { Button, Card, CardMedia, CardOverlay, CircularProgress, Stack } from '@elementor/ui';
|
|
5
|
+
import { useWpMediaAttachment, useWpMediaFrame } from '@elementor/wp-media';
|
|
6
|
+
import { __ } from '@wordpress/i18n';
|
|
7
|
+
|
|
8
|
+
import { useBoundProp } from '../bound-prop-context';
|
|
9
|
+
import ControlActions from '../control-actions/control-actions';
|
|
10
|
+
import { createControl } from '../create-control';
|
|
11
|
+
import { TILES_GRADIENT_FORMULA } from './svg-media-control';
|
|
12
|
+
|
|
13
|
+
const PLACEHOLDER_IMAGE = window.elementorCommon?.config?.urls?.assets + '/shapes/play-triangle.svg';
|
|
14
|
+
|
|
15
|
+
export const VideoMediaControl = createControl( () => {
|
|
16
|
+
const { value, setValue } = useBoundProp( videoSrcPropTypeUtil );
|
|
17
|
+
const { id, url } = value ?? {};
|
|
18
|
+
|
|
19
|
+
const { data: attachment, isFetching } = useWpMediaAttachment( id?.value || null );
|
|
20
|
+
const videoUrl = attachment?.url ?? url?.value ?? null;
|
|
21
|
+
|
|
22
|
+
const { open } = useWpMediaFrame( {
|
|
23
|
+
mediaTypes: [ 'video' ],
|
|
24
|
+
multiple: false,
|
|
25
|
+
selected: id?.value || null,
|
|
26
|
+
onSelect: ( selectedAttachment ) => {
|
|
27
|
+
setValue( {
|
|
28
|
+
id: {
|
|
29
|
+
$$type: 'video-attachment-id',
|
|
30
|
+
value: selectedAttachment.id,
|
|
31
|
+
},
|
|
32
|
+
url: null,
|
|
33
|
+
} );
|
|
34
|
+
},
|
|
35
|
+
} );
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<ControlActions>
|
|
39
|
+
<Card variant="outlined">
|
|
40
|
+
<CardMedia
|
|
41
|
+
sx={ {
|
|
42
|
+
height: 140,
|
|
43
|
+
backgroundColor: 'white',
|
|
44
|
+
backgroundSize: '8px 8px',
|
|
45
|
+
backgroundPosition: '0 0, 4px 4px',
|
|
46
|
+
backgroundRepeat: 'repeat',
|
|
47
|
+
backgroundImage: `${ TILES_GRADIENT_FORMULA }, ${ TILES_GRADIENT_FORMULA }`,
|
|
48
|
+
display: 'flex',
|
|
49
|
+
justifyContent: 'center',
|
|
50
|
+
alignItems: 'center',
|
|
51
|
+
} }
|
|
52
|
+
>
|
|
53
|
+
<VideoPreview isFetching={ isFetching } videoUrl={ videoUrl } />
|
|
54
|
+
</CardMedia>
|
|
55
|
+
<CardOverlay>
|
|
56
|
+
<Stack gap={ 1 }>
|
|
57
|
+
<Button
|
|
58
|
+
size="tiny"
|
|
59
|
+
color="inherit"
|
|
60
|
+
variant="outlined"
|
|
61
|
+
onClick={ () => open( { mode: 'browse' } ) }
|
|
62
|
+
>
|
|
63
|
+
{ __( 'Select video', 'elementor' ) }
|
|
64
|
+
</Button>
|
|
65
|
+
<Button
|
|
66
|
+
size="tiny"
|
|
67
|
+
variant="text"
|
|
68
|
+
color="inherit"
|
|
69
|
+
startIcon={ <UploadIcon /> }
|
|
70
|
+
onClick={ () => open( { mode: 'upload' } ) }
|
|
71
|
+
>
|
|
72
|
+
{ __( 'Upload', 'elementor' ) }
|
|
73
|
+
</Button>
|
|
74
|
+
</Stack>
|
|
75
|
+
</CardOverlay>
|
|
76
|
+
</Card>
|
|
77
|
+
</ControlActions>
|
|
78
|
+
);
|
|
79
|
+
} );
|
|
80
|
+
|
|
81
|
+
const VideoPreview = ( { isFetching = false, videoUrl }: { isFetching?: boolean; videoUrl?: string } ) => {
|
|
82
|
+
if ( isFetching ) {
|
|
83
|
+
return <CircularProgress />;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if ( videoUrl ) {
|
|
87
|
+
return (
|
|
88
|
+
<video
|
|
89
|
+
src={ videoUrl }
|
|
90
|
+
muted
|
|
91
|
+
preload="metadata"
|
|
92
|
+
style={ {
|
|
93
|
+
width: '100%',
|
|
94
|
+
height: '100%',
|
|
95
|
+
objectFit: 'cover',
|
|
96
|
+
pointerEvents: 'none',
|
|
97
|
+
} }
|
|
98
|
+
/>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
return <img src={ PLACEHOLDER_IMAGE } alt="No video selected" />;
|
|
102
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { useEffect, useRef } from 'react';
|
|
2
|
+
|
|
3
|
+
export type UseTypingBufferOptions = {
|
|
4
|
+
limit?: number;
|
|
5
|
+
timeout?: number;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export function useTypingBuffer( options: UseTypingBufferOptions = {} ) {
|
|
9
|
+
const { limit = 3, timeout = 600 } = options;
|
|
10
|
+
|
|
11
|
+
const inputBufferRef = useRef( '' );
|
|
12
|
+
const timeoutRef = useRef< ReturnType< typeof setTimeout > | null >( null );
|
|
13
|
+
|
|
14
|
+
const appendKey = ( key: string ) => {
|
|
15
|
+
inputBufferRef.current = ( inputBufferRef.current + key ).slice( -limit );
|
|
16
|
+
|
|
17
|
+
if ( timeoutRef.current ) {
|
|
18
|
+
clearTimeout( timeoutRef.current );
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
timeoutRef.current = setTimeout( () => {
|
|
22
|
+
inputBufferRef.current = '';
|
|
23
|
+
timeoutRef.current = null;
|
|
24
|
+
}, timeout );
|
|
25
|
+
|
|
26
|
+
return inputBufferRef.current;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const startsWith = ( haystack: string, needle: string ) => {
|
|
30
|
+
// At least 2 characters in needle for longer haystack.
|
|
31
|
+
if ( 3 < haystack.length && 2 > needle.length ) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
return haystack.startsWith( needle );
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
useEffect( () => {
|
|
38
|
+
return () => {
|
|
39
|
+
inputBufferRef.current = '';
|
|
40
|
+
if ( timeoutRef.current ) {
|
|
41
|
+
clearTimeout( timeoutRef.current );
|
|
42
|
+
timeoutRef.current = null;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}, [] );
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
buffer: inputBufferRef.current,
|
|
49
|
+
appendKey,
|
|
50
|
+
startsWith,
|
|
51
|
+
};
|
|
52
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -23,6 +23,7 @@ export { QueryControl } from './controls/query-control';
|
|
|
23
23
|
export { GapControl } from './controls/gap-control';
|
|
24
24
|
export { AspectRatioControl } from './controls/aspect-ratio-control';
|
|
25
25
|
export { SvgMediaControl } from './controls/svg-media-control';
|
|
26
|
+
export { VideoMediaControl } from './controls/video-media-control';
|
|
26
27
|
export { BackgroundControl } from './controls/background-control/background-control';
|
|
27
28
|
export { SwitchControl } from './controls/switch-control';
|
|
28
29
|
export { RepeatableControl } from './controls/repeatable-control';
|
|
@@ -66,7 +67,14 @@ export type { ControlActionsItems } from './control-actions/control-actions-cont
|
|
|
66
67
|
export type { AdornmentComponent } from './control-adornments/control-adornments-context';
|
|
67
68
|
export type { PropProviderProps } from './bound-prop-context';
|
|
68
69
|
export type { SetValue, SetValueMeta } from './bound-prop-context/prop-context';
|
|
69
|
-
export
|
|
70
|
+
export {
|
|
71
|
+
isUnitExtendedOption,
|
|
72
|
+
type ExtendedOption,
|
|
73
|
+
type Unit,
|
|
74
|
+
type LengthUnit,
|
|
75
|
+
type AngleUnit,
|
|
76
|
+
type TimeUnit,
|
|
77
|
+
} from './utils/size-control';
|
|
70
78
|
export type { ToggleControlProps } from './controls/toggle-control';
|
|
71
79
|
export type { FontCategory } from './controls/font-family-control/font-family-control';
|
|
72
80
|
export type { InlineEditorToolbarProps } from './components/inline-editor-toolbar';
|
|
@@ -96,5 +104,5 @@ export {
|
|
|
96
104
|
|
|
97
105
|
// hooks
|
|
98
106
|
export { useSyncExternalState } from './hooks/use-sync-external-state';
|
|
99
|
-
export { useElementCanHaveChildren } from './hooks/use-element-can-have-children';
|
|
100
107
|
export { useFontFamilies } from './hooks/use-font-families';
|
|
108
|
+
export { useTypingBuffer, type UseTypingBufferOptions } from './hooks/use-typing-buffer';
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { useMemo } from 'react';
|
|
2
|
-
import { getContainer, useSelectedElement } from '@elementor/editor-elements';
|
|
3
|
-
|
|
4
|
-
export const useElementCanHaveChildren = (): boolean => {
|
|
5
|
-
const { element } = useSelectedElement();
|
|
6
|
-
const elementId = element?.id || '';
|
|
7
|
-
|
|
8
|
-
return useMemo( () => {
|
|
9
|
-
const container = getContainer( elementId );
|
|
10
|
-
|
|
11
|
-
if ( ! container ) {
|
|
12
|
-
return false;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
return container.model.get( 'elType' ) !== 'widget';
|
|
16
|
-
}, [ elementId ] );
|
|
17
|
-
};
|