From 76a63a1f93062bd1c28210813911ae39ca93e56f Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Mon, 21 Aug 2023 11:59:37 +0200 Subject: [PATCH 1/8] Add failing test --- .../directive-key/block.json | 14 ++++++++ .../directive-key/render.php | 9 +++++ .../interactive-blocks/directive-key/view.js | 16 +++++++++ .../specs/interactivity/directive-key.spec.ts | 34 +++++++++++++++++++ 4 files changed, 73 insertions(+) create mode 100644 packages/e2e-tests/plugins/interactive-blocks/directive-key/block.json create mode 100644 packages/e2e-tests/plugins/interactive-blocks/directive-key/render.php create mode 100644 packages/e2e-tests/plugins/interactive-blocks/directive-key/view.js create mode 100644 test/e2e/specs/interactivity/directive-key.spec.ts diff --git a/packages/e2e-tests/plugins/interactive-blocks/directive-key/block.json b/packages/e2e-tests/plugins/interactive-blocks/directive-key/block.json new file mode 100644 index 0000000000000..0cbdd065e63a1 --- /dev/null +++ b/packages/e2e-tests/plugins/interactive-blocks/directive-key/block.json @@ -0,0 +1,14 @@ +{ + "apiVersion": 2, + "name": "test/directive-key", + "title": "E2E Interactivity tests - directive key", + "category": "text", + "icon": "heart", + "description": "", + "supports": { + "interactivity": true + }, + "textdomain": "e2e-interactivity", + "viewScript": "directive-key-view", + "render": "file:./render.php" +} diff --git a/packages/e2e-tests/plugins/interactive-blocks/directive-key/render.php b/packages/e2e-tests/plugins/interactive-blocks/directive-key/render.php new file mode 100644 index 0000000000000..9edffa6ab0ca5 --- /dev/null +++ b/packages/e2e-tests/plugins/interactive-blocks/directive-key/render.php @@ -0,0 +1,9 @@ + + +
diff --git a/packages/e2e-tests/plugins/interactive-blocks/directive-key/view.js b/packages/e2e-tests/plugins/interactive-blocks/directive-key/view.js new file mode 100644 index 0000000000000..7e741879cf063 --- /dev/null +++ b/packages/e2e-tests/plugins/interactive-blocks/directive-key/view.js @@ -0,0 +1,16 @@ +( ( { wp } ) => { + const { store, navigate } = wp.interactivity; + + const add = '
' + + store( { + actions: { + add: () => { + navigate( window.location, { + force: true, + html: add, + } ); + }, + }, + } ); +} )( window ); diff --git a/test/e2e/specs/interactivity/directive-key.spec.ts b/test/e2e/specs/interactivity/directive-key.spec.ts new file mode 100644 index 0000000000000..dcdfbfa5f5caf --- /dev/null +++ b/test/e2e/specs/interactivity/directive-key.spec.ts @@ -0,0 +1,34 @@ +/** + * Internal dependencies + */ +import { test, expect } from './fixtures'; + +test.describe( 'data-wp-key', () => { + test.beforeAll( async ( { interactivityUtils: utils } ) => { + await utils.activatePlugins(); + await utils.addPostWithBlock( 'test/directive-key' ); + } ); + + test.beforeEach( async ( { interactivityUtils: utils, page } ) => { + await page.goto( utils.getLink( 'test/directive-key' ) ); + } ); + + test.afterAll( async ( { interactivityUtils: utils } ) => { + await utils.deactivatePlugins(); + await utils.deleteAllPosts(); + } ); + + test( 'should keep the elements when adding items to the start of the array', async ( { + page, + } ) => { + // Add + await page + .getByTestId( 'first-item' ) + .evaluate( ( n ) => ( ( n as any )._id = 123 ) ); + await page.getByTestId( 'add' ).click(); + const id = await page + .getByTestId( 'second-item' ) + .evaluate( ( n ) => ( n as any )._id ); + expect( id ).toBe( 123 ); + } ); +} ); From c0676129418bbd9030af933a3f864918f4b96c35 Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Mon, 21 Aug 2023 11:59:37 +0200 Subject: [PATCH 2/8] Fix test using key --- .../plugins/interactive-blocks/directive-key/render.php | 2 +- .../e2e-tests/plugins/interactive-blocks/directive-key/view.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/e2e-tests/plugins/interactive-blocks/directive-key/render.php b/packages/e2e-tests/plugins/interactive-blocks/directive-key/render.php index 9edffa6ab0ca5..bd9a320e20707 100644 --- a/packages/e2e-tests/plugins/interactive-blocks/directive-key/render.php +++ b/packages/e2e-tests/plugins/interactive-blocks/directive-key/render.php @@ -6,4 +6,4 @@ */ ?> -
  • 2
  • 3
+
  • 2
  • 3
diff --git a/packages/e2e-tests/plugins/interactive-blocks/directive-key/view.js b/packages/e2e-tests/plugins/interactive-blocks/directive-key/view.js index 7e741879cf063..33dc247bab720 100644 --- a/packages/e2e-tests/plugins/interactive-blocks/directive-key/view.js +++ b/packages/e2e-tests/plugins/interactive-blocks/directive-key/view.js @@ -1,7 +1,7 @@ ( ( { wp } ) => { const { store, navigate } = wp.interactivity; - const add = '
  • 1
  • 2
  • 3
' + const add = '
  • 1
  • 2
  • 3
' store( { actions: { From b0017ce360c6a5867969bbd6ca205795337a8b8a Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Mon, 21 Aug 2023 11:59:37 +0200 Subject: [PATCH 3/8] Replace key with data-wp-key --- .../plugins/interactive-blocks/directive-key/render.php | 2 +- .../e2e-tests/plugins/interactive-blocks/directive-key/view.js | 2 +- packages/interactivity/src/hooks.js | 1 + test/e2e/specs/interactivity/directive-key.spec.ts | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/e2e-tests/plugins/interactive-blocks/directive-key/render.php b/packages/e2e-tests/plugins/interactive-blocks/directive-key/render.php index bd9a320e20707..8d23a18af6876 100644 --- a/packages/e2e-tests/plugins/interactive-blocks/directive-key/render.php +++ b/packages/e2e-tests/plugins/interactive-blocks/directive-key/render.php @@ -6,4 +6,4 @@ */ ?> -
  • 2
  • 3
+
  • 2
  • 3
diff --git a/packages/e2e-tests/plugins/interactive-blocks/directive-key/view.js b/packages/e2e-tests/plugins/interactive-blocks/directive-key/view.js index 33dc247bab720..9706d213a77f6 100644 --- a/packages/e2e-tests/plugins/interactive-blocks/directive-key/view.js +++ b/packages/e2e-tests/plugins/interactive-blocks/directive-key/view.js @@ -1,7 +1,7 @@ ( ( { wp } ) => { const { store, navigate } = wp.interactivity; - const add = '
  • 1
  • 2
  • 3
' + const add = '
  • 1
  • 2
  • 3
' store( { actions: { diff --git a/packages/interactivity/src/hooks.js b/packages/interactivity/src/hooks.js index 448060caf2b2e..d5b019300fed1 100644 --- a/packages/interactivity/src/hooks.js +++ b/packages/interactivity/src/hooks.js @@ -205,6 +205,7 @@ options.vnode = ( vnode ) => { if ( vnode.props.__directives ) { const props = vnode.props; const directives = props.__directives; + if ( directives.key ) vnode.key = directives.key.default; delete props.__directives; const priorityLevels = getPriorityLevels( directives ); if ( priorityLevels.length > 0 ) { diff --git a/test/e2e/specs/interactivity/directive-key.spec.ts b/test/e2e/specs/interactivity/directive-key.spec.ts index dcdfbfa5f5caf..3700c430bb398 100644 --- a/test/e2e/specs/interactivity/directive-key.spec.ts +++ b/test/e2e/specs/interactivity/directive-key.spec.ts @@ -21,7 +21,7 @@ test.describe( 'data-wp-key', () => { test( 'should keep the elements when adding items to the start of the array', async ( { page, } ) => { - // Add + // Add a number to the node so we can check later that it is still there. await page .getByTestId( 'first-item' ) .evaluate( ( n ) => ( ( n as any )._id = 123 ) ); From 6545b5e85f483cdd16cd5a49ba6272831f7e0a37 Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Mon, 21 Aug 2023 11:59:37 +0200 Subject: [PATCH 4/8] Refactor test a bit --- .../interactive-blocks/directive-key/render.php | 10 +++++++++- .../interactive-blocks/directive-key/view.js | 13 ++++++++++--- test/e2e/specs/interactivity/directive-key.spec.ts | 2 +- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/packages/e2e-tests/plugins/interactive-blocks/directive-key/render.php b/packages/e2e-tests/plugins/interactive-blocks/directive-key/render.php index 8d23a18af6876..ca8237fbc2bf8 100644 --- a/packages/e2e-tests/plugins/interactive-blocks/directive-key/render.php +++ b/packages/e2e-tests/plugins/interactive-blocks/directive-key/render.php @@ -6,4 +6,12 @@ */ ?> -
  • 2
  • 3
+
+
    +
  • 2
  • +
  • 3
  • +
+ +
diff --git a/packages/e2e-tests/plugins/interactive-blocks/directive-key/view.js b/packages/e2e-tests/plugins/interactive-blocks/directive-key/view.js index 9706d213a77f6..a155dec99e0aa 100644 --- a/packages/e2e-tests/plugins/interactive-blocks/directive-key/view.js +++ b/packages/e2e-tests/plugins/interactive-blocks/directive-key/view.js @@ -1,14 +1,21 @@ ( ( { wp } ) => { const { store, navigate } = wp.interactivity; - const add = '
  • 1
  • 2
  • 3
' + const html = ` +
+
    +
  • 1
  • +
  • 2
  • +
  • 3
  • +
+
`; store( { actions: { - add: () => { + navigate: () => { navigate( window.location, { force: true, - html: add, + html, } ); }, }, diff --git a/test/e2e/specs/interactivity/directive-key.spec.ts b/test/e2e/specs/interactivity/directive-key.spec.ts index 3700c430bb398..b780100b92a6d 100644 --- a/test/e2e/specs/interactivity/directive-key.spec.ts +++ b/test/e2e/specs/interactivity/directive-key.spec.ts @@ -25,7 +25,7 @@ test.describe( 'data-wp-key', () => { await page .getByTestId( 'first-item' ) .evaluate( ( n ) => ( ( n as any )._id = 123 ) ); - await page.getByTestId( 'add' ).click(); + await page.getByTestId( 'navigate' ).click(); const id = await page .getByTestId( 'second-item' ) .evaluate( ( n ) => ( n as any )._id ); From 6c9dfb4d822390e4899e323226e9280cd17514a7 Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Mon, 21 Aug 2023 12:09:56 +0200 Subject: [PATCH 5/8] Add changelog --- packages/interactivity/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/interactivity/CHANGELOG.md b/packages/interactivity/CHANGELOG.md index 83f58772c11dc..3584e9542cc18 100644 --- a/packages/interactivity/CHANGELOG.md +++ b/packages/interactivity/CHANGELOG.md @@ -4,6 +4,7 @@ ### New Features +- Support keys using `data-wp-key`. ([#53844](https://github.com/WordPress/gutenberg/pull/53844)) - Support region-based client-side navigation. ([#53733](https://github.com/WordPress/gutenberg/pull/53733)) - Allow passing optional `afterLoad` callbacks to `store` calls. ([#53363](https://github.com/WordPress/gutenberg/pull/53363)) From aa08d7d43d9ce7b00de6877cc82ce48d77d75a5a Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Mon, 21 Aug 2023 12:30:00 +0200 Subject: [PATCH 6/8] Add docs --- .../interactivity/docs/2-api-reference.md | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/packages/interactivity/docs/2-api-reference.md b/packages/interactivity/docs/2-api-reference.md index 920b27f4727d5..dbd6b205aba19 100644 --- a/packages/interactivity/docs/2-api-reference.md +++ b/packages/interactivity/docs/2-api-reference.md @@ -22,6 +22,7 @@ DOM elements are connected to data stored in the state & context through directi - [`wp-on`](#wp-on) ![](https://img.shields.io/badge/EVENT_HANDLERS-afd2e3.svg) - [`wp-effect`](#wp-effect) ![](https://img.shields.io/badge/SIDE_EFFECTS-afd2e3.svg) - [`wp-init`](#wp-init) ![](https://img.shields.io/badge/SIDE_EFFECTS-afd2e3.svg) + - [`wp-key`](#wp-key) ![](https://img.shields.io/badge/TEMPLATING-afd2e3.svg) - [Values of directives are references to store properties](#values-of-directives-are-references-to-store-properties) - [The store](#the-store) - [Elements of the store](#elements-of-the-store) @@ -449,6 +450,32 @@ store( { The `wp-init` can return a function. If it does, the returned function will run when the element is removed from the DOM. +#### `wp-key` + +Here is the text for the `wp-key` directive description: + +The `wp-key` directive assigns a unique key to an element to help the Interactivity API identify it when iterating through arrays of elements. This becomes important if your array elements can move (e.g. due to sorting), get inserted, or get deleted. A well-chosen key value helps the Interactivity API infer what exactly has changed in the array, allowing it to make the correct updates to the DOM. + +The key should be a string that uniquely identifies the element among its siblings. Typically it is used on repeated elements like list items. For example: + +```html +
    +
  • Item 1
  • +
  • Item 2
  • +
+``` + +But it can also be used on other elements: + +```html + +``` + +When the list is re-rendered, the Interactivity API will match elements by their keys to determine if an item was added/removed/reordered. Elements without keys might be recreated unnecessarily. + ### Values of directives are references to store properties The value assigned to a directive is a string pointing to a specific state, selector, action, or effect. *Using a Namespace is highly recommended* to define these elements of the store. From 9dd4ff16ad4f5454c5e199419080abd10e559293 Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Mon, 21 Aug 2023 14:14:49 +0200 Subject: [PATCH 7/8] Remove unnecessary paragraph --- packages/interactivity/docs/2-api-reference.md | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/interactivity/docs/2-api-reference.md b/packages/interactivity/docs/2-api-reference.md index dbd6b205aba19..36811ae61bc4d 100644 --- a/packages/interactivity/docs/2-api-reference.md +++ b/packages/interactivity/docs/2-api-reference.md @@ -452,7 +452,6 @@ The `wp-init` can return a function. If it does, the returned function will run #### `wp-key` -Here is the text for the `wp-key` directive description: The `wp-key` directive assigns a unique key to an element to help the Interactivity API identify it when iterating through arrays of elements. This becomes important if your array elements can move (e.g. due to sorting), get inserted, or get deleted. A well-chosen key value helps the Interactivity API infer what exactly has changed in the array, allowing it to make the correct updates to the DOM. From 5ca3702d66e3cc1a264e590534a7a8e8f01ec33f Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Tue, 22 Aug 2023 09:57:01 +0200 Subject: [PATCH 8/8] Fix lint error --- .../plugins/interactive-blocks/directive-key/render.php | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/e2e-tests/plugins/interactive-blocks/directive-key/render.php b/packages/e2e-tests/plugins/interactive-blocks/directive-key/render.php index ca8237fbc2bf8..07c6e4e3de161 100644 --- a/packages/e2e-tests/plugins/interactive-blocks/directive-key/render.php +++ b/packages/e2e-tests/plugins/interactive-blocks/directive-key/render.php @@ -4,6 +4,7 @@ * * @package gutenberg-test-interactive-blocks */ + ?>