-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve guidance to editing template when focused on editing a page #51366
Changes from 7 commits
045df9e
11fb888
2f9cf3c
b5490df
0ad5f11
4d1cda0
9de65d5
1f946eb
734d914
7f633ca
f7ff0dc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { useSelect, useDispatch } from '@wordpress/data'; | ||
import { useEffect, useRef } from '@wordpress/element'; | ||
import { store as noticesStore } from '@wordpress/notices'; | ||
import { __ } from '@wordpress/i18n'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import { store as editSiteStore } from '../../store'; | ||
|
||
/** | ||
* Component that displays a 'You are editing a template' notification when the | ||
* user switches from focusing on editing page content to editing a template. | ||
*/ | ||
export default function BackToPageNotification() { | ||
useBackToPageNotification(); | ||
return null; | ||
} | ||
|
||
/** | ||
* Hook that displays a 'You are editing a template' notification when the user | ||
* switches from focusing on editing page content to editing a template. | ||
*/ | ||
export function useBackToPageNotification() { | ||
const hasPageContentFocus = useSelect( | ||
( select ) => select( editSiteStore ).hasPageContentFocus(), | ||
[] | ||
); | ||
|
||
const alreadySeen = useRef( false ); | ||
const prevHasPageContentFocus = useRef( false ); | ||
|
||
const { createInfoNotice } = useDispatch( noticesStore ); | ||
const { setHasPageContentFocus } = useDispatch( editSiteStore ); | ||
|
||
useEffect( () => { | ||
if ( | ||
! alreadySeen.current && | ||
prevHasPageContentFocus.current && | ||
! hasPageContentFocus | ||
) { | ||
createInfoNotice( __( 'You are editing a template' ), { | ||
isDismissible: true, | ||
type: 'snackbar', | ||
actions: [ | ||
{ | ||
label: __( 'Back to page' ), | ||
onClick: () => setHasPageContentFocus( true ), | ||
}, | ||
], | ||
} ); | ||
alreadySeen.current = true; | ||
} | ||
prevHasPageContentFocus.current = hasPageContentFocus; | ||
}, [ | ||
alreadySeen, | ||
prevHasPageContentFocus, | ||
hasPageContentFocus, | ||
createInfoNotice, | ||
setHasPageContentFocus, | ||
] ); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { useDispatch } from '@wordpress/data'; | ||
import { useEffect, useState } from '@wordpress/element'; | ||
import { __ } from '@wordpress/i18n'; | ||
import { __experimentalConfirmDialog as ConfirmDialog } from '@wordpress/components'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import { store as editSiteStore } from '../../store'; | ||
|
||
/** | ||
* Component that displays a 'Edit your template to edit this block' | ||
* notification when the user is focusing on editing page content and clicks on | ||
* a disabled template block. | ||
* | ||
* @param {Object} props | ||
* @param {import('react').RefObject<HTMLElement>} props.contentRef Ref to the block | ||
* editor iframe canvas. | ||
*/ | ||
export default function EditTemplateDialog( { contentRef } ) { | ||
const [ isOpen, setIsOpen ] = useState( false ); | ||
|
||
useEffect( () => { | ||
const handleDblClick = ( event ) => { | ||
if ( event.target.classList.contains( 'is-root-container' ) ) { | ||
setIsOpen( true ); | ||
} | ||
}; | ||
const canvas = contentRef.current; | ||
canvas?.addEventListener( 'dblclick', handleDblClick ); | ||
return () => canvas?.removeEventListener( 'dblclick', handleDblClick ); | ||
}, [ contentRef.current ] ); | ||
|
||
const { setHasPageContentFocus } = useDispatch( editSiteStore ); | ||
|
||
return ( | ||
<ConfirmDialog | ||
isOpen={ isOpen } | ||
confirmButtonText={ __( 'Edit template' ) } | ||
onConfirm={ () => { | ||
setIsOpen( false ); | ||
setHasPageContentFocus( false ); | ||
} } | ||
onCancel={ () => setIsOpen( false ) } | ||
> | ||
{ __( 'Edit your template to edit this block' ) } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tiny nit: for text within the dialog, should we end the sentence in a full-stop? Also, not a blocker (and wording can be tweaked in follow-ups), but since we have a modal, I was wondering if it's worth including more explanatory text in this one. E.g. something along the lines of, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will add the periods! 👍 Not 100% sure about changing the copy. Wdyt @SaxonF? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this sort of copy is indeed difficult. I'd be fine shipping as is and follow up with a copy pass. |
||
</ConfirmDialog> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { useSelect, useDispatch } from '@wordpress/data'; | ||
import { useEffect, useRef } from '@wordpress/element'; | ||
import { store as noticesStore } from '@wordpress/notices'; | ||
import { __ } from '@wordpress/i18n'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import { store as editSiteStore } from '../../store'; | ||
|
||
/** | ||
* Component that displays a 'Edit your template to edit this block' | ||
* notification when the user is focusing on editing page content and clicks on | ||
* a disabled template block. | ||
* | ||
* @param {Object} props | ||
* @param {import('react').RefObject<HTMLElement>} props.contentRef Ref to the block | ||
* editor iframe canvas. | ||
*/ | ||
noisysocks marked this conversation as resolved.
Show resolved
Hide resolved
|
||
export default function EditTemplateNotification( { contentRef } ) { | ||
useEditTemplateNotification( contentRef ); | ||
return null; | ||
} | ||
|
||
/** | ||
* Hook that displays a 'Edit your template to edit this block' notification | ||
* when the user is focusing on editing page content and clicks on a disabled | ||
* template block. | ||
* | ||
* @param {import('react').RefObject<HTMLElement>} contentRef Ref to the block | ||
* editor iframe canvas. | ||
*/ | ||
function useEditTemplateNotification( contentRef ) { | ||
const hasPageContentFocus = useSelect( | ||
( select ) => select( editSiteStore ).hasPageContentFocus(), | ||
[] | ||
); | ||
const { getNotices } = useSelect( noticesStore ); | ||
|
||
const { createInfoNotice } = useDispatch( noticesStore ); | ||
const { setHasPageContentFocus } = useDispatch( editSiteStore ); | ||
|
||
const lastNoticeId = useRef( 0 ); | ||
|
||
useEffect( () => { | ||
const handleClick = async ( event ) => { | ||
const isNoticeAlreadyShowing = getNotices().some( | ||
noisysocks marked this conversation as resolved.
Show resolved
Hide resolved
|
||
( notice ) => notice.id === lastNoticeId.current | ||
); | ||
if ( | ||
! isNoticeAlreadyShowing && | ||
hasPageContentFocus && | ||
event.target.classList.contains( 'is-root-container' ) | ||
) { | ||
const { notice } = await createInfoNotice( | ||
__( 'Edit your template to edit this block' ), | ||
{ | ||
isDismissible: true, | ||
type: 'snackbar', | ||
actions: [ | ||
{ | ||
label: __( 'Edit template' ), | ||
onClick: () => setHasPageContentFocus( false ), | ||
}, | ||
], | ||
} | ||
); | ||
lastNoticeId.current = notice.id; | ||
} | ||
}; | ||
const canvas = contentRef.current; | ||
canvas?.addEventListener( 'click', handleClick ); | ||
return () => canvas?.removeEventListener( 'click', handleClick ); | ||
}, [ lastNoticeId, hasPageContentFocus, contentRef.current ] ); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { useSelect } from '@wordpress/data'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import { store as editSiteStore } from '../../store'; | ||
import DisableNonPageContentBlocks from './disable-non-page-content-blocks'; | ||
import EditTemplateDialog from './edit-template-dialog'; | ||
import EditTemplateNotification from './edit-template-notification'; | ||
import BackToPageNotification from './back-to-page-notification'; | ||
|
||
export default function PageContentFocusManager( { contentRef } ) { | ||
const hasPageContentFocus = useSelect( | ||
( select ) => select( editSiteStore ).hasPageContentFocus(), | ||
[] | ||
); | ||
return ( | ||
<> | ||
{ hasPageContentFocus && ( | ||
<> | ||
<DisableNonPageContentBlocks /> | ||
<EditTemplateDialog contentRef={ contentRef } /> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. By putting the notification behind a timeout? Not sure how this could be done 😀 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No idea either, but the double notification isn't ideal. Not sure how to do it either without probably a refactor. Just noting it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah maybe we can dismiss the notification automatically when modal appears. I'd have to smoosh the components together though. I guess that's not so bad. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How's this? f7ff0dc There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice 👍 2023-06-19.14.26.06.mp4 |
||
</> | ||
) } | ||
<EditTemplateNotification contentRef={ contentRef } /> | ||
<BackToPageNotification /> | ||
</> | ||
); | ||
} |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: There's no need to add mutable values like refs as dependencies. When you provide them,
alreadySeen.current
ESLint shows a warning.