-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
Add an API to add a plugin sidebar (new) #4777
Changes from all commits
a69476e
f5586c9
26c088e
d221bd9
d31b21c
b69794b
1db6a05
3cdf86f
fbf1225
f30e950
380a125
cdfc5a6
872ddcc
271db7c
e116f96
6bed5f5
2388b60
c417b7e
0570733
29beb82
ab02dff
85d6ff1
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,4 @@ | ||
export { | ||
registerSidebar, | ||
activateSidebar, | ||
} from './sidebar'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
/* eslint no-console: [ 'error', { allow: [ 'error' ] } ] */ | ||
|
||
/* External dependencies */ | ||
import { isFunction } from 'lodash'; | ||
|
||
/* Internal dependencies */ | ||
import store from '../store'; | ||
import { setGeneralSidebarActivePanel, openGeneralSidebar } from '../store/actions'; | ||
import { applyFilters } from '@wordpress/hooks'; | ||
|
||
const sidebars = {}; | ||
|
||
/** | ||
* Registers a sidebar to the editor. | ||
* | ||
* A button will be shown in the settings menu to open the sidebar. The sidebar | ||
* can be manually opened by calling the `activateSidebar` function. | ||
* | ||
* @param {string} name The name of the sidebar. Should be in | ||
* `[plugin]/[sidebar]` format. | ||
* @param {Object} settings The settings for this sidebar. | ||
* @param {string} settings.title The name to show in the settings menu. | ||
* @param {Function} settings.render The function that renders the sidebar. | ||
* | ||
* @return {Object} The final sidebar settings object. | ||
*/ | ||
export function registerSidebar( name, settings ) { | ||
settings = { | ||
name, | ||
...settings, | ||
}; | ||
|
||
if ( typeof name !== 'string' ) { | ||
console.error( | ||
'Sidebar names must be strings.' | ||
); | ||
return null; | ||
} | ||
if ( ! /^[a-z][a-z0-9-]*\/[a-z][a-z0-9-]*$/.test( name ) ) { | ||
console.error( | ||
'Sidebar names must contain a namespace prefix, include only lowercase alphanumeric characters or dashes, and start with a letter. Example: my-plugin/my-custom-sidebar.' | ||
); | ||
return null; | ||
} | ||
if ( ! settings || ! isFunction( settings.render ) ) { | ||
console.error( | ||
'The "render" property must be specified and must be a valid function.' | ||
); | ||
return null; | ||
} | ||
if ( sidebars[ name ] ) { | ||
console.error( | ||
`Sidebar ${ name } is already registered.` | ||
); | ||
} | ||
|
||
if ( ! settings.title ) { | ||
console.error( | ||
`The sidebar ${ name } must have a title.` | ||
); | ||
return null; | ||
} | ||
if ( typeof settings.title !== 'string' ) { | ||
console.error( | ||
'Sidebar titles must be strings.' | ||
); | ||
return null; | ||
} | ||
|
||
settings = applyFilters( 'editor.registerSidebar', settings, name ); | ||
|
||
return sidebars[ name ] = settings; | ||
} | ||
|
||
/** | ||
* Retrieves the sidebar settings object. | ||
* | ||
* @param {string} name The name of the sidebar to retrieve the settings for. | ||
* | ||
* @return {Object} The settings object of the sidebar. Or null if the | ||
* sidebar doesn't exist. | ||
*/ | ||
export function getSidebarSettings( name ) { | ||
if ( ! sidebars.hasOwnProperty( name ) ) { | ||
return null; | ||
} | ||
return sidebars[ name ]; | ||
} | ||
/** | ||
* Activates the given sidebar. | ||
* | ||
* @param {string} name The name of the sidebar to activate. | ||
* @return {void} | ||
*/ | ||
export function activateSidebar( name ) { | ||
store.dispatch( openGeneralSidebar( 'plugin' ) ); | ||
store.dispatch( setGeneralSidebarActivePanel( 'plugin', name ) ); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import { connect } from 'react-redux'; | ||
|
||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { __ } from '@wordpress/i18n'; | ||
import { IconButton, withFocusReturn } from '@wordpress/components'; | ||
|
||
/** | ||
* Internal Dependencies | ||
*/ | ||
import './style.scss'; | ||
import { getSidebarSettings } from '../../api/sidebar'; | ||
import { getActivePlugin } from '../../store/selectors'; | ||
import { closeGeneralSidebar } from '../../store/actions'; | ||
|
||
function PluginsPanel( { onClose, plugin } ) { | ||
const pluginSidebar = getSidebarSettings( plugin ); | ||
|
||
if ( ! pluginSidebar ) { | ||
return null; | ||
} | ||
|
||
const { | ||
title, | ||
render, | ||
} = pluginSidebar; | ||
|
||
return ( | ||
<div | ||
className="edit-post-sidebar edit-post-plugins-panel" | ||
role="region" | ||
aria-label={ __( 'Editor plugins' ) } | ||
tabIndex="-1"> | ||
<div className="edit-post-plugins-panel__header"> | ||
<h3>{ title }</h3> | ||
<IconButton | ||
onClick={ onClose } | ||
icon="no-alt" | ||
label={ __( 'Close settings' ) } | ||
/> | ||
</div> | ||
<div className="edit-post-plugins-panel__content"> | ||
{ render() } | ||
</div> | ||
</div> | ||
); | ||
} | ||
|
||
export default connect( | ||
( state ) => { | ||
return { | ||
plugin: getActivePlugin( state ), | ||
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. It looks like this will always return null (and we will see the 'No matching plugin sidebar found for plugin ""'), because the store being queried here is not the store that contains the active ActiveEditorPanel preference.
|
||
}; | ||
}, { | ||
onClose: closeGeneralSidebar, | ||
}, | ||
undefined, | ||
{ storeKey: 'edit-post' } | ||
)( withFocusReturn( PluginsPanel ) ); |
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 think we have the same logic in
blocks.registerBlockType
. I'm afraid this needs to be further discussed. The thing is that it happens after validation process is done, so you can update all settings however you want and it won't be validated again. It seems like this should happen before the validation begins.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.
This will be addressed in a next iteration