PluginProbe
Extendify / 0.2.0
Extendify v0.2.0
3.2.1 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 All 127 releases
extendify / src / components / ImportTemplateBlock.js

ImportTemplateBlock.js in Extendify 0.2.0, at src/components/ImportTemplateBlock.js

149 lines 5.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import classNames from 'classnames'
2 import { useEffect, useState, useRef } from '@wordpress/element'
3 import { __, sprintf } from '@wordpress/i18n'
4 import { BlockPreview } from '@wordpress/block-editor'
5 import { rawHandler } from '@wordpress/blocks'
6 import { AuthorizationCheck, Middleware } from '../middleware'
7 import { injectTemplateBlocks } from '../util/templateInjection'
8 import { useUserStore } from '../state/User'
9 import { useGlobalStore } from '../state/GlobalState'
10 import { Templates as TemplatesApi } from '../api/Templates'
11 import { useIsDevMode } from '../hooks/helpers'
12 import { DevButtonOverlay } from './DevHelpers'
13 import { NoImportModal } from './modals/NoImportModal'
14 import { ProModal } from './modals/ProModal'
15
16 const canImportMiddleware = Middleware([
17 'NeedsRegistrationModal',
18 'hasRequiredPlugins',
19 'hasPluginsActivated',
20 ])
21
22 export function ImportTemplateBlock({ template }) {
23 const importButtonRef = useRef(null)
24 const once = useRef(false)
25 const hasAvailableImports = useUserStore(
26 (state) => state.hasAvailableImports,
27 )
28 const loggedIn = useUserStore((state) => state.apiKey.length)
29 const setOpen = useGlobalStore((state) => state.setOpen)
30 const setCurrentModal = useGlobalStore((state) => state.setCurrentModal)
31 const blocks = rawHandler({ HTML: template.fields.code })
32 const [loaded, setLoaded] = useState(false)
33 const devMode = useIsDevMode()
34
35 const focusTrapInnerBlocks = () => {
36 if (once.current) return
37 once.current = true
38 Array.from(
39 importButtonRef.current.querySelectorAll(
40 'a, button, input, textarea, select, details, [tabindex]:not([tabindex="-1"])',
41 ),
42 ).forEach((el) => el.setAttribute('tabIndex', '-1'))
43 }
44
45 const importTemplates = async () => {
46 await canImportMiddleware.check(template)
47 AuthorizationCheck(canImportMiddleware)
48 .then(() => {
49 setTimeout(() => {
50 injectTemplateBlocks(blocks, template)
51 .then(() => setCurrentModal(null))
52 .then(() => setOpen(false))
53 .then(() => canImportMiddleware.reset())
54 }, 100)
55 })
56 .catch(() => {})
57 }
58
59 const handleKeyDown = (event) => {
60 if (['Enter', 'Space', ' '].includes(event.key)) {
61 event.stopPropagation()
62 event.preventDefault()
63 importTemplate()
64 }
65 }
66
67 const importTemplate = () => {
68 // Make a note that they attempted to import
69 TemplatesApi.maybeImport(template)
70
71 if (template?.fields?.pro && !loggedIn) {
72 setCurrentModal(<ProModal />)
73 return
74 }
75 if (!hasAvailableImports()) {
76 setCurrentModal(<NoImportModal />)
77 return
78 }
79
80 importTemplates()
81 }
82
83 // Trigger resize event on the live previews to add
84 // Grammerly/Loom/etc compatability
85 // TODO: This can probably be removed after WP 5.9
86 useEffect(() => {
87 const rafIds = []
88 let rafId1, rafId2, rafId3
89 rafId1 = window.requestAnimationFrame(() => {
90 rafId2 = window.requestAnimationFrame(() => {
91 importButtonRef.current
92 .querySelectorAll('iframe')
93 .forEach((frame) => {
94 const rafId = window.requestAnimationFrame(() => {
95 frame.contentWindow.dispatchEvent(
96 new Event('resize'),
97 )
98 })
99 rafIds.push(rafId)
100 })
101 rafId3 = window.requestAnimationFrame(() => {
102 window.dispatchEvent(new Event('resize'))
103 setLoaded(true)
104 })
105 })
106 })
107 return () =>
108 [...rafIds, rafId1, rafId2, rafId3].forEach((id) =>
109 window.cancelAnimationFrame(id),
110 )
111 }, [])
112
113 return (
114 <div className="relative group">
115 <div
116 role="button"
117 tabIndex="0"
118 ref={importButtonRef}
119 aria-label={sprintf(
120 __('Press to import %s', 'extendify'),
121 template?.fields?.type,
122 )}
123 className="mb-6 md:mb-8 cursor-pointer button-focus"
124 onFocus={focusTrapInnerBlocks}
125 onClick={importTemplate}
126 onKeyDown={handleKeyDown}>
127 <div
128 className={classNames('with-light-shadow relative', {
129 [`is-template--${template.fields.status}`]:
130 template?.fields?.status && devMode,
131 })}>
132 <BlockPreview
133 blocks={blocks}
134 live={false}
135 viewportWidth={1400}
136 />
137 </div>
138 </div>
139 {/* Show dev info after the preview is loaded to trigger observer */}
140 {devMode && loaded && <DevButtonOverlay template={template} />}
141 {template?.fields?.pro && (
142 <div className="bg-white border font-semibold border-black absolute z-20 top-3 right-3 py-1 px-2 rounded-md shadow-md no-underline text-black pointer-events-none">
143 {__('Pro', 'extendify')}
144 </div>
145 )}
146 </div>
147 )
148 }
149