@gechiui/block-editor
Version:
179 lines (165 loc) • 6.35 kB
JavaScript
import _extends from "@babel/runtime/helpers/esm/extends";
import { createElement } from "@gechiui/element";
/**
* GeChiUI dependencies
*/
import { useMergeRefs, __experimentalUseFixedWindowList as useFixedWindowList } from '@gechiui/compose';
import { __experimentalTreeGrid as TreeGrid } from '@gechiui/components';
import { AsyncModeProvider, useDispatch, useSelect } from '@gechiui/data';
import { useCallback, useEffect, useMemo, useRef, useReducer, forwardRef } from '@gechiui/element';
import { __ } from '@gechiui/i18n';
/**
* Internal dependencies
*/
import ListViewBranch from './branch';
import { ListViewContext } from './context';
import ListViewDropIndicator from './drop-indicator';
import useListViewClientIds from './use-list-view-client-ids';
import useListViewDropZone from './use-list-view-drop-zone';
import { store as blockEditorStore } from '../../store';
const noop = () => {};
const expanded = (state, action) => {
switch (action.type) {
case 'expand':
return { ...state,
...{
[action.clientId]: true
}
};
case 'collapse':
return { ...state,
...{
[action.clientId]: false
}
};
default:
return state;
}
};
/**
* Wrap `ListViewRows` with `TreeGrid`. ListViewRows is a
* recursive component (it renders itself), so this ensures TreeGrid is only
* present at the very top of the navigation grid.
*
* @param {Object} props Components props.
* @param {Array} props.blocks Custom subset of block client IDs to be used instead of the default hierarchy.
* @param {Function} props.onSelect Block selection callback.
* @param {boolean} props.showNestedBlocks Flag to enable displaying nested blocks.
* @param {boolean} props.showBlockMovers Flag to enable block movers
* @param {boolean} props.__experimentalFeatures Flag to enable experimental features.
* @param {boolean} props.__experimentalPersistentListViewFeatures Flag to enable features for the Persistent List View experiment.
* @param {boolean} props.__experimentalHideContainerBlockActions Flag to hide actions of top level blocks (like core/widget-area)
* @param {Object} ref Forwarded ref
*/
function ListView(_ref, ref) {
let {
blocks,
onSelect = noop,
__experimentalFeatures,
__experimentalPersistentListViewFeatures,
__experimentalHideContainerBlockActions,
showNestedBlocks,
showBlockMovers,
...props
} = _ref;
const {
clientIdsTree,
draggedClientIds,
selectedClientIds
} = useListViewClientIds(blocks);
const {
selectBlock
} = useDispatch(blockEditorStore);
const {
visibleBlockCount
} = useSelect(select => {
const {
getGlobalBlockCount,
getClientIdsOfDescendants
} = select(blockEditorStore);
const draggedBlockCount = (draggedClientIds === null || draggedClientIds === void 0 ? void 0 : draggedClientIds.length) > 0 ? getClientIdsOfDescendants(draggedClientIds).length + 1 : 0;
return {
visibleBlockCount: getGlobalBlockCount() - draggedBlockCount
};
}, [draggedClientIds]);
const selectEditorBlock = useCallback(clientId => {
selectBlock(clientId);
onSelect(clientId);
}, [selectBlock, onSelect]);
const [expandedState, setExpandedState] = useReducer(expanded, {});
const {
ref: dropZoneRef,
target: blockDropTarget
} = useListViewDropZone();
const elementRef = useRef();
const treeGridRef = useMergeRefs([elementRef, dropZoneRef, ref]);
const isMounted = useRef(false);
useEffect(() => {
isMounted.current = true;
}, []); // List View renders a fixed number of items and relies on each having a fixed item height of 36px.
// If this value changes, we should also change the itemHeight value set in useFixedWindowList.
// See: https://github.com/GeChiUI/gutenberg/pull/35230 for additional context.
const [fixedListWindow] = useFixedWindowList(elementRef, 36, visibleBlockCount, {
useWindowing: __experimentalPersistentListViewFeatures,
windowOverscan: 40
});
const expand = useCallback(clientId => {
if (!clientId) {
return;
}
setExpandedState({
type: 'expand',
clientId
});
}, [setExpandedState]);
const collapse = useCallback(clientId => {
if (!clientId) {
return;
}
setExpandedState({
type: 'collapse',
clientId
});
}, [setExpandedState]);
const expandRow = useCallback(row => {
var _row$dataset;
expand(row === null || row === void 0 ? void 0 : (_row$dataset = row.dataset) === null || _row$dataset === void 0 ? void 0 : _row$dataset.block);
}, [expand]);
const collapseRow = useCallback(row => {
var _row$dataset2;
collapse(row === null || row === void 0 ? void 0 : (_row$dataset2 = row.dataset) === null || _row$dataset2 === void 0 ? void 0 : _row$dataset2.block);
}, [collapse]);
const contextValue = useMemo(() => ({
__experimentalFeatures,
__experimentalPersistentListViewFeatures,
__experimentalHideContainerBlockActions,
isTreeGridMounted: isMounted.current,
draggedClientIds,
expandedState,
expand,
collapse
}), [__experimentalFeatures, __experimentalPersistentListViewFeatures, __experimentalHideContainerBlockActions, isMounted.current, draggedClientIds, expandedState, expand, collapse]);
return createElement(AsyncModeProvider, {
value: true
}, createElement(ListViewDropIndicator, {
listViewRef: elementRef,
blockDropTarget: blockDropTarget
}), createElement(TreeGrid, {
className: "block-editor-list-view-tree",
"aria-label": __('区块导航结构'),
ref: treeGridRef,
onCollapseRow: collapseRow,
onExpandRow: expandRow
}, createElement(ListViewContext.Provider, {
value: contextValue
}, createElement(ListViewBranch, _extends({
blocks: clientIdsTree,
selectBlock: selectEditorBlock,
showNestedBlocks: showNestedBlocks,
showBlockMovers: showBlockMovers,
fixedListWindow: fixedListWindow,
selectedClientIds: selectedClientIds
}, props)))));
}
export default forwardRef(ListView);
//# sourceMappingURL=index.js.map