@elementor/editor-controls 3.35.0-327 → 3.35.0-328
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 +195 -76
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +184 -64
- package/dist/index.mjs.map +1 -1
- package/package.json +16 -15
- package/src/components/inline-editor-toolbar.tsx +61 -3
- package/src/components/inline-editor.tsx +7 -0
- package/src/components/url-popover.tsx +73 -0
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": "3.35.0-
|
|
4
|
+
"version": "3.35.0-328",
|
|
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": "3.35.0-
|
|
44
|
-
"@elementor/editor-elements": "3.35.0-
|
|
45
|
-
"@elementor/editor-props": "3.35.0-
|
|
46
|
-
"@elementor/editor-responsive": "3.35.0-
|
|
47
|
-
"@elementor/editor-ui": "3.35.0-
|
|
48
|
-
"@elementor/editor-v1-adapters": "3.35.0-
|
|
49
|
-
"@elementor/env": "3.35.0-
|
|
50
|
-
"@elementor/http-client": "3.35.0-
|
|
43
|
+
"@elementor/editor-current-user": "3.35.0-328",
|
|
44
|
+
"@elementor/editor-elements": "3.35.0-328",
|
|
45
|
+
"@elementor/editor-props": "3.35.0-328",
|
|
46
|
+
"@elementor/editor-responsive": "3.35.0-328",
|
|
47
|
+
"@elementor/editor-ui": "3.35.0-328",
|
|
48
|
+
"@elementor/editor-v1-adapters": "3.35.0-328",
|
|
49
|
+
"@elementor/env": "3.35.0-328",
|
|
50
|
+
"@elementor/http-client": "3.35.0-328",
|
|
51
51
|
"@elementor/icons": "^1.61.1",
|
|
52
|
-
"@elementor/locations": "3.35.0-
|
|
53
|
-
"@elementor/mixpanel": "3.35.0-
|
|
54
|
-
"@elementor/query": "3.35.0-
|
|
55
|
-
"@elementor/session": "3.35.0-
|
|
52
|
+
"@elementor/locations": "3.35.0-328",
|
|
53
|
+
"@elementor/mixpanel": "3.35.0-328",
|
|
54
|
+
"@elementor/query": "3.35.0-328",
|
|
55
|
+
"@elementor/session": "3.35.0-328",
|
|
56
56
|
"@elementor/ui": "1.36.17",
|
|
57
|
-
"@elementor/utils": "3.35.0-
|
|
58
|
-
"@elementor/wp-media": "3.35.0-
|
|
57
|
+
"@elementor/utils": "3.35.0-328",
|
|
58
|
+
"@elementor/wp-media": "3.35.0-328",
|
|
59
59
|
"@wordpress/i18n": "^5.13.0",
|
|
60
60
|
"@monaco-editor/react": "^4.7.0",
|
|
61
61
|
"dayjs": "^1.11.18",
|
|
@@ -68,6 +68,7 @@
|
|
|
68
68
|
"@tiptap/extension-superscript": "^3.11.1",
|
|
69
69
|
"@tiptap/extension-text": "^3.11.1",
|
|
70
70
|
"@tiptap/extension-underline": "^3.11.1",
|
|
71
|
+
"@tiptap/extension-link": "^3.11.1",
|
|
71
72
|
"@tiptap/pm": "^3.11.1",
|
|
72
73
|
"@tiptap/react": "^3.11.1",
|
|
73
74
|
"@tiptap/starter-kit": "^3.11.1"
|
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { useMemo } from 'react';
|
|
2
|
+
import { useMemo, useRef, useState } from 'react';
|
|
3
3
|
import {
|
|
4
4
|
BoldIcon,
|
|
5
5
|
ItalicIcon,
|
|
6
|
+
LinkIcon,
|
|
6
7
|
MinusIcon,
|
|
7
8
|
StrikethroughIcon,
|
|
8
9
|
SubscriptIcon,
|
|
9
10
|
SuperscriptIcon,
|
|
10
11
|
UnderlineIcon,
|
|
11
12
|
} from '@elementor/icons';
|
|
12
|
-
import { Box, IconButton, ToggleButton, ToggleButtonGroup, Tooltip } from '@elementor/ui';
|
|
13
|
+
import { Box, IconButton, ToggleButton, ToggleButtonGroup, Tooltip, usePopupState } from '@elementor/ui';
|
|
13
14
|
import { type Editor, useEditorState } from '@tiptap/react';
|
|
14
15
|
import { __ } from '@wordpress/i18n';
|
|
15
16
|
|
|
17
|
+
import { UrlPopover } from './url-popover';
|
|
18
|
+
|
|
16
19
|
type InlineEditorToolbarProps = {
|
|
17
20
|
editor: Editor;
|
|
18
21
|
};
|
|
@@ -74,6 +77,12 @@ const toolbarButtons = {
|
|
|
74
77
|
editor.chain().focus().toggleSubscript().run();
|
|
75
78
|
},
|
|
76
79
|
},
|
|
80
|
+
link: {
|
|
81
|
+
label: __( 'Link', 'elementor' ),
|
|
82
|
+
icon: <LinkIcon fontSize="tiny" />,
|
|
83
|
+
action: 'link',
|
|
84
|
+
method: null,
|
|
85
|
+
},
|
|
77
86
|
} as const;
|
|
78
87
|
|
|
79
88
|
type ToolbarButtonKeys = keyof typeof toolbarButtons;
|
|
@@ -85,6 +94,11 @@ const { clear: clearButton, ...formatButtons } = toolbarButtons;
|
|
|
85
94
|
const possibleFormats: FormatAction[] = Object.keys( formatButtons ) as FormatAction[];
|
|
86
95
|
|
|
87
96
|
export const InlineEditorToolbar = ( { editor }: InlineEditorToolbarProps ) => {
|
|
97
|
+
const [ urlValue, setUrlValue ] = useState( '' );
|
|
98
|
+
const [ openInNewTab, setOpenInNewTab ] = useState( false );
|
|
99
|
+
const toolbarRef = useRef< HTMLDivElement >( null );
|
|
100
|
+
const popupState = usePopupState( { variant: 'popover' } );
|
|
101
|
+
|
|
88
102
|
const editorState = useEditorState( {
|
|
89
103
|
editor,
|
|
90
104
|
selector: ( ctx ) => possibleFormats.filter( ( format ) => ctx.editor.isActive( format ) ),
|
|
@@ -92,8 +106,40 @@ export const InlineEditorToolbar = ( { editor }: InlineEditorToolbarProps ) => {
|
|
|
92
106
|
|
|
93
107
|
const formatButtonsList = useMemo( () => Object.values( formatButtons ), [] );
|
|
94
108
|
|
|
109
|
+
const handleLinkClick = () => {
|
|
110
|
+
const linkAttrs = editor.getAttributes( 'link' );
|
|
111
|
+
setUrlValue( linkAttrs.href || '' );
|
|
112
|
+
setOpenInNewTab( linkAttrs.target === '_blank' );
|
|
113
|
+
popupState.open( toolbarRef.current );
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const handleUrlChange = ( event: React.ChangeEvent< HTMLInputElement > ) => {
|
|
117
|
+
setUrlValue( event.target.value );
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const handleToggleNewTab = () => {
|
|
121
|
+
setOpenInNewTab( ! openInNewTab );
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const handleUrlSubmit = () => {
|
|
125
|
+
if ( urlValue ) {
|
|
126
|
+
editor
|
|
127
|
+
.chain()
|
|
128
|
+
.focus()
|
|
129
|
+
.setLink( {
|
|
130
|
+
href: urlValue,
|
|
131
|
+
target: openInNewTab ? '_blank' : '_self',
|
|
132
|
+
} )
|
|
133
|
+
.run();
|
|
134
|
+
} else {
|
|
135
|
+
editor.chain().focus().unsetLink().run();
|
|
136
|
+
}
|
|
137
|
+
popupState.close();
|
|
138
|
+
};
|
|
139
|
+
|
|
95
140
|
return (
|
|
96
141
|
<Box
|
|
142
|
+
ref={ toolbarRef }
|
|
97
143
|
sx={ {
|
|
98
144
|
position: 'absolute',
|
|
99
145
|
top: -40,
|
|
@@ -104,6 +150,7 @@ export const InlineEditorToolbar = ( { editor }: InlineEditorToolbarProps ) => {
|
|
|
104
150
|
backgroundColor: 'background.paper',
|
|
105
151
|
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.2)',
|
|
106
152
|
alignItems: 'center',
|
|
153
|
+
visibility: popupState.isOpen ? 'hidden' : 'visible',
|
|
107
154
|
} }
|
|
108
155
|
>
|
|
109
156
|
<Tooltip title={ clearButton.label } placement="top">
|
|
@@ -125,13 +172,24 @@ export const InlineEditorToolbar = ( { editor }: InlineEditorToolbarProps ) => {
|
|
|
125
172
|
value={ button.action }
|
|
126
173
|
aria-label={ button.label }
|
|
127
174
|
size="tiny"
|
|
128
|
-
onClick={ () =>
|
|
175
|
+
onClick={ () =>
|
|
176
|
+
button.action === 'link' ? handleLinkClick() : button.method?.( editor )
|
|
177
|
+
}
|
|
129
178
|
>
|
|
130
179
|
{ button.icon }
|
|
131
180
|
</ToggleButton>
|
|
132
181
|
</Tooltip>
|
|
133
182
|
) ) }
|
|
134
183
|
</ToggleButtonGroup>
|
|
184
|
+
<UrlPopover
|
|
185
|
+
popupState={ popupState }
|
|
186
|
+
anchorRef={ toolbarRef }
|
|
187
|
+
restoreValue={ handleUrlSubmit }
|
|
188
|
+
value={ urlValue }
|
|
189
|
+
onChange={ handleUrlChange }
|
|
190
|
+
openInNewTab={ openInNewTab }
|
|
191
|
+
onToggleNewTab={ handleToggleNewTab }
|
|
192
|
+
/>
|
|
135
193
|
</Box>
|
|
136
194
|
);
|
|
137
195
|
};
|
|
@@ -5,6 +5,7 @@ import Bold from '@tiptap/extension-bold';
|
|
|
5
5
|
import Document from '@tiptap/extension-document';
|
|
6
6
|
import HardBreak from '@tiptap/extension-hard-break';
|
|
7
7
|
import Italic from '@tiptap/extension-italic';
|
|
8
|
+
import Link from '@tiptap/extension-link';
|
|
8
9
|
import Strike from '@tiptap/extension-strike';
|
|
9
10
|
import Subscript from '@tiptap/extension-subscript';
|
|
10
11
|
import Superscript from '@tiptap/extension-superscript';
|
|
@@ -52,6 +53,9 @@ export const InlineEditor = React.forwardRef(
|
|
|
52
53
|
Underline,
|
|
53
54
|
Superscript,
|
|
54
55
|
Subscript,
|
|
56
|
+
Link.configure( {
|
|
57
|
+
openOnClick: false,
|
|
58
|
+
} ),
|
|
55
59
|
HardBreak.extend( {
|
|
56
60
|
addKeyboardShortcuts() {
|
|
57
61
|
return {
|
|
@@ -98,6 +102,9 @@ export const InlineEditor = React.forwardRef(
|
|
|
98
102
|
'& .ProseMirror': {
|
|
99
103
|
minHeight: '70px',
|
|
100
104
|
fontSize: '12px',
|
|
105
|
+
'& a': {
|
|
106
|
+
color: 'inherit',
|
|
107
|
+
},
|
|
101
108
|
},
|
|
102
109
|
...sx,
|
|
103
110
|
} }
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { type RefObject, useEffect, useRef } from 'react';
|
|
3
|
+
import { ExternalLinkIcon } from '@elementor/icons';
|
|
4
|
+
import { bindPopover, Popover, type PopupState, Stack, TextField, ToggleButton } from '@elementor/ui';
|
|
5
|
+
import { __ } from '@wordpress/i18n';
|
|
6
|
+
|
|
7
|
+
type Props = {
|
|
8
|
+
popupState: PopupState;
|
|
9
|
+
anchorRef: RefObject< HTMLDivElement | null >;
|
|
10
|
+
restoreValue: () => void;
|
|
11
|
+
value: string;
|
|
12
|
+
onChange: ( event: React.ChangeEvent< HTMLInputElement > ) => void;
|
|
13
|
+
openInNewTab: boolean;
|
|
14
|
+
onToggleNewTab: () => void;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const UrlPopover = ( {
|
|
18
|
+
popupState,
|
|
19
|
+
restoreValue,
|
|
20
|
+
anchorRef,
|
|
21
|
+
value,
|
|
22
|
+
onChange,
|
|
23
|
+
openInNewTab,
|
|
24
|
+
onToggleNewTab,
|
|
25
|
+
}: Props ) => {
|
|
26
|
+
const inputRef = useRef< HTMLInputElement >( null );
|
|
27
|
+
|
|
28
|
+
useEffect( () => {
|
|
29
|
+
if ( popupState.isOpen ) {
|
|
30
|
+
requestAnimationFrame( () => inputRef.current?.focus() );
|
|
31
|
+
}
|
|
32
|
+
}, [ popupState.isOpen ] );
|
|
33
|
+
|
|
34
|
+
const handleClose = () => {
|
|
35
|
+
restoreValue();
|
|
36
|
+
popupState.close();
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<Popover
|
|
41
|
+
slotProps={ {
|
|
42
|
+
paper: { sx: { borderRadius: '16px', width: anchorRef.current?.offsetWidth + 'px', marginTop: -1 } },
|
|
43
|
+
} }
|
|
44
|
+
{ ...bindPopover( popupState ) }
|
|
45
|
+
anchorOrigin={ { vertical: 'top', horizontal: 'left' } }
|
|
46
|
+
transformOrigin={ { vertical: 'top', horizontal: 'left' } }
|
|
47
|
+
onClose={ handleClose }
|
|
48
|
+
>
|
|
49
|
+
<Stack direction="row" alignItems="center" gap={ 1 } sx={ { p: 1.5 } }>
|
|
50
|
+
<TextField
|
|
51
|
+
value={ value }
|
|
52
|
+
onChange={ onChange }
|
|
53
|
+
size="tiny"
|
|
54
|
+
fullWidth
|
|
55
|
+
placeholder={ __( 'Type a URL', 'elementor' ) }
|
|
56
|
+
inputProps={ { ref: inputRef } }
|
|
57
|
+
color="secondary"
|
|
58
|
+
InputProps={ { sx: { borderRadius: '8px' } } }
|
|
59
|
+
/>
|
|
60
|
+
<ToggleButton
|
|
61
|
+
size="tiny"
|
|
62
|
+
value="newTab"
|
|
63
|
+
selected={ openInNewTab }
|
|
64
|
+
onClick={ onToggleNewTab }
|
|
65
|
+
aria-label={ __( 'Open in a new tab', 'elementor' ) }
|
|
66
|
+
sx={ { borderRadius: '8px' } }
|
|
67
|
+
>
|
|
68
|
+
<ExternalLinkIcon fontSize="tiny" />
|
|
69
|
+
</ToggleButton>
|
|
70
|
+
</Stack>
|
|
71
|
+
</Popover>
|
|
72
|
+
);
|
|
73
|
+
};
|