@gechiui/block-editor
Version:
148 lines (140 loc) • 6.14 kB
JavaScript
/**
* External dependencies
*/
import classnames from 'classnames';
/**
* GeChiUI dependencies
*/
import { useContext } from '@gechiui/element';
import { __, sprintf } from '@gechiui/i18n';
import { __unstableGetBlockProps as getBlockProps, getBlockType } from '@gechiui/blocks';
import { useMergeRefs } from '@gechiui/compose';
import { useSelect } from '@gechiui/data';
import warning from '@gechiui/warning';
/**
* Internal dependencies
*/
import useMovingAnimation from '../../use-moving-animation';
import { BlockListBlockContext } from '../block';
import { useFocusFirstElement } from './use-focus-first-element';
import { useIsHovered } from './use-is-hovered';
import { useBlockEditContext } from '../../block-edit/context';
import { useBlockClassNames } from './use-block-class-names';
import { useBlockDefaultClassName } from './use-block-default-class-name';
import { useBlockCustomClassName } from './use-block-custom-class-name';
import { useBlockMovingModeClassNames } from './use-block-moving-mode-class-names';
import { useFocusHandler } from './use-focus-handler';
import { useEventHandlers } from './use-selected-block-event-handlers';
import { useNavModeExit } from './use-nav-mode-exit';
import { useScrollIntoView } from './use-scroll-into-view';
import { useBlockRefProvider } from './use-block-refs';
import { useMultiSelection } from './use-multi-selection';
import { useIntersectionObserver } from './use-intersection-observer';
import { store as blockEditorStore } from '../../../store';
/**
* If the block count exceeds the threshold, we disable the reordering animation
* to avoid laginess.
*/
const BLOCK_ANIMATION_THRESHOLD = 200;
/**
* This hook is used to lightly mark an element as a block element. The element
* should be the outermost element of a block. Call this hook and pass the
* returned props to the element to mark as a block. If you define a ref for the
* element, it is important to pass the ref to this hook, which the hook in turn
* will pass to the component through the props it returns. Optionally, you can
* also pass any other props through this hook, and they will be merged and
* returned.
*
* @param {Object} props Optional. Props to pass to the element. Must contain
* the ref if one is defined.
* @param {Object} options Options for internal use only.
* @param {boolean} options.__unstableIsHtml
*
* @return {Object} Props to pass to the element to mark as a block.
*/
export function useBlockProps() {
let props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
let {
__unstableIsHtml
} = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
const {
clientId,
className,
wrapperProps = {},
isAligned
} = useContext(BlockListBlockContext);
const {
index,
mode,
name,
blockApiVersion,
blockTitle,
isPartOfSelection,
adjustScrolling,
enableAnimation
} = useSelect(select => {
const {
getBlockIndex,
getBlockMode,
getBlockName,
isTyping,
getGlobalBlockCount,
isBlockSelected,
isBlockMultiSelected,
isAncestorMultiSelected,
isFirstMultiSelectedBlock
} = select(blockEditorStore);
const isSelected = isBlockSelected(clientId);
const isPartOfMultiSelection = isBlockMultiSelected(clientId) || isAncestorMultiSelected(clientId);
const blockName = getBlockName(clientId);
const blockType = getBlockType(blockName);
return {
index: getBlockIndex(clientId),
mode: getBlockMode(clientId),
name: blockName,
blockApiVersion: (blockType === null || blockType === void 0 ? void 0 : blockType.apiVersion) || 1,
blockTitle: blockType === null || blockType === void 0 ? void 0 : blockType.title,
isPartOfSelection: isSelected || isPartOfMultiSelection,
adjustScrolling: isSelected || isFirstMultiSelectedBlock(clientId),
enableAnimation: !isTyping() && getGlobalBlockCount() <= BLOCK_ANIMATION_THRESHOLD
};
}, [clientId]); // translators: %s: Type of block (i.e. Text, Image etc)
const blockLabel = sprintf(__('区块:%s'), blockTitle);
const htmlSuffix = mode === 'html' && !__unstableIsHtml ? '-visual' : '';
const mergedRefs = useMergeRefs([props.ref, useFocusFirstElement(clientId), // Must happen after focus because we check for focus in the block.
useScrollIntoView(clientId), useBlockRefProvider(clientId), useFocusHandler(clientId), useMultiSelection(clientId), useEventHandlers(clientId), useNavModeExit(clientId), useIsHovered(), useIntersectionObserver(), useMovingAnimation({
isSelected: isPartOfSelection,
adjustScrolling,
enableAnimation,
triggerAnimationOnChange: index
})]);
const blockEditContext = useBlockEditContext(); // Ensures it warns only inside the `edit` implementation for the block.
if (blockApiVersion < 2 && clientId === blockEditContext.clientId) {
typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" ? warning(`Block type "${name}" must support API version 2 or higher to work correctly with "useBlockProps" method.`) : void 0;
}
return { ...wrapperProps,
...props,
ref: mergedRefs,
id: `block-${clientId}${htmlSuffix}`,
tabIndex: 0,
role: 'document',
'aria-label': blockLabel,
'data-block': clientId,
'data-type': name,
'data-title': blockTitle,
className: classnames( // The gc-block className is important for editor styles.
classnames('block-editor-block-list__block', {
'gc-block': !isAligned
}), className, props.className, wrapperProps.className, useBlockClassNames(clientId), useBlockDefaultClassName(clientId), useBlockCustomClassName(clientId), useBlockMovingModeClassNames(clientId)),
style: { ...wrapperProps.style,
...props.style
}
};
}
/**
* Call within a save function to get the props for the block wrapper.
*
* @param {Object} props Optional. Props to pass to the element.
*/
useBlockProps.save = getBlockProps;
//# sourceMappingURL=index.js.map