UNPKG

@wordpress/block-editor

Version:
162 lines (151 loc) 5.13 kB
import { createElement } from "@wordpress/element"; /** * External dependencies */ import classnames from 'classnames'; /** * WordPress dependencies */ import { AsyncModeProvider, useSelect, useDispatch, useRegistry } from '@wordpress/data'; import { useViewportMatch, useMergeRefs, useDebounce } from '@wordpress/compose'; import { createContext, useState, useMemo, useCallback } from '@wordpress/element'; /** * Internal dependencies */ import BlockListBlock from './block'; import BlockListAppender from '../block-list-appender'; import { useInBetweenInserter } from './use-in-between-inserter'; import { store as blockEditorStore } from '../../store'; import { usePreParsePatterns } from '../../utils/pre-parse-patterns'; import { LayoutProvider, defaultLayout } from './layout'; import BlockToolsBackCompat from '../block-tools/back-compat'; import { useBlockSelectionClearer } from '../block-selection-clearer'; import { useInnerBlocksProps } from '../inner-blocks'; import { BlockEditContextProvider, DEFAULT_BLOCK_EDIT_CONTEXT } from '../block-edit/context'; const elementContext = createContext(); export const IntersectionObserver = createContext(); const pendingBlockVisibilityUpdatesPerRegistry = new WeakMap(); function Root({ className, ...settings }) { const [element, setElement] = useState(); const isLargeViewport = useViewportMatch('medium'); const { isOutlineMode, isFocusMode, editorMode } = useSelect(select => { const { getSettings, __unstableGetEditorMode } = select(blockEditorStore); const { outlineMode, focusMode } = getSettings(); return { isOutlineMode: outlineMode, isFocusMode: focusMode, editorMode: __unstableGetEditorMode() }; }, []); const registry = useRegistry(); const { setBlockVisibility } = useDispatch(blockEditorStore); const delayedBlockVisibilityUpdates = useDebounce(useCallback(() => { const updates = {}; pendingBlockVisibilityUpdatesPerRegistry.get(registry).forEach(([id, isIntersecting]) => { updates[id] = isIntersecting; }); setBlockVisibility(updates); }, [registry]), 300, { trailing: true }); const intersectionObserver = useMemo(() => { const { IntersectionObserver: Observer } = window; if (!Observer) { return; } return new Observer(entries => { if (!pendingBlockVisibilityUpdatesPerRegistry.get(registry)) { pendingBlockVisibilityUpdatesPerRegistry.set(registry, []); } for (const entry of entries) { const clientId = entry.target.getAttribute('data-block'); pendingBlockVisibilityUpdatesPerRegistry.get(registry).push([clientId, entry.isIntersecting]); } delayedBlockVisibilityUpdates(); }); }, []); const innerBlocksProps = useInnerBlocksProps({ ref: useMergeRefs([useBlockSelectionClearer(), useInBetweenInserter(), setElement]), className: classnames('is-root-container', className, { 'is-outline-mode': isOutlineMode, 'is-focus-mode': isFocusMode && isLargeViewport, 'is-navigate-mode': editorMode === 'navigation' }) }, settings); return createElement(elementContext.Provider, { value: element }, createElement(IntersectionObserver.Provider, { value: intersectionObserver }, createElement("div", innerBlocksProps))); } export default function BlockList(settings) { usePreParsePatterns(); return createElement(BlockToolsBackCompat, null, createElement(BlockEditContextProvider, { value: DEFAULT_BLOCK_EDIT_CONTEXT }, createElement(Root, settings))); } BlockList.__unstableElementContext = elementContext; function Items({ placeholder, rootClientId, renderAppender, __experimentalAppenderTagName, __experimentalLayout: layout = defaultLayout }) { const { order, selectedBlocks, visibleBlocks } = useSelect(select => { const { getBlockOrder, getSelectedBlockClientIds, __unstableGetVisibleBlocks } = select(blockEditorStore); return { order: getBlockOrder(rootClientId), selectedBlocks: getSelectedBlockClientIds(), visibleBlocks: __unstableGetVisibleBlocks() }; }, [rootClientId]); return createElement(LayoutProvider, { value: layout }, order.map(clientId => createElement(AsyncModeProvider, { key: clientId, value: // Only provide data asynchronously if the block is // not visible and not selected. !visibleBlocks.has(clientId) && !selectedBlocks.includes(clientId) }, createElement(BlockListBlock, { rootClientId: rootClientId, clientId: clientId }))), order.length < 1 && placeholder, createElement(BlockListAppender, { tagName: __experimentalAppenderTagName, rootClientId: rootClientId, renderAppender: renderAppender })); } export function BlockListItems(props) { // This component needs to always be synchronous as it's the one changing // the async mode depending on the block selection. return createElement(AsyncModeProvider, { value: false }, createElement(Items, props)); } //# sourceMappingURL=index.js.map