Skip to content
92 changes: 20 additions & 72 deletions packages/block-editor/src/components/block-inspector/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
__experimentalHStack as HStack,
__experimentalVStack as VStack,
Button,
__unstableMotion as motion,
} from '@wordpress/components';
import { useSelect, useDispatch } from '@wordpress/data';
import { useMemo, useCallback } from '@wordpress/element';
Expand All @@ -35,6 +34,7 @@ import { default as InspectorControls } from '../inspector-controls';
import { default as InspectorControlsTabs } from '../inspector-controls-tabs';
import useInspectorControlsTabs from '../inspector-controls-tabs/use-inspector-controls-tabs';
import AdvancedControls from '../inspector-controls-tabs/advanced-controls-panel';
import NavigationInspector from './navigation-inspector';

function useContentBlocks( blockTypes, block ) {
const contentBlocksObjectAux = useMemo( () => {
Expand Down Expand Up @@ -169,26 +169,11 @@ const BlockInspector = ( { showNoBlockSelectedMessage = true } ) => {
};
}, [] );

const availableTabs = useInspectorControlsTabs( blockType?.name );
const showTabs = availableTabs?.length > 1;

const isOffCanvasNavigationEditorEnabled =
window?.__experimentalEnableOffCanvasNavigationEditor === true;

const blockInspectorAnimationSettings = useSelect(
( select ) => {
if ( isOffCanvasNavigationEditorEnabled ) {
const globalBlockInspectorAnimationSettings =
select( blockEditorStore ).getSettings()
.__experimentalBlockInspectorAnimation;
return globalBlockInspectorAnimationSettings?.[
blockType.name
];
}
return null;
},
[ selectedBlockClientId, isOffCanvasNavigationEditorEnabled, blockType ]
);
const availableTabs = useInspectorControlsTabs( blockType?.name );
const showTabs = availableTabs?.length > 1;

if ( count > 1 ) {
return (
Expand Down Expand Up @@ -251,64 +236,26 @@ const BlockInspector = ( { showNoBlockSelectedMessage = true } ) => {
);
}

return (
<BlockInspectorSingleBlockWrapper
animate={
isOffCanvasNavigationEditorEnabled &&
blockInspectorAnimationSettings
}
wrapper={ ( children ) => (
<AnimatedContainer
blockInspectorAnimationSettings={
blockInspectorAnimationSettings
}
selectedBlockClientId={ selectedBlockClientId }
>
{ children }
</AnimatedContainer>
) }
>
<BlockInspectorSingleBlock
clientId={ selectedBlockClientId }
if (
isOffCanvasNavigationEditorEnabled &&
( blockType.name === 'core/navigation' ||
blockType.name === 'core/navigation-link' ||
blockType.name === 'core/navigation-submenu' )
) {
return (
<NavigationInspector
selectedBlockClientId={ selectedBlockClientId }
blockName={ blockType.name }
blockInspectorSingleBlock={ BlockInspectorSingleBlock }
/>
</BlockInspectorSingleBlockWrapper>
);
};

const BlockInspectorSingleBlockWrapper = ( { animate, wrapper, children } ) => {
return animate ? wrapper( children ) : children;
};

const AnimatedContainer = ( {
blockInspectorAnimationSettings,
selectedBlockClientId,
children,
} ) => {
const animationOrigin =
blockInspectorAnimationSettings &&
blockInspectorAnimationSettings.enterDirection === 'leftToRight'
? -50
: 50;
);
}

return (
<motion.div
animate={ {
x: 0,
opacity: 1,
transition: {
ease: 'easeInOut',
duration: 0.14,
},
} }
initial={ {
x: animationOrigin,
opacity: 0,
} }
key={ selectedBlockClientId }
>
{ children }
</motion.div>
<BlockInspectorSingleBlock
clientId={ selectedBlockClientId }
blockName={ blockType.name }
/>
);
};

Expand All @@ -324,6 +271,7 @@ const BlockInspectorSingleBlock = ( { clientId, blockName } ) => {
},
[ blockName ]
);

const blockInformation = useBlockDisplayInformation( clientId );

return (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
/**
* WordPress dependencies
*/
import {
__experimentalNavigatorProvider as NavigatorProvider,
__experimentalNavigatorScreen as NavigatorScreen,
__experimentalUseNavigator as useNavigator,
} from '@wordpress/components';
import { useSelect } from '@wordpress/data';
import { useEffect, useRef } from '@wordpress/element';

/**
* Internal dependencies
*/
import { store as blockEditorStore } from '../../store';

const NavigationInspector = ( {
selectedBlockClientId,
blockName,
blockInspectorSingleBlock,
} ) => {
const { parentNavBlock, childNavBlocks } = useSelect(
( select ) => {
const {
getBlockParentsByBlockName,
getClientIdsOfDescendants,
getBlock,
} = select( blockEditorStore );

let navBlockClientId;

if ( blockName === 'core/navigation' ) {
navBlockClientId = selectedBlockClientId;
} else if (
blockName === 'core/navigation-link' ||
blockName === 'core/navigation-submenu'
) {
navBlockClientId = getBlockParentsByBlockName(
selectedBlockClientId,
'core/navigation',
true
)[ 0 ];
}

const _childClientIds = getClientIdsOfDescendants( [
navBlockClientId,
] );

return {
parentNavBlock: getBlock( navBlockClientId ),
childNavBlocks: _childClientIds.map( ( id ) => {
return getBlock( id );
} ),
};
},
[ selectedBlockClientId, blockName ]
);

return (
<NavigatorProvider
initialPath={ selectedBlockClientId }
initialAnimationOverride="disableAnimation"
>
<NavigationInspectorScreens
selectedBlockClientId={ selectedBlockClientId }
parentNavBlock={ parentNavBlock }
childNavBlocks={ childNavBlocks }
blockInspectorSingleBlock={ blockInspectorSingleBlock }
/>
</NavigatorProvider>
);
};

const NavigationInspectorScreens = ( {
selectedBlockClientId,
parentNavBlock,
childNavBlocks,
blockInspectorSingleBlock: BlockInspectorSingleBlock,
} ) => {
const { goTo } = useNavigator();
const previousDepth = useRef( -1 );
const { navBlockTree } = useSelect(
( select ) => {
const { __unstableGetClientIdWithClientIdsTree } =
select( blockEditorStore );

return {
navBlockTree: __unstableGetClientIdWithClientIdsTree(
parentNavBlock.clientId
),
};
},
[ selectedBlockClientId ]
);

const getBlockDepth = ( targetClientId, currentDepth, rootBlock ) => {
if ( targetClientId === rootBlock.clientId ) {
return currentDepth;
}
for ( let i = 0; i < rootBlock.innerBlocks.length; i++ ) {
const newDepth = getBlockDepth(
targetClientId,
currentDepth + 1,
rootBlock.innerBlocks[ i ]
);
if ( newDepth > currentDepth ) {
return newDepth;
}
}
};

useEffect( () => {
const currentDepth = getBlockDepth(
selectedBlockClientId,
0,
navBlockTree
);
let animationOverride = 'disableAnimation';
if ( currentDepth === 0 && previousDepth.current > 0 ) {
animationOverride = 'forceForward';
} else if ( currentDepth > 0 && previousDepth.current === 0 ) {
animationOverride = 'forceBackward';
}
previousDepth.current = currentDepth;
goTo( selectedBlockClientId, {}, animationOverride );
}, [ selectedBlockClientId ] );

return (
<>
<NavigatorScreen path={ parentNavBlock.clientId }>
<BlockInspectorSingleBlock
clientId={ parentNavBlock.clientId }
blockName={ parentNavBlock.name }
/>
</NavigatorScreen>
{ childNavBlocks.map( ( childNavBlock ) => {
return (
<NavigatorScreen
path={ childNavBlock.clientId }
key={ childNavBlock.clientId }
>
<BlockInspectorSingleBlock
clientId={ childNavBlock.clientId }
blockName={ childNavBlock.name }
/>
</NavigatorScreen>
);
} ) }
</>
);
};

export default NavigationInspector;
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,13 @@ function UnconnectedNavigatorProvider(
props: WordPressComponentProps< NavigatorProviderProps, 'div' >,
forwardedRef: ForwardedRef< any >
) {
const { initialPath, children, className, ...otherProps } =
useContextSystem( props, 'NavigatorProvider' );
const {
initialPath,
initialAnimationOverride = null,
children,
className,
...otherProps
} = useContextSystem( props, 'NavigatorProvider' );

const [ locationHistory, setLocationHistory ] = useState<
NavigatorLocation[]
Expand All @@ -41,8 +46,13 @@ function UnconnectedNavigatorProvider(
},
] );

const [ animationOverride, setAnimationOverride ] = useState(
initialAnimationOverride
);

const goTo: NavigatorContextType[ 'goTo' ] = useCallback(
( path, options = {} ) => {
( path, options = {}, newAnimationOverride = null ) => {
setAnimationOverride( newAnimationOverride );
setLocationHistory( ( prevLocationHistory ) => [
...prevLocationHistory,
{
Expand Down Expand Up @@ -80,8 +90,9 @@ function UnconnectedNavigatorProvider(
},
goTo,
goBack,
animationOverride,
} ),
[ locationHistory, goTo, goBack ]
[ locationHistory, goTo, goBack, animationOverride ]
);

const cx = useCx();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ type Props = Omit<
keyof MotionProps
>;

type AnimationInitial = boolean | { opacity: number; x: number };

function UnconnectedNavigatorScreen(
props: Props,
forwardedRef: ForwardedRef< any >
Expand All @@ -54,7 +56,7 @@ function UnconnectedNavigatorScreen(
);

const prefersReducedMotion = useReducedMotion();
const { location } = useContext( NavigatorContext );
const { location, animationOverride } = useContext( NavigatorContext );
const isMatch = location.path === escapeAttribute( path );
const wrapperRef = useRef< HTMLDivElement >( null );

Expand Down Expand Up @@ -161,13 +163,28 @@ function UnconnectedNavigatorScreen(
},
x: 0,
};
const initial = {
let initial: AnimationInitial = {
opacity: 0,
x:
( isRTL() && location.isBack ) || ( ! isRTL() && ! location.isBack )
? 50
: -50,
};
if ( animationOverride ) {
switch ( animationOverride ) {
case 'forceForward':
initial.x = isRTL() ? 50 : -50;
break;

case 'forceBackward':
initial.x = isRTL() ? -50 : 50;
break;

case 'disableAnimation':
initial = false;
break;
}
}
const exit = {
delay: animationExitDelay,
opacity: 0,
Expand Down
Loading