PluginProbe
Extendify / 1.9.0
Extendify v1.9.0
3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 0.6.0 0.7.0 All 126 releases
extendify / src / Draft / components / InsertMenu.js

InsertMenu.js in Extendify 1.9.0, at src/Draft/components/InsertMenu.js

209 lines 6.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { createBlock, pasteHandler } from '@wordpress/blocks'
2 import {
3 MenuGroup,
4 MenuItem,
5 __experimentalDivider as Divider,
6 } from '@wordpress/components'
7 import { useDispatch, useSelect } from '@wordpress/data'
8 import { useEffect } from '@wordpress/element'
9 import { __ } from '@wordpress/i18n'
10 import { Icon } from '@wordpress/icons'
11 import { useContentHighlight } from '@draft/hooks/useContentHighlight'
12 import { replace, replay, below, trash, shorter, longer } from '@draft/svg'
13
14 export const InsertMenu = ({
15 prompt,
16 completion,
17 loading,
18 setPrompt,
19 setInputText,
20 }) => {
21 const { toggleHighlight, toggleInsertionPoint } = useContentHighlight()
22 const { insertBlocks, replaceBlocks } = useDispatch('core/block-editor')
23 const selectedBlock = useSelect(
24 (select) => select('core/block-editor').getSelectedBlock(),
25 [],
26 )
27 const selectedBlockClientIds = useSelect(
28 (select) => select('core/block-editor').getSelectedBlockClientIds(),
29 [],
30 )
31 const { getBlockRootClientId, getBlockIndex, getBlock } = useSelect(
32 (select) => select('core/block-editor'),
33 [],
34 )
35
36 const canReplaceContent = () => {
37 const targetBlock = selectedBlock
38 ? selectedBlock
39 : getBlock(selectedBlockClientIds[0])
40 if (!targetBlock) {
41 return true
42 }
43 return typeof targetBlock?.attributes?.content === 'undefined'
44 }
45
46 const transformBlocks = (blocks, targetBlockId) => {
47 const targetBlock = getBlock(targetBlockId)
48 return blocks.map((block) => {
49 return {
50 ...block,
51 name: targetBlock.name,
52 attributes: {
53 ...targetBlock.attributes,
54 content: block.attributes.content,
55 },
56 }
57 })
58 }
59
60 const plainTextToBlocks = (plainText) => {
61 let blocks = pasteHandler({ plainText: plainText })
62 if (!Array.isArray(blocks)) {
63 blocks = [
64 createBlock('core/paragraph', {
65 content: blocks,
66 }),
67 ]
68 }
69 return blocks
70 }
71
72 const insertCompletion = ({ replaceContent = false }) => {
73 setPrompt({ text: '', promptType: '', systemMessageKey: '' })
74
75 const targetBlockId = selectedBlock
76 ? selectedBlock?.clientId
77 : selectedBlockClientIds[0]
78
79 let blocks = plainTextToBlocks(completion)
80
81 if (selectedBlock && selectedBlock?.attributes?.content === '') {
82 replaceContent = true
83 }
84
85 if (replaceContent) {
86 blocks = transformBlocks(blocks, targetBlockId)
87 replaceBlocks(selectedBlockClientIds, blocks)
88 } else if (!targetBlockId) {
89 insertBlocks(blocks)
90 } else {
91 const parentBlockId = getBlockRootClientId(targetBlockId)
92 const blockIndex = getBlockIndex(
93 selectedBlockClientIds.at(-1),
94 parentBlockId,
95 )
96 if (parentBlockId) {
97 blocks = transformBlocks(blocks, targetBlockId)
98 }
99 insertBlocks(blocks, blockIndex + 1, parentBlockId)
100 }
101 }
102
103 const handleEdit = (promptType) => {
104 setInputText('')
105 setPrompt({
106 text: completion,
107 promptType,
108 systemMessageKey: 'edit',
109 })
110 }
111
112 const discard = () => {
113 setInputText('')
114 setPrompt({ text: '', promptType: '', systemMessageKey: '' })
115 }
116
117 const retry = () => {
118 setInputText('')
119 setPrompt({ text: '', promptType: '', systemMessageKey: '' })
120 setTimeout(() => setPrompt(prompt))
121 }
122
123 useEffect(() => {
124 return () => {
125 toggleHighlight(selectedBlockClientIds, { isHighlighted: false })
126 }
127 }, [selectedBlockClientIds, toggleHighlight])
128
129 return (
130 <MenuGroup>
131 <MenuItem
132 onClick={() => insertCompletion({ replaceContent: true })}
133 onMouseEnter={() =>
134 toggleHighlight(selectedBlockClientIds, {
135 isHighlighted: true,
136 })
137 }
138 onMouseLeave={() =>
139 toggleHighlight(selectedBlockClientIds, {
140 isHighlighted: false,
141 })
142 }
143 disabled={loading || canReplaceContent()}>
144 <Icon
145 icon={replace}
146 className="flex-shrink-0 fill-current w-5 h-5 mr-2"
147 />
148 <span className="whitespace-normal text-left">
149 {__('Replace selected block text', 'extendify')}
150 </span>
151 </MenuItem>
152 <MenuItem
153 onClick={() => insertCompletion({ replaceContent: false })}
154 onMouseEnter={() => toggleInsertionPoint(true)}
155 onMouseLeave={() => toggleInsertionPoint(false)}
156 disabled={loading}>
157 <Icon
158 icon={below}
159 className="flex-shrink-0 fill-current w-5 h-5 mr-2"
160 />
161 <span className="whitespace-normal text-left">
162 {__('Insert below', 'extendify')}
163 </span>
164 </MenuItem>
165 <MenuItem
166 onClick={() => handleEdit('make-shorter')}
167 disabled={loading}
168 className="group">
169 <Icon
170 icon={shorter}
171 className="flex-shrink-0 fill-current w-5 h-5 mr-2"
172 />
173 {__('Make shorter', 'extendify')}
174 </MenuItem>
175 <MenuItem
176 onClick={() => handleEdit('make-longer')}
177 disabled={loading}
178 className="group">
179 <Icon
180 icon={longer}
181 className="flex-shrink-0 fill-current w-5 h-5 mr-2"
182 />
183 <span className="whitespace-normal text-left">
184 {__('Make longer', 'extendify')}
185 </span>
186 </MenuItem>
187 <Divider />
188 <MenuItem onClick={retry} disabled={loading}>
189 <Icon
190 icon={replay}
191 className="flex-shrink-0 fill-current w-5 h-5 mr-2"
192 />
193 <span className="whitespace-normal text-left">
194 {__('Try again', 'extendify')}
195 </span>
196 </MenuItem>
197 <MenuItem onClick={discard} disabled={loading}>
198 <Icon
199 icon={trash}
200 className="flex-shrink-0 fill-current w-5 h-5 mr-2"
201 />
202 <span className="whitespace-normal text-left">
203 {__('Discard', 'extendify')}
204 </span>
205 </MenuItem>
206 </MenuGroup>
207 )
208 }
209