From 653832dc33ba1f667be05b24d9608829abdc716f Mon Sep 17 00:00:00 2001 From: Carlos Bravo <37012961+c4rl0sbr4v0@users.noreply.github.com> Date: Thu, 18 Jan 2024 20:02:43 +0100 Subject: [PATCH] Interactivity API: Add `wp-data-on-window` and `wp-data-on-document` directives (#57931) * Add wp-data-on-window and wp-data-on-document directives * Update changelog * Rename directives tests files to unify them * Use callbacks instead of actions, remove not needed counter * Add event listener removal tests * Add documentation * Test that events are reattached * Fix docs typos * Fix docs typos * Fix indentation in docs * Fix e2e test --- .../directive-on-document/block.json | 15 ++ .../directive-on-document/render.php | 18 ++ .../directive-on-document/view.js | 34 ++++ .../directive-on-window/block.json | 15 ++ .../directive-on-window/render.php | 18 ++ .../directive-on-window/view.js | 34 ++++ packages/interactivity/CHANGELOG.md | 1 + .../interactivity/docs/2-api-reference.md | 160 +++++++++++++----- packages/interactivity/src/directives.js | 98 +++++++---- ...es-body.spec.ts => directive-body.spec.ts} | 0 ...-class.spec.ts => directive-class.spec.ts} | 0 ...text.spec.ts => directive-context.spec.ts} | 0 .../directive-on-document.spec.ts | 47 +++++ .../interactivity/directive-on-window.spec.ts | 45 +++++ ...-style.spec.ts => directive-style.spec.ts} | 0 ...es-text.spec.ts => directive-text.spec.ts} | 0 16 files changed, 404 insertions(+), 81 deletions(-) create mode 100644 packages/e2e-tests/plugins/interactive-blocks/directive-on-document/block.json create mode 100644 packages/e2e-tests/plugins/interactive-blocks/directive-on-document/render.php create mode 100644 packages/e2e-tests/plugins/interactive-blocks/directive-on-document/view.js create mode 100644 packages/e2e-tests/plugins/interactive-blocks/directive-on-window/block.json create mode 100644 packages/e2e-tests/plugins/interactive-blocks/directive-on-window/render.php create mode 100644 packages/e2e-tests/plugins/interactive-blocks/directive-on-window/view.js rename test/e2e/specs/interactivity/{directives-body.spec.ts => directive-body.spec.ts} (100%) rename test/e2e/specs/interactivity/{directives-class.spec.ts => directive-class.spec.ts} (100%) rename test/e2e/specs/interactivity/{directives-context.spec.ts => directive-context.spec.ts} (100%) create mode 100644 test/e2e/specs/interactivity/directive-on-document.spec.ts create mode 100644 test/e2e/specs/interactivity/directive-on-window.spec.ts rename test/e2e/specs/interactivity/{directives-style.spec.ts => directive-style.spec.ts} (100%) rename test/e2e/specs/interactivity/{directives-text.spec.ts => directive-text.spec.ts} (100%) diff --git a/packages/e2e-tests/plugins/interactive-blocks/directive-on-document/block.json b/packages/e2e-tests/plugins/interactive-blocks/directive-on-document/block.json new file mode 100644 index 00000000000000..296a9b2f041905 --- /dev/null +++ b/packages/e2e-tests/plugins/interactive-blocks/directive-on-document/block.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 2, + "name": "test/directive-on-document", + "title": "E2E Interactivity tests - directive on document", + "category": "text", + "icon": "heart", + "description": "", + "supports": { + "interactivity": true + }, + "textdomain": "e2e-interactivity", + "viewScript": "directive-on-document-view", + "render": "file:./render.php" +} diff --git a/packages/e2e-tests/plugins/interactive-blocks/directive-on-document/render.php b/packages/e2e-tests/plugins/interactive-blocks/directive-on-document/render.php new file mode 100644 index 00000000000000..d04cb79ea58522 --- /dev/null +++ b/packages/e2e-tests/plugins/interactive-blocks/directive-on-document/render.php @@ -0,0 +1,18 @@ + + +
+ +
+
+

0

+
+
+
diff --git a/packages/e2e-tests/plugins/interactive-blocks/directive-on-document/view.js b/packages/e2e-tests/plugins/interactive-blocks/directive-on-document/view.js new file mode 100644 index 00000000000000..b3cb891e4d6cb5 --- /dev/null +++ b/packages/e2e-tests/plugins/interactive-blocks/directive-on-document/view.js @@ -0,0 +1,34 @@ +/** + * WordPress dependencies + */ +import { store, directive, getContext } from '@wordpress/interactivity'; + +// Mock `data-wp-show` directive to test when things are removed from the +// DOM. Replace with `data-wp-show` when it's ready. +directive( + 'show-mock', + ( { directives: { 'show-mock': showMock }, element, evaluate } ) => { + const entry = showMock.find( ( { suffix } ) => suffix === 'default' ); + if ( ! evaluate( entry ) ) { + return null; + } + return element; + } +); + +const { state } = store( 'directive-on-document', { + state: { + counter: 0, + }, + callbacks: { + keydownHandler: ( ) => { + state.counter += 1; + }, + }, + actions: { + visibilityHandler: () => { + const context = getContext(); + context.isVisible = ! context.isVisible; + }, + } +} ); diff --git a/packages/e2e-tests/plugins/interactive-blocks/directive-on-window/block.json b/packages/e2e-tests/plugins/interactive-blocks/directive-on-window/block.json new file mode 100644 index 00000000000000..9d55395b087a68 --- /dev/null +++ b/packages/e2e-tests/plugins/interactive-blocks/directive-on-window/block.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 2, + "name": "test/directive-on-window", + "title": "E2E Interactivity tests - directive on window", + "category": "text", + "icon": "heart", + "description": "", + "supports": { + "interactivity": true + }, + "textdomain": "e2e-interactivity", + "viewScript": "directive-on-window-view", + "render": "file:./render.php" +} diff --git a/packages/e2e-tests/plugins/interactive-blocks/directive-on-window/render.php b/packages/e2e-tests/plugins/interactive-blocks/directive-on-window/render.php new file mode 100644 index 00000000000000..e9c8792354e2a5 --- /dev/null +++ b/packages/e2e-tests/plugins/interactive-blocks/directive-on-window/render.php @@ -0,0 +1,18 @@ + + +
+ +
+
+

0

+
+
+
diff --git a/packages/e2e-tests/plugins/interactive-blocks/directive-on-window/view.js b/packages/e2e-tests/plugins/interactive-blocks/directive-on-window/view.js new file mode 100644 index 00000000000000..11d01b7a216d1c --- /dev/null +++ b/packages/e2e-tests/plugins/interactive-blocks/directive-on-window/view.js @@ -0,0 +1,34 @@ +/** + * WordPress dependencies + */ +import { store, directive, getContext } from '@wordpress/interactivity'; + +// Mock `data-wp-show` directive to test when things are removed from the +// DOM. Replace with `data-wp-show` when it's ready. +directive( + 'show-mock', + ( { directives: { 'show-mock': showMock }, element, evaluate } ) => { + const entry = showMock.find( ( { suffix } ) => suffix === 'default' ); + if ( ! evaluate( entry ) ) { + return null; + } + return element; + } +); + +const { state } = store( 'directive-on-window', { + state: { + counter: 0, + }, + callbacks: { + resizeHandler: ( ) => { + state.counter += 1; + }, + }, + actions: { + visibilityHandler: () => { + const context = getContext(); + context.isVisible = ! context.isVisible; + }, + } +} ); diff --git a/packages/interactivity/CHANGELOG.md b/packages/interactivity/CHANGELOG.md index 71ec27e50a87e4..d660032cbc0381 100644 --- a/packages/interactivity/CHANGELOG.md +++ b/packages/interactivity/CHANGELOG.md @@ -10,6 +10,7 @@ ### New Features - Add the `data-wp-run` directive along with the `useInit` and `useWatch` hooks. ([57805](https://github.com/WordPress/gutenberg/pull/57805)) +- Add `wp-data-on-window` and `wp-data-on-document` directives. ([57931](https://github.com/WordPress/gutenberg/pull/57931)) ### Breaking Changes diff --git a/packages/interactivity/docs/2-api-reference.md b/packages/interactivity/docs/2-api-reference.md index 7980c31b984f8d..922662c10a8e2b 100644 --- a/packages/interactivity/docs/2-api-reference.md +++ b/packages/interactivity/docs/2-api-reference.md @@ -20,6 +20,8 @@ DOM elements are connected to data stored in the state and context through direc - [`wp-style`](#wp-style) ![](https://img.shields.io/badge/ATTRIBUTES-afd2e3.svg) - [`wp-text`](#wp-text) ![](https://img.shields.io/badge/CONTENT-afd2e3.svg) - [`wp-on`](#wp-on) ![](https://img.shields.io/badge/EVENT_HANDLERS-afd2e3.svg) + - [`wp-on-window`](#wp-on-window) ![](https://img.shields.io/badge/EVENT_HANDLERS-afd2e3.svg) + - [`wp-on-document`](#wp-on-document) ![](https://img.shields.io/badge/EVENT_HANDLERS-afd2e3.svg) - [`wp-watch`](#wp-watch) ![](https://img.shields.io/badge/SIDE_EFFECTS-afd2e3.svg) - [`wp-init`](#wp-init) ![](https://img.shields.io/badge/SIDE_EFFECTS-afd2e3.svg) - [`wp-run`](#wp-run) ![](https://img.shields.io/badge/SIDE_EFFECTS-afd2e3.svg) @@ -55,7 +57,7 @@ _Example of directives used in the HTML markup_ > Toggle - +

This element is now visible!

@@ -68,13 +70,13 @@ Directives can also be injected dynamically using the [HTML Tag Processor](https With directives, we can directly manage behavior related to things such as side effects, state, event handlers, attributes or content. -#### `wp-interactive` +#### `wp-interactive` The `wp-interactive` directive "activates" the interactivity for the DOM element and its children through the Interactivity API (directives and store). It includes a namespace to reference a specific store. ```html -
@@ -88,13 +90,13 @@ The `wp-interactive` directive "activates" the interactivity for the DOM element > **Note** > The use of `data-wp-interactive` is a requirement for the Interactivity API "engine" to work. In the following examples the `data-wp-interactive` has not been added for the sake of simplicity. Also, the `data-wp-interactive` directive will be injected automatically in the future. -#### `wp-context` +#### `wp-context` It provides a **local** state available to a specific HTML node and its children. The `wp-context` directive accepts a stringified JSON as a value. -_Example of `wp-context` directive_ +_Example of `wp-context` directive_ ```php //render.php @@ -139,13 +141,13 @@ Different contexts can be defined at different levels, and deeper levels will me
``` -#### `wp-bind` +#### `wp-bind` It allows setting HTML attributes on elements based on a boolean or string value. > This directive follows the syntax `data-wp-bind--attribute`. -_Example of `wp-bind` directive_ +_Example of `wp-bind` directive_ ```html
  • @@ -183,10 +185,10 @@ store( "myPlugin", { The `wp-bind` directive is executed: -- When the element is created. +- When the element is created. - Each time there's a change on any of the properties of the `state` or `context` involved in getting the final value of the directive (inside the callback or the expression passed as reference). -When `wp-bind` directive references a callback to get its final value: +When `wp-bind` directive references a callback to get its final value: - The `wp-bind` directive will be executed each time there's a change on any of the properties of the `state` or `context` used inside this callback. - The returned value in the callback function is used to change the value of the associated attribute. @@ -198,24 +200,24 @@ The `wp-bind` will do different things over the DOM element is applied, dependin - If the value is a string, the attribute is added with its value assigned: `
    `. -#### `wp-class` +#### `wp-class` It adds or removes a class to an HTML element, depending on a boolean value. > This directive follows the syntax `data-wp-class--classname`. -_Example of `wp-class` directive_ +_Example of `wp-class` directive_ ```html
    -
  • Option 1
  • -
  • This directive follows the syntax `data-wp-style--css-property`. -_Example of `wp-style` directive_ +_Example of `wp-style` directive_ ```html
    @@ -296,7 +298,7 @@ The value received by the directive is used to add or remove the style attribute - If the value is `false`, the style attribute is removed: `
    `. - If the value is a string, the attribute is added with its value assigned: `
    `. -#### `wp-text` +#### `wp-text` It sets the inner text of an HTML element. @@ -333,13 +335,13 @@ The `wp-text` directive is executed: The returned value is used to change the inner content of the element: `
    value
    `. -#### `wp-on` +#### `wp-on` -It runs code on dispatched DOM events like `click` or `keyup`. +It runs code on dispatched DOM events like `click` or `keyup`. > The syntax of this directive is `data-wp-on--[event]` (like `data-wp-on--click` or `data-wp-on--keyup`). -_Example of `wp-on` directive_ +_Example of `wp-on` directive_ ```php