Skip to content
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

Publish types for plugins package #49649

Merged
merged 9 commits into from
Apr 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
- `Modal`: Increased border radius ([#49870](https://github.com/WordPress/gutenberg/pull/49870)).
- `Modal`: Updated spacing / dimensions of `isFullScreen` ([#49894](https://github.com/WordPress/gutenberg/pull/49894)).
- `SlotFill`: Added util for creating private SlotFills and supporting Symbol keys ([#49819](https://github.com/WordPress/gutenberg/pull/49819)).
noahtallen marked this conversation as resolved.
Show resolved Hide resolved

- `IconType`: Export for external use ([#49649](https://github.com/WordPress/gutenberg/pull/49649)).

### Documentation

Expand Down
1 change: 1 addition & 0 deletions packages/components/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ export { default as GuidePage } from './guide/page';
export { Heading as __experimentalHeading } from './heading';
export { HStack as __experimentalHStack } from './h-stack';
export { default as Icon } from './icon';
export type { IconType } from './icon';
noahtallen marked this conversation as resolved.
Show resolved Hide resolved
export { default as IconButton } from './button/deprecated';
export {
ItemGroup as __experimentalItemGroup,
Expand Down
6 changes: 3 additions & 3 deletions packages/is-shallow-equal/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ export { default as isShallowEqualArrays } from './arrays';

/**
* Returns true if the two arrays or objects are shallow equal, or false
* otherwise.
* otherwise. Also handles primitive values, just in case.
*
* @param {any[]|ComparableObject} a First object or array to compare.
* @param {any[]|ComparableObject} b Second object or array to compare.
noahtallen marked this conversation as resolved.
Show resolved Hide resolved
* @param {unknown} a First object or array to compare.
* @param {unknown} b Second object or array to compare.
*
* @return {boolean} Whether the two values are shallow equal.
*/
Expand Down
4 changes: 4 additions & 0 deletions packages/plugins/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

### Breaking Changes

- Publish types for `@wordpress/plugins` ([#49649](https://github.com/WordPress/gutenberg/pull/49649))

## 5.8.0 (2023-04-12)

## 5.7.0 (2023-03-29)
Expand Down
18 changes: 9 additions & 9 deletions packages/plugins/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,15 @@ _Parameters_

_Returns_

- `?WPPlugin`: Plugin setting.
- `WPPlugin | undefined`: Plugin setting.

#### getPlugins

Returns all registered plugins without a scope or for a given scope.

_Parameters_

- _scope_ `[string]`: The scope to be used when rendering inside a plugin area. No scope by default.
- _scope_ `string`: The scope to be used when rendering inside a plugin area. No scope by default.

_Returns_

Expand Down Expand Up @@ -70,9 +70,9 @@ const Layout = () => (

_Parameters_

- _props_ `Object`:
- _props.scope_ `string|undefined`:
- _props.onError_ `Function|undefined`:
- _props_ `{ scope?: string; onError?: ( name: WPPlugin[ 'name' ], error: Error ) => void; }`:
- _props.scope_ `string`:
- _props.onError_ `( name: WPPlugin[ 'name' ], error: Error ) => void`:

_Returns_

Expand Down Expand Up @@ -147,12 +147,12 @@ registerPlugin( 'plugin-name', {

_Parameters_

- _name_ `string`: A string identifying the plugin.Must be unique across all registered plugins.
- _settings_ `Omit<WPPlugin, 'name'>`: The settings for this plugin.
- _name_ `string`: A string identifying the plugin. Must be unique across all registered plugins.
- _settings_ `PluginSettings`: The settings for this plugin.

_Returns_

- `WPPlugin`: The final plugin settings object.
- `PluginSettings | null`: The final plugin settings object.

#### unregisterPlugin

Expand Down Expand Up @@ -188,7 +188,7 @@ A Higher Order Component used to inject Plugin context to the wrapped component.

_Parameters_

- _mapContextToProps_ `Function`: Function called on every context change, expected to return object of props to merge with the component's own props.
- _mapContextToProps_ `( context: PluginContext, props: T ) => T & PluginContext`: Function called on every context change, expected to return object of props to merge with the component's own props.

_Returns_

Expand Down
2 changes: 2 additions & 0 deletions packages/plugins/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@
"main": "build/index.js",
"module": "build-module/index.js",
"react-native": "src/index",
"types": "build-types",
"dependencies": {
"@babel/runtime": "^7.16.0",
"@wordpress/components": "file:../components",
"@wordpress/compose": "file:../compose",
"@wordpress/element": "file:../element",
"@wordpress/hooks": "file:../hooks",
Expand Down
noahtallen marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -5,37 +5,50 @@
*/
import { applyFilters, doAction } from '@wordpress/hooks';
import { plugins as pluginsIcon } from '@wordpress/icons';
import type { IconType } from '@wordpress/components';
import type { WPComponent } from '@wordpress/element';

/**
* Defined behavior of a plugin type.
*
* @typedef {Object} WPPlugin
*
* @property {string} name A string identifying the plugin. Must be
* unique across all registered plugins.
* @property {string|WPElement|Function} [icon] An icon to be shown in the UI. It can
* be a slug of the Dashicon, or an element
* (or function returning an element) if you
* choose to render your own SVG.
* @property {Function} render A component containing the UI elements
* to be rendered.
* @property {string} [scope] The optional scope to be used when rendering inside
* a plugin area. No scope by default.
*/
export interface WPPlugin {
noahtallen marked this conversation as resolved.
Show resolved Hide resolved
/**
* A string identifying the plugin. Must be unique across all registered plugins.
*/
name: string;

/**
* An icon to be shown in the UI. It can be a slug of the Dashicon, or an
* element (or function returning an element) if you choose to render your
* own SVG.
*/
icon?: IconType;

/**
* A component containing the UI elements to be rendered.
*/
render: WPComponent;

/**
* The optional scope to be used when rendering inside a plugin area.
* No scope by default.
*/
scope?: string;
}

type PluginSettings = Omit< WPPlugin, 'name' >;

/**
* Plugin definitions keyed by plugin name.
*
* @type {Object.<string,WPPlugin>}
*/
const plugins = {};
const plugins = {} as Record< string, WPPlugin >;

/**
* Registers a plugin to the editor.
*
* @param {string} name A string identifying the plugin.Must be
* unique across all registered plugins.
* @param {Omit<WPPlugin, 'name'>} settings The settings for this plugin.
* @param name A string identifying the plugin. Must be
* unique across all registered plugins.
* @param settings The settings for this plugin.
*
* @example
* ```js
Expand Down Expand Up @@ -105,9 +118,12 @@ const plugins = {};
* } );
* ```
*
* @return {WPPlugin} The final plugin settings object.
* @return The final plugin settings object.
*/
export function registerPlugin( name, settings ) {
export function registerPlugin(
name: string,
settings: PluginSettings
): PluginSettings | null {
if ( typeof settings !== 'object' ) {
console.error( 'No settings object provided!' );
return null;
Expand All @@ -126,7 +142,11 @@ export function registerPlugin( name, settings ) {
console.error( `Plugin "${ name }" is already registered.` );
}

settings = applyFilters( 'plugins.registerPlugin', settings, name );
settings = applyFilters(
'plugins.registerPlugin',
settings,
name
) as PluginSettings;

const { render, scope } = settings;

Expand Down Expand Up @@ -165,7 +185,7 @@ export function registerPlugin( name, settings ) {
/**
* Unregisters a plugin by name.
*
* @param {string} name Plugin name.
* @param name Plugin name.
*
* @example
* ```js
Expand All @@ -183,10 +203,10 @@ export function registerPlugin( name, settings ) {
* unregisterPlugin( 'plugin-name' );
* ```
*
* @return {WPPlugin | undefined} The previous plugin settings object, if it has been
* successfully unregistered; otherwise `undefined`.
* @return The previous plugin settings object, if it has been
* successfully unregistered; otherwise `undefined`.
*/
export function unregisterPlugin( name ) {
export function unregisterPlugin( name: string ): WPPlugin | undefined {
if ( ! plugins[ name ] ) {
console.error( 'Plugin "' + name + '" is not registered.' );
return;
Expand All @@ -202,23 +222,23 @@ export function unregisterPlugin( name ) {
/**
* Returns a registered plugin settings.
*
* @param {string} name Plugin name.
* @param name Plugin name.
*
* @return {?WPPlugin} Plugin setting.
* @return Plugin setting.
*/
export function getPlugin( name ) {
export function getPlugin( name: string ): WPPlugin | undefined {
return plugins[ name ];
}

/**
* Returns all registered plugins without a scope or for a given scope.
*
* @param {string} [scope] The scope to be used when rendering inside
* a plugin area. No scope by default.
* @param scope The scope to be used when rendering inside
* a plugin area. No scope by default.
*
* @return {WPPlugin[]} The list of plugins without a scope or for a given scope.
* @return The list of plugins without a scope or for a given scope.
*/
export function getPlugins( scope ) {
export function getPlugins( scope?: string ): WPPlugin[] {
return Object.values( plugins ).filter(
( plugin ) => plugin.scope === scope
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,22 @@ import isShallowEqual from '@wordpress/is-shallow-equal';
import { PluginContextProvider } from '../plugin-context';
import { PluginErrorBoundary } from '../plugin-error-boundary';
import { getPlugins } from '../../api';
import type { PluginContext } from '../plugin-context';
import type { WPPlugin } from '../../api';

const getPluginContext = memoize( ( icon, name ) => ( { icon, name } ) );
const getPluginContext = memoize(
( icon: PluginContext[ 'icon' ], name: PluginContext[ 'name' ] ) => ( {
icon,
name,
} )
);

/**
* A component that renders all plugin fills in a hidden div.
*
* @param {Object} props
* @param {string|undefined} props.scope
* @param {Function|undefined} props.onError
* @param props
* @param props.scope
Copy link
Contributor

@adamziel adamziel Apr 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have to list all the properties now that they are statically typed? AFAIR other places just say @param props

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My IDE automatically inserts them on save, so I think yes?

* @param props.onError
* @example
* ```js
* // Using ES5 syntax
Expand Down Expand Up @@ -56,12 +63,23 @@ const getPluginContext = memoize( ( icon, name ) => ( { icon, name } ) );
*
* @return {WPComponent} The component to be rendered.
*/
function PluginArea( { scope, onError } ) {
function PluginArea( {
scope,
onError,
}: {
scope?: string;
onError?: ( name: WPPlugin[ 'name' ], error: Error ) => void;
} ) {
const store = useMemo( () => {
let lastValue;
let lastValue: WPPlugin[] = [];

return {
subscribe( listener ) {
subscribe(
listener: (
plugin: Omit< WPPlugin, 'name' >,
name: WPPlugin[ 'name' ]
) => void
) {
addAction(
'plugins.pluginRegistered',
'core/plugins/plugin-area/plugins-registered',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,17 @@
import { createContext } from '@wordpress/element';
import { createHigherOrderComponent } from '@wordpress/compose';

const { Consumer, Provider } = createContext( {
/**
* Internal dependencies
*/
import type { WPPlugin } from '../../api';

export interface PluginContext {
name: null | WPPlugin[ 'name' ];
icon: null | WPPlugin[ 'icon' ];
}

const { Consumer, Provider } = createContext< PluginContext >( {
name: null,
icon: null,
} );
Expand All @@ -15,13 +25,18 @@ export { Provider as PluginContextProvider };
* A Higher Order Component used to inject Plugin context to the
* wrapped component.
*
* @param {Function} mapContextToProps Function called on every context change,
* expected to return object of props to
* merge with the component's own props.
* @param mapContextToProps Function called on every context change,
* expected to return object of props to
* merge with the component's own props.
*
* @return {WPComponent} Enhanced component with injected context as props.
noahtallen marked this conversation as resolved.
Show resolved Hide resolved
*/
export const withPluginContext = ( mapContextToProps ) =>
export const withPluginContext = (
mapContextToProps: < T >(
context: PluginContext,
props: T
) => T & PluginContext
) =>
createHigherOrderComponent( ( OriginalComponent ) => {
return ( props ) => (
<Consumer>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
import { Component } from '@wordpress/element';

export class PluginErrorBoundary extends Component {
/**
* @param {Object} props
*/
constructor( props ) {
super( props );
this.state = {
Expand All @@ -15,6 +18,9 @@ export class PluginErrorBoundary extends Component {
return { hasError: true };
}

/**
* @param {Error} error Error object passed by React.
*/
componentDidCatch( error ) {
const { name, onError } = this.props;
if ( onError ) {
Expand Down
Loading