-
Notifications
You must be signed in to change notification settings - Fork 4k
/
index.js
178 lines (169 loc) · 5.77 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/**
* External dependencies
*/
import classnames from 'classnames';
/**
* WordPress dependencies
*/
import { useContext } from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';
import {
__unstableGetBlockProps as getBlockProps,
getBlockType,
} from '@wordpress/blocks';
import { useMergeRefs, useDisabled } from '@wordpress/compose';
import { useSelect } from '@wordpress/data';
import warning from '@wordpress/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 { useBlockRefProvider } from './use-block-refs';
import { useIntersectionObserver } from './use-intersection-observer';
import { useBlockScreenReaderDescription } from './use-block-screen-reader-description';
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
* @param {boolean} options.__unstableIsDisabled Whether the block should be disabled.
*
* @return {Object} Props to pass to the element to mark as a block.
*/
export function useBlockProps(
props = {},
{ __unstableIsHtml, __unstableIsDisabled = false } = {}
) {
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?.apiVersion || 1,
blockTitle: 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( __( 'Block: %s' ), blockTitle );
const htmlSuffix = mode === 'html' && ! __unstableIsHtml ? '-visual' : '';
const mergedRefs = useMergeRefs( [
props.ref,
useFocusFirstElement( clientId ),
useBlockRefProvider( clientId ),
useFocusHandler( clientId ),
useEventHandlers( clientId ),
useNavModeExit( clientId ),
useIsHovered(),
useIntersectionObserver(),
useMovingAnimation( {
isSelected: isPartOfSelection,
adjustScrolling,
enableAnimation,
triggerAnimationOnChange: index,
} ),
useDisabled( { isDisabled: ! __unstableIsDisabled } ),
] );
const blockEditContext = useBlockEditContext();
// Ensures it warns only inside the `edit` implementation for the block.
if ( blockApiVersion < 2 && clientId === blockEditContext.clientId ) {
warning(
`Block type "${ name }" must support API version 2 or higher to work correctly with "useBlockProps" method.`
);
}
return {
...wrapperProps,
...props,
ref: mergedRefs,
id: `block-${ clientId }${ htmlSuffix }`,
tabIndex: 0,
role: 'document',
'aria-label': blockLabel,
'aria-description': useBlockScreenReaderDescription( clientId ),
'data-block': clientId,
'data-type': name,
'data-title': blockTitle,
className: classnames(
// The wp-block className is important for editor styles.
classnames( 'block-editor-block-list__block', {
'wp-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;