From b860b47b9b89229e7f2d1f6da2c456c46483be6d Mon Sep 17 00:00:00 2001
From: Peter Wilson <519727+peterwilsoncc@users.noreply.github.com>
Date: Thu, 13 Jul 2023 13:29:25 +1000
Subject: [PATCH] Restore `@wordpress/nux` to WP 6.2 branch (#52452)
* Revert "Remove the nux package (#46110)"
This reverts commit 9ea80f6f363f847b31c5faa3bac6be1c05f5ef63.
* Set peterwilsoncc as owner following revert.
* Use legacy fake timers for tests.
* Supress browserlist warning causing unit tests to fail.
---
.github/CODEOWNERS | 1 +
.github/workflows/end2end-test.yml | 3 +
.github/workflows/performance.yml | 3 +
.github/workflows/unit-test.yml | 3 +
docs/contributors/code/scripts.md | 1 +
docs/manifest.json | 12 ++
docs/reference-guides/README.md | 1 +
docs/reference-guides/data/README.md | 1 +
docs/reference-guides/data/data-core-nux.md | 99 ++++++++++++
docs/toc.json | 1 +
lib/client-assets.php | 13 +-
package-lock.json | 14 ++
package.json | 1 +
packages/base-styles/_z-index.scss | 5 +-
packages/nux/.npmrc | 1 +
packages/nux/CHANGELOG.md | 124 +++++++++++++++
packages/nux/README.md | 114 ++++++++++++++
packages/nux/package.json | 50 ++++++
packages/nux/src/components/dot-tip/README.md | 38 +++++
packages/nux/src/components/dot-tip/index.js | 93 +++++++++++
.../nux/src/components/dot-tip/style.scss | 123 +++++++++++++++
.../dot-tip/test/__snapshots__/index.js.snap | 46 ++++++
.../nux/src/components/dot-tip/test/index.js | 86 +++++++++++
packages/nux/src/index.js | 13 ++
packages/nux/src/store/actions.js | 52 +++++++
packages/nux/src/store/index.js | 36 +++++
packages/nux/src/store/reducer.js | 70 +++++++++
packages/nux/src/store/selectors.js | 81 ++++++++++
packages/nux/src/store/test/actions.js | 40 +++++
packages/nux/src/store/test/reducer.js | 69 +++++++++
packages/nux/src/store/test/selectors.js | 146 ++++++++++++++++++
packages/nux/src/style.scss | 1 +
.../local-storage-overrides.json | 6 +
33 files changed, 1344 insertions(+), 3 deletions(-)
create mode 100644 docs/reference-guides/data/data-core-nux.md
create mode 100644 packages/nux/.npmrc
create mode 100644 packages/nux/CHANGELOG.md
create mode 100644 packages/nux/README.md
create mode 100644 packages/nux/package.json
create mode 100644 packages/nux/src/components/dot-tip/README.md
create mode 100644 packages/nux/src/components/dot-tip/index.js
create mode 100644 packages/nux/src/components/dot-tip/style.scss
create mode 100644 packages/nux/src/components/dot-tip/test/__snapshots__/index.js.snap
create mode 100644 packages/nux/src/components/dot-tip/test/index.js
create mode 100644 packages/nux/src/index.js
create mode 100644 packages/nux/src/store/actions.js
create mode 100644 packages/nux/src/store/index.js
create mode 100644 packages/nux/src/store/reducer.js
create mode 100644 packages/nux/src/store/selectors.js
create mode 100644 packages/nux/src/store/test/actions.js
create mode 100644 packages/nux/src/store/test/reducer.js
create mode 100644 packages/nux/src/store/test/selectors.js
create mode 100644 packages/nux/src/style.scss
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index aa19138a958f1d..5767a64f7b270f 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -86,6 +86,7 @@
/packages/compose @ajitbohra
/packages/element @ajitbohra
/packages/notices @ajitbohra
+/packages/nux @ajitbohra @peterwilsoncc
/packages/viewport @ajitbohra
/packages/base-styles
/packages/icons
diff --git a/.github/workflows/end2end-test.yml b/.github/workflows/end2end-test.yml
index 13f4bf11d6e04d..94ddd379050c1b 100644
--- a/.github/workflows/end2end-test.yml
+++ b/.github/workflows/end2end-test.yml
@@ -15,6 +15,9 @@ concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.sha }}
cancel-in-progress: true
+env:
+ BROWSERSLIST_IGNORE_OLD_DATA: true
+
jobs:
e2e-puppeteer:
name: Puppeteer - ${{ matrix.part }}
diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml
index de759f50a9677c..bf8af797223d27 100644
--- a/.github/workflows/performance.yml
+++ b/.github/workflows/performance.yml
@@ -14,6 +14,9 @@ concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.sha }}
cancel-in-progress: true
+env:
+ BROWSERSLIST_IGNORE_OLD_DATA: true
+
jobs:
performance:
name: Run performance tests
diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml
index 8b1884835f416e..74e7deaf3e6207 100644
--- a/.github/workflows/unit-test.yml
+++ b/.github/workflows/unit-test.yml
@@ -25,6 +25,9 @@ jobs:
runs-on: ubuntu-latest
if: ${{ github.repository == 'WordPress/gutenberg' || github.event_name == 'pull_request' }}
+ env:
+ BROWSERSLIST_IGNORE_OLD_DATA: true
+
strategy:
fail-fast: false
matrix:
diff --git a/docs/contributors/code/scripts.md b/docs/contributors/code/scripts.md
index b7cabe0130d71c..3b36c8f4be4956 100644
--- a/docs/contributors/code/scripts.md
+++ b/docs/contributors/code/scripts.md
@@ -31,6 +31,7 @@ The editor includes a number of packages to enable various pieces of functionali
| [Is Shallow Equal](/packages/is-shallow-equal/README.md) | wp-is-shallow-equal | A function for performing a shallow comparison between two objects or arrays |
| [Keycodes](/packages/keycodes/README.md) | wp-keycodes | Keycodes utilities for WordPress, used to check the key pressed in events like `onKeyDown` |
| [List Reusable blocks](/packages/list-reusable-blocks/README.md) | wp-list-reusable-blocks | Package used to add import/export links to the listing page of the reusable blocks |
+| [NUX](/packages/nux/README.md) | wp-nux | Components, and wp.data methods useful for onboarding a new user to the WordPress admin interface |
| [Plugins](/packages/plugins/README.md) | wp-plugins | Plugins module for WordPress |
| [Redux Routine](/packages/redux-routine/README.md) | wp-redux-routine | Redux middleware for generator coroutines |
| [Rich Text](/packages/rich-text/README.md) | wp-rich-text | Helper functions to convert HTML or a DOM tree into a rich text value and back |
diff --git a/docs/manifest.json b/docs/manifest.json
index 2f6e3338e1c046..90af145df19433 100644
--- a/docs/manifest.json
+++ b/docs/manifest.json
@@ -1727,6 +1727,12 @@
"markdown_source": "../packages/npm-package-json-lint-config/README.md",
"parent": "packages"
},
+ {
+ "title": "@wordpress/nux",
+ "slug": "packages-nux",
+ "markdown_source": "../packages/nux/README.md",
+ "parent": "packages"
+ },
{
"title": "@wordpress/plugins",
"slug": "packages-plugins",
@@ -1967,6 +1973,12 @@
"markdown_source": "../docs/reference-guides/data/data-core-notices.md",
"parent": "data"
},
+ {
+ "title": "The NUX (New User Experience) Data",
+ "slug": "data-core-nux",
+ "markdown_source": "../docs/reference-guides/data/data-core-nux.md",
+ "parent": "data"
+ },
{
"title": "Preferences",
"slug": "data-core-preferences",
diff --git a/docs/reference-guides/README.md b/docs/reference-guides/README.md
index f13c838697f2de..33fdd9aa602414 100644
--- a/docs/reference-guides/README.md
+++ b/docs/reference-guides/README.md
@@ -63,6 +63,7 @@
- [**core/editor**: The Post Editor’s Data](/docs/reference-guides/data/data-core-editor.md)
- [**core/keyboard-shortcuts**: The Keyboard Shortcuts Data](/docs/reference-guides/data/data-core-keyboard-shortcuts.md)
- [**core/notices**: Notices Data](/docs/reference-guides/data/data-core-notices.md)
+ - [**core/nux**: The NUX (New User Experience) Data](/docs/reference-guides/data/data-core-nux.md)
- [**core/preferences**: Preferences](/docs/reference-guides/data/data-core-preferences.md)
- [**core/reusable-blocks**: Reusable blocks](/docs/reference-guides/data/data-core-reusable-blocks.md)
- [**core/rich-text**: Rich Text](/docs/reference-guides/data/data-core-rich-text.md)
diff --git a/docs/reference-guides/data/README.md b/docs/reference-guides/data/README.md
index 5f4d8d92d4bd49..1134c1d5ddd307 100644
--- a/docs/reference-guides/data/README.md
+++ b/docs/reference-guides/data/README.md
@@ -12,6 +12,7 @@
- [**core/editor**: The Post Editor’s Data](/docs/reference-guides/data/data-core-editor.md)
- [**core/keyboard-shortcuts**: The Keyboard Shortcuts Data](/docs/reference-guides/data/data-core-keyboard-shortcuts.md)
- [**core/notices**: Notices Data](/docs/reference-guides/data/data-core-notices.md)
+- [**core/nux**: The NUX (New User Experience) Data](/docs/reference-guides/data/data-core-nux.md)
- [**core/preferences**: Preferences](/docs/reference-guides/data/data-core-preferences.md)
- [**core/reusable-blocks**: Reusable blocks](/docs/reference-guides/data/data-core-reusable-blocks.md)
- [**core/rich-text**: Rich Text](/docs/reference-guides/data/data-core-rich-text.md)
diff --git a/docs/reference-guides/data/data-core-nux.md b/docs/reference-guides/data/data-core-nux.md
new file mode 100644
index 00000000000000..4d2e8a0d98d546
--- /dev/null
+++ b/docs/reference-guides/data/data-core-nux.md
@@ -0,0 +1,99 @@
+# The NUX (New User Experience) Data
+
+Namespace: `core/nux`.
+
+## Selectors
+
+
+
+### areTipsEnabled
+
+Returns whether or not tips are globally enabled.
+
+_Parameters_
+
+- _state_ `Object`: Global application state.
+
+_Returns_
+
+- `boolean`: Whether tips are globally enabled.
+
+### getAssociatedGuide
+
+Returns an object describing the guide, if any, that the given tip is a part
+of.
+
+_Parameters_
+
+- _state_ `Object`: Global application state.
+- _tipId_ `string`: The tip to query.
+
+_Returns_
+
+- `?NUXGuideInfo`: Information about the associated guide.
+
+### isTipVisible
+
+Determines whether or not the given tip is showing. Tips are hidden if they
+are disabled, have been dismissed, or are not the current tip in any
+guide that they have been added to.
+
+_Parameters_
+
+- _state_ `Object`: Global application state.
+- _tipId_ `string`: The tip to query.
+
+_Returns_
+
+- `boolean`: Whether or not the given tip is showing.
+
+
+
+## Actions
+
+
+
+### disableTips
+
+Returns an action object that, when dispatched, prevents all tips from
+showing again.
+
+_Returns_
+
+- `Object`: Action object.
+
+### dismissTip
+
+Returns an action object that, when dispatched, dismisses the given tip. A
+dismissed tip will not show again.
+
+_Parameters_
+
+- _id_ `string`: The tip to dismiss.
+
+_Returns_
+
+- `Object`: Action object.
+
+### enableTips
+
+Returns an action object that, when dispatched, makes all tips show again.
+
+_Returns_
+
+- `Object`: Action object.
+
+### triggerGuide
+
+Returns an action object that, when dispatched, presents a guide that takes
+the user through a series of tips step by step.
+
+_Parameters_
+
+- _tipIds_ `string[]`: Which tips to show in the guide.
+
+_Returns_
+
+- `Object`: Action object.
+
+
diff --git a/docs/toc.json b/docs/toc.json
index 4203f40c16cbc4..532e6ef2d20e1d 100644
--- a/docs/toc.json
+++ b/docs/toc.json
@@ -278,6 +278,7 @@
"docs/reference-guides/data/data-core-keyboard-shortcuts.md": []
},
{ "docs/reference-guides/data/data-core-notices.md": [] },
+ { "docs/reference-guides/data/data-core-nux.md": [] },
{
"docs/reference-guides/data/data-core-preferences.md": []
},
diff --git a/lib/client-assets.php b/lib/client-assets.php
index 0f6e64c27c0144..8373e725cfc650 100644
--- a/lib/client-assets.php
+++ b/lib/client-assets.php
@@ -274,7 +274,7 @@ function gutenberg_register_packages_styles( $styles ) {
$styles,
'wp-editor',
gutenberg_url( 'build/editor/style.css' ),
- array( 'wp-components', 'wp-block-editor', 'wp-reusable-blocks' ),
+ array( 'wp-components', 'wp-block-editor', 'wp-nux', 'wp-reusable-blocks' ),
$version
);
$styles->add_data( 'wp-editor', 'rtl', 'replace' );
@@ -283,7 +283,7 @@ function gutenberg_register_packages_styles( $styles ) {
$styles,
'wp-edit-post',
gutenberg_url( 'build/edit-post/style.css' ),
- array( 'wp-components', 'wp-block-editor', 'wp-editor', 'wp-edit-blocks', 'wp-block-library' ),
+ array( 'wp-components', 'wp-block-editor', 'wp-editor', 'wp-edit-blocks', 'wp-block-library', 'wp-nux' ),
$version
);
$styles->add_data( 'wp-edit-post', 'rtl', 'replace' );
@@ -367,6 +367,15 @@ function gutenberg_register_packages_styles( $styles ) {
);
$styles->add_data( 'wp-edit-blocks', 'rtl', 'replace' );
+ gutenberg_override_style(
+ $styles,
+ 'wp-nux',
+ gutenberg_url( 'build/nux/style.css' ),
+ array( 'wp-components' ),
+ $version
+ );
+ $styles->add_data( 'wp-nux', 'rtl', 'replace' );
+
gutenberg_override_style(
$styles,
'wp-block-library-theme',
diff --git a/package-lock.json b/package-lock.json
index d7d9a6351578ff..6ac95813557b65 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -18212,6 +18212,20 @@
"version": "file:packages/npm-package-json-lint-config",
"dev": true
},
+ "@wordpress/nux": {
+ "version": "file:packages/nux",
+ "requires": {
+ "@babel/runtime": "^7.16.0",
+ "@wordpress/components": "file:packages/components",
+ "@wordpress/compose": "file:packages/compose",
+ "@wordpress/data": "file:packages/data",
+ "@wordpress/deprecated": "file:packages/deprecated",
+ "@wordpress/element": "file:packages/element",
+ "@wordpress/i18n": "file:packages/i18n",
+ "@wordpress/icons": "file:packages/icons",
+ "rememo": "^4.0.0"
+ }
+ },
"@wordpress/plugins": {
"version": "file:packages/plugins",
"requires": {
diff --git a/package.json b/package.json
index f3a78d3c15cbb0..6cb47cb94e36ef 100644
--- a/package.json
+++ b/package.json
@@ -62,6 +62,7 @@
"@wordpress/list-reusable-blocks": "file:packages/list-reusable-blocks",
"@wordpress/media-utils": "file:packages/media-utils",
"@wordpress/notices": "file:packages/notices",
+ "@wordpress/nux": "file:packages/nux",
"@wordpress/plugins": "file:packages/plugins",
"@wordpress/preferences": "file:packages/preferences",
"@wordpress/preferences-persistence": "file:packages/preferences-persistence",
diff --git a/packages/base-styles/_z-index.scss b/packages/base-styles/_z-index.scss
index 97427da1fd525e..8c6ac35c0c91d0 100644
--- a/packages/base-styles/_z-index.scss
+++ b/packages/base-styles/_z-index.scss
@@ -144,7 +144,10 @@ $z-layers: (
// The focus styles of the region navigation containers should be above their content.
".is-focusing-regions {region} :focus::after": 1000000,
- // Show tooltips above wp-admin menus, submenus, and sidebar:
+ // Show NUX tips above popovers, wp-admin menus, submenus, and sidebar:
+ ".nux-dot-tip": 1000001,
+
+ // Show tooltips above NUX tips, wp-admin menus, submenus, and sidebar:
".components-tooltip": 1000002,
// Keep template popover underneath 'Create custom template' modal overlay.
diff --git a/packages/nux/.npmrc b/packages/nux/.npmrc
new file mode 100644
index 00000000000000..43c97e719a5a82
--- /dev/null
+++ b/packages/nux/.npmrc
@@ -0,0 +1 @@
+package-lock=false
diff --git a/packages/nux/CHANGELOG.md b/packages/nux/CHANGELOG.md
new file mode 100644
index 00000000000000..edbf4c88a21f0f
--- /dev/null
+++ b/packages/nux/CHANGELOG.md
@@ -0,0 +1,124 @@
+
+
+## Unreleased
+
+### Breaking Changes
+
+- Updated dependencies to require React 18 ([45235](https://github.com/WordPress/gutenberg/pull/45235))
+
+## 5.20.0 (2022-11-16)
+
+## 5.19.0 (2022-11-02)
+
+## 5.18.0 (2022-10-19)
+
+## 5.17.0 (2022-10-05)
+
+## 5.16.0 (2022-09-21)
+
+## 5.15.0 (2022-09-13)
+
+## 5.14.0 (2022-08-24)
+
+## 5.13.0 (2022-08-10)
+
+## 5.12.0 (2022-07-27)
+
+## 5.11.0 (2022-07-13)
+
+## 5.10.0 (2022-06-29)
+
+## 5.9.0 (2022-06-15)
+
+## 5.8.0 (2022-06-01)
+
+## 5.7.0 (2022-05-18)
+
+## 5.6.0 (2022-05-04)
+
+## 5.5.0 (2022-04-21)
+
+## 5.4.0 (2022-04-08)
+
+## 5.3.0 (2022-03-23)
+
+## 5.2.0 (2022-03-11)
+
+## 5.1.0 (2022-01-27)
+
+## 5.0.0 (2021-07-29)
+
+### Breaking Change
+
+- Upgraded React components to work with v17.0 ([#29118](https://github.com/WordPress/gutenberg/pull/29118)). There are no new features in React v17.0 as explained in the [blog post](https://reactjs.org/blog/2020/10/20/react-v17.html).
+
+## 4.2.0 (2021-07-21)
+
+## 4.1.0 (2021-05-20)
+
+## 4.0.0 (2021-05-14)
+
+### Breaking Changes
+
+- Drop support for Internet Explorer 11 ([#31110](https://github.com/WordPress/gutenberg/pull/31110)). Learn more at https://make.wordpress.org/core/2021/04/22/ie-11-support-phase-out-plan/.
+- Increase the minimum Node.js version to v12 matching Long Term Support releases ([#31270](https://github.com/WordPress/gutenberg/pull/31270)). Learn more at https://nodejs.org/en/about/releases/.
+
+## 3.25.0 (2021-03-17)
+
+## 3.24.0 (2020-12-17)
+
+### New Feature
+
+- Added a store definition `store` for the core data namespace to use with `@wordpress/data` API ([#26655](https://github.com/WordPress/gutenberg/pull/26655)).
+
+# 3.1.0 (2019-06-03)
+
+- The `@wordpress/nux` package has been deprecated. Please use the `Guide` component in `@wordpress/components` to show a user guide.
+
+## 3.0.6 (2019-01-03)
+
+## 3.0.5 (2018-12-12)
+
+## 3.0.4 (2018-11-30)
+
+## 3.0.3 (2018-11-22)
+
+## 3.0.2 (2018-11-21)
+
+## 3.0.1 (2018-11-20)
+
+## 3.0.0 (2018-11-15)
+
+### Breaking Changes
+
+- The id prop of DotTip has been removed. Please use the tipId prop instead.
+
+## 2.0.13 (2018-11-12)
+
+## 2.0.12 (2018-11-12)
+
+## 2.0.11 (2018-11-09)
+
+## 2.0.10 (2018-11-09)
+
+## 2.0.9 (2018-11-03)
+
+## 2.0.8 (2018-10-30)
+
+## 2.0.7 (2018-10-29)
+
+### Deprecations
+
+- The id prop of DotTip has been deprecated. Please use the tipId prop instead.
+
+## 2.0.6 (2018-10-22)
+
+## 2.0.5 (2018-10-19)
+
+## 2.0.4 (2018-10-18)
+
+## 2.0.0 (2018-09-05)
+
+### Breaking Change
+
+- Change how required built-ins are polyfilled with Babel 7 ([#9171](https://github.com/WordPress/gutenberg/pull/9171)). If you're using an environment that has limited or no support for ES2015+ such as lower versions of IE then using [core-js](https://github.com/zloirock/core-js) or [@babel/polyfill](https://babeljs.io/docs/en/next/babel-polyfill) will add support for these methods.
diff --git a/packages/nux/README.md b/packages/nux/README.md
new file mode 100644
index 00000000000000..c0941ddd0c5f2a
--- /dev/null
+++ b/packages/nux/README.md
@@ -0,0 +1,114 @@
+# New User eXperience (NUX)
+
+The NUX module exposes components, and `wp.data` methods useful for onboarding a new user to the WordPress admin interface. Specifically, it exposes _tips_ and _guides_.
+
+A _tip_ is a component that points to an element in the UI and contains text that explains the element's functionality. The user can dismiss a tip, in which case it never shows again. The user can also disable tips entirely. Information about tips is persisted between sessions using `localStorage`.
+
+A _guide_ allows a series of tips to be presented to the user one by one. When a user dismisses a tip that is in a guide, the next tip in the guide is shown.
+
+## Installation
+
+Install the module
+
+```bash
+npm install @wordpress/nux --save
+```
+
+_This package assumes that your code will run in an **ES2015+** environment. If you're using an environment that has limited or no support for such language features and APIs, you should include [the polyfill shipped in `@wordpress/babel-preset-default`](https://github.com/WordPress/gutenberg/tree/HEAD/packages/babel-preset-default#polyfill) in your code._
+
+## DotTip
+
+`DotTip` is a React component that renders a single _tip_ on the screen. The tip will point to the React element that `DotTip` is nested within. Each tip is uniquely identified by a string passed to `tipId`.
+
+See [the component's README][dot-tip-readme] for more information.
+
+[dot-tip-readme]: https://github.com/WordPress/gutenberg/tree/HEAD/packages/nux/src/components/dot-tip/README.md
+
+```jsx
+
+}
+```
+
+## Determining if a tip is visible
+
+You can programmatically determine if a tip is visible using the `isTipVisible` select method.
+
+```jsx
+const isVisible = select( 'core/nux' ).isTipVisible( 'acme/add-to-cart' );
+console.log( isVisible ); // true or false
+```
+
+## Manually dismissing a tip
+
+`dismissTip` is a dispatch method that allows you to programmatically dismiss a tip.
+
+```jsx
+
+```
+
+## Disabling and enabling tips
+
+Tips can be programatically disabled or enabled using the `disableTips` and `enableTips` dispatch methods. You can query the current setting by using the `areTipsEnabled` select method.
+
+Calling `enableTips` will also un-dismiss all previously dismissed tips.
+
+```jsx
+const areTipsEnabled = select( 'core/nux' ).areTipsEnabled();
+return (
+
+);
+```
+
+## Triggering a guide
+
+You can group a series of tips into a guide by calling the `triggerGuide` dispatch method. The given tips will then appear one by one.
+
+A tip cannot be added to more than one guide.
+
+```jsx
+dispatch( 'core/nux' ).triggerGuide( [
+ 'acme/product-info',
+ 'acme/add-to-cart',
+ 'acme/checkout',
+] );
+```
+
+## Getting information about a guide
+
+`getAssociatedGuide` is a select method that returns useful information about the state of the guide that a tip is associated with.
+
+```jsx
+const guide = select( 'core/nux' ).getAssociatedGuide( 'acme/add-to-cart' );
+console.log( 'Tips in this guide:', guide.tipIds );
+console.log( 'Currently showing:', guide.currentTipId );
+console.log( 'Next to show:', guide.nextTipId );
+```
+
+## Contributing to this package
+
+This is an individual package that's part of the Gutenberg project. The project is organized as a monorepo. It's made up of multiple self-contained software packages, each with a specific purpose. The packages in this monorepo are published to [npm](https://www.npmjs.com/) and used by [WordPress](https://make.wordpress.org/core/) as well as other software projects.
+
+To find out more about contributing to this package or Gutenberg as a whole, please read the project's main [contributor guide](https://github.com/WordPress/gutenberg/tree/HEAD/CONTRIBUTING.md).
+
+
{ children }
++ +
+ ++ It looks like you’re writing a letter. Would you like help? +
++ +
+ +