@wordpress/block-editor
Version:
162 lines (151 loc) • 5.13 kB
JavaScript
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