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

[PoC] Bindings API: handling data sync in the Model context #60173

Closed
wants to merge 43 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
b25d67d
edit
retrofox Mar 6, 2024
7e5b8a1
introduce withBlockResetwithBlockReset() HOC
retrofox Mar 6, 2024
4059c23
remove
retrofox Mar 6, 2024
4d1c570
edito
retrofox Mar 6, 2024
9c84e22
store get. discard useSource
retrofox Mar 6, 2024
8214922
remove useSource from data handler
retrofox Mar 6, 2024
94f31fa
move binding helpers to its main folder
retrofox Mar 6, 2024
57e58cf
remove use binding attibute hook
retrofox Mar 6, 2024
b4b1334
introduce connect() source handler
retrofox Mar 7, 2024
485bfa2
move logic to update bound attrs to actions
retrofox Mar 7, 2024
b8d80d2
set onPropChange() optional
retrofox Mar 7, 2024
9b4129b
minor code change
retrofox Mar 7, 2024
0abc716
group bound attrs by block. Update once
retrofox Mar 7, 2024
4c8889d
batch actions when updating bound attrs
retrofox Mar 7, 2024
9299b60
do not register changes when updating from external source
retrofox Mar 7, 2024
85b4c0c
Refactor useMarkPersistent function
michalczaplinski Feb 26, 2024
1411bbf
introduce core/bindings package
retrofox Mar 7, 2024
f66da95
register @wordpress/binding package
retrofox Mar 20, 2024
f454c83
register source handlers in the bindings store
retrofox Mar 20, 2024
b83d061
add bindings dep
retrofox Mar 20, 2024
8e8ece0
edit
retrofox Mar 21, 2024
67acce2
register children blocks with bound attrs
retrofox Mar 21, 2024
172dcc6
simplify core/post-meta source handler
retrofox Mar 21, 2024
bf9b46d
introduce and register core/post-entity
retrofox Mar 21, 2024
8b4b45b
check metadata attr before to register prop
retrofox Mar 21, 2024
6565ae0
updateCallback is optional
retrofox Mar 21, 2024
8b791f4
move observer into an action
retrofox Mar 22, 2024
e9e3c54
introduce getBoundAttributeValue block-editore selector
retrofox Mar 22, 2024
15f6f1c
doc
retrofox Mar 22, 2024
3bd6f47
iterate over reset blocks bindings
retrofox Mar 25, 2024
5609270
update bindings pkg
retrofox Mar 25, 2024
8a61272
finish beta approach
retrofox Mar 25, 2024
ec17e36
check value before to set prop entity
retrofox Mar 25, 2024
5f6f17d
extend all props when registering source handler
retrofox Mar 25, 2024
607c8a0
restore lockAttributesEditing handling in rich-text
retrofox Mar 25, 2024
b638e78
add bindings dep to block-library
retrofox Mar 25, 2024
e4a84a1
restore locking bounds for buttons
retrofox Mar 25, 2024
9cdb97f
restore locking image block
retrofox Mar 25, 2024
d4791db
clean
retrofox Mar 25, 2024
af07f0f
rename and doc API
retrofox Mar 25, 2024
31b7eb5
lock post meta attributes editing by defaul
retrofox Mar 25, 2024
8a543f6
do not lock attributes bound to the post-meta handler
retrofox Mar 25, 2024
ce2fc58
rename and doc blocks-editor code
retrofox Mar 25, 2024
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
6 changes: 6 additions & 0 deletions docs/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -1397,6 +1397,12 @@
"markdown_source": "../packages/base-styles/README.md",
"parent": "packages"
},
{
"title": "@wordpress/bindings",
"slug": "packages-bindings",
"markdown_source": "../packages/bindings/README.md",
"parent": "packages"
},
{
"title": "@wordpress/blob",
"slug": "packages-blob",
Expand Down
38 changes: 38 additions & 0 deletions docs/reference-guides/data/data-core-block-editor.md
Original file line number Diff line number Diff line change
Expand Up @@ -1555,6 +1555,36 @@ _Returns_

- `Object`: Action object.

### resetBindingBlocks

Creates an action to register a block's attribute binding to an external property.

It registers a specific block attribute to be updated based on the value of an external property, identified by a unique key.

_Parameters_

- _clientId_ `string`: - Block client ID.
- _attribute_ `string`: - The name of the block attribute to bind.
- _key_ `string`: - The key representing the external property.

_Returns_

- `Object`: Redux 'RESET_BINDING_CONNECTION_BLOCKS' type action.

### resetBlockBindingConnections

Connect blocks with bound attributes to external data sources.

Attributes specified in block metadata bindings are updated according to the corresponding external values.

_Parameters_

- _blocks_ `Object`: - Blocks list.

_Returns_

- `Function`: Returns a Redux thunk function that processes blocks and sets up bindings.

### resetBlocks

Action that resets blocks state to the specified array of blocks, taking precedence over any other content reflected as an edit in state.
Expand Down Expand Up @@ -1796,6 +1826,10 @@ _Returns_

- `Object`: Action object.

### unregisterBlockBinding

Undocumented declaration.

### unsetBlockEditingMode

Clears the block editing mode for a given block.
Expand Down Expand Up @@ -1839,6 +1873,10 @@ _Returns_

- `Object`: Action object.

### updateBlockBoundAttributes

Undocumented declaration.

### updateBlockListSettings

Action that changes the nested settings of a given block.
Expand Down
35 changes: 35 additions & 0 deletions package-lock.json

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

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"@wordpress/annotations": "file:packages/annotations",
"@wordpress/api-fetch": "file:packages/api-fetch",
"@wordpress/autop": "file:packages/autop",
"@wordpress/bindings": "file:packages/bindings",
"@wordpress/blob": "file:packages/blob",
"@wordpress/block-directory": "file:packages/block-directory",
"@wordpress/block-editor": "file:packages/block-editor",
Expand Down
Empty file added packages/bindings/.npmrc
Empty file.
3 changes: 3 additions & 0 deletions packages/bindings/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<!-- Learn how to maintain this file at https://github.com/WordPress/gutenberg/tree/HEAD/packages#maintaining-changelogs. -->

Initial release.
1 change: 1 addition & 0 deletions packages/bindings/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Bindings API
39 changes: 39 additions & 0 deletions packages/bindings/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"name": "@wordpress/bindings",
"version": "0.23.0",
"description": "Connect to external sources by using the Bindings API.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
"keywords": [
"wordpress",
"gutenberg",
"bindings"
],
"homepage": "https://github.com/WordPress/gutenberg/tree/HEAD/packages/bindings/README.md",
"repository": {
"type": "git",
"url": "https://github.com/WordPress/gutenberg.git",
"directory": "packages/bindings"
},
"bugs": {
"url": "https://github.com/WordPress/gutenberg/issues"
},
"engines": {
"node": ">=12"
},
"main": "build/index.js",
"module": "build-module/index.js",
"react-native": "src/index",
"dependencies": {
"@babel/runtime": "^7.16.0",
"@wordpress/data": "file:../data",
"@wordpress/private-apis": "file:../private-apis"
},
"peerDependencies": {
"react": "^18.0.0",
"react-dom": "^18.0.0"
},
"publishConfig": {
"access": "public"
}
}
1 change: 1 addition & 0 deletions packages/bindings/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { store } from './store';
10 changes: 10 additions & 0 deletions packages/bindings/src/lock-unlock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* WordPress dependencies
*/
import { __dangerousOptInToUnstableAPIsOnlyForCoreModules } from '@wordpress/private-apis';

export const { lock, unlock } =
__dangerousOptInToUnstableAPIsOnlyForCoreModules(
'I know using unstable features means my theme or plugin will inevitably break in the next version of WordPress.',
'@wordpress/commands'
);
37 changes: 37 additions & 0 deletions packages/bindings/src/store/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* WordPress dependencies
*/
import { createReduxStore, register } from '@wordpress/data';

/**
* Internal dependencies
*/
import reducer from './reducer';
import * as privateActions from './private-actions';
import * as privateSelectors from './private-selectors';
import { unlock } from '../lock-unlock';

const STORE_NAME = 'core/bindings';

/**
* Store definition for the bindings namespace.
*
* @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/data/README.md#createReduxStore
*
* @type {Object}
*
* @example
* ```js
* import { store as bindingsStore } from '@wordpress/bindings';
* import { dispatch } from '@wordpress/data';
*
* const { registerBindingsSource } = dispatch( bindingsStore );
* ```
*/
export const store = createReduxStore( STORE_NAME, {
reducer,
} );

register( store );
unlock( store ).registerPrivateActions( privateActions );
unlock( store ).registerPrivateSelectors( privateSelectors );
107 changes: 107 additions & 0 deletions packages/bindings/src/store/private-actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/**
* Internal dependencies
*/
import { generateBindingsConnectionKey } from './utils';

/**
* Register an external source
*
* @param {string} source Name of the source to register.
*/
export function registerBindingsSource( source ) {
return {
type: 'REGISTER_BINDINGS_SOURCE',
...source,
};
}

/**
* Sets up a subscription to monitor changes
* in a specified bindings connection.
*
* @param {string} key - The key identifying the bindings connection to observe.
* @param {Function} [updateCallback] - Optional callback invoked when the observed property changes.
* @return {Function} Thunk.
*/
export function observeBindingsConnectionChange( key, updateCallback ) {
return ( { select, registry, dispatch } ) => {
const handler = select.getBindingsConnectionHandler( key );
let currentValue = handler.get();

function watchValueChanges() {
const value = select.getBindingsConnectionValue( key );
if ( value === currentValue ) {
return;
}

currentValue = value;
updateCallback?.( value );
}

dispatch( {
type: 'UPDATE_BINDINGS_CONNECTION',
key,
unsubscribe: registry.subscribe( watchValueChanges ),
} );
};
}

/**
* Registers a connection to a bindings source.
* The connection is established by a combination
* of the source handler name and the binding arguments.
*
* @param {Object} settings - Settings.
* @param {string} settings.source - The source handler name.
* @param {Object} settings.args - The binding arguments.
* @param {Function} updateCallback - Callback invoked when the connection value changes.
* @return {Function} Thunk function for Redux dispatch, registers the connection.
*/
export function registerBindingsConnection( { source, args }, updateCallback ) {
return ( { dispatch, select } ) => {
const settings = select.getBindingsSource( source );
if ( ! settings ) {
return;
}

// Do not register if it's already registered.
const key = generateBindingsConnectionKey( { source, args } );
if ( select.getBindingsConnectionHandler( key ) ) {
return;
}

const { connect } = settings;
const handler = connect( args );

dispatch( {
type: 'REGISTER_BINDINGS_CONNECTION',
key,
...handler,
} );

/*
* Observe the external property to monitor changes.
* To do: scale this to register multiple callbacks.
*/
dispatch.observeBindingsConnectionChange( key, updateCallback );
};
}

/**
* Updates the value of a bindings connection.
* The connection is identified by the connection key.
*
* @param {string} key - The connection key.
* @param {*} value - The new value.
* @return {Function} Thunk function for Redux dispatch, updates the connection value.
*/
export function updateBindingsConnectionValue( key, value ) {
return ( { select } ) => {
const bindingsConnection = select.getBindingsConnectionHandler( key );
if ( ! bindingsConnection ) {
return;
}

bindingsConnection.update( value );
};
}
Loading
Loading