@wordpress/preferences 1.3.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 2.0.0 (2022-05-04)
6
+
7
+ ### Breaking change
8
+
9
+ - The preferences package is no longer compatible with the `@wordpress/data` persistence plugin. Please use the new `setPersistenceLayer` API. ([#39795](https://github.com/WordPress/gutenberg/pull/39795))
10
+
11
+ ### Enhancement
12
+
13
+ - A new `setPersistenceLayer` action has been introduced. ([#39795](https://github.com/WordPress/gutenberg/pull/39795))
14
+
5
15
  ## 1.3.0 (2022-04-21)
6
16
 
7
17
  ## 1.2.0 (2022-04-08)
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Preferences
2
2
 
3
- Utilities for storing WordPress preferences.
3
+ A key/value store for application preferences.
4
4
 
5
5
  ## Installation
6
6
 
@@ -12,12 +12,28 @@ npm install @wordpress/preferences --save
12
12
 
13
13
  _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._
14
14
 
15
+ ## Key concepts
16
+
17
+ ### Scope
18
+
19
+ Many API calls require a 'scope' parameter that acts like a namespace. If you have multiple parameters with the same key but they apply to different parts of your application, using scopes is the best way to segregate them.
20
+
21
+ ### Key
22
+
23
+ Each preference is set against a key that should be a string.
24
+
25
+ ### Value
26
+
27
+ Values can be of any type, but the types supported may be limited by the persistence layer configure. For example if preferences are saved to browser localStorage in JSON format, only JSON serializable types should be used.
28
+
29
+ ### Defaults
30
+
31
+ Defaults are the value returned when a preference is `undefined`. These are not persisted, they are only kept in memory. They should be during the initialization of an application.
32
+
15
33
  ## Examples
16
34
 
17
35
  ### Data store
18
36
 
19
- Preferences are persisted values of any kind.
20
-
21
37
  Set the default preferences for any features on initialization by dispatching an action:
22
38
 
23
39
  ```js
@@ -38,7 +54,7 @@ function initialize() {
38
54
  }
39
55
  ```
40
56
 
41
- Or the `get` selector to get a preference value, and the `set` action to update a preference to any value:
57
+ Use the `get` selector to get a preference value, and the `set` action to update a preference:
42
58
 
43
59
  ```js
44
60
  wp.data
@@ -66,6 +82,58 @@ wp.data
66
82
  .get( 'namespace/editor-or-plugin-name', 'myPreferenceName' ); // false
67
83
  ```
68
84
 
85
+ #### Setting up a persistence layer
86
+
87
+ By default, this package only stores values in-memory. But it can be configured to persist preferences to browser storage or a database via an optional persistence layer.
88
+
89
+ Use the `setPersistenceLayer` action to configure how the store persists its preference values.
90
+
91
+ ```js
92
+ wp.data.dispatch( 'core/preferences' ).setPersistenceLayer( {
93
+ // `get` is asynchronous to support persisting preferences using a REST API.
94
+ // it will immediately be called by `setPersistenceLayer` and the returned
95
+ // value used as the initial state of the preferences.
96
+ async get() {
97
+ return JSON.parse( window.localStorage.getItem( 'MY_PREFERENCES' ) );
98
+ },
99
+
100
+ // `set` is synchronous. It's ok to use asynchronous code, but the
101
+ // preferences store won't wait for a promise to resolve, the function is
102
+ // 'fire and forget'.
103
+ set( preferences ) {
104
+ window.localStorage.setItem(
105
+ 'MY_PREFERENCES',
106
+ JSON.stringify( preferences )
107
+ );
108
+ },
109
+ } );
110
+ ```
111
+
112
+ For application that persist data to an asynchronous API, a concern is that loading preferences can lead to slower application start up.
113
+
114
+ A recommendation is to pre-load any persistence layer data and keep it in a local cache particularly if you're using an asynchronous API to persist data.
115
+
116
+ Note: currently `get` is called only when `setPersistenceLayer` is triggered. This may change in the future, so it's sensible to optimize `get` using a local cache, as shown in the example below.
117
+
118
+ ```js
119
+ // Preloaded data from the server.
120
+ let cache = preloadedData;
121
+ wp.data.dispatch( 'core/preferences' ).setPersistenceLayer( {
122
+ async get() {
123
+ if ( cache ) {
124
+ return cache;
125
+ }
126
+
127
+ // Call to a made-up async API.
128
+ return await api.preferences.get();
129
+ },
130
+ set( preferences ) {
131
+ cache = preferences;
132
+ api.preferences.set( { data: preferences } );
133
+ },
134
+ } );
135
+ ```
136
+
69
137
  ### Components
70
138
 
71
139
  The `PreferenceToggleMenuItem` components can be used with a `DropdownMenu` to implement a menu for changing preferences.
@@ -130,6 +198,27 @@ _Returns_
130
198
 
131
199
  - `Object`: Action object.
132
200
 
201
+ #### setPersistenceLayer
202
+
203
+ Sets the persistence layer.
204
+
205
+ When a persistence layer is set, the preferences store will:
206
+
207
+ - call `get` immediately and update the store state to the value returned.
208
+ - call `set` with all preferences whenever a preference changes value.
209
+
210
+ `setPersistenceLayer` should ideally be dispatched at the start of an
211
+ application's lifecycle, before any other actions have been dispatched to
212
+ the preferences store.
213
+
214
+ _Parameters_
215
+
216
+ - _persistenceLayer_ `WPPreferencesPersistenceLayer`: The persistence layer.
217
+
218
+ _Returns_
219
+
220
+ - `Object`: Action object.
221
+
133
222
  #### toggle
134
223
 
135
224
  Returns an action object used in signalling that a preference should be
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.set = set;
7
7
  exports.setDefaults = setDefaults;
8
+ exports.setPersistenceLayer = setPersistenceLayer;
8
9
  exports.toggle = toggle;
9
10
 
10
11
  /**
@@ -62,4 +63,40 @@ function setDefaults(scope, defaults) {
62
63
  defaults
63
64
  };
64
65
  }
66
+ /** @typedef {() => Promise<Object>} WPPreferencesPersistenceLayerGet */
67
+
68
+ /** @typedef {(*) => void} WPPreferencesPersistenceLayerSet */
69
+
70
+ /**
71
+ * @typedef WPPreferencesPersistenceLayer
72
+ *
73
+ * @property {WPPreferencesPersistenceLayerGet} get An async function that gets data from the persistence layer.
74
+ * @property {WPPreferencesPersistenceLayerSet} set A function that sets data in the persistence layer.
75
+ */
76
+
77
+ /**
78
+ * Sets the persistence layer.
79
+ *
80
+ * When a persistence layer is set, the preferences store will:
81
+ * - call `get` immediately and update the store state to the value returned.
82
+ * - call `set` with all preferences whenever a preference changes value.
83
+ *
84
+ * `setPersistenceLayer` should ideally be dispatched at the start of an
85
+ * application's lifecycle, before any other actions have been dispatched to
86
+ * the preferences store.
87
+ *
88
+ * @param {WPPreferencesPersistenceLayer} persistenceLayer The persistence layer.
89
+ *
90
+ * @return {Object} Action object.
91
+ */
92
+
93
+
94
+ async function setPersistenceLayer(persistenceLayer) {
95
+ const persistedData = await persistenceLayer.get();
96
+ return {
97
+ type: 'SET_PERSISTENCE_LAYER',
98
+ persistenceLayer,
99
+ persistedData
100
+ };
101
+ }
65
102
  //# sourceMappingURL=actions.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["@wordpress/preferences/src/store/actions.js"],"names":["toggle","scope","name","select","dispatch","currentValue","get","set","value","type","setDefaults","defaults"],"mappings":";;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASA,MAAT,CAAiBC,KAAjB,EAAwBC,IAAxB,EAA+B;AACrC,SAAO,gBAAkC;AAAA,QAAvB;AAAEC,MAAAA,MAAF;AAAUC,MAAAA;AAAV,KAAuB;AACxC,UAAMC,YAAY,GAAGF,MAAM,CAACG,GAAP,CAAYL,KAAZ,EAAmBC,IAAnB,CAArB;AACAE,IAAAA,QAAQ,CAACG,GAAT,CAAcN,KAAd,EAAqBC,IAArB,EAA2B,CAAEG,YAA7B;AACA,GAHD;AAIA;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AACO,SAASE,GAAT,CAAcN,KAAd,EAAqBC,IAArB,EAA2BM,KAA3B,EAAmC;AACzC,SAAO;AACNC,IAAAA,IAAI,EAAE,sBADA;AAENR,IAAAA,KAFM;AAGNC,IAAAA,IAHM;AAINM,IAAAA;AAJM,GAAP;AAMA;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AACO,SAASE,WAAT,CAAsBT,KAAtB,EAA6BU,QAA7B,EAAwC;AAC9C,SAAO;AACNF,IAAAA,IAAI,EAAE,yBADA;AAENR,IAAAA,KAFM;AAGNU,IAAAA;AAHM,GAAP;AAKA","sourcesContent":["/**\n * Returns an action object used in signalling that a preference should be\n * toggled.\n *\n * @param {string} scope The preference scope (e.g. core/edit-post).\n * @param {string} name The preference name.\n */\nexport function toggle( scope, name ) {\n\treturn function ( { select, dispatch } ) {\n\t\tconst currentValue = select.get( scope, name );\n\t\tdispatch.set( scope, name, ! currentValue );\n\t};\n}\n\n/**\n * Returns an action object used in signalling that a preference should be set\n * to a value\n *\n * @param {string} scope The preference scope (e.g. core/edit-post).\n * @param {string} name The preference name.\n * @param {*} value The value to set.\n *\n * @return {Object} Action object.\n */\nexport function set( scope, name, value ) {\n\treturn {\n\t\ttype: 'SET_PREFERENCE_VALUE',\n\t\tscope,\n\t\tname,\n\t\tvalue,\n\t};\n}\n\n/**\n * Returns an action object used in signalling that preference defaults should\n * be set.\n *\n * @param {string} scope The preference scope (e.g. core/edit-post).\n * @param {Object<string, *>} defaults A key/value map of preference names to values.\n *\n * @return {Object} Action object.\n */\nexport function setDefaults( scope, defaults ) {\n\treturn {\n\t\ttype: 'SET_PREFERENCE_DEFAULTS',\n\t\tscope,\n\t\tdefaults,\n\t};\n}\n"]}
1
+ {"version":3,"sources":["@wordpress/preferences/src/store/actions.js"],"names":["toggle","scope","name","select","dispatch","currentValue","get","set","value","type","setDefaults","defaults","setPersistenceLayer","persistenceLayer","persistedData"],"mappings":";;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASA,MAAT,CAAiBC,KAAjB,EAAwBC,IAAxB,EAA+B;AACrC,SAAO,gBAAkC;AAAA,QAAvB;AAAEC,MAAAA,MAAF;AAAUC,MAAAA;AAAV,KAAuB;AACxC,UAAMC,YAAY,GAAGF,MAAM,CAACG,GAAP,CAAYL,KAAZ,EAAmBC,IAAnB,CAArB;AACAE,IAAAA,QAAQ,CAACG,GAAT,CAAcN,KAAd,EAAqBC,IAArB,EAA2B,CAAEG,YAA7B;AACA,GAHD;AAIA;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AACO,SAASE,GAAT,CAAcN,KAAd,EAAqBC,IAArB,EAA2BM,KAA3B,EAAmC;AACzC,SAAO;AACNC,IAAAA,IAAI,EAAE,sBADA;AAENR,IAAAA,KAFM;AAGNC,IAAAA,IAHM;AAINM,IAAAA;AAJM,GAAP;AAMA;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AACO,SAASE,WAAT,CAAsBT,KAAtB,EAA6BU,QAA7B,EAAwC;AAC9C,SAAO;AACNF,IAAAA,IAAI,EAAE,yBADA;AAENR,IAAAA,KAFM;AAGNU,IAAAA;AAHM,GAAP;AAKA;AAED;;AACA;;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AACO,eAAeC,mBAAf,CAAoCC,gBAApC,EAAuD;AAC7D,QAAMC,aAAa,GAAG,MAAMD,gBAAgB,CAACP,GAAjB,EAA5B;AACA,SAAO;AACNG,IAAAA,IAAI,EAAE,uBADA;AAENI,IAAAA,gBAFM;AAGNC,IAAAA;AAHM,GAAP;AAKA","sourcesContent":["/**\n * Returns an action object used in signalling that a preference should be\n * toggled.\n *\n * @param {string} scope The preference scope (e.g. core/edit-post).\n * @param {string} name The preference name.\n */\nexport function toggle( scope, name ) {\n\treturn function ( { select, dispatch } ) {\n\t\tconst currentValue = select.get( scope, name );\n\t\tdispatch.set( scope, name, ! currentValue );\n\t};\n}\n\n/**\n * Returns an action object used in signalling that a preference should be set\n * to a value\n *\n * @param {string} scope The preference scope (e.g. core/edit-post).\n * @param {string} name The preference name.\n * @param {*} value The value to set.\n *\n * @return {Object} Action object.\n */\nexport function set( scope, name, value ) {\n\treturn {\n\t\ttype: 'SET_PREFERENCE_VALUE',\n\t\tscope,\n\t\tname,\n\t\tvalue,\n\t};\n}\n\n/**\n * Returns an action object used in signalling that preference defaults should\n * be set.\n *\n * @param {string} scope The preference scope (e.g. core/edit-post).\n * @param {Object<string, *>} defaults A key/value map of preference names to values.\n *\n * @return {Object} Action object.\n */\nexport function setDefaults( scope, defaults ) {\n\treturn {\n\t\ttype: 'SET_PREFERENCE_DEFAULTS',\n\t\tscope,\n\t\tdefaults,\n\t};\n}\n\n/** @typedef {() => Promise<Object>} WPPreferencesPersistenceLayerGet */\n/** @typedef {(*) => void} WPPreferencesPersistenceLayerSet */\n/**\n * @typedef WPPreferencesPersistenceLayer\n *\n * @property {WPPreferencesPersistenceLayerGet} get An async function that gets data from the persistence layer.\n * @property {WPPreferencesPersistenceLayerSet} set A function that sets data in the persistence layer.\n */\n\n/**\n * Sets the persistence layer.\n *\n * When a persistence layer is set, the preferences store will:\n * - call `get` immediately and update the store state to the value returned.\n * - call `set` with all preferences whenever a preference changes value.\n *\n * `setPersistenceLayer` should ideally be dispatched at the start of an\n * application's lifecycle, before any other actions have been dispatched to\n * the preferences store.\n *\n * @param {WPPreferencesPersistenceLayer} persistenceLayer The persistence layer.\n *\n * @return {Object} Action object.\n */\nexport async function setPersistenceLayer( persistenceLayer ) {\n\tconst persistedData = await persistenceLayer.get();\n\treturn {\n\t\ttype: 'SET_PERSISTENCE_LAYER',\n\t\tpersistenceLayer,\n\t\tpersistedData,\n\t};\n}\n"]}
@@ -29,10 +29,6 @@ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj &&
29
29
  * Internal dependencies
30
30
  */
31
31
 
32
- /**
33
- * Internal dependencies
34
- */
35
-
36
32
  /**
37
33
  * Store definition for the interface namespace.
38
34
  *
@@ -43,16 +39,8 @@ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj &&
43
39
  const store = (0, _data.createReduxStore)(_constants.STORE_NAME, {
44
40
  reducer: _reducer.default,
45
41
  actions,
46
- selectors,
47
- persist: ['preferences']
48
- }); // Once we build a more generic persistence plugin that works across types of stores
49
- // we'd be able to replace this with a register call.
50
-
51
- exports.store = store;
52
- (0, _data.registerStore)(_constants.STORE_NAME, {
53
- reducer: _reducer.default,
54
- actions,
55
- selectors,
56
- persist: ['preferences']
42
+ selectors
57
43
  });
44
+ exports.store = store;
45
+ (0, _data.register)(store);
58
46
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["@wordpress/preferences/src/store/index.js"],"names":["store","STORE_NAME","reducer","actions","selectors","persist"],"mappings":";;;;;;;;;AAGA;;AAQA;;AACA;;AACA;;AACA;;;;;;AAdA;AACA;AACA;;AAGA;AACA;AACA;;AACA;AACA;AACA;;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAMA,KAAK,GAAG,4BAAkBC,qBAAlB,EAA8B;AAClDC,EAAAA,OAAO,EAAPA,gBADkD;AAElDC,EAAAA,OAFkD;AAGlDC,EAAAA,SAHkD;AAIlDC,EAAAA,OAAO,EAAE,CAAE,aAAF;AAJyC,CAA9B,CAAd,C,CAOP;AACA;;;AACA,yBAAeJ,qBAAf,EAA2B;AAC1BC,EAAAA,OAAO,EAAPA,gBAD0B;AAE1BC,EAAAA,OAF0B;AAG1BC,EAAAA,SAH0B;AAI1BC,EAAAA,OAAO,EAAE,CAAE,aAAF;AAJiB,CAA3B","sourcesContent":["/**\n * WordPress dependencies\n */\nimport { createReduxStore, registerStore } from '@wordpress/data';\n\n/**\n * Internal dependencies\n */\n/**\n * Internal dependencies\n */\nimport reducer from './reducer';\nimport * as actions from './actions';\nimport * as selectors from './selectors';\nimport { STORE_NAME } from './constants';\n\n/**\n * Store definition for the interface namespace.\n *\n * @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/data/README.md#createReduxStore\n *\n * @type {Object}\n */\nexport const store = createReduxStore( STORE_NAME, {\n\treducer,\n\tactions,\n\tselectors,\n\tpersist: [ 'preferences' ],\n} );\n\n// Once we build a more generic persistence plugin that works across types of stores\n// we'd be able to replace this with a register call.\nregisterStore( STORE_NAME, {\n\treducer,\n\tactions,\n\tselectors,\n\tpersist: [ 'preferences' ],\n} );\n"]}
1
+ {"version":3,"sources":["@wordpress/preferences/src/store/index.js"],"names":["store","STORE_NAME","reducer","actions","selectors"],"mappings":";;;;;;;;;AAGA;;AAKA;;AACA;;AACA;;AACA;;;;;;AAXA;AACA;AACA;;AAGA;AACA;AACA;;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAMA,KAAK,GAAG,4BAAkBC,qBAAlB,EAA8B;AAClDC,EAAAA,OAAO,EAAPA,gBADkD;AAElDC,EAAAA,OAFkD;AAGlDC,EAAAA;AAHkD,CAA9B,CAAd;;AAMP,oBAAUJ,KAAV","sourcesContent":["/**\n * WordPress dependencies\n */\nimport { createReduxStore, register } from '@wordpress/data';\n\n/**\n * Internal dependencies\n */\nimport reducer from './reducer';\nimport * as actions from './actions';\nimport * as selectors from './selectors';\nimport { STORE_NAME } from './constants';\n\n/**\n * Store definition for the interface namespace.\n *\n * @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/data/README.md#createReduxStore\n *\n * @type {Object}\n */\nexport const store = createReduxStore( STORE_NAME, {\n\treducer,\n\tactions,\n\tselectors,\n} );\n\nregister( store );\n"]}
@@ -5,7 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
  exports.defaults = defaults;
8
- exports.preferences = preferences;
8
+ exports.preferences = void 0;
9
9
 
10
10
  var _data = require("@wordpress/data");
11
11
 
@@ -42,6 +42,43 @@ function defaults() {
42
42
 
43
43
  return state;
44
44
  }
45
+ /**
46
+ * Higher order reducer that does the following:
47
+ * - Merges any data from the persistence layer into the state when the
48
+ * `SET_PERSISTENCE_LAYER` action is received.
49
+ * - Passes any preferences changes to the persistence layer.
50
+ *
51
+ * @param {Function} reducer The preferences reducer.
52
+ *
53
+ * @return {Function} The enhanced reducer.
54
+ */
55
+
56
+
57
+ function withPersistenceLayer(reducer) {
58
+ let persistenceLayer;
59
+ return (state, action) => {
60
+ // Setup the persistence layer, and return the persisted data
61
+ // as the state.
62
+ if (action.type === 'SET_PERSISTENCE_LAYER') {
63
+ const {
64
+ persistenceLayer: persistence,
65
+ persistedData
66
+ } = action;
67
+ persistenceLayer = persistence;
68
+ return persistedData;
69
+ }
70
+
71
+ const nextState = reducer(state, action);
72
+
73
+ if (action.type === 'SET_PREFERENCE_VALUE') {
74
+ var _persistenceLayer;
75
+
76
+ (_persistenceLayer = persistenceLayer) === null || _persistenceLayer === void 0 ? void 0 : _persistenceLayer.set(nextState);
77
+ }
78
+
79
+ return nextState;
80
+ };
81
+ }
45
82
  /**
46
83
  * Reducer returning the user preferences.
47
84
  *
@@ -52,7 +89,7 @@ function defaults() {
52
89
  */
53
90
 
54
91
 
55
- function preferences() {
92
+ const preferences = withPersistenceLayer(function () {
56
93
  let state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
57
94
  let action = arguments.length > 1 ? arguments[1] : undefined;
58
95
 
@@ -70,7 +107,8 @@ function preferences() {
70
107
  }
71
108
 
72
109
  return state;
73
- }
110
+ });
111
+ exports.preferences = preferences;
74
112
 
75
113
  var _default = (0, _data.combineReducers)({
76
114
  defaults,
@@ -1 +1 @@
1
- {"version":3,"sources":["@wordpress/preferences/src/store/reducer.js"],"names":["defaults","state","action","type","scope","values","preferences","name","value"],"mappings":";;;;;;;;;AAGA;;AAHA;AACA;AACA;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASA,QAAT,GAAwC;AAAA,MAArBC,KAAqB,uEAAb,EAAa;AAAA,MAATC,MAAS;;AAC9C,MAAKA,MAAM,CAACC,IAAP,KAAgB,yBAArB,EAAiD;AAChD,UAAM;AAAEC,MAAAA,KAAF;AAASJ,MAAAA,QAAQ,EAAEK;AAAnB,QAA8BH,MAApC;AACA,WAAO,EACN,GAAGD,KADG;AAEN,OAAEG,KAAF,GAAW,EACV,GAAGH,KAAK,CAAEG,KAAF,CADE;AAEV,WAAGC;AAFO;AAFL,KAAP;AAOA;;AAED,SAAOJ,KAAP;AACA;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AACO,SAASK,WAAT,GAA2C;AAAA,MAArBL,KAAqB,uEAAb,EAAa;AAAA,MAATC,MAAS;;AACjD,MAAKA,MAAM,CAACC,IAAP,KAAgB,sBAArB,EAA8C;AAC7C,UAAM;AAAEC,MAAAA,KAAF;AAASG,MAAAA,IAAT;AAAeC,MAAAA;AAAf,QAAyBN,MAA/B;AACA,WAAO,EACN,GAAGD,KADG;AAEN,OAAEG,KAAF,GAAW,EACV,GAAGH,KAAK,CAAEG,KAAF,CADE;AAEV,SAAEG,IAAF,GAAUC;AAFA;AAFL,KAAP;AAOA;;AAED,SAAOP,KAAP;AACA;;eAEc,2BAAiB;AAC/BD,EAAAA,QAD+B;AAE/BM,EAAAA;AAF+B,CAAjB,C","sourcesContent":["/**\n * WordPress dependencies\n */\nimport { combineReducers } from '@wordpress/data';\n\n/**\n * Reducer returning the defaults for user preferences.\n *\n * This is kept intentionally separate from the preferences\n * themselves so that defaults are not persisted.\n *\n * @param {Object} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {Object} Updated state.\n */\nexport function defaults( state = {}, action ) {\n\tif ( action.type === 'SET_PREFERENCE_DEFAULTS' ) {\n\t\tconst { scope, defaults: values } = action;\n\t\treturn {\n\t\t\t...state,\n\t\t\t[ scope ]: {\n\t\t\t\t...state[ scope ],\n\t\t\t\t...values,\n\t\t\t},\n\t\t};\n\t}\n\n\treturn state;\n}\n\n/**\n * Reducer returning the user preferences.\n *\n * @param {Object} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {Object} Updated state.\n */\nexport function preferences( state = {}, action ) {\n\tif ( action.type === 'SET_PREFERENCE_VALUE' ) {\n\t\tconst { scope, name, value } = action;\n\t\treturn {\n\t\t\t...state,\n\t\t\t[ scope ]: {\n\t\t\t\t...state[ scope ],\n\t\t\t\t[ name ]: value,\n\t\t\t},\n\t\t};\n\t}\n\n\treturn state;\n}\n\nexport default combineReducers( {\n\tdefaults,\n\tpreferences,\n} );\n"]}
1
+ {"version":3,"sources":["@wordpress/preferences/src/store/reducer.js"],"names":["defaults","state","action","type","scope","values","withPersistenceLayer","reducer","persistenceLayer","persistence","persistedData","nextState","set","preferences","name","value"],"mappings":";;;;;;;;;AAGA;;AAHA;AACA;AACA;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASA,QAAT,GAAwC;AAAA,MAArBC,KAAqB,uEAAb,EAAa;AAAA,MAATC,MAAS;;AAC9C,MAAKA,MAAM,CAACC,IAAP,KAAgB,yBAArB,EAAiD;AAChD,UAAM;AAAEC,MAAAA,KAAF;AAASJ,MAAAA,QAAQ,EAAEK;AAAnB,QAA8BH,MAApC;AACA,WAAO,EACN,GAAGD,KADG;AAEN,OAAEG,KAAF,GAAW,EACV,GAAGH,KAAK,CAAEG,KAAF,CADE;AAEV,WAAGC;AAFO;AAFL,KAAP;AAOA;;AAED,SAAOJ,KAAP;AACA;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AACA,SAASK,oBAAT,CAA+BC,OAA/B,EAAyC;AACxC,MAAIC,gBAAJ;AAEA,SAAO,CAAEP,KAAF,EAASC,MAAT,KAAqB;AAC3B;AACA;AACA,QAAKA,MAAM,CAACC,IAAP,KAAgB,uBAArB,EAA+C;AAC9C,YAAM;AAAEK,QAAAA,gBAAgB,EAAEC,WAApB;AAAiCC,QAAAA;AAAjC,UAAmDR,MAAzD;AACAM,MAAAA,gBAAgB,GAAGC,WAAnB;AACA,aAAOC,aAAP;AACA;;AAED,UAAMC,SAAS,GAAGJ,OAAO,CAAEN,KAAF,EAASC,MAAT,CAAzB;;AACA,QAAKA,MAAM,CAACC,IAAP,KAAgB,sBAArB,EAA8C;AAAA;;AAC7C,2BAAAK,gBAAgB,UAAhB,8DAAkBI,GAAlB,CAAuBD,SAAvB;AACA;;AAED,WAAOA,SAAP;AACA,GAfD;AAgBA;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AACO,MAAME,WAAW,GAAGP,oBAAoB,CAAE,YAA0B;AAAA,MAAxBL,KAAwB,uEAAhB,EAAgB;AAAA,MAAZC,MAAY;;AAC1E,MAAKA,MAAM,CAACC,IAAP,KAAgB,sBAArB,EAA8C;AAC7C,UAAM;AAAEC,MAAAA,KAAF;AAASU,MAAAA,IAAT;AAAeC,MAAAA;AAAf,QAAyBb,MAA/B;AACA,WAAO,EACN,GAAGD,KADG;AAEN,OAAEG,KAAF,GAAW,EACV,GAAGH,KAAK,CAAEG,KAAF,CADE;AAEV,SAAEU,IAAF,GAAUC;AAFA;AAFL,KAAP;AAOA;;AAED,SAAOd,KAAP;AACA,CAb8C,CAAxC;;;eAeQ,2BAAiB;AAC/BD,EAAAA,QAD+B;AAE/Ba,EAAAA;AAF+B,CAAjB,C","sourcesContent":["/**\n * WordPress dependencies\n */\nimport { combineReducers } from '@wordpress/data';\n\n/**\n * Reducer returning the defaults for user preferences.\n *\n * This is kept intentionally separate from the preferences\n * themselves so that defaults are not persisted.\n *\n * @param {Object} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {Object} Updated state.\n */\nexport function defaults( state = {}, action ) {\n\tif ( action.type === 'SET_PREFERENCE_DEFAULTS' ) {\n\t\tconst { scope, defaults: values } = action;\n\t\treturn {\n\t\t\t...state,\n\t\t\t[ scope ]: {\n\t\t\t\t...state[ scope ],\n\t\t\t\t...values,\n\t\t\t},\n\t\t};\n\t}\n\n\treturn state;\n}\n\n/**\n * Higher order reducer that does the following:\n * - Merges any data from the persistence layer into the state when the\n * `SET_PERSISTENCE_LAYER` action is received.\n * - Passes any preferences changes to the persistence layer.\n *\n * @param {Function} reducer The preferences reducer.\n *\n * @return {Function} The enhanced reducer.\n */\nfunction withPersistenceLayer( reducer ) {\n\tlet persistenceLayer;\n\n\treturn ( state, action ) => {\n\t\t// Setup the persistence layer, and return the persisted data\n\t\t// as the state.\n\t\tif ( action.type === 'SET_PERSISTENCE_LAYER' ) {\n\t\t\tconst { persistenceLayer: persistence, persistedData } = action;\n\t\t\tpersistenceLayer = persistence;\n\t\t\treturn persistedData;\n\t\t}\n\n\t\tconst nextState = reducer( state, action );\n\t\tif ( action.type === 'SET_PREFERENCE_VALUE' ) {\n\t\t\tpersistenceLayer?.set( nextState );\n\t\t}\n\n\t\treturn nextState;\n\t};\n}\n\n/**\n * Reducer returning the user preferences.\n *\n * @param {Object} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {Object} Updated state.\n */\nexport const preferences = withPersistenceLayer( ( state = {}, action ) => {\n\tif ( action.type === 'SET_PREFERENCE_VALUE' ) {\n\t\tconst { scope, name, value } = action;\n\t\treturn {\n\t\t\t...state,\n\t\t\t[ scope ]: {\n\t\t\t\t...state[ scope ],\n\t\t\t\t[ name ]: value,\n\t\t\t},\n\t\t};\n\t}\n\n\treturn state;\n} );\n\nexport default combineReducers( {\n\tdefaults,\n\tpreferences,\n} );\n"]}
@@ -51,4 +51,39 @@ export function setDefaults(scope, defaults) {
51
51
  defaults
52
52
  };
53
53
  }
54
+ /** @typedef {() => Promise<Object>} WPPreferencesPersistenceLayerGet */
55
+
56
+ /** @typedef {(*) => void} WPPreferencesPersistenceLayerSet */
57
+
58
+ /**
59
+ * @typedef WPPreferencesPersistenceLayer
60
+ *
61
+ * @property {WPPreferencesPersistenceLayerGet} get An async function that gets data from the persistence layer.
62
+ * @property {WPPreferencesPersistenceLayerSet} set A function that sets data in the persistence layer.
63
+ */
64
+
65
+ /**
66
+ * Sets the persistence layer.
67
+ *
68
+ * When a persistence layer is set, the preferences store will:
69
+ * - call `get` immediately and update the store state to the value returned.
70
+ * - call `set` with all preferences whenever a preference changes value.
71
+ *
72
+ * `setPersistenceLayer` should ideally be dispatched at the start of an
73
+ * application's lifecycle, before any other actions have been dispatched to
74
+ * the preferences store.
75
+ *
76
+ * @param {WPPreferencesPersistenceLayer} persistenceLayer The persistence layer.
77
+ *
78
+ * @return {Object} Action object.
79
+ */
80
+
81
+ export async function setPersistenceLayer(persistenceLayer) {
82
+ const persistedData = await persistenceLayer.get();
83
+ return {
84
+ type: 'SET_PERSISTENCE_LAYER',
85
+ persistenceLayer,
86
+ persistedData
87
+ };
88
+ }
54
89
  //# sourceMappingURL=actions.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["@wordpress/preferences/src/store/actions.js"],"names":["toggle","scope","name","select","dispatch","currentValue","get","set","value","type","setDefaults","defaults"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASA,MAAT,CAAiBC,KAAjB,EAAwBC,IAAxB,EAA+B;AACrC,SAAO,gBAAkC;AAAA,QAAvB;AAAEC,MAAAA,MAAF;AAAUC,MAAAA;AAAV,KAAuB;AACxC,UAAMC,YAAY,GAAGF,MAAM,CAACG,GAAP,CAAYL,KAAZ,EAAmBC,IAAnB,CAArB;AACAE,IAAAA,QAAQ,CAACG,GAAT,CAAcN,KAAd,EAAqBC,IAArB,EAA2B,CAAEG,YAA7B;AACA,GAHD;AAIA;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AACA,OAAO,SAASE,GAAT,CAAcN,KAAd,EAAqBC,IAArB,EAA2BM,KAA3B,EAAmC;AACzC,SAAO;AACNC,IAAAA,IAAI,EAAE,sBADA;AAENR,IAAAA,KAFM;AAGNC,IAAAA,IAHM;AAINM,IAAAA;AAJM,GAAP;AAMA;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AACA,OAAO,SAASE,WAAT,CAAsBT,KAAtB,EAA6BU,QAA7B,EAAwC;AAC9C,SAAO;AACNF,IAAAA,IAAI,EAAE,yBADA;AAENR,IAAAA,KAFM;AAGNU,IAAAA;AAHM,GAAP;AAKA","sourcesContent":["/**\n * Returns an action object used in signalling that a preference should be\n * toggled.\n *\n * @param {string} scope The preference scope (e.g. core/edit-post).\n * @param {string} name The preference name.\n */\nexport function toggle( scope, name ) {\n\treturn function ( { select, dispatch } ) {\n\t\tconst currentValue = select.get( scope, name );\n\t\tdispatch.set( scope, name, ! currentValue );\n\t};\n}\n\n/**\n * Returns an action object used in signalling that a preference should be set\n * to a value\n *\n * @param {string} scope The preference scope (e.g. core/edit-post).\n * @param {string} name The preference name.\n * @param {*} value The value to set.\n *\n * @return {Object} Action object.\n */\nexport function set( scope, name, value ) {\n\treturn {\n\t\ttype: 'SET_PREFERENCE_VALUE',\n\t\tscope,\n\t\tname,\n\t\tvalue,\n\t};\n}\n\n/**\n * Returns an action object used in signalling that preference defaults should\n * be set.\n *\n * @param {string} scope The preference scope (e.g. core/edit-post).\n * @param {Object<string, *>} defaults A key/value map of preference names to values.\n *\n * @return {Object} Action object.\n */\nexport function setDefaults( scope, defaults ) {\n\treturn {\n\t\ttype: 'SET_PREFERENCE_DEFAULTS',\n\t\tscope,\n\t\tdefaults,\n\t};\n}\n"]}
1
+ {"version":3,"sources":["@wordpress/preferences/src/store/actions.js"],"names":["toggle","scope","name","select","dispatch","currentValue","get","set","value","type","setDefaults","defaults","setPersistenceLayer","persistenceLayer","persistedData"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASA,MAAT,CAAiBC,KAAjB,EAAwBC,IAAxB,EAA+B;AACrC,SAAO,gBAAkC;AAAA,QAAvB;AAAEC,MAAAA,MAAF;AAAUC,MAAAA;AAAV,KAAuB;AACxC,UAAMC,YAAY,GAAGF,MAAM,CAACG,GAAP,CAAYL,KAAZ,EAAmBC,IAAnB,CAArB;AACAE,IAAAA,QAAQ,CAACG,GAAT,CAAcN,KAAd,EAAqBC,IAArB,EAA2B,CAAEG,YAA7B;AACA,GAHD;AAIA;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AACA,OAAO,SAASE,GAAT,CAAcN,KAAd,EAAqBC,IAArB,EAA2BM,KAA3B,EAAmC;AACzC,SAAO;AACNC,IAAAA,IAAI,EAAE,sBADA;AAENR,IAAAA,KAFM;AAGNC,IAAAA,IAHM;AAINM,IAAAA;AAJM,GAAP;AAMA;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AACA,OAAO,SAASE,WAAT,CAAsBT,KAAtB,EAA6BU,QAA7B,EAAwC;AAC9C,SAAO;AACNF,IAAAA,IAAI,EAAE,yBADA;AAENR,IAAAA,KAFM;AAGNU,IAAAA;AAHM,GAAP;AAKA;AAED;;AACA;;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AACA,OAAO,eAAeC,mBAAf,CAAoCC,gBAApC,EAAuD;AAC7D,QAAMC,aAAa,GAAG,MAAMD,gBAAgB,CAACP,GAAjB,EAA5B;AACA,SAAO;AACNG,IAAAA,IAAI,EAAE,uBADA;AAENI,IAAAA,gBAFM;AAGNC,IAAAA;AAHM,GAAP;AAKA","sourcesContent":["/**\n * Returns an action object used in signalling that a preference should be\n * toggled.\n *\n * @param {string} scope The preference scope (e.g. core/edit-post).\n * @param {string} name The preference name.\n */\nexport function toggle( scope, name ) {\n\treturn function ( { select, dispatch } ) {\n\t\tconst currentValue = select.get( scope, name );\n\t\tdispatch.set( scope, name, ! currentValue );\n\t};\n}\n\n/**\n * Returns an action object used in signalling that a preference should be set\n * to a value\n *\n * @param {string} scope The preference scope (e.g. core/edit-post).\n * @param {string} name The preference name.\n * @param {*} value The value to set.\n *\n * @return {Object} Action object.\n */\nexport function set( scope, name, value ) {\n\treturn {\n\t\ttype: 'SET_PREFERENCE_VALUE',\n\t\tscope,\n\t\tname,\n\t\tvalue,\n\t};\n}\n\n/**\n * Returns an action object used in signalling that preference defaults should\n * be set.\n *\n * @param {string} scope The preference scope (e.g. core/edit-post).\n * @param {Object<string, *>} defaults A key/value map of preference names to values.\n *\n * @return {Object} Action object.\n */\nexport function setDefaults( scope, defaults ) {\n\treturn {\n\t\ttype: 'SET_PREFERENCE_DEFAULTS',\n\t\tscope,\n\t\tdefaults,\n\t};\n}\n\n/** @typedef {() => Promise<Object>} WPPreferencesPersistenceLayerGet */\n/** @typedef {(*) => void} WPPreferencesPersistenceLayerSet */\n/**\n * @typedef WPPreferencesPersistenceLayer\n *\n * @property {WPPreferencesPersistenceLayerGet} get An async function that gets data from the persistence layer.\n * @property {WPPreferencesPersistenceLayerSet} set A function that sets data in the persistence layer.\n */\n\n/**\n * Sets the persistence layer.\n *\n * When a persistence layer is set, the preferences store will:\n * - call `get` immediately and update the store state to the value returned.\n * - call `set` with all preferences whenever a preference changes value.\n *\n * `setPersistenceLayer` should ideally be dispatched at the start of an\n * application's lifecycle, before any other actions have been dispatched to\n * the preferences store.\n *\n * @param {WPPreferencesPersistenceLayer} persistenceLayer The persistence layer.\n *\n * @return {Object} Action object.\n */\nexport async function setPersistenceLayer( persistenceLayer ) {\n\tconst persistedData = await persistenceLayer.get();\n\treturn {\n\t\ttype: 'SET_PERSISTENCE_LAYER',\n\t\tpersistenceLayer,\n\t\tpersistedData,\n\t};\n}\n"]}
@@ -1,11 +1,7 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
- import { createReduxStore, registerStore } from '@wordpress/data';
5
- /**
6
- * Internal dependencies
7
- */
8
-
4
+ import { createReduxStore, register } from '@wordpress/data';
9
5
  /**
10
6
  * Internal dependencies
11
7
  */
@@ -25,15 +21,7 @@ import { STORE_NAME } from './constants';
25
21
  export const store = createReduxStore(STORE_NAME, {
26
22
  reducer,
27
23
  actions,
28
- selectors,
29
- persist: ['preferences']
30
- }); // Once we build a more generic persistence plugin that works across types of stores
31
- // we'd be able to replace this with a register call.
32
-
33
- registerStore(STORE_NAME, {
34
- reducer,
35
- actions,
36
- selectors,
37
- persist: ['preferences']
24
+ selectors
38
25
  });
26
+ register(store);
39
27
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["@wordpress/preferences/src/store/index.js"],"names":["createReduxStore","registerStore","reducer","actions","selectors","STORE_NAME","store","persist"],"mappings":"AAAA;AACA;AACA;AACA,SAASA,gBAAT,EAA2BC,aAA3B,QAAgD,iBAAhD;AAEA;AACA;AACA;;AACA;AACA;AACA;;AACA,OAAOC,OAAP,MAAoB,WAApB;AACA,OAAO,KAAKC,OAAZ,MAAyB,WAAzB;AACA,OAAO,KAAKC,SAAZ,MAA2B,aAA3B;AACA,SAASC,UAAT,QAA2B,aAA3B;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AACA,OAAO,MAAMC,KAAK,GAAGN,gBAAgB,CAAEK,UAAF,EAAc;AAClDH,EAAAA,OADkD;AAElDC,EAAAA,OAFkD;AAGlDC,EAAAA,SAHkD;AAIlDG,EAAAA,OAAO,EAAE,CAAE,aAAF;AAJyC,CAAd,CAA9B,C,CAOP;AACA;;AACAN,aAAa,CAAEI,UAAF,EAAc;AAC1BH,EAAAA,OAD0B;AAE1BC,EAAAA,OAF0B;AAG1BC,EAAAA,SAH0B;AAI1BG,EAAAA,OAAO,EAAE,CAAE,aAAF;AAJiB,CAAd,CAAb","sourcesContent":["/**\n * WordPress dependencies\n */\nimport { createReduxStore, registerStore } from '@wordpress/data';\n\n/**\n * Internal dependencies\n */\n/**\n * Internal dependencies\n */\nimport reducer from './reducer';\nimport * as actions from './actions';\nimport * as selectors from './selectors';\nimport { STORE_NAME } from './constants';\n\n/**\n * Store definition for the interface namespace.\n *\n * @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/data/README.md#createReduxStore\n *\n * @type {Object}\n */\nexport const store = createReduxStore( STORE_NAME, {\n\treducer,\n\tactions,\n\tselectors,\n\tpersist: [ 'preferences' ],\n} );\n\n// Once we build a more generic persistence plugin that works across types of stores\n// we'd be able to replace this with a register call.\nregisterStore( STORE_NAME, {\n\treducer,\n\tactions,\n\tselectors,\n\tpersist: [ 'preferences' ],\n} );\n"]}
1
+ {"version":3,"sources":["@wordpress/preferences/src/store/index.js"],"names":["createReduxStore","register","reducer","actions","selectors","STORE_NAME","store"],"mappings":"AAAA;AACA;AACA;AACA,SAASA,gBAAT,EAA2BC,QAA3B,QAA2C,iBAA3C;AAEA;AACA;AACA;;AACA,OAAOC,OAAP,MAAoB,WAApB;AACA,OAAO,KAAKC,OAAZ,MAAyB,WAAzB;AACA,OAAO,KAAKC,SAAZ,MAA2B,aAA3B;AACA,SAASC,UAAT,QAA2B,aAA3B;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AACA,OAAO,MAAMC,KAAK,GAAGN,gBAAgB,CAAEK,UAAF,EAAc;AAClDH,EAAAA,OADkD;AAElDC,EAAAA,OAFkD;AAGlDC,EAAAA;AAHkD,CAAd,CAA9B;AAMPH,QAAQ,CAAEK,KAAF,CAAR","sourcesContent":["/**\n * WordPress dependencies\n */\nimport { createReduxStore, register } from '@wordpress/data';\n\n/**\n * Internal dependencies\n */\nimport reducer from './reducer';\nimport * as actions from './actions';\nimport * as selectors from './selectors';\nimport { STORE_NAME } from './constants';\n\n/**\n * Store definition for the interface namespace.\n *\n * @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/data/README.md#createReduxStore\n *\n * @type {Object}\n */\nexport const store = createReduxStore( STORE_NAME, {\n\treducer,\n\tactions,\n\tselectors,\n} );\n\nregister( store );\n"]}
@@ -32,6 +32,42 @@ export function defaults() {
32
32
 
33
33
  return state;
34
34
  }
35
+ /**
36
+ * Higher order reducer that does the following:
37
+ * - Merges any data from the persistence layer into the state when the
38
+ * `SET_PERSISTENCE_LAYER` action is received.
39
+ * - Passes any preferences changes to the persistence layer.
40
+ *
41
+ * @param {Function} reducer The preferences reducer.
42
+ *
43
+ * @return {Function} The enhanced reducer.
44
+ */
45
+
46
+ function withPersistenceLayer(reducer) {
47
+ let persistenceLayer;
48
+ return (state, action) => {
49
+ // Setup the persistence layer, and return the persisted data
50
+ // as the state.
51
+ if (action.type === 'SET_PERSISTENCE_LAYER') {
52
+ const {
53
+ persistenceLayer: persistence,
54
+ persistedData
55
+ } = action;
56
+ persistenceLayer = persistence;
57
+ return persistedData;
58
+ }
59
+
60
+ const nextState = reducer(state, action);
61
+
62
+ if (action.type === 'SET_PREFERENCE_VALUE') {
63
+ var _persistenceLayer;
64
+
65
+ (_persistenceLayer = persistenceLayer) === null || _persistenceLayer === void 0 ? void 0 : _persistenceLayer.set(nextState);
66
+ }
67
+
68
+ return nextState;
69
+ };
70
+ }
35
71
  /**
36
72
  * Reducer returning the user preferences.
37
73
  *
@@ -41,7 +77,8 @@ export function defaults() {
41
77
  * @return {Object} Updated state.
42
78
  */
43
79
 
44
- export function preferences() {
80
+
81
+ export const preferences = withPersistenceLayer(function () {
45
82
  let state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
46
83
  let action = arguments.length > 1 ? arguments[1] : undefined;
47
84
 
@@ -59,7 +96,7 @@ export function preferences() {
59
96
  }
60
97
 
61
98
  return state;
62
- }
99
+ });
63
100
  export default combineReducers({
64
101
  defaults,
65
102
  preferences
@@ -1 +1 @@
1
- {"version":3,"sources":["@wordpress/preferences/src/store/reducer.js"],"names":["combineReducers","defaults","state","action","type","scope","values","preferences","name","value"],"mappings":"AAAA;AACA;AACA;AACA,SAASA,eAAT,QAAgC,iBAAhC;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AACA,OAAO,SAASC,QAAT,GAAwC;AAAA,MAArBC,KAAqB,uEAAb,EAAa;AAAA,MAATC,MAAS;;AAC9C,MAAKA,MAAM,CAACC,IAAP,KAAgB,yBAArB,EAAiD;AAChD,UAAM;AAAEC,MAAAA,KAAF;AAASJ,MAAAA,QAAQ,EAAEK;AAAnB,QAA8BH,MAApC;AACA,WAAO,EACN,GAAGD,KADG;AAEN,OAAEG,KAAF,GAAW,EACV,GAAGH,KAAK,CAAEG,KAAF,CADE;AAEV,WAAGC;AAFO;AAFL,KAAP;AAOA;;AAED,SAAOJ,KAAP;AACA;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AACA,OAAO,SAASK,WAAT,GAA2C;AAAA,MAArBL,KAAqB,uEAAb,EAAa;AAAA,MAATC,MAAS;;AACjD,MAAKA,MAAM,CAACC,IAAP,KAAgB,sBAArB,EAA8C;AAC7C,UAAM;AAAEC,MAAAA,KAAF;AAASG,MAAAA,IAAT;AAAeC,MAAAA;AAAf,QAAyBN,MAA/B;AACA,WAAO,EACN,GAAGD,KADG;AAEN,OAAEG,KAAF,GAAW,EACV,GAAGH,KAAK,CAAEG,KAAF,CADE;AAEV,SAAEG,IAAF,GAAUC;AAFA;AAFL,KAAP;AAOA;;AAED,SAAOP,KAAP;AACA;AAED,eAAeF,eAAe,CAAE;AAC/BC,EAAAA,QAD+B;AAE/BM,EAAAA;AAF+B,CAAF,CAA9B","sourcesContent":["/**\n * WordPress dependencies\n */\nimport { combineReducers } from '@wordpress/data';\n\n/**\n * Reducer returning the defaults for user preferences.\n *\n * This is kept intentionally separate from the preferences\n * themselves so that defaults are not persisted.\n *\n * @param {Object} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {Object} Updated state.\n */\nexport function defaults( state = {}, action ) {\n\tif ( action.type === 'SET_PREFERENCE_DEFAULTS' ) {\n\t\tconst { scope, defaults: values } = action;\n\t\treturn {\n\t\t\t...state,\n\t\t\t[ scope ]: {\n\t\t\t\t...state[ scope ],\n\t\t\t\t...values,\n\t\t\t},\n\t\t};\n\t}\n\n\treturn state;\n}\n\n/**\n * Reducer returning the user preferences.\n *\n * @param {Object} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {Object} Updated state.\n */\nexport function preferences( state = {}, action ) {\n\tif ( action.type === 'SET_PREFERENCE_VALUE' ) {\n\t\tconst { scope, name, value } = action;\n\t\treturn {\n\t\t\t...state,\n\t\t\t[ scope ]: {\n\t\t\t\t...state[ scope ],\n\t\t\t\t[ name ]: value,\n\t\t\t},\n\t\t};\n\t}\n\n\treturn state;\n}\n\nexport default combineReducers( {\n\tdefaults,\n\tpreferences,\n} );\n"]}
1
+ {"version":3,"sources":["@wordpress/preferences/src/store/reducer.js"],"names":["combineReducers","defaults","state","action","type","scope","values","withPersistenceLayer","reducer","persistenceLayer","persistence","persistedData","nextState","set","preferences","name","value"],"mappings":"AAAA;AACA;AACA;AACA,SAASA,eAAT,QAAgC,iBAAhC;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AACA,OAAO,SAASC,QAAT,GAAwC;AAAA,MAArBC,KAAqB,uEAAb,EAAa;AAAA,MAATC,MAAS;;AAC9C,MAAKA,MAAM,CAACC,IAAP,KAAgB,yBAArB,EAAiD;AAChD,UAAM;AAAEC,MAAAA,KAAF;AAASJ,MAAAA,QAAQ,EAAEK;AAAnB,QAA8BH,MAApC;AACA,WAAO,EACN,GAAGD,KADG;AAEN,OAAEG,KAAF,GAAW,EACV,GAAGH,KAAK,CAAEG,KAAF,CADE;AAEV,WAAGC;AAFO;AAFL,KAAP;AAOA;;AAED,SAAOJ,KAAP;AACA;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AACA,SAASK,oBAAT,CAA+BC,OAA/B,EAAyC;AACxC,MAAIC,gBAAJ;AAEA,SAAO,CAAEP,KAAF,EAASC,MAAT,KAAqB;AAC3B;AACA;AACA,QAAKA,MAAM,CAACC,IAAP,KAAgB,uBAArB,EAA+C;AAC9C,YAAM;AAAEK,QAAAA,gBAAgB,EAAEC,WAApB;AAAiCC,QAAAA;AAAjC,UAAmDR,MAAzD;AACAM,MAAAA,gBAAgB,GAAGC,WAAnB;AACA,aAAOC,aAAP;AACA;;AAED,UAAMC,SAAS,GAAGJ,OAAO,CAAEN,KAAF,EAASC,MAAT,CAAzB;;AACA,QAAKA,MAAM,CAACC,IAAP,KAAgB,sBAArB,EAA8C;AAAA;;AAC7C,2BAAAK,gBAAgB,UAAhB,8DAAkBI,GAAlB,CAAuBD,SAAvB;AACA;;AAED,WAAOA,SAAP;AACA,GAfD;AAgBA;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AACA,OAAO,MAAME,WAAW,GAAGP,oBAAoB,CAAE,YAA0B;AAAA,MAAxBL,KAAwB,uEAAhB,EAAgB;AAAA,MAAZC,MAAY;;AAC1E,MAAKA,MAAM,CAACC,IAAP,KAAgB,sBAArB,EAA8C;AAC7C,UAAM;AAAEC,MAAAA,KAAF;AAASU,MAAAA,IAAT;AAAeC,MAAAA;AAAf,QAAyBb,MAA/B;AACA,WAAO,EACN,GAAGD,KADG;AAEN,OAAEG,KAAF,GAAW,EACV,GAAGH,KAAK,CAAEG,KAAF,CADE;AAEV,SAAEU,IAAF,GAAUC;AAFA;AAFL,KAAP;AAOA;;AAED,SAAOd,KAAP;AACA,CAb8C,CAAxC;AAeP,eAAeF,eAAe,CAAE;AAC/BC,EAAAA,QAD+B;AAE/Ba,EAAAA;AAF+B,CAAF,CAA9B","sourcesContent":["/**\n * WordPress dependencies\n */\nimport { combineReducers } from '@wordpress/data';\n\n/**\n * Reducer returning the defaults for user preferences.\n *\n * This is kept intentionally separate from the preferences\n * themselves so that defaults are not persisted.\n *\n * @param {Object} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {Object} Updated state.\n */\nexport function defaults( state = {}, action ) {\n\tif ( action.type === 'SET_PREFERENCE_DEFAULTS' ) {\n\t\tconst { scope, defaults: values } = action;\n\t\treturn {\n\t\t\t...state,\n\t\t\t[ scope ]: {\n\t\t\t\t...state[ scope ],\n\t\t\t\t...values,\n\t\t\t},\n\t\t};\n\t}\n\n\treturn state;\n}\n\n/**\n * Higher order reducer that does the following:\n * - Merges any data from the persistence layer into the state when the\n * `SET_PERSISTENCE_LAYER` action is received.\n * - Passes any preferences changes to the persistence layer.\n *\n * @param {Function} reducer The preferences reducer.\n *\n * @return {Function} The enhanced reducer.\n */\nfunction withPersistenceLayer( reducer ) {\n\tlet persistenceLayer;\n\n\treturn ( state, action ) => {\n\t\t// Setup the persistence layer, and return the persisted data\n\t\t// as the state.\n\t\tif ( action.type === 'SET_PERSISTENCE_LAYER' ) {\n\t\t\tconst { persistenceLayer: persistence, persistedData } = action;\n\t\t\tpersistenceLayer = persistence;\n\t\t\treturn persistedData;\n\t\t}\n\n\t\tconst nextState = reducer( state, action );\n\t\tif ( action.type === 'SET_PREFERENCE_VALUE' ) {\n\t\t\tpersistenceLayer?.set( nextState );\n\t\t}\n\n\t\treturn nextState;\n\t};\n}\n\n/**\n * Reducer returning the user preferences.\n *\n * @param {Object} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {Object} Updated state.\n */\nexport const preferences = withPersistenceLayer( ( state = {}, action ) => {\n\tif ( action.type === 'SET_PREFERENCE_VALUE' ) {\n\t\tconst { scope, name, value } = action;\n\t\treturn {\n\t\t\t...state,\n\t\t\t[ scope ]: {\n\t\t\t\t...state[ scope ],\n\t\t\t\t[ name ]: value,\n\t\t\t},\n\t\t};\n\t}\n\n\treturn state;\n} );\n\nexport default combineReducers( {\n\tdefaults,\n\tpreferences,\n} );\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/preferences",
3
- "version": "1.3.0",
3
+ "version": "2.0.0",
4
4
  "description": "Utilities for managing WordPress preferences.",
5
5
  "author": "The WordPress Contributors",
6
6
  "license": "GPL-2.0-or-later",
@@ -30,11 +30,11 @@
30
30
  "sideEffects": false,
31
31
  "dependencies": {
32
32
  "@babel/runtime": "^7.16.0",
33
- "@wordpress/a11y": "^3.7.0",
34
- "@wordpress/components": "^19.9.0",
35
- "@wordpress/data": "^6.7.0",
36
- "@wordpress/i18n": "^4.7.0",
37
- "@wordpress/icons": "^8.3.0",
33
+ "@wordpress/a11y": "^3.8.0",
34
+ "@wordpress/components": "^19.10.0",
35
+ "@wordpress/data": "^6.8.0",
36
+ "@wordpress/i18n": "^4.8.0",
37
+ "@wordpress/icons": "^8.4.0",
38
38
  "classnames": "^2.3.1"
39
39
  },
40
40
  "peerDependencies": {
@@ -44,5 +44,5 @@
44
44
  "publishConfig": {
45
45
  "access": "public"
46
46
  },
47
- "gitHead": "1ba52312b56db563df2d8d4fba5b00613fb46d8c"
47
+ "gitHead": "4631d515033397fcfeda77e5755960253caef9bf"
48
48
  }
@@ -47,3 +47,36 @@ export function setDefaults( scope, defaults ) {
47
47
  defaults,
48
48
  };
49
49
  }
50
+
51
+ /** @typedef {() => Promise<Object>} WPPreferencesPersistenceLayerGet */
52
+ /** @typedef {(*) => void} WPPreferencesPersistenceLayerSet */
53
+ /**
54
+ * @typedef WPPreferencesPersistenceLayer
55
+ *
56
+ * @property {WPPreferencesPersistenceLayerGet} get An async function that gets data from the persistence layer.
57
+ * @property {WPPreferencesPersistenceLayerSet} set A function that sets data in the persistence layer.
58
+ */
59
+
60
+ /**
61
+ * Sets the persistence layer.
62
+ *
63
+ * When a persistence layer is set, the preferences store will:
64
+ * - call `get` immediately and update the store state to the value returned.
65
+ * - call `set` with all preferences whenever a preference changes value.
66
+ *
67
+ * `setPersistenceLayer` should ideally be dispatched at the start of an
68
+ * application's lifecycle, before any other actions have been dispatched to
69
+ * the preferences store.
70
+ *
71
+ * @param {WPPreferencesPersistenceLayer} persistenceLayer The persistence layer.
72
+ *
73
+ * @return {Object} Action object.
74
+ */
75
+ export async function setPersistenceLayer( persistenceLayer ) {
76
+ const persistedData = await persistenceLayer.get();
77
+ return {
78
+ type: 'SET_PERSISTENCE_LAYER',
79
+ persistenceLayer,
80
+ persistedData,
81
+ };
82
+ }
@@ -1,11 +1,8 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
- import { createReduxStore, registerStore } from '@wordpress/data';
4
+ import { createReduxStore, register } from '@wordpress/data';
5
5
 
6
- /**
7
- * Internal dependencies
8
- */
9
6
  /**
10
7
  * Internal dependencies
11
8
  */
@@ -25,14 +22,6 @@ export const store = createReduxStore( STORE_NAME, {
25
22
  reducer,
26
23
  actions,
27
24
  selectors,
28
- persist: [ 'preferences' ],
29
25
  } );
30
26
 
31
- // Once we build a more generic persistence plugin that works across types of stores
32
- // we'd be able to replace this with a register call.
33
- registerStore( STORE_NAME, {
34
- reducer,
35
- actions,
36
- selectors,
37
- persist: [ 'preferences' ],
38
- } );
27
+ register( store );
@@ -29,6 +29,37 @@ export function defaults( state = {}, action ) {
29
29
  return state;
30
30
  }
31
31
 
32
+ /**
33
+ * Higher order reducer that does the following:
34
+ * - Merges any data from the persistence layer into the state when the
35
+ * `SET_PERSISTENCE_LAYER` action is received.
36
+ * - Passes any preferences changes to the persistence layer.
37
+ *
38
+ * @param {Function} reducer The preferences reducer.
39
+ *
40
+ * @return {Function} The enhanced reducer.
41
+ */
42
+ function withPersistenceLayer( reducer ) {
43
+ let persistenceLayer;
44
+
45
+ return ( state, action ) => {
46
+ // Setup the persistence layer, and return the persisted data
47
+ // as the state.
48
+ if ( action.type === 'SET_PERSISTENCE_LAYER' ) {
49
+ const { persistenceLayer: persistence, persistedData } = action;
50
+ persistenceLayer = persistence;
51
+ return persistedData;
52
+ }
53
+
54
+ const nextState = reducer( state, action );
55
+ if ( action.type === 'SET_PREFERENCE_VALUE' ) {
56
+ persistenceLayer?.set( nextState );
57
+ }
58
+
59
+ return nextState;
60
+ };
61
+ }
62
+
32
63
  /**
33
64
  * Reducer returning the user preferences.
34
65
  *
@@ -37,7 +68,7 @@ export function defaults( state = {}, action ) {
37
68
  *
38
69
  * @return {Object} Updated state.
39
70
  */
40
- export function preferences( state = {}, action ) {
71
+ export const preferences = withPersistenceLayer( ( state = {}, action ) => {
41
72
  if ( action.type === 'SET_PREFERENCE_VALUE' ) {
42
73
  const { scope, name, value } = action;
43
74
  return {
@@ -50,7 +81,7 @@ export function preferences( state = {}, action ) {
50
81
  }
51
82
 
52
83
  return state;
53
- }
84
+ } );
54
85
 
55
86
  export default combineReducers( {
56
87
  defaults,
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import { setPersistenceLayer } from '../actions';
5
+
6
+ describe( 'setPersistenceLayer', () => {
7
+ it( 'returns an action that contains the persistence layer and the result of calling `persistenceLayer.get`', async () => {
8
+ const result = {
9
+ testA: 1,
10
+ testB: 2,
11
+ };
12
+ const testPersistenceLayer = {
13
+ async get() {
14
+ return result;
15
+ },
16
+ set() {},
17
+ };
18
+
19
+ const action = await setPersistenceLayer( testPersistenceLayer );
20
+
21
+ expect( action ).toEqual( {
22
+ type: 'SET_PERSISTENCE_LAYER',
23
+ persistenceLayer: testPersistenceLayer,
24
+ persistedData: result,
25
+ } );
26
+ } );
27
+ } );
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import { preferences } from '../reducer';
5
+
6
+ describe( 'withPersistenceLayer( preferences )', () => {
7
+ it( 'updates the store state to the persisted data when called with the `SET_PERSISTENCE_LAYER` action', () => {
8
+ const persistedData = {
9
+ a: 1,
10
+ b: 2,
11
+ };
12
+
13
+ const action = {
14
+ type: 'SET_PERSISTENCE_LAYER',
15
+ persistedData,
16
+ };
17
+
18
+ expect( preferences( {}, action ) ).toEqual( persistedData );
19
+ } );
20
+
21
+ it( 'calls the persistence layer `set` function with the updated store state whenever the `SET_PREFERENCE_VALUE` action is dispatched', () => {
22
+ const set = jest.fn();
23
+ const persistenceLayer = {
24
+ set,
25
+ };
26
+
27
+ const setPersistenceLayerAction = {
28
+ type: 'SET_PERSISTENCE_LAYER',
29
+ persistenceLayer,
30
+ persistedData: {},
31
+ };
32
+
33
+ // Set the persistence layer.
34
+ preferences( {}, setPersistenceLayerAction );
35
+
36
+ // Update a value.
37
+ const setPreferenceValueAction = {
38
+ type: 'SET_PREFERENCE_VALUE',
39
+ name: 'myPreference',
40
+ value: 'myValue',
41
+ };
42
+
43
+ const state = preferences( {}, setPreferenceValueAction );
44
+
45
+ expect( set ).toHaveBeenCalledWith( state );
46
+ } );
47
+ } );