Skip to content

Commit

Permalink
Design tweaks to Post Visibility popover (#40530)
Browse files Browse the repository at this point in the history
* Adjust copy and margins

* Fix mobile styling

* Simplify CSS

* Add close button

* Use hooks

* Adjust colors and margins to look more like mockup

* Anchor visibility popover to middle of entire row
  • Loading branch information
noisysocks authored Apr 28, 2022
1 parent f2124de commit 057bc30
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 229 deletions.
14 changes: 12 additions & 2 deletions packages/edit-post/src/components/sidebar/post-visibility/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ import {
PostVisibilityLabel,
PostVisibilityCheck,
} from '@wordpress/editor';
import { useRef } from '@wordpress/element';

export function PostVisibility() {
const rowRef = useRef();
return (
<PostVisibilityCheck
render={ ( { canEdit } ) => (
<PanelRow className="edit-post-post-visibility">
<PanelRow ref={ rowRef } className="edit-post-post-visibility">
<span>{ __( 'Visibility' ) }</span>
{ ! canEdit && (
<span>
Expand All @@ -24,6 +26,12 @@ export function PostVisibility() {
<Dropdown
position="bottom left"
contentClassName="edit-post-post-visibility__dialog"
popoverProps={ {
// Anchor the popover to the middle of the
// entire row so that it doesn't move around
// when the label changes.
anchorRef: rowRef.current,
} }
renderToggle={ ( { isOpen, onToggle } ) => (
<Button
aria-expanded={ isOpen }
Expand All @@ -34,7 +42,9 @@ export function PostVisibility() {
<PostVisibilityLabel />
</Button>
) }
renderContent={ () => <PostVisibilityForm /> }
renderContent={ ( { onClose } ) => (
<PostVisibilityForm onClose={ onClose } />
) }
/>
) }
</PanelRow>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,34 +9,6 @@
}

.edit-post-post-visibility__dialog .components-popover__content {
@include break-medium {
// 279px (sidebar width) - 20px (padding) - 2px (horizontal borders)
width: 257px;
}
}

.edit-post-post-visibility__dialog-legend {
font-weight: 600;
}

.edit-post-post-visibility__choice {
margin: 10px 0;
}

.edit-post-post-visibility__dialog-radio,
.edit-post-post-visibility__dialog-label {
vertical-align: top;
}

.edit-post-post-visibility__dialog-password-input {
width: calc(100% - 20px);
margin-left: 20px;
}

.edit-post-post-visibility__dialog-info {
color: $gray-700;
padding-left: 20px;
font-style: italic;
margin: 4px 0 0;
line-height: 1.4;
// sidebar width - padding - horizontal borders
width: $sidebar-width - $grid-unit-20 - $border-width * 2;
}
280 changes: 130 additions & 150 deletions packages/editor/src/components/post-visibility/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,186 +2,166 @@
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { Component } from '@wordpress/element';
import { useState } from '@wordpress/element';
import {
VisuallyHidden,
__experimentalConfirmDialog as ConfirmDialog,
Button,
} from '@wordpress/components';
import { withInstanceId, compose } from '@wordpress/compose';
import { withSelect, withDispatch } from '@wordpress/data';
import { useInstanceId } from '@wordpress/compose';
import { useSelect, useDispatch } from '@wordpress/data';
import { close as closeIcon } from '@wordpress/icons';

/**
* Internal dependencies
*/
import { visibilityOptions } from './utils';
import { store as editorStore } from '../../store';

export class PostVisibility extends Component {
constructor( props ) {
super( ...arguments );
export default function PostVisibility( { onClose } ) {
const instanceId = useInstanceId( PostVisibility );

this.setPublic = this.setPublic.bind( this );
this.setPrivate = this.setPrivate.bind( this );
this.setPasswordProtected = this.setPasswordProtected.bind( this );
this.updatePassword = this.updatePassword.bind( this );
const { status, visibility, password } = useSelect( ( select ) => ( {
status: select( editorStore ).getEditedPostAttribute( 'status' ),
visibility: select( editorStore ).getEditedPostVisibility(),
password: select( editorStore ).getEditedPostAttribute( 'password' ),
} ) );

this.state = {
hasPassword: !! props.password,
showPrivateConfirmDialog: false,
};
}
const { editPost, savePost } = useDispatch( editorStore );

setPublic() {
const { visibility, onUpdateVisibility, status } = this.props;
const [ hasPassword, setHasPassword ] = useState( !! password );
const [ showPrivateConfirmDialog, setShowPrivateConfirmDialog ] = useState(
false
);

onUpdateVisibility( visibility === 'private' ? 'draft' : status );
this.setState( { hasPassword: false } );
}

setPrivate() {
this.setState( { showPrivateConfirmDialog: true } );
}

confirmPrivate = () => {
const { onUpdateVisibility, onSave } = this.props;

onUpdateVisibility( 'private' );
this.setState( {
hasPassword: false,
showPrivateConfirmDialog: false,
const setPublic = () => {
editPost( {
status: visibility === 'private' ? 'draft' : status,
password: '',
} );
onSave();
setHasPassword( false );
};

handleDialogCancel = () => {
this.setState( { showPrivateConfirmDialog: false } );
const setPrivate = () => {
setShowPrivateConfirmDialog( true );
};

setPasswordProtected() {
const { visibility, onUpdateVisibility, status, password } = this.props;

onUpdateVisibility(
visibility === 'private' ? 'draft' : status,
password || ''
);
this.setState( { hasPassword: true } );
}
const confirmPrivate = () => {
editPost( { status: 'private', password: '' } );
setHasPassword( false );
setShowPrivateConfirmDialog( false );
savePost();
};

updatePassword( event ) {
const { status, onUpdateVisibility } = this.props;
onUpdateVisibility( status, event.target.value );
}
const handleDialogCancel = () => {
setShowPrivateConfirmDialog( false );
};

render() {
const { visibility, password, instanceId } = this.props;
const setPasswordProtected = () => {
editPost( {
status: visibility === 'private' ? 'draft' : status,
password: password || '',
} );
setHasPassword( true );
};

const visibilityHandlers = {
public: {
onSelect: this.setPublic,
checked: visibility === 'public' && ! this.state.hasPassword,
},
private: {
onSelect: this.setPrivate,
checked: visibility === 'private',
},
password: {
onSelect: this.setPasswordProtected,
checked: this.state.hasPassword,
},
};
const updatePassword = ( event ) => {
editPost( { password: event.target.value } );
};

return [
<fieldset
key="visibility-selector"
className="editor-post-visibility__dialog-fieldset"
>
<legend className="editor-post-visibility__dialog-legend">
{ __( 'Post Visibility' ) }
return (
<>
<Button
className="editor-post-visibility__close"
isSmall
icon={ closeIcon }
onClick={ onClose }
/>
<fieldset className="editor-post-visibility__fieldset">
<legend className="editor-post-visibility__legend">
{ __( 'Visibility' ) }
</legend>
{ visibilityOptions.map( ( { value, label, info } ) => (
<div
key={ value }
className="editor-post-visibility__choice"
>
<p className="editor-post-visibility__description">
{ __( 'Control how this post is viewed.' ) }
</p>
<PostVisibilityChoice
instanceId={ instanceId }
value="public"
label={ visibilityOptions.public.label }
info={ visibilityOptions.public.info }
checked={ visibility === 'public' && ! hasPassword }
onChange={ setPublic }
/>
<PostVisibilityChoice
instanceId={ instanceId }
value="private"
label={ visibilityOptions.private.label }
info={ visibilityOptions.private.info }
checked={ visibility === 'private' }
onChange={ setPrivate }
/>
<PostVisibilityChoice
instanceId={ instanceId }
value="password"
label={ visibilityOptions.password.label }
info={ visibilityOptions.password.info }
checked={ hasPassword }
onChange={ setPasswordProtected }
/>
{ hasPassword && (
<div className="editor-post-visibility__password">
<VisuallyHidden
as="label"
htmlFor={ `editor-post-visibility__password-input-${ instanceId }` }
>
{ __( 'Create password' ) }
</VisuallyHidden>
<input
type="radio"
name={ `editor-post-visibility__setting-${ instanceId }` }
value={ value }
onChange={ visibilityHandlers[ value ].onSelect }
checked={ visibilityHandlers[ value ].checked }
id={ `editor-post-${ value }-${ instanceId }` }
aria-describedby={ `editor-post-${ value }-${ instanceId }-description` }
className="editor-post-visibility__dialog-radio"
className="editor-post-visibility__password-input"
id={ `editor-post-visibility__password-input-${ instanceId }` }
type="text"
onChange={ updatePassword }
value={ password }
placeholder={ __( 'Use a secure password' ) }
/>
<label
htmlFor={ `editor-post-${ value }-${ instanceId }` }
className="editor-post-visibility__dialog-label"
>
{ label }
</label>
{
<p
id={ `editor-post-${ value }-${ instanceId }-description` }
className="editor-post-visibility__dialog-info"
>
{ info }
</p>
}
</div>
) ) }
</fieldset>,
this.state.hasPassword && (
<div
className="editor-post-visibility__dialog-password"
key="password-selector"
>
<VisuallyHidden
as="label"
htmlFor={ `editor-post-visibility__dialog-password-input-${ instanceId }` }
>
{ __( 'Create password' ) }
</VisuallyHidden>
<input
className="editor-post-visibility__dialog-password-input"
id={ `editor-post-visibility__dialog-password-input-${ instanceId }` }
type="text"
onChange={ this.updatePassword }
value={ password }
placeholder={ __( 'Use a secure password' ) }
/>
</div>
),
) }
</fieldset>
<ConfirmDialog
key="private-publish-confirmation"
isOpen={ this.state.showPrivateConfirmDialog }
onConfirm={ this.confirmPrivate }
onCancel={ this.handleDialogCancel }
isOpen={ showPrivateConfirmDialog }
onConfirm={ confirmPrivate }
onCancel={ handleDialogCancel }
>
{ __( 'Would you like to privately publish this post now?' ) }
</ConfirmDialog>,
];
}
</ConfirmDialog>
</>
);
}

export default compose( [
withSelect( ( select ) => {
const { getEditedPostAttribute, getEditedPostVisibility } = select(
editorStore
);
return {
status: getEditedPostAttribute( 'status' ),
visibility: getEditedPostVisibility(),
password: getEditedPostAttribute( 'password' ),
};
} ),
withDispatch( ( dispatch ) => {
const { savePost, editPost } = dispatch( editorStore );
return {
onSave: savePost,
onUpdateVisibility( status, password = '' ) {
editPost( { status, password } );
},
};
} ),
withInstanceId,
] )( PostVisibility );
function PostVisibilityChoice( { instanceId, value, label, info, ...props } ) {
return (
<div className="editor-post-visibility__choice">
<input
type="radio"
name={ `editor-post-visibility__setting-${ instanceId }` }
value={ value }
id={ `editor-post-${ value }-${ instanceId }` }
aria-describedby={ `editor-post-${ value }-${ instanceId }-description` }
className="editor-post-visibility__radio"
{ ...props }
/>
<label
htmlFor={ `editor-post-${ value }-${ instanceId }` }
className="editor-post-visibility__label"
>
{ label }
</label>
<p
id={ `editor-post-${ value }-${ instanceId }-description` }
className="editor-post-visibility__info"
>
{ info }
</p>
</div>
);
}
Loading

0 comments on commit 057bc30

Please sign in to comment.