Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add hovered block store and show hovered template part's label in edit site header component. #25348

Closed
wants to merge 38 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
f3ed074
add basic store
Addison-Stavlo Sep 15, 2020
85dbaec
add mouseEnter/Leave on wrapper div for now...
Addison-Stavlo Sep 15, 2020
3b38bac
basic display name logic, ugly second header to see it
Addison-Stavlo Sep 15, 2020
f3cfa9c
remove ugly header and div wrapper
Addison-Stavlo Sep 21, 2020
b6bfe45
Merge branch 'master' into try/hovered-block-tracking
Addison-Stavlo Sep 21, 2020
ae3c8c6
add listener to wrapper ref, hovered label to new component
Addison-Stavlo Sep 21, 2020
d42d11f
remove added newline
Addison-Stavlo Sep 21, 2020
182c127
small refactor
Addison-Stavlo Sep 22, 2020
bf47233
rebase goo
Addison-Stavlo Sep 22, 2020
471453f
try setHoveredBlocks with elements under cursor
Addison-Stavlo Sep 22, 2020
de35a4f
use the getBlockDisplayText function
Addison-Stavlo Sep 22, 2020
db24e03
make useSelect destructuring consistent
Addison-Stavlo Sep 23, 2020
3706483
remove unused filter
Addison-Stavlo Sep 23, 2020
dd5a78d
name action type by standard convention
Addison-Stavlo Sep 23, 2020
5548826
refactor useSecondaryText to determine if hovered item should be active
Addison-Stavlo Sep 24, 2020
1db5151
check event timeStamp before evaluating
Addison-Stavlo Sep 24, 2020
5138c5e
add comment to timeStamp check
Addison-Stavlo Sep 24, 2020
6f3751e
add getHoveredBlockByBlockName selector
Addison-Stavlo Sep 25, 2020
292b262
don't pass an object to the dispatch
Addison-Stavlo Sep 25, 2020
0724f2c
add comment for parsing elements under cursor
Addison-Stavlo Sep 25, 2020
930052f
restrict event handlers to FSE experiment
Addison-Stavlo Sep 29, 2020
869dd4c
oops, restrict everything in the effect to FSE experiment
Addison-Stavlo Sep 29, 2020
4ff2b34
convert to __experimental labels + memoize selector
Addison-Stavlo Sep 29, 2020
74de248
hovered label comparison for active state by clientId
Addison-Stavlo Sep 29, 2020
0b2b810
limit reruns to 10ms bc firefox doesnt create timestamps right
Addison-Stavlo Sep 29, 2020
285b78e
create a new timeStamp after evaluation instead of using the event's …
Addison-Stavlo Sep 30, 2020
90f3c8e
update selector to return Id instead of block
Addison-Stavlo Oct 2, 2020
c85aed9
reduce lockout timer to what is necessary
Addison-Stavlo Oct 2, 2020
727f46b
nevermind that
Addison-Stavlo Oct 2, 2020
f1c267f
convert to early return and rid of unnecessary async func
Addison-Stavlo Oct 2, 2020
bcb7dac
Merge branch 'master' into try/hovered-block-tracking
Addison-Stavlo Oct 2, 2020
a732b05
compare previous mouse coords
Addison-Stavlo Oct 2, 2020
5742496
move hovered blocks functions to a separate file
Addison-Stavlo Oct 6, 2020
3a4dd91
update docs and comments
Addison-Stavlo Oct 6, 2020
16d496b
Merge branch 'master' into try/hovered-block-tracking
Addison-Stavlo Oct 8, 2020
da643e1
rebase and fix merge conflicts
Addison-Stavlo Oct 9, 2020
e41e82d
use debounce instead
Addison-Stavlo Nov 7, 2020
669b02f
Merge branch 'master' into try/hovered-block-tracking
Addison-Stavlo Nov 7, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import useMovingAnimation from '../use-moving-animation';
import { Context, SetBlockNodes } from './root-container';
import { BlockListBlockContext } from './block';
import ELEMENTS from './block-wrapper-elements';
import { evaluateHoveredBlocks } from './hovered-blocks';

/**
* This hook is used to lightly mark an element as a block element. The element
Expand Down Expand Up @@ -91,6 +92,7 @@ export function useBlockProps( props = {}, { __unstableIsHtml } = {} ) {
},
[ isSelected ]
);

const { insertDefaultBlock, removeBlock } = useDispatch(
'core/block-editor'
);
Expand Down Expand Up @@ -279,6 +281,22 @@ export function useBlockProps( props = {}, { __unstableIsHtml } = {} ) {
};
}, [ isNavigationMode, isHovered, setHovered ] );

useEffect( () => {
ref.current.addEventListener( 'mouseenter', evaluateHoveredBlocks );
ref.current.addEventListener( 'mouseleave', evaluateHoveredBlocks );

return () => {
ref.current.removeEventListener(
'mouseenter',
evaluateHoveredBlocks
);
ref.current.removeEventListener(
'mouseleave',
evaluateHoveredBlocks
);
};
}, [] );

const htmlSuffix = mode === 'html' && ! __unstableIsHtml ? '-visual' : '';

return {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* WordPress dependencies
*/
import { dispatch } from '@wordpress/data';

/**
* External dependencies
*/
import { debounce } from 'lodash';

/**
* Returns an array of block clientIds found under the cursor.
* Block clientIds are ordered from child to parent.
*
* @param {Object} event Mouse event object.
*
* @return {string[]} Array of block clientIds.
*/
export function getHoveredBlocksFromCursor( event ) {
const hoveredElements = document.elementsFromPoint(
event.clientX,
event.clientY
);
const blockIds = [];
hoveredElements.forEach( ( element ) => {
if ( element.dataset.block ) {
blockIds.push( element.dataset.block );
}
} );
return blockIds;
}

/**
* Conditionally evaluates and dispatches hovered block clientIds to the block-editor store.
*
* @param {Object} event Mouse event object.
*/
export const evaluateHoveredBlocks = debounce(
( event ) => {
// To accurately determine which blocks are hovered we must look at the elements under the cursor.
// Internal block inserters will fire events like mouseleave for blocks they are visually contained within,
// which makes an add/remove by clientId per individual block approach inaccurate.
const hoveredBlocks = getHoveredBlocksFromCursor( event );

dispatch( 'core/block-editor' ).__experimentalSetHoveredBlocks(
hoveredBlocks
);
},
// Debounce this on 20ms to ensure we do not unnecessarily evaluate and dispatch
// multiple times when this is called simultaneously from groups of nested blocks.
20,
// Apply a maxWait to ensure this still fires during lots of mouse movement.
{ maxWait: 50 }
);
12 changes: 12 additions & 0 deletions packages/block-editor/src/store/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -1104,3 +1104,15 @@ export function setHasControlledInnerBlocks(
clientId,
};
}

/**
* Returns an action object that sets clientIds for the hovered blocks.
*
* @param {string[]} hoveredBlockIds Array of block clientIds.
*/
export function __experimentalSetHoveredBlocks( hoveredBlockIds ) {
return {
type: 'SET_HOVERED_BLOCKS',
hoveredBlockIds,
};
}
18 changes: 18 additions & 0 deletions packages/block-editor/src/store/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -1645,6 +1645,23 @@ export function highlightedBlock( state, action ) {
return state;
}

/**
* Reducer returning hovered blocks state.
*
* @param {Object} state Current hovered blocks state.
* @param {Object} action Dispatched action.
*
* @return {Object} Updated state.
*/
export function hoveredBlocks( state = [], action ) {
switch ( action.type ) {
case 'SET_HOVERED_BLOCKS':
return action.hoveredBlockIds;
Addison-Stavlo marked this conversation as resolved.
Show resolved Hide resolved
}

return state;
}

export default combineReducers( {
blocks,
isTyping,
Expand All @@ -1666,4 +1683,5 @@ export default combineReducers( {
hasBlockMovingClientId,
automaticChangeStatus,
highlightedBlock,
hoveredBlocks,
noahtallen marked this conversation as resolved.
Show resolved Hide resolved
} );
31 changes: 30 additions & 1 deletion packages/block-editor/src/store/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -1806,7 +1806,36 @@ export function areInnerBlocksControlled( state, clientId ) {
}

/**
* Returns the clientId for the first 'active' block of a given array of block names.
* Returns an array of clientIds for hovered blocks set in full site editing.
* Block Ids set in FSE are ordered from child to parent.
noahtallen marked this conversation as resolved.
Show resolved Hide resolved
*
* @param {Object} state Global application state.
*
* @return {string[]} Array of clientIds for hovered blocks.
*/
export function __experimentalGetHoveredBlocks( state ) {
return state.hoveredBlocks;
}

/**
* Returns the clientId for the most interior hovered block of the given block name.
*
* @param {Object} state Global application state.
* @param {string} blockName Name of block type to return.
*
* @return {string} Parsed block object.
*/
export const __experimentalGetHoveredBlockIdByBlockName = createSelector(
( state, blockName ) => {
const matchingBlockClientId = state.hoveredBlocks.find(
( blockId ) => getBlockName( state, blockId ) === blockName
);
return matchingBlockClientId;
},
( state ) => [ state.hoveredBlocks ]
);

/** Returns the clientId for the first 'active' block of a given array of block names.
* A block is 'active' if it (or a child) is the selected block.
* Returns the first match moving up the DOM from the selected block.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,36 @@ function getBlockDisplayText( block ) {
}

function useSecondaryText() {
const { activeEntityBlockId, getBlock } = useSelect( ( select ) => {
const {
activeEntityBlockId,
getBlock,
hoveredTemplatePartBlockId,
} = useSelect( ( select ) => {
return {
activeEntityBlockId: select(
'core/block-editor'
).__experimentalGetActiveBlockIdByBlockNames( [
'core/template-part',
] ),
getBlock: select( 'core/block-editor' ).getBlock,
hoveredTemplatePartBlockId: select(
'core/block-editor'
).__experimentalGetHoveredBlockIdByBlockName(
'core/template-part'
),
};
} );

if ( hoveredTemplatePartBlockId ) {
const hoveredBlockLabel = getBlockDisplayText(
getBlock( hoveredTemplatePartBlockId )
);
return {
label: hoveredBlockLabel,
isActive: hoveredTemplatePartBlockId === activeEntityBlockId,
};
}

if ( activeEntityBlockId ) {
return {
label: getBlockDisplayText( getBlock( activeEntityBlockId ) ),
Expand Down