diff --git a/packages/block-library/src/navigation-link/block-inserter.js b/packages/block-library/src/navigation-link/block-inserter.js new file mode 100644 index 00000000000000..704641c3801e6f --- /dev/null +++ b/packages/block-library/src/navigation-link/block-inserter.js @@ -0,0 +1,65 @@ +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; +import { useSelect } from '@wordpress/data'; +import { + store as blockEditorStore, + privateApis as blockEditorPrivateApis, +} from '@wordpress/block-editor'; + +/** + * Internal dependencies + */ +import DialogWrapper from './dialog-wrapper'; +import { unlock } from '../lock-unlock'; + +const { PrivateQuickInserter: QuickInserter } = unlock( + blockEditorPrivateApis +); + +/** + * Component for inserting blocks within the Navigation Link UI. + * + * @param {Object} props Component props. + * @param {string} props.clientId Client ID of the navigation link block. + * @param {Function} props.onBack Callback when user wants to go back. + * @param {Function} props.onBlockInsert Callback when a block is inserted. + */ +function LinkUIBlockInserter( { clientId, onBack, onBlockInsert } ) { + const { rootBlockClientId } = useSelect( + ( select ) => { + const { getBlockRootClientId } = select( blockEditorStore ); + + return { + rootBlockClientId: getBlockRootClientId( clientId ), + }; + }, + [ clientId ] + ); + + if ( ! clientId ) { + return null; + } + + return ( + + + + ); +} + +export default LinkUIBlockInserter; diff --git a/packages/block-library/src/navigation-link/dialog-wrapper.js b/packages/block-library/src/navigation-link/dialog-wrapper.js new file mode 100644 index 00000000000000..e37166a1dfc7c2 --- /dev/null +++ b/packages/block-library/src/navigation-link/dialog-wrapper.js @@ -0,0 +1,74 @@ +/** + * WordPress dependencies + */ +import { Button, VisuallyHidden } from '@wordpress/components'; +import { __, isRTL } from '@wordpress/i18n'; +import { chevronLeftSmall, chevronRightSmall } from '@wordpress/icons'; +import { useInstanceId, useFocusOnMount } from '@wordpress/compose'; + +/** + * Shared BackButton component for consistent navigation across LinkUI sub-components. + * + * @param {Object} props Component props. + * @param {string} props.className CSS class name for the button. + * @param {Function} props.onBack Callback when user wants to go back. + */ +function BackButton( { className, onBack } ) { + return ( + + ); +} + +/** + * Shared DialogWrapper component for consistent dialog structure across LinkUI sub-components. + * + * @param {Object} props Component props. + * @param {string} props.className CSS class name for the dialog container. + * @param {string} props.title Dialog title for accessibility. + * @param {string} props.description Dialog description for accessibility. + * @param {Function} props.onBack Callback when user wants to go back. + * @param {Object} props.children Child components to render inside the dialog. + */ +function DialogWrapper( { className, title, description, onBack, children } ) { + const dialogTitleId = useInstanceId( + DialogWrapper, + 'link-ui-dialog-title' + ); + const dialogDescriptionId = useInstanceId( + DialogWrapper, + 'link-ui-dialog-description' + ); + const focusOnMountRef = useFocusOnMount( 'firstElement' ); + const backButtonClassName = `${ className }__back`; + + return ( +
+ +

{ title }

+

{ description }

+
+ + + + { children } +
+ ); +} + +export default DialogWrapper; diff --git a/packages/block-library/src/navigation-link/link-ui.js b/packages/block-library/src/navigation-link/link-ui.js index eca905d399c34e..62a30186c5e716 100644 --- a/packages/block-library/src/navigation-link/link-ui.js +++ b/packages/block-library/src/navigation-link/link-ui.js @@ -8,13 +8,8 @@ import { VisuallyHidden, __experimentalVStack as VStack, } from '@wordpress/components'; -import { __, isRTL } from '@wordpress/i18n'; -import { - LinkControl, - store as blockEditorStore, - privateApis as blockEditorPrivateApis, - useBlockEditingMode, -} from '@wordpress/block-editor'; +import { __ } from '@wordpress/i18n'; +import { LinkControl, useBlockEditingMode } from '@wordpress/block-editor'; import { useMemo, useState, @@ -23,19 +18,14 @@ import { forwardRef, } from '@wordpress/element'; import { useResourcePermissions } from '@wordpress/core-data'; -import { useSelect } from '@wordpress/data'; -import { chevronLeftSmall, chevronRightSmall, plus } from '@wordpress/icons'; -import { useInstanceId, useFocusOnMount } from '@wordpress/compose'; +import { plus } from '@wordpress/icons'; +import { useInstanceId } from '@wordpress/compose'; /** * Internal dependencies */ -import { unlock } from '../lock-unlock'; import { LinkUIPageCreator } from './page-creator'; - -const { PrivateQuickInserter: QuickInserter } = unlock( - blockEditorPrivateApis -); +import LinkUIBlockInserter from './block-inserter'; /** * Given the Link block's type attribute, return the query params to give to @@ -75,74 +65,6 @@ export function getSuggestionsQuery( type, kind ) { } } -function LinkUIBlockInserter( { clientId, onBack, onBlockInsert } ) { - const { rootBlockClientId } = useSelect( - ( select ) => { - const { getBlockRootClientId } = select( blockEditorStore ); - - return { - rootBlockClientId: getBlockRootClientId( clientId ), - }; - }, - [ clientId ] - ); - - const focusOnMountRef = useFocusOnMount( 'firstElement' ); - - const dialogTitleId = useInstanceId( - LinkControl, - `link-ui-block-inserter__title` - ); - const dialogDescriptionId = useInstanceId( - LinkControl, - `link-ui-block-inserter__description` - ); - - if ( ! clientId ) { - return null; - } - - return ( -
- -

{ __( 'Add block' ) }

- -

- { __( 'Choose a block to add to your Navigation.' ) } -

-
- - - - -
- ); -} - function UnforwardedLinkUI( props, ref ) { const { label, url, opensInNewTab, type, kind } = props.link; const postType = type || 'page'; @@ -151,7 +73,7 @@ function UnforwardedLinkUI( props, ref ) { const [ addingPage, setAddingPage ] = useState( false ); const [ focusAddBlockButton, setFocusAddBlockButton ] = useState( false ); const [ focusAddPageButton, setFocusAddPageButton ] = useState( false ); - const permissions = useResourcePermissions( { + const { canCreate: canCreatePage } = useResourcePermissions( { kind: 'postType', name: postType, } ); @@ -176,11 +98,11 @@ function UnforwardedLinkUI( props, ref ) { const dialogTitleId = useInstanceId( LinkUI, - `link-ui-link-control__title` + 'link-ui-link-control__title' ); const dialogDescriptionId = useInstanceId( LinkUI, - `link-ui-link-control__description` + 'link-ui-link-control__description' ); const blockEditingMode = useBlockEditingMode(); @@ -233,8 +155,8 @@ function UnforwardedLinkUI( props, ref ) { setAddingPage( true ); setFocusAddPageButton( false ); } } - canCreatePage={ permissions.canCreate } blockEditingMode={ blockEditingMode } + canCreatePage={ canCreatePage } /> ) } diff --git a/packages/block-library/src/navigation-link/page-creator.js b/packages/block-library/src/navigation-link/page-creator.js index bb11be81732bdd..40701718649c5d 100644 --- a/packages/block-library/src/navigation-link/page-creator.js +++ b/packages/block-library/src/navigation-link/page-creator.js @@ -9,13 +9,16 @@ import { __experimentalVStack as VStack, __experimentalHStack as HStack, } from '@wordpress/components'; -import { __, isRTL } from '@wordpress/i18n'; +import { __ } from '@wordpress/i18n'; import { useSelect, useDispatch } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; import { decodeEntities } from '@wordpress/html-entities'; import { useState } from '@wordpress/element'; -import { chevronLeftSmall, chevronRightSmall } from '@wordpress/icons'; -import { useFocusOnMount } from '@wordpress/compose'; + +/** + * Internal dependencies + */ +import DialogWrapper from './dialog-wrapper'; /** * Component for creating new pages within the Navigation Link UI. @@ -35,9 +38,6 @@ export function LinkUIPageCreator( { const [ title, setTitle ] = useState( initialTitle ); const [ shouldPublish, setShouldPublish ] = useState( false ); - // Focus the first element when the component mounts - const focusOnMountRef = useFocusOnMount( 'firstElement' ); - // Check if the title is valid for submission const isTitleValid = title.trim().length > 0; @@ -95,19 +95,12 @@ export function LinkUIPageCreator( { const isSubmitDisabled = isSaving || ! isTitleValid; return ( -
- - +
@@ -159,6 +152,6 @@ export function LinkUIPageCreator( {
-
+ ); }