UNPKG

@wordpress/block-editor

Version:
213 lines (176 loc) 5.65 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _element = require("@wordpress/element"); var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _i18n = require("@wordpress/i18n"); var _compose = require("@wordpress/compose"); var _components = require("@wordpress/components"); /** * WordPress dependencies */ const BODY_CLASS_NAME = 'editor-styles-wrapper'; const BLOCK_PREFIX = 'wp-block'; /** * Clones stylesheets targetting the editor canvas to the given document. A * stylesheet is considered targetting the editor a canvas if it contains the * `editor-styles-wrapper`, `wp-block`, or `wp-block-*` class selectors. * * Ideally, this hook should be removed in the future and styles should be added * explicitly as editor styles. * * @param {Document} doc The document to append cloned stylesheets to. */ function styleSheetsCompat(doc) { // Search the document for stylesheets targetting the editor canvas. Array.from(document.styleSheets).forEach(styleSheet => { try { // May fail for external styles. // eslint-disable-next-line no-unused-expressions styleSheet.cssRules; } catch (e) { return; } const { ownerNode, cssRules } = styleSheet; if (!cssRules) { return; } const isMatch = Array.from(cssRules).find(({ selectorText }) => selectorText && (selectorText.includes(`.${BODY_CLASS_NAME}`) || selectorText.includes(`.${BLOCK_PREFIX}`))); if (isMatch && !doc.getElementById(ownerNode.id)) { doc.head.appendChild(ownerNode.cloneNode(true)); } }); } /** * Bubbles some event types (keydown, keypress, and dragover) to parent document * document to ensure that the keyboard shortcuts and drag and drop work. * * Ideally, we should remove event bubbling in the future. Keyboard shortcuts * should be context dependent, e.g. actions on blocks like Cmd+A should not * work globally outside the block editor. * * @param {Document} doc Document to attach listeners to. */ function bubbleEvents(doc) { const { defaultView } = doc; const { frameElement } = defaultView; function bubbleEvent(event) { const prototype = Object.getPrototypeOf(event); const constructorName = prototype.constructor.name; const Constructor = window[constructorName]; const init = {}; for (const key in event) { init[key] = event[key]; } if (event instanceof defaultView.MouseEvent) { const rect = frameElement.getBoundingClientRect(); init.clientX += rect.left; init.clientY += rect.top; } const newEvent = new Constructor(event.type, init); const cancelled = !frameElement.dispatchEvent(newEvent); if (cancelled) { event.preventDefault(); } } const eventTypes = ['keydown', 'keypress', 'dragover']; for (const name of eventTypes) { doc.addEventListener(name, bubbleEvent); } } /** * Sets the document direction. * * Sets the `editor-styles-wrapper` class name on the body. * * Copies the `admin-color-*` class name to the body so that the admin color * scheme applies to components in the iframe. * * @param {Document} doc Document to add class name to. */ function setBodyClassName(doc) { doc.dir = document.dir; doc.body.className = BODY_CLASS_NAME; for (const name of document.body.classList) { if (name.startsWith('admin-color-')) { doc.body.classList.add(name); } } } /** * Sets the document head and default styles. * * @param {Document} doc Document to set the head for. * @param {string} head HTML to set as the head. */ function setHead(doc, head) { doc.head.innerHTML = // Body margin must be overridable by themes. '<style>body{margin:0}</style>' + head; } function Iframe({ contentRef, children, head, headHTML, ...props }, ref) { const [iframeDocument, setIframeDocument] = (0, _element.useState)(); const setRef = (0, _element.useCallback)(node => { if (!node) { return; } function setDocumentIfReady() { const { contentDocument } = node; const { readyState, body } = contentDocument; if (readyState !== 'interactive' && readyState !== 'complete') { return false; } if (typeof contentRef === 'function') { contentRef(body); } else if (contentRef) { contentRef.current = body; } setHead(contentDocument, headHTML); setBodyClassName(contentDocument); styleSheetsCompat(contentDocument); bubbleEvents(contentDocument); setBodyClassName(contentDocument); setIframeDocument(contentDocument); return true; } if (setDocumentIfReady()) { return; } // Document is not immediately loaded in Firefox. node.addEventListener('load', () => { setDocumentIfReady(); }); }, []); return (0, _element.createElement)("iframe", (0, _extends2.default)({}, props, { ref: (0, _compose.useMergeRefs)([ref, setRef]), tabIndex: "0", title: (0, _i18n.__)('Editor canvas'), name: "editor-canvas" }), iframeDocument && (0, _element.createPortal)((0, _element.createElement)(_components.__experimentalStyleProvider, { document: iframeDocument }, children), iframeDocument.body), iframeDocument && (0, _element.createPortal)(head, iframeDocument.head)); } var _default = (0, _element.forwardRef)(Iframe); exports.default = _default; //# sourceMappingURL=index.js.map