From e13f07ef6e592bd8c409db5179db104521a86455 Mon Sep 17 00:00:00 2001
From: Peter Wilson <519727+peterwilsoncc@users.noreply.github.com>
Date: Mon, 10 Jul 2023 10:56:04 +1000
Subject: [PATCH] Revert "Remove the nux package (#46110)"
This reverts commit 9ea80f6f363f847b31c5faa3bac6be1c05f5ef63.
# Conflicts:
# lib/client-assets.php
---
.github/CODEOWNERS | 1 +
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 | 78 ++++++++++
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 +
30 files changed, 1327 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 7ba9e884259ea4..257624c8f9862f 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -88,6 +88,7 @@
/packages/compose @ajitbohra
/packages/element @ajitbohra
/packages/notices @ajitbohra
+/packages/nux @ajitbohra
/packages/viewport @ajitbohra
/packages/base-styles
/packages/icons
diff --git a/docs/contributors/code/scripts.md b/docs/contributors/code/scripts.md
index 5cd7efd2fffdad..1483a409a4d08f 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 ec55132cd7d4b2..5f75e49924f355 100644
--- a/docs/manifest.json
+++ b/docs/manifest.json
@@ -1757,6 +1757,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",
@@ -2003,6 +2009,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 085bbb536ece2b..1660afdcc29497 100644
--- a/docs/toc.json
+++ b/docs/toc.json
@@ -284,6 +284,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 99aa7f147ecbfc..966c469f3319c3 100644
--- a/lib/client-assets.php
+++ b/lib/client-assets.php
@@ -275,7 +275,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' );
@@ -284,7 +284,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', 'wp-commands' ),
+ array( 'wp-components', 'wp-block-editor', 'wp-editor', 'wp-edit-blocks', 'wp-block-library', 'wp-commands', 'wp-nux' ),
$version
);
$styles->add_data( 'wp-edit-post', 'rtl', 'replace' );
@@ -368,6 +368,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 3c96f25259cbce..c3994a2be134e1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -18259,6 +18259,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 5032f589b592fd..5bdef1e9e589e0 100644
--- a/package.json
+++ b/package.json
@@ -65,6 +65,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 cc4a42df98f0aa..7987e1b4b5b4dc 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).
+
+
diff --git a/packages/nux/package.json b/packages/nux/package.json
new file mode 100644
index 00000000000000..9089f865e729de
--- /dev/null
+++ b/packages/nux/package.json
@@ -0,0 +1,50 @@
+{
+ "name": "@wordpress/nux",
+ "version": "5.20.0",
+ "description": "NUX (New User eXperience) module for WordPress.",
+ "author": "The WordPress Contributors",
+ "license": "GPL-2.0-or-later",
+ "keywords": [
+ "wordpress",
+ "gutenberg",
+ "nux"
+ ],
+ "homepage": "https://github.com/WordPress/gutenberg/tree/HEAD/packages/nux/README.md",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/WordPress/gutenberg.git",
+ "directory": "packages/nux"
+ },
+ "bugs": {
+ "url": "https://github.com/WordPress/gutenberg/issues"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "main": "build/index.js",
+ "module": "build-module/index.js",
+ "react-native": "src/index",
+ "sideEffects": [
+ "build-style/**",
+ "src/**/*.scss",
+ "{src,build,build-module}/{index.js,store/index.js}"
+ ],
+ "dependencies": {
+ "@babel/runtime": "^7.16.0",
+ "@wordpress/components": "file:../components",
+ "@wordpress/compose": "file:../compose",
+ "@wordpress/data": "file:../data",
+ "@wordpress/deprecated": "file:../deprecated",
+ "@wordpress/element": "file:../element",
+ "@wordpress/i18n": "file:../i18n",
+ "@wordpress/icons": "file:../icons",
+ "rememo": "^4.0.0"
+ },
+ "peerDependencies": {
+ "react": "^18.0.0",
+ "react-dom": "^18.0.0"
+ },
+ "publishConfig": {
+ "access": "public"
+ }
+}
diff --git a/packages/nux/src/components/dot-tip/README.md b/packages/nux/src/components/dot-tip/README.md
new file mode 100644
index 00000000000000..f143a22a222588
--- /dev/null
+++ b/packages/nux/src/components/dot-tip/README.md
@@ -0,0 +1,38 @@
+# 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`.
+
+## Usage
+
+```jsx
+
+}
+```
+
+## Props
+
+The component accepts the following props:
+
+### tipId
+
+A string that uniquely identifies the tip. Identifiers should be prefixed with the name of the plugin, followed by a `/`. For example, `acme/add-to-cart`.
+
+- Type: `string`
+- Required: Yes
+
+### position
+
+The direction in which the popover should open relative to its parent node. Specify y- and x-axis as a space-separated string. Supports `"top"`, `"middle"`, `"bottom"` y axis, and `"left"`, `"center"`, `"right"` x axis.
+
+- Type: `String`
+- Required: No
+- Default: `"middle right"`
+
+### children
+
+Any React element or elements can be passed as children. They will be rendered within the tip bubble.
diff --git a/packages/nux/src/components/dot-tip/index.js b/packages/nux/src/components/dot-tip/index.js
new file mode 100644
index 00000000000000..50de7ddb3be9df
--- /dev/null
+++ b/packages/nux/src/components/dot-tip/index.js
@@ -0,0 +1,93 @@
+/**
+ * WordPress dependencies
+ */
+import { compose } from '@wordpress/compose';
+import { Popover, Button } from '@wordpress/components';
+import { __ } from '@wordpress/i18n';
+import { withSelect, withDispatch } from '@wordpress/data';
+import { useCallback, useRef } from '@wordpress/element';
+import { close } from '@wordpress/icons';
+
+/**
+ * Internal dependencies
+ */
+import { store as nuxStore } from '../../store';
+
+function onClick( event ) {
+ // Tips are often nested within buttons. We stop propagation so that clicking
+ // on a tip doesn't result in the button being clicked.
+ event.stopPropagation();
+}
+
+export function DotTip( {
+ position = 'middle right',
+ children,
+ isVisible,
+ hasNextTip,
+ onDismiss,
+ onDisable,
+} ) {
+ const anchorParent = useRef( null );
+ const onFocusOutsideCallback = useCallback(
+ ( event ) => {
+ if ( ! anchorParent.current ) {
+ return;
+ }
+ if ( anchorParent.current.contains( event.relatedTarget ) ) {
+ return;
+ }
+ onDisable();
+ },
+ [ onDisable, anchorParent ]
+ );
+ if ( ! isVisible ) {
+ return null;
+ }
+
+ return (
+
+