Skip to content

Commit

Permalink
Improve PostURL terminology and accessibility (WordPress#63669)
Browse files Browse the repository at this point in the history
* Improve PostURL terminology and accessibility.

* Restore createInterpolateElement after rebase.

* Remove value truncation after PR 64053.

* Replace term URL with Permalink.

* Reduce post url intro text top margin.

Co-authored-by: afercia <afercia@git.wordpress.org>
Co-authored-by: joedolson <joedolson@git.wordpress.org>
Co-authored-by: richtabor <richtabor@git.wordpress.org>
Co-authored-by: annezazu <annezazu@git.wordpress.org>
Co-authored-by: t-hamano <wildworks@git.wordpress.org>
  • Loading branch information
6 people authored and karthick-murugan committed Nov 13, 2024
1 parent 213a39c commit bec03e0
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 91 deletions.
122 changes: 67 additions & 55 deletions packages/editor/src/components/post-url/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
import { store as noticesStore } from '@wordpress/notices';
import { copySmall } from '@wordpress/icons';
import { store as coreStore } from '@wordpress/core-data';
import { useCopyToClipboard } from '@wordpress/compose';
import { useCopyToClipboard, useInstanceId } from '@wordpress/compose';

/**
* Internal dependencies
Expand Down Expand Up @@ -70,25 +70,29 @@ export default function PostURL( { onClose } ) {
const { createNotice } = useDispatch( noticesStore );
const [ forceEmptyField, setForceEmptyField ] = useState( false );
const copyButtonRef = useCopyToClipboard( permalink, () => {
createNotice( 'info', __( 'Copied URL to clipboard.' ), {
createNotice( 'info', __( 'Copied Permalink to clipboard.' ), {
isDismissible: true,
type: 'snackbar',
} );
} );
const postUrlSlugDescriptionId =
'editor-post-url__slug-descriotion-' + useInstanceId( PostURL );

return (
<div className="editor-post-url">
<InspectorPopoverHeader
title={ __( 'Link' ) }
title={ __( 'Slug' ) }
onClose={ onClose }
/>
<VStack spacing={ 3 }>
{ isEditable && (
<div>
<p className="editor-post-url__intro">
{ createInterpolateElement(
__(
'Customize the last part of the URL. <a>Learn more.</a>'
'<span>Customize the last part of the Permalink.</span> <a>Learn more.</a>'
),
{
span: <span id={ postUrlSlugDescriptionId } />,
a: (
<ExternalLink
href={ __(
Expand All @@ -98,59 +102,67 @@ export default function PostURL( { onClose } ) {
),
}
) }
</div>
</p>
) }
<div>
{ isEditable && (
<InputControl
__next40pxDefaultSize
prefix={
<InputControlPrefixWrapper>
/
</InputControlPrefixWrapper>
}
suffix={
<InputControlSuffixWrapper variant="control">
<Button
icon={ copySmall }
ref={ copyButtonRef }
size="small"
label="Copy"
/>
</InputControlSuffixWrapper>
}
label={ __( 'Link' ) }
hideLabelFromVision
value={ forceEmptyField ? '' : postSlug }
autoComplete="off"
spellCheck="false"
type="text"
className="editor-post-url__input"
onChange={ ( newValue ) => {
editPost( { slug: newValue } );
// When we delete the field the permalink gets
// reverted to the original value.
// The forceEmptyField logic allows the user to have
// the field temporarily empty while typing.
if ( ! newValue ) {
if ( ! forceEmptyField ) {
setForceEmptyField( true );
}
return;
<>
<InputControl
__next40pxDefaultSize
prefix={
<InputControlPrefixWrapper>
/
</InputControlPrefixWrapper>
}
if ( forceEmptyField ) {
setForceEmptyField( false );
suffix={
<InputControlSuffixWrapper variant="control">
<Button
icon={ copySmall }
ref={ copyButtonRef }
size="small"
label="Copy"
/>
</InputControlSuffixWrapper>
}
} }
onBlur={ ( event ) => {
editPost( {
slug: cleanForSlug( event.target.value ),
} );
if ( forceEmptyField ) {
setForceEmptyField( false );
}
} }
help={
label={ __( 'Slug' ) }
hideLabelFromVision
value={ forceEmptyField ? '' : postSlug }
autoComplete="off"
spellCheck="false"
type="text"
className="editor-post-url__input"
onChange={ ( newValue ) => {
editPost( { slug: newValue } );
// When we delete the field the permalink gets
// reverted to the original value.
// The forceEmptyField logic allows the user to have
// the field temporarily empty while typing.
if ( ! newValue ) {
if ( ! forceEmptyField ) {
setForceEmptyField( true );
}
return;
}
if ( forceEmptyField ) {
setForceEmptyField( false );
}
} }
onBlur={ ( event ) => {
editPost( {
slug: cleanForSlug(
event.target.value
),
} );
if ( forceEmptyField ) {
setForceEmptyField( false );
}
} }
aria-describedby={ postUrlSlugDescriptionId }
/>
<p className="editor-post-url__permalink">
<span className="editor-post-url__permalink-visual-label">
{ __( 'Permalink:' ) }
</span>
<ExternalLink
className="editor-post-url__link"
href={ postLink }
Expand All @@ -166,8 +178,8 @@ export default function PostURL( { onClose } ) {
{ permalinkSuffix }
</span>
</ExternalLink>
}
/>
</p>
</>
) }
{ ! isEditable && (
<ExternalLink
Expand Down
90 changes: 57 additions & 33 deletions packages/editor/src/components/post-url/panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,7 @@
*/
import { useMemo, useState } from '@wordpress/element';
import { useSelect } from '@wordpress/data';
import {
Dropdown,
Button,
__experimentalTruncate as Truncate,
} from '@wordpress/components';
import { Dropdown, Button, ExternalLink } from '@wordpress/components';
import { __, sprintf } from '@wordpress/i18n';
import { safeDecodeURIComponent } from '@wordpress/url';
import { store as coreStore } from '@wordpress/core-data';
Expand All @@ -26,6 +22,20 @@ import { store as editorStore } from '../../store';
* @return {JSX.Element} The rendered PostURLPanel component.
*/
export default function PostURLPanel() {
const { isFrontPage } = useSelect( ( select ) => {
const { getCurrentPostId } = select( editorStore );
const { getEditedEntityRecord, canUser } = select( coreStore );
const siteSettings = canUser( 'read', {
kind: 'root',
name: 'site',
} )
? getEditedEntityRecord( 'root', 'site' )
: undefined;
const _id = getCurrentPostId();
return {
isFrontPage: siteSettings?.page_on_front === _id,
};
}, [] );
// Use internal state instead of a ref to make sure that the component
// re-renders when the popover's anchor updates.
const [ popoverAnchor, setPopoverAnchor ] = useState( null );
Expand All @@ -42,41 +52,38 @@ export default function PostURLPanel() {
[ popoverAnchor ]
);

const label = isFrontPage ? __( 'Link' ) : __( 'Slug' );

return (
<PostURLCheck>
<PostPanelRow label={ __( 'Link' ) } ref={ setPopoverAnchor }>
<Dropdown
popoverProps={ popoverProps }
className="editor-post-url__panel-dropdown"
contentClassName="editor-post-url__panel-dialog"
focusOnMount
renderToggle={ ( { isOpen, onToggle } ) => (
<PostURLToggle isOpen={ isOpen } onClick={ onToggle } />
) }
renderContent={ ( { onClose } ) => (
<PostURL onClose={ onClose } />
) }
/>
<PostPanelRow label={ label } ref={ setPopoverAnchor }>
{ ! isFrontPage && (
<Dropdown
popoverProps={ popoverProps }
className="editor-post-url__panel-dropdown"
contentClassName="editor-post-url__panel-dialog"
focusOnMount
renderToggle={ ( { isOpen, onToggle } ) => (
<PostURLToggle
isOpen={ isOpen }
onClick={ onToggle }
/>
) }
renderContent={ ( { onClose } ) => (
<PostURL onClose={ onClose } />
) }
/>
) }
{ isFrontPage && <FrontPageLink /> }
</PostPanelRow>
</PostURLCheck>
);
}

function PostURLToggle( { isOpen, onClick } ) {
const { slug, isFrontPage, postLink } = useSelect( ( select ) => {
const { getCurrentPostId, getCurrentPost } = select( editorStore );
const { getEditedEntityRecord, canUser } = select( coreStore );
const siteSettings = canUser( 'read', {
kind: 'root',
name: 'site',
} )
? getEditedEntityRecord( 'root', 'site' )
: undefined;
const _id = getCurrentPostId();
const { slug } = useSelect( ( select ) => {
return {
slug: select( editorStore ).getEditedPostSlug(),
isFrontPage: siteSettings?.page_on_front === _id,
postLink: getCurrentPost()?.link,
};
}, [] );
const decodedSlug = safeDecodeURIComponent( slug );
Expand All @@ -90,9 +97,26 @@ function PostURLToggle( { isOpen, onClick } ) {
aria-label={ sprintf( __( 'Change link: %s' ), decodedSlug ) }
onClick={ onClick }
>
<Truncate numberOfLines={ 1 }>
{ isFrontPage ? postLink : `/${ decodedSlug }` }
</Truncate>
<>{ decodedSlug }</>
</Button>
);
}

function FrontPageLink() {
const { postLink } = useSelect( ( select ) => {
const { getCurrentPost } = select( editorStore );
return {
postLink: getCurrentPost()?.link,
};
}, [] );

return (
<ExternalLink
className="editor-post-url__front-page-link"
href={ postLink }
target="_blank"
>
{ postLink }
</ExternalLink>
);
}
24 changes: 21 additions & 3 deletions packages/editor/src/components/post-url/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,19 @@
}

/* rtl:begin:ignore */
.editor-post-url__link {
.editor-post-url__link,
.editor-post-url__front-page-link {
direction: ltr;
word-break: break-word;
margin-top: $grid-unit-05;
color: $gray-700;
}
/* rtl:end:ignore */

.editor-post-url__front-page-link {
// Match padding on tertiary buttons for alignment.
padding: $grid-unit-15 * 0.5 0 $grid-unit-15 * 0.5 $grid-unit-15;
}


.editor-post-url__link-slug {
font-weight: 600;
}
Expand All @@ -30,3 +35,16 @@
.editor-post-url__panel-toggle {
word-break: break-word;
}

.editor-post-url__intro {
margin: 0;
}

.editor-post-url__permalink {
margin-top: $grid-unit-10;
margin-bottom: 0;

&-visual-label {
display: block;
}
}

0 comments on commit bec03e0

Please sign in to comment.