From 1a1a9a03ee72eb309738175c4046faa4135cf9ab Mon Sep 17 00:00:00 2001 From: Addison Stavlo Date: Thu, 9 Sep 2021 07:46:50 -0400 Subject: [PATCH] Site Editor - add basic plugin support (#34460) * add sidebar and menu items * add general sidebar actions * remove unnecessary props * Update packages/edit-site/src/components/header/plugin-more-menu-item/index.js --- .../header/plugin-more-menu-item/index.js | 71 ++++++++++++++++ .../plugin-sidebar-more-menu-item/index.js | 64 +++++++++++++++ .../sidebar/plugin-sidebar/index.js | 80 +++++++++++++++++++ packages/edit-site/src/index.js | 3 + packages/edit-site/src/store/actions.js | 29 +++++++ 5 files changed, 247 insertions(+) create mode 100644 packages/edit-site/src/components/header/plugin-more-menu-item/index.js create mode 100644 packages/edit-site/src/components/header/plugin-sidebar-more-menu-item/index.js create mode 100644 packages/edit-site/src/components/sidebar/plugin-sidebar/index.js diff --git a/packages/edit-site/src/components/header/plugin-more-menu-item/index.js b/packages/edit-site/src/components/header/plugin-more-menu-item/index.js new file mode 100644 index 0000000000000..1c9707074f90f --- /dev/null +++ b/packages/edit-site/src/components/header/plugin-more-menu-item/index.js @@ -0,0 +1,71 @@ +/** + * WordPress dependencies + */ +import { ActionItem } from '@wordpress/interface'; +import { compose } from '@wordpress/compose'; +import { withPluginContext } from '@wordpress/plugins'; + +/** + * Renders a menu item in `Plugins` group in `More Menu` drop down, and can be used to as a button or link depending on the props provided. + * The text within the component appears as the menu item label. + * + * @param {Object} props Component properties. + * @param {string} [props.href] When `href` is provided then the menu item is represented as an anchor rather than button. It corresponds to the `href` attribute of the anchor. + * @param {WPBlockTypeIconRender} [props.icon=inherits from the plugin] The [Dashicon](https://developer.wordpress.org/resource/dashicons/) icon slug string, or an SVG WP element, to be rendered to the left of the menu item label. + * @param {Function} [props.onClick=noop] The callback function to be executed when the user clicks the menu item. + * @param {...*} [props.other] Any additional props are passed through to the underlying [Button](/packages/components/src/button/README.md) component. + * + * @example + * ```js + * // Using ES5 syntax + * var __ = wp.i18n.__; + * var PluginMoreMenuItem = wp.editSite.PluginMoreMenuItem; + * var moreIcon = wp.element.createElement( 'svg' ); //... svg element. + * + * function onButtonClick() { + * alert( 'Button clicked.' ); + * } + * + * function MyButtonMoreMenuItem() { + * return wp.element.createElement( + * PluginMoreMenuItem, + * { + * icon: moreIcon, + * onClick: onButtonClick, + * }, + * __( 'My button title' ) + * ); + * } + * ``` + * + * @example + * ```jsx + * // Using ESNext syntax + * import { __ } from '@wordpress/i18n'; + * import { PluginMoreMenuItem } from '@wordpress/edit-site'; + * import { more } from '@wordpress/icons'; + * + * function onButtonClick() { + * alert( 'Button clicked.' ); + * } + * + * const MyButtonMoreMenuItem = () => ( + * + * { __( 'My button title' ) } + * + * ); + * ``` + * + * @return {WPComponent} The component to be rendered. + */ +export default compose( + withPluginContext( ( context, ownProps ) => { + return { + icon: ownProps.icon || context.icon, + name: 'core/edit-site/plugin-more-menu', + }; + } ) +)( ActionItem ); diff --git a/packages/edit-site/src/components/header/plugin-sidebar-more-menu-item/index.js b/packages/edit-site/src/components/header/plugin-sidebar-more-menu-item/index.js new file mode 100644 index 0000000000000..3b9bbd9288142 --- /dev/null +++ b/packages/edit-site/src/components/header/plugin-sidebar-more-menu-item/index.js @@ -0,0 +1,64 @@ +/** + * WordPress dependencies + */ +import { ComplementaryAreaMoreMenuItem } from '@wordpress/interface'; + +/** + * Renders a menu item in `Plugins` group in `More Menu` drop down, + * and can be used to activate the corresponding `PluginSidebar` component. + * The text within the component appears as the menu item label. + * + * @param {Object} props Component props. + * @param {string} props.target A string identifying the target sidebar you wish to be activated by this menu item. Must be the same as the `name` prop you have given to that sidebar. + * @param {WPBlockTypeIconRender} [props.icon=inherits from the plugin] The [Dashicon](https://developer.wordpress.org/resource/dashicons/) icon slug string, or an SVG WP element, to be rendered to the left of the menu item label. + * + * @example + * ```js + * // Using ES5 syntax + * var __ = wp.i18n.__; + * var PluginSidebarMoreMenuItem = wp.editSite.PluginSidebarMoreMenuItem; + * var moreIcon = wp.element.createElement( 'svg' ); //... svg element. + * + * function MySidebarMoreMenuItem() { + * return wp.element.createElement( + * PluginSidebarMoreMenuItem, + * { + * target: 'my-sidebar', + * icon: moreIcon, + * }, + * __( 'My sidebar title' ) + * ) + * } + * ``` + * + * @example + * ```jsx + * // Using ESNext syntax + * import { __ } from '@wordpress/i18n'; + * import { PluginSidebarMoreMenuItem } from '@wordpress/edit-site'; + * import { more } from '@wordpress/icons'; + * + * const MySidebarMoreMenuItem = () => ( + * + * { __( 'My sidebar title' ) } + * + * ); + * ``` + * + * @return {WPComponent} The component to be rendered. + */ + +export default function PluginSidebarMoreMenuItem( props ) { + return ( + + ); +} diff --git a/packages/edit-site/src/components/sidebar/plugin-sidebar/index.js b/packages/edit-site/src/components/sidebar/plugin-sidebar/index.js new file mode 100644 index 0000000000000..c6d88a53b014b --- /dev/null +++ b/packages/edit-site/src/components/sidebar/plugin-sidebar/index.js @@ -0,0 +1,80 @@ +/** + * WordPress dependencies + */ +import { ComplementaryArea } from '@wordpress/interface'; + +/** + * Renders a sidebar when activated. The contents within the `PluginSidebar` will appear as content within the sidebar. + * It also automatically renders a corresponding `PluginSidebarMenuItem` component when `isPinnable` flag is set to `true`. + * If you wish to display the sidebar, you can with use the `PluginSidebarMoreMenuItem` component or the `wp.data.dispatch` API: + * + * ```js + * wp.data.dispatch( 'core/edit-site' ).openGeneralSidebar( 'plugin-name/sidebar-name' ); + * ``` + * + * @see PluginSidebarMoreMenuItem + * + * @param {Object} props Element props. + * @param {string} props.name A string identifying the sidebar. Must be unique for every sidebar registered within the scope of your plugin. + * @param {string} [props.className] An optional class name added to the sidebar body. + * @param {string} props.title Title displayed at the top of the sidebar. + * @param {boolean} [props.isPinnable=true] Whether to allow to pin sidebar to the toolbar. When set to `true` it also automatically renders a corresponding menu item. + * @param {WPBlockTypeIconRender} [props.icon=inherits from the plugin] The [Dashicon](https://developer.wordpress.org/resource/dashicons/) icon slug string, or an SVG WP element, to be rendered when the sidebar is pinned to toolbar. + * + * @example + * ```js + * // Using ES5 syntax + * var __ = wp.i18n.__; + * var el = wp.element.createElement; + * var PanelBody = wp.components.PanelBody; + * var PluginSidebar = wp.editSite.PluginSidebar; + * var moreIcon = wp.element.createElement( 'svg' ); //... svg element. + * + * function MyPluginSidebar() { + * return el( + * PluginSidebar, + * { + * name: 'my-sidebar', + * title: 'My sidebar title', + * icon: moreIcon, + * }, + * el( + * PanelBody, + * {}, + * __( 'My sidebar content' ) + * ) + * ); + * } + * ``` + * + * @example + * ```jsx + * // Using ESNext syntax + * import { __ } from '@wordpress/i18n'; + * import { PanelBody } from '@wordpress/components'; + * import { PluginSidebar } from '@wordpress/edit-site'; + * import { more } from '@wordpress/icons'; + * + * const MyPluginSidebar = () => ( + * + * + * { __( 'My sidebar content' ) } + * + * + * ); + * ``` + */ +export default function PluginSidebarEditSite( { className, ...props } ) { + return ( + + ); +} diff --git a/packages/edit-site/src/index.js b/packages/edit-site/src/index.js index 8a33589ad9f60..ec81f5c3ccb19 100644 --- a/packages/edit-site/src/index.js +++ b/packages/edit-site/src/index.js @@ -62,3 +62,6 @@ export function initialize( id, settings ) { export { default as __experimentalMainDashboardButton } from './components/main-dashboard-button'; export { default as __experimentalNavigationToggle } from './components/navigation-sidebar/navigation-toggle'; +export { default as PluginSidebar } from './components/sidebar/plugin-sidebar'; +export { default as PluginSidebarMoreMenuItem } from './components/header/plugin-sidebar-more-menu-item'; +export { default as PluginMoreMenuItem } from './components/header/plugin-more-menu-item'; diff --git a/packages/edit-site/src/store/actions.js b/packages/edit-site/src/store/actions.js index a7b7e63c9a299..770fccab93a74 100644 --- a/packages/edit-site/src/store/actions.js +++ b/packages/edit-site/src/store/actions.js @@ -8,6 +8,7 @@ import { addQueryArgs, getPathAndQueryString } from '@wordpress/url'; import { __ } from '@wordpress/i18n'; import { store as noticesStore } from '@wordpress/notices'; import { store as coreStore } from '@wordpress/core-data'; +import { store as interfaceStore } from '@wordpress/interface'; /** * Internal dependencies @@ -441,3 +442,31 @@ export function* revertTemplate( template ) { ); } } +/** + * Returns an action object used in signalling that the user opened an editor sidebar. + * + * @param {?string} name Sidebar name to be opened. + * + * @yield {Object} Action object. + */ +export function* openGeneralSidebar( name ) { + yield controls.dispatch( + interfaceStore, + 'enableComplementaryArea', + editSiteStoreName, + name + ); +} + +/** + * Returns an action object signalling that the user closed the sidebar. + * + * @yield {Object} Action object. + */ +export function* closeGeneralSidebar() { + yield controls.dispatch( + interfaceStore, + 'disableComplementaryArea', + editSiteStoreName + ); +}