-
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
Enhance: Added Dialog Wrapper for EntitiesSavedStatesExtensible
#67352
Changes from 3 commits
fca00ad
8c4caa5
d977929
0db9b84
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 |
---|---|---|
|
@@ -8,10 +8,6 @@ import { | |
useRef, | ||
createInterpolateElement, | ||
} from '@wordpress/element'; | ||
import { | ||
__experimentalUseDialog as useDialog, | ||
useInstanceId, | ||
} from '@wordpress/compose'; | ||
import { useDispatch } from '@wordpress/data'; | ||
|
||
/** | ||
|
@@ -29,23 +25,15 @@ function identity( values ) { | |
/** | ||
* Renders the component for managing saved states of entities. | ||
* | ||
* @param {Object} props The component props. | ||
* @param {Function} props.close The function to close the dialog. | ||
* @param {Function} props.renderDialog The function to render the dialog. | ||
* @param {Object} props The component props. | ||
* @param {Function} props.close The function to close the dialog. | ||
* | ||
* @return {JSX.Element} The rendered component. | ||
*/ | ||
export default function EntitiesSavedStates( { | ||
close, | ||
renderDialog = undefined, | ||
} ) { | ||
export default function EntitiesSavedStates( { close } ) { | ||
const isDirtyProps = useIsDirty(); | ||
return ( | ||
<EntitiesSavedStatesExtensible | ||
close={ close } | ||
renderDialog={ renderDialog } | ||
{ ...isDirtyProps } | ||
/> | ||
<EntitiesSavedStatesExtensible close={ close } { ...isDirtyProps } /> | ||
); | ||
} | ||
|
||
|
@@ -58,7 +46,6 @@ export default function EntitiesSavedStates( { | |
* @param {Function} props.onSave Function to call when saving entities. | ||
* @param {boolean} props.saveEnabled Flag indicating if save is enabled. | ||
* @param {string} props.saveLabel Label for the save button. | ||
* @param {Function} props.renderDialog Function to render a custom dialog. | ||
* @param {Array} props.dirtyEntityRecords Array of dirty entity records. | ||
* @param {boolean} props.isDirty Flag indicating if there are dirty entities. | ||
* @param {Function} props.setUnselectedEntities Function to set unselected entities. | ||
|
@@ -72,7 +59,6 @@ export function EntitiesSavedStatesExtensible( { | |
onSave = identity, | ||
saveEnabled: saveEnabledProp = undefined, | ||
saveLabel = __( 'Save' ), | ||
renderDialog = undefined, | ||
dirtyEntityRecords, | ||
isDirty, | ||
setUnselectedEntities, | ||
|
@@ -109,24 +95,8 @@ export function EntitiesSavedStatesExtensible( { | |
// its own will use the event object in place of the expected saved entities. | ||
const dismissPanel = useCallback( () => close(), [ close ] ); | ||
|
||
const [ saveDialogRef, saveDialogProps ] = useDialog( { | ||
onClose: () => dismissPanel(), | ||
} ); | ||
const dialogLabel = useInstanceId( EntitiesSavedStatesExtensible, 'label' ); | ||
const dialogDescription = useInstanceId( | ||
EntitiesSavedStatesExtensible, | ||
'description' | ||
); | ||
|
||
return ( | ||
<div | ||
ref={ saveDialogRef } | ||
{ ...saveDialogProps } | ||
className="entities-saved-states__panel" | ||
role={ renderDialog ? 'dialog' : undefined } | ||
aria-labelledby={ renderDialog ? dialogLabel : undefined } | ||
aria-describedby={ renderDialog ? dialogDescription : undefined } | ||
> | ||
<div className="entities-saved-states__panel"> | ||
<Flex className="entities-saved-states__panel-header" gap={ 2 }> | ||
<FlexItem | ||
isBlock | ||
|
@@ -160,16 +130,13 @@ export function EntitiesSavedStatesExtensible( { | |
</Flex> | ||
|
||
<div className="entities-saved-states__text-prompt"> | ||
<div | ||
className="entities-saved-states__text-prompt--header-wrapper" | ||
id={ renderDialog ? dialogLabel : undefined } | ||
> | ||
<div className="entities-saved-states__text-prompt--header-wrapper"> | ||
<strong className="entities-saved-states__text-prompt--header"> | ||
{ __( 'Are you ready to save?' ) } | ||
</strong> | ||
{ additionalPrompt } | ||
</div> | ||
<p id={ renderDialog ? dialogDescription : undefined }> | ||
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. removing this id will make the dialog aria-describedby fail |
||
<p> | ||
{ isDirty | ||
? createInterpolateElement( | ||
sprintf( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,11 +5,17 @@ import { useSelect, useDispatch } from '@wordpress/data'; | |
import { Button, createSlotFill } from '@wordpress/components'; | ||
import { __ } from '@wordpress/i18n'; | ||
import { useCallback } from '@wordpress/element'; | ||
import { | ||
__experimentalUseDialog as useDialog, | ||
useInstanceId, | ||
} from '@wordpress/compose'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import EntitiesSavedStates from '../entities-saved-states'; | ||
import EntitiesSavedStates, { | ||
EntitiesSavedStatesExtensible, | ||
} from '../entities-saved-states'; | ||
import PostPublishPanel from '../post-publish-panel'; | ||
import PluginPrePublishPanel from '../plugin-pre-publish-panel'; | ||
import PluginPostPublishPanel from '../plugin-post-publish-panel'; | ||
|
@@ -102,10 +108,47 @@ export default function SavePublishPanels( { | |
return ( | ||
<> | ||
{ isEntitiesSavedStatesOpen && ( | ||
<EntitiesSavedStates close={ closeEntitiesSavedStates } /> | ||
<EntitieDialogWrapper close={ closeEntitiesSavedStates }> | ||
<EntitiesSavedStates close={ closeEntitiesSavedStates } /> | ||
</EntitieDialogWrapper> | ||
) } | ||
<Slot bubblesVirtually /> | ||
{ ! isEntitiesSavedStatesOpen && unmountableContent } | ||
</> | ||
); | ||
} | ||
|
||
/** | ||
* A wrapper component that renders a dialog for displaying entities. | ||
* | ||
* @param {Object} props The component's props. | ||
* @param {React.ReactNode} props.children The content to be displayed inside the dialog. | ||
* @param {Function} props.close A function to close the dialog. | ||
* | ||
* @return {React.Element} The rendered dialog element with children. | ||
*/ | ||
export function EntitieDialogWrapper( { children, close } ) { | ||
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 new wrapper should be used in other palces as well, for example for the save panel in the theme preview, see 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. The name of the component should make clear it is meant as a wrapper for 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. Noted. I only worked on save panel as If it was acceptable solution then probably can add to theme preview aswell. |
||
const dismissPanel = useCallback( () => close(), [ close ] ); | ||
const [ saveDialogRef, saveDialogProps ] = useDialog( { | ||
onClose: () => dismissPanel(), | ||
} ); | ||
|
||
const dialogLabel = useInstanceId( EntitiesSavedStatesExtensible, 'label' ); | ||
const dialogDescription = useInstanceId( | ||
EntitiesSavedStatesExtensible, | ||
'description' | ||
); | ||
|
||
return ( | ||
<div | ||
ref={ saveDialogRef } | ||
{ ...saveDialogProps } | ||
role="dialog" | ||
aria-labelledby={ dialogLabel } | ||
aria-describedby={ dialogDescription } | ||
> | ||
{ ' ' } | ||
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. Why this empty space? 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. seems to be added by |
||
{ children } | ||
</div> | ||
); | ||
} |
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.
removing this id will make the dialog labeling fail
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.
I was thinking that might be the case, Might have to look into an alternate way to pass down Ids maybe?
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.
yes but I would argue that given we need to pass down the unique ID, how this would be better than using the current approach that passed down the
renderDialog
prop? The only difference would be that the logic is abstracted in a wrapper component but I'm not sure that would be a substantial improvement code-wise.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.
True, but looking at the original code, it seems that the aria tags were missing anyway. I’m not entirely sure how much impact the aria tags would have, but we could consider #67351
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.
True, they were missing because the
renderDialog
prop was not passe down correctly. Looking at the original PR that introduced thie behavior #59622, the intent is to make all 'Save panels' behave like a sort of modal dialog and use theuseDialog
props and also the IDs for aria-labelledby and aria-describedby.