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 (
-
-
-
+
-
+
);
}