| 1 |
import { isEmbedded } from '@shared/lib/embedded-guard'; |
| 2 |
import { dispatch } from '@wordpress/data'; |
| 3 |
import domReady from '@wordpress/dom-ready'; |
| 4 |
import { createRoot, render } from '@wordpress/element'; |
| 5 |
import { InlineEditor } from './components/InlineEditor'; |
| 6 |
import { bindAdminBarToggle } from './lib/admin-bar'; |
| 7 |
import { wireGlobalEscape } from './lib/global-escape'; |
| 8 |
import { |
| 9 |
attach as attachHoverBar, |
| 10 |
detach as detachHoverBar, |
| 11 |
} from './lib/hover-bar'; |
| 12 |
import { attachKeyboardEntry, detachKeyboardEntry } from './lib/keyboard-entry'; |
| 13 |
import { |
| 14 |
announcePostReload, |
| 15 |
attachKeyboardUndo, |
| 16 |
detachKeyboardUndo, |
| 17 |
} from './lib/keyboard-undo'; |
| 18 |
import { fetchLinkSuggestions } from './lib/link-suggestions'; |
| 19 |
// Side-effect import: subscribes html.extendify-quick-edit-on before first paint. |
| 20 |
import { STORAGE_KEY, useEditModeStore } from './state/edit-mode'; |
| 21 |
import { useQuickEditStore } from './state/store'; |
| 22 |
|
| 23 |
import './quick-edit.css'; |
| 24 |
|
| 25 |
// Cross-bundle race: edit-mode.js is shared with the Agent bundle (via |
| 26 |
// Chat.jsx and the QuickEdit store). When the Agent bundle's script tag fires |
| 27 |
// first, the shared chunk evaluates before this bundle's inline |
| 28 |
// `window.extQuickEditData = …` has run, so DEFAULT_ON resolves to |
| 29 |
// false and the store freezes with on=false. By the time THIS module |
| 30 |
// loads, our `'before'` inline has fired, so re-seed if the server says |
| 31 |
// defaultOn AND the user has no persisted choice to honor. |
| 32 |
(() => { |
| 33 |
if (isEmbedded()) return; |
| 34 |
if (!window.extQuickEditData?.defaultOn) return; |
| 35 |
let persisted; |
| 36 |
try { |
| 37 |
persisted = JSON.parse(localStorage.getItem(STORAGE_KEY) ?? 'null'); |
| 38 |
} catch { |
| 39 |
persisted = null; |
| 40 |
} |
| 41 |
if (persisted) return; |
| 42 |
useEditModeStore.getState().setOn(true); |
| 43 |
})(); |
| 44 |
|
| 45 |
const App = () => <InlineEditor />; |
| 46 |
|
| 47 |
const mount = () => { |
| 48 |
if (!window.extQuickEditData) return; |
| 49 |
// Never run framed — Customizer preview, multilingual editors, page-builder |
| 50 |
// previews are all front-end renders, but QE only belongs on the live page. |
| 51 |
if (isEmbedded()) return; |
| 52 |
|
| 53 |
const hasTargets = |
| 54 |
document.querySelector( |
| 55 |
'[data-extendify-agent-block-id], [data-extendify-part-block-id]', |
| 56 |
) !== null; |
| 57 |
if (!hasTargets) return; |
| 58 |
|
| 59 |
// The wrapper class is the postcss-prefix-selector scope key (see |
| 60 |
// `quick-edit` in webpack.config.mjs filePrefixes). Tailwind's preflight + |
| 61 |
// utilities are all scoped to descendants of `div.extendify-quick-edit`. |
| 62 |
const host = document.createElement('div'); |
| 63 |
host.id = 'extendify-quick-edit-root'; |
| 64 |
host.className = 'extendify-quick-edit'; |
| 65 |
document.body.appendChild(host); |
| 66 |
|
| 67 |
if (typeof createRoot === 'function') { |
| 68 |
createRoot(host).render(<App />); |
| 69 |
} else { |
| 70 |
render(<App />, host); |
| 71 |
} |
| 72 |
|
| 73 |
bindAdminBarToggle(); |
| 74 |
|
| 75 |
// LinkControl outside our BlockEditorProvider (e.g. NavItemModal in a Modal |
| 76 |
// portal) needs the global core/block-editor settings hooked too. |
| 77 |
dispatch('core/block-editor')?.updateSettings({ |
| 78 |
__experimentalFetchLinkSuggestions: fetchLinkSuggestions, |
| 79 |
}); |
| 80 |
|
| 81 |
// Don't pay the hover/keyboard listener cost when edit mode is off. |
| 82 |
const getSession = () => !!useQuickEditStore.getState().selected; |
| 83 |
const apply = (on) => { |
| 84 |
if (on) { |
| 85 |
attachHoverBar(); |
| 86 |
attachKeyboardEntry({ getSession }); |
| 87 |
attachKeyboardUndo(); |
| 88 |
} else { |
| 89 |
detachKeyboardUndo(); |
| 90 |
detachKeyboardEntry(); |
| 91 |
detachHoverBar(); |
| 92 |
} |
| 93 |
}; |
| 94 |
apply(useEditModeStore.getState().on); |
| 95 |
useEditModeStore.subscribe((state) => apply(state.on)); |
| 96 |
|
| 97 |
wireGlobalEscape(); |
| 98 |
|
| 99 |
announcePostReload(); |
| 100 |
|
| 101 |
// Toolbar bundle (#3334) dispatches this event so it doesn't need to import our store. |
| 102 |
window.addEventListener('extendify-quick-edit:toggle', () => { |
| 103 |
useEditModeStore.getState().toggle(); |
| 104 |
}); |
| 105 |
}; |
| 106 |
|
| 107 |
domReady(mount); |
| 108 |
|