@wordpress/data 6.1.4 → 6.2.1

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.
Files changed (73) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/LICENSE.md +1 -1
  3. package/README.md +77 -71
  4. package/build/components/use-dispatch/use-dispatch.js +8 -8
  5. package/build/components/use-dispatch/use-dispatch.js.map +1 -1
  6. package/build/components/use-select/index.js +58 -43
  7. package/build/components/use-select/index.js.map +1 -1
  8. package/build/controls.js +16 -16
  9. package/build/controls.js.map +1 -1
  10. package/build/index.js +14 -14
  11. package/build/index.js.map +1 -1
  12. package/build/plugins/index.js +0 -8
  13. package/build/plugins/index.js.map +1 -1
  14. package/build/redux-store/index.js +15 -15
  15. package/build/redux-store/index.js.map +1 -1
  16. package/build/registry.js +82 -68
  17. package/build/registry.js.map +1 -1
  18. package/build/resolvers-cache-middleware.js +5 -3
  19. package/build/resolvers-cache-middleware.js.map +1 -1
  20. package/build/store/index.js +42 -43
  21. package/build/store/index.js.map +1 -1
  22. package/build/utils/emitter.js +1 -1
  23. package/build/utils/emitter.js.map +1 -1
  24. package/build-module/components/use-dispatch/use-dispatch.js +8 -8
  25. package/build-module/components/use-dispatch/use-dispatch.js.map +1 -1
  26. package/build-module/components/use-select/index.js +60 -44
  27. package/build-module/components/use-select/index.js.map +1 -1
  28. package/build-module/controls.js +16 -16
  29. package/build-module/controls.js.map +1 -1
  30. package/build-module/index.js +14 -14
  31. package/build-module/index.js.map +1 -1
  32. package/build-module/plugins/index.js +0 -1
  33. package/build-module/plugins/index.js.map +1 -1
  34. package/build-module/redux-store/index.js +15 -15
  35. package/build-module/redux-store/index.js.map +1 -1
  36. package/build-module/registry.js +82 -68
  37. package/build-module/registry.js.map +1 -1
  38. package/build-module/resolvers-cache-middleware.js +3 -3
  39. package/build-module/resolvers-cache-middleware.js.map +1 -1
  40. package/build-module/store/index.js +42 -42
  41. package/build-module/store/index.js.map +1 -1
  42. package/build-module/utils/emitter.js +1 -1
  43. package/build-module/utils/emitter.js.map +1 -1
  44. package/build-types/types.d.ts +29 -16
  45. package/build-types/types.d.ts.map +1 -1
  46. package/build-types/utils/emitter.d.ts +2 -2
  47. package/build-types/utils/emitter.d.ts.map +1 -1
  48. package/package.json +10 -10
  49. package/src/components/use-dispatch/test/use-dispatch.js +1 -1
  50. package/src/components/use-dispatch/use-dispatch.js +9 -9
  51. package/src/components/use-select/index.js +61 -46
  52. package/src/components/use-select/test/index.js +32 -32
  53. package/src/controls.js +22 -22
  54. package/src/index.js +14 -14
  55. package/src/plugins/index.js +0 -1
  56. package/src/redux-store/index.js +15 -15
  57. package/src/registry.js +88 -75
  58. package/src/resolvers-cache-middleware.js +3 -3
  59. package/src/store/index.js +49 -48
  60. package/src/test/registry.js +33 -47
  61. package/src/types.ts +44 -16
  62. package/src/utils/emitter.js +1 -1
  63. package/tsconfig.tsbuildinfo +1 -1
  64. package/build/plugins/controls/index.js +0 -24
  65. package/build/plugins/controls/index.js.map +0 -1
  66. package/build/store/name.js +0 -15
  67. package/build/store/name.js.map +0 -1
  68. package/build-module/plugins/controls/index.js +0 -12
  69. package/build-module/plugins/controls/index.js.map +0 -1
  70. package/build-module/store/name.js +0 -7
  71. package/build-module/store/name.js.map +0 -1
  72. package/src/plugins/controls/index.js +0 -12
  73. package/src/store/name.js +0 -6
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Create an event emitter.
3
3
  *
4
- * @return {import("../types").WPDataEmitter} Emitter.
4
+ * @return {import("../types").DataEmitter} Emitter.
5
5
  */
6
6
  export function createEmitter() {
7
7
  let isPaused = false;
@@ -1 +1 @@
1
- {"version":3,"sources":["@wordpress/data/src/utils/emitter.js"],"names":["createEmitter","isPaused","isPending","listeners","Set","notifyListeners","Array","from","forEach","listener","subscribe","add","delete","pause","resume","emit"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASA,aAAT,GAAyB;AAC/B,MAAIC,QAAQ,GAAG,KAAf;AACA,MAAIC,SAAS,GAAG,KAAhB;AACA,QAAMC,SAAS,GAAG,IAAIC,GAAJ,EAAlB;;AACA,QAAMC,eAAe,GAAG,MACvB;AACA;AACA;AACAC,EAAAA,KAAK,CAACC,IAAN,CAAYJ,SAAZ,EAAwBK,OAAxB,CAAmCC,QAAF,IAAgBA,QAAQ,EAAzD,CAJD;;AAMA,SAAO;AACN,QAAIR,QAAJ,GAAe;AACd,aAAOA,QAAP;AACA,KAHK;;AAKNS,IAAAA,SAAS,CAAED,QAAF,EAAa;AACrBN,MAAAA,SAAS,CAACQ,GAAV,CAAeF,QAAf;AACA,aAAO,MAAMN,SAAS,CAACS,MAAV,CAAkBH,QAAlB,CAAb;AACA,KARK;;AAUNI,IAAAA,KAAK,GAAG;AACPZ,MAAAA,QAAQ,GAAG,IAAX;AACA,KAZK;;AAcNa,IAAAA,MAAM,GAAG;AACRb,MAAAA,QAAQ,GAAG,KAAX;;AACA,UAAKC,SAAL,EAAiB;AAChBA,QAAAA,SAAS,GAAG,KAAZ;AACAG,QAAAA,eAAe;AACf;AACD,KApBK;;AAsBNU,IAAAA,IAAI,GAAG;AACN,UAAKd,QAAL,EAAgB;AACfC,QAAAA,SAAS,GAAG,IAAZ;AACA;AACA;;AACDG,MAAAA,eAAe;AACf;;AA5BK,GAAP;AA8BA","sourcesContent":["/**\n * Create an event emitter.\n *\n * @return {import(\"../types\").WPDataEmitter} Emitter.\n */\nexport function createEmitter() {\n\tlet isPaused = false;\n\tlet isPending = false;\n\tconst listeners = new Set();\n\tconst notifyListeners = () =>\n\t\t// We use Array.from to clone the listeners Set\n\t\t// This ensures that we don't run a listener\n\t\t// that was added as a response to another listener.\n\t\tArray.from( listeners ).forEach( ( listener ) => listener() );\n\n\treturn {\n\t\tget isPaused() {\n\t\t\treturn isPaused;\n\t\t},\n\n\t\tsubscribe( listener ) {\n\t\t\tlisteners.add( listener );\n\t\t\treturn () => listeners.delete( listener );\n\t\t},\n\n\t\tpause() {\n\t\t\tisPaused = true;\n\t\t},\n\n\t\tresume() {\n\t\t\tisPaused = false;\n\t\t\tif ( isPending ) {\n\t\t\t\tisPending = false;\n\t\t\t\tnotifyListeners();\n\t\t\t}\n\t\t},\n\n\t\temit() {\n\t\t\tif ( isPaused ) {\n\t\t\t\tisPending = true;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tnotifyListeners();\n\t\t},\n\t};\n}\n"]}
1
+ {"version":3,"sources":["@wordpress/data/src/utils/emitter.js"],"names":["createEmitter","isPaused","isPending","listeners","Set","notifyListeners","Array","from","forEach","listener","subscribe","add","delete","pause","resume","emit"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASA,aAAT,GAAyB;AAC/B,MAAIC,QAAQ,GAAG,KAAf;AACA,MAAIC,SAAS,GAAG,KAAhB;AACA,QAAMC,SAAS,GAAG,IAAIC,GAAJ,EAAlB;;AACA,QAAMC,eAAe,GAAG,MACvB;AACA;AACA;AACAC,EAAAA,KAAK,CAACC,IAAN,CAAYJ,SAAZ,EAAwBK,OAAxB,CAAmCC,QAAF,IAAgBA,QAAQ,EAAzD,CAJD;;AAMA,SAAO;AACN,QAAIR,QAAJ,GAAe;AACd,aAAOA,QAAP;AACA,KAHK;;AAKNS,IAAAA,SAAS,CAAED,QAAF,EAAa;AACrBN,MAAAA,SAAS,CAACQ,GAAV,CAAeF,QAAf;AACA,aAAO,MAAMN,SAAS,CAACS,MAAV,CAAkBH,QAAlB,CAAb;AACA,KARK;;AAUNI,IAAAA,KAAK,GAAG;AACPZ,MAAAA,QAAQ,GAAG,IAAX;AACA,KAZK;;AAcNa,IAAAA,MAAM,GAAG;AACRb,MAAAA,QAAQ,GAAG,KAAX;;AACA,UAAKC,SAAL,EAAiB;AAChBA,QAAAA,SAAS,GAAG,KAAZ;AACAG,QAAAA,eAAe;AACf;AACD,KApBK;;AAsBNU,IAAAA,IAAI,GAAG;AACN,UAAKd,QAAL,EAAgB;AACfC,QAAAA,SAAS,GAAG,IAAZ;AACA;AACA;;AACDG,MAAAA,eAAe;AACf;;AA5BK,GAAP;AA8BA","sourcesContent":["/**\n * Create an event emitter.\n *\n * @return {import(\"../types\").DataEmitter} Emitter.\n */\nexport function createEmitter() {\n\tlet isPaused = false;\n\tlet isPending = false;\n\tconst listeners = new Set();\n\tconst notifyListeners = () =>\n\t\t// We use Array.from to clone the listeners Set\n\t\t// This ensures that we don't run a listener\n\t\t// that was added as a response to another listener.\n\t\tArray.from( listeners ).forEach( ( listener ) => listener() );\n\n\treturn {\n\t\tget isPaused() {\n\t\t\treturn isPaused;\n\t\t},\n\n\t\tsubscribe( listener ) {\n\t\t\tlisteners.add( listener );\n\t\t\treturn () => listeners.delete( listener );\n\t\t},\n\n\t\tpause() {\n\t\t\tisPaused = true;\n\t\t},\n\n\t\tresume() {\n\t\t\tisPaused = false;\n\t\t\tif ( isPending ) {\n\t\t\t\tisPending = false;\n\t\t\t\tnotifyListeners();\n\t\t\t}\n\t\t},\n\n\t\temit() {\n\t\t\tif ( isPaused ) {\n\t\t\t\tisPending = true;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tnotifyListeners();\n\t\t},\n\t};\n}\n"]}
@@ -1,35 +1,48 @@
1
- export declare type WPDataFunctionOrGeneratorArray = Array<Function | Generator>;
2
- export declare type WPDataFunctionArray = Array<Function>;
3
- export interface WPDataAttachedStore {
4
- getSelectors: () => WPDataFunctionArray;
5
- getActions: () => WPDataFunctionArray;
1
+ declare type MapOf<T> = {
2
+ [name: string]: T;
3
+ };
4
+ export declare type ActionCreator = Function | Generator;
5
+ export declare type Resolver = Function | Generator;
6
+ export declare type Selector = Function;
7
+ export declare type AnyConfig = ReduxStoreConfig<any, any, any>;
8
+ export interface StoreInstance<Config extends AnyConfig> {
9
+ getSelectors: () => SelectorsOf<Config>;
10
+ getActions: () => ActionCreatorsOf<Config>;
6
11
  subscribe: (listener: () => void) => () => void;
7
12
  }
8
- export interface WPDataStore {
13
+ export interface StoreDescriptor<Config extends AnyConfig> {
9
14
  /**
10
15
  * Store Name
11
16
  */
12
17
  name: string;
13
18
  /**
14
- * Store configuration object.
19
+ * Creates a store instance
15
20
  */
16
- instantiate: (registry: WPDataRegistry) => WPDataAttachedStore;
21
+ instantiate: (registry: DataRegistry) => StoreInstance<Config>;
17
22
  }
18
- export interface WPDataReduxStoreConfig {
23
+ export interface ReduxStoreConfig<State, ActionCreators extends MapOf<ActionCreator>, Selectors extends MapOf<Selector>> {
24
+ initialState?: State;
19
25
  reducer: (state: any, action: any) => any;
20
- actions?: WPDataFunctionOrGeneratorArray;
21
- resolvers?: WPDataFunctionOrGeneratorArray;
22
- selectors?: WPDataFunctionArray;
23
- controls?: WPDataFunctionArray;
26
+ actions?: ActionCreators;
27
+ resolvers?: MapOf<Resolver>;
28
+ selectors?: Selectors;
29
+ controls?: MapOf<Function>;
24
30
  }
25
- export interface WPDataRegistry {
26
- register: (store: WPDataStore) => void;
31
+ export interface DataRegistry {
32
+ register: (store: StoreDescriptor<any>) => void;
27
33
  }
28
- export interface WPDataEmitter {
34
+ export interface DataEmitter {
29
35
  emit: () => void;
30
36
  subscribe: (listener: () => void) => () => void;
31
37
  pause: () => void;
32
38
  resume: () => void;
33
39
  isPaused: boolean;
34
40
  }
41
+ declare type ActionCreatorsOf<Config extends AnyConfig> = Config extends ReduxStoreConfig<any, infer ActionCreators, any> ? {
42
+ [name in keyof ActionCreators]: Function | Generator;
43
+ } : never;
44
+ declare type SelectorsOf<Config extends AnyConfig> = Config extends ReduxStoreConfig<any, any, infer Selectors> ? {
45
+ [name in keyof Selectors]: Function;
46
+ } : never;
47
+ export {};
35
48
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,oBAAY,8BAA8B,GAAG,KAAK,CAAE,QAAQ,GAAG,SAAS,CAAE,CAAC;AAC3E,oBAAY,mBAAmB,GAAG,KAAK,CAAE,QAAQ,CAAE,CAAC;AAEpD,MAAM,WAAW,mBAAmB;IACnC,YAAY,EAAE,MAAM,mBAAmB,CAAC;IACxC,UAAU,EAAE,MAAM,mBAAmB,CAAC;IACtC,SAAS,EAAE,CAAE,QAAQ,EAAE,MAAM,IAAI,KAAM,MAAM,IAAI,CAAC;CAClD;AAED,MAAM,WAAW,WAAW;IAC3B;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,WAAW,EAAE,CAAE,QAAQ,EAAE,cAAc,KAAM,mBAAmB,CAAC;CACjE;AAED,MAAM,WAAW,sBAAsB;IACtC,OAAO,EAAE,CAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,KAAM,GAAG,CAAC;IAC5C,OAAO,CAAC,EAAE,8BAA8B,CAAC;IACzC,SAAS,CAAC,EAAE,8BAA8B,CAAC;IAC3C,SAAS,CAAC,EAAE,mBAAmB,CAAC;IAChC,QAAQ,CAAC,EAAE,mBAAmB,CAAC;CAC/B;AAED,MAAM,WAAW,cAAc;IAC9B,QAAQ,EAAE,CAAE,KAAK,EAAE,WAAW,KAAM,IAAI,CAAC;CACzC;AAED,MAAM,WAAW,aAAa;IAC7B,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,SAAS,EAAE,CAAE,QAAQ,EAAE,MAAM,IAAI,KAAM,MAAM,IAAI,CAAC;IAClD,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;CAClB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,aAAK,KAAK,CAAE,CAAC,IAAK;IAAE,CAAE,IAAI,EAAE,MAAM,GAAI,CAAC,CAAA;CAAE,CAAC;AAE1C,oBAAY,aAAa,GAAG,QAAQ,GAAG,SAAS,CAAC;AACjD,oBAAY,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;AAC5C,oBAAY,QAAQ,GAAG,QAAQ,CAAC;AAEhC,oBAAY,SAAS,GAAG,gBAAgB,CAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAE,CAAC;AAE1D,MAAM,WAAW,aAAa,CAAE,MAAM,SAAS,SAAS;IACvD,YAAY,EAAE,MAAM,WAAW,CAAE,MAAM,CAAE,CAAC;IAC1C,UAAU,EAAE,MAAM,gBAAgB,CAAE,MAAM,CAAE,CAAC;IAC7C,SAAS,EAAE,CAAE,QAAQ,EAAE,MAAM,IAAI,KAAM,MAAM,IAAI,CAAC;CAClD;AAED,MAAM,WAAW,eAAe,CAAE,MAAM,SAAS,SAAS;IACzD;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,WAAW,EAAE,CAAE,QAAQ,EAAE,YAAY,KAAM,aAAa,CAAE,MAAM,CAAE,CAAC;CACnE;AAED,MAAM,WAAW,gBAAgB,CAChC,KAAK,EACL,cAAc,SAAS,KAAK,CAAE,aAAa,CAAE,EAC7C,SAAS,SAAS,KAAK,CAAE,QAAQ,CAAE;IAEnC,YAAY,CAAC,EAAE,KAAK,CAAC;IACrB,OAAO,EAAE,CAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,KAAM,GAAG,CAAC;IAC5C,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,SAAS,CAAC,EAAE,KAAK,CAAE,QAAQ,CAAE,CAAC;IAC9B,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,QAAQ,CAAC,EAAE,KAAK,CAAE,QAAQ,CAAE,CAAC;CAC7B;AAED,MAAM,WAAW,YAAY;IAC5B,QAAQ,EAAE,CAAE,KAAK,EAAE,eAAe,CAAE,GAAG,CAAE,KAAM,IAAI,CAAC;CACpD;AAED,MAAM,WAAW,WAAW;IAC3B,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,SAAS,EAAE,CAAE,QAAQ,EAAE,MAAM,IAAI,KAAM,MAAM,IAAI,CAAC;IAClD,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;CAClB;AAMD,aAAK,gBAAgB,CACpB,MAAM,SAAS,SAAS,IACrB,MAAM,SAAS,gBAAgB,CAAE,GAAG,EAAE,MAAM,cAAc,EAAE,GAAG,CAAE,GAClE;KAAI,IAAI,IAAI,MAAM,cAAc,GAAI,QAAQ,GAAG,SAAS;CAAE,GAC1D,KAAK,CAAC;AAET,aAAK,WAAW,CAAE,MAAM,SAAS,SAAS,IAAK,MAAM,SAAS,gBAAgB,CAC7E,GAAG,EACH,GAAG,EACH,MAAM,SAAS,CACf,GACE;KAAI,IAAI,IAAI,MAAM,SAAS,GAAI,QAAQ;CAAE,GACzC,KAAK,CAAC"}
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Create an event emitter.
3
3
  *
4
- * @return {import("../types").WPDataEmitter} Emitter.
4
+ * @return {import("../types").DataEmitter} Emitter.
5
5
  */
6
- export function createEmitter(): import("../types").WPDataEmitter;
6
+ export function createEmitter(): import("../types").DataEmitter;
7
7
  //# sourceMappingURL=emitter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"emitter.d.ts","sourceRoot":"","sources":["../../src/utils/emitter.js"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,iCAFY,OAAO,UAAU,EAAE,aAAa,CA0C3C"}
1
+ {"version":3,"file":"emitter.d.ts","sourceRoot":"","sources":["../../src/utils/emitter.js"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,iCAFY,OAAO,UAAU,EAAE,WAAW,CA0CzC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/data",
3
- "version": "6.1.4",
3
+ "version": "6.2.1",
4
4
  "description": "Data module for WordPress.",
5
5
  "author": "The WordPress Contributors",
6
6
  "license": "GPL-2.0-or-later",
@@ -28,24 +28,24 @@
28
28
  "sideEffects": false,
29
29
  "dependencies": {
30
30
  "@babel/runtime": "^7.16.0",
31
- "@wordpress/compose": "^5.0.6",
32
- "@wordpress/deprecated": "^3.2.3",
33
- "@wordpress/element": "^4.0.4",
34
- "@wordpress/is-shallow-equal": "^4.2.1",
35
- "@wordpress/priority-queue": "^2.2.3",
36
- "@wordpress/redux-routine": "^4.2.2",
31
+ "@wordpress/compose": "^5.1.1",
32
+ "@wordpress/deprecated": "^3.3.1",
33
+ "@wordpress/element": "^4.1.1",
34
+ "@wordpress/is-shallow-equal": "^4.3.1",
35
+ "@wordpress/priority-queue": "^2.3.1",
36
+ "@wordpress/redux-routine": "^4.3.1",
37
37
  "equivalent-key-map": "^0.2.2",
38
38
  "is-promise": "^4.0.0",
39
39
  "lodash": "^4.17.21",
40
- "memize": "^1.1.0",
40
+ "redux": "^4.1.2",
41
41
  "turbo-combine-reducers": "^1.0.2",
42
42
  "use-memo-one": "^1.1.1"
43
43
  },
44
44
  "peerDependencies": {
45
- "redux": "^4.1.0"
45
+ "react": "^17.0.0"
46
46
  },
47
47
  "publishConfig": {
48
48
  "access": "public"
49
49
  },
50
- "gitHead": "9a1dd3474d937468e4cf9caf9886ad61ef0a8f50"
50
+ "gitHead": "2e4922861e49f5a090f9dc52056165092cfba163"
51
51
  }
@@ -82,7 +82,7 @@ describe( 'useDispatch', () => {
82
82
  expect( testAction ).toHaveBeenCalledTimes( 1 );
83
83
  } );
84
84
 
85
- it( 'returns expected action creators from store for given store definition', () => {
85
+ it( 'returns expected action creators from store for given store descriptor', () => {
86
86
  const noop = () => ( { type: '__INERT__' } );
87
87
  const testAction = jest.fn().mockImplementation( noop );
88
88
  registry.registerStore( 'demoStore', {
@@ -3,7 +3,7 @@
3
3
  */
4
4
  import useRegistry from '../registry-provider/use-registry';
5
5
 
6
- /** @typedef {import('./types').WPDataStore} WPDataStore */
6
+ /** @typedef {import('../../types').StoreDescriptor} StoreDescriptor */
7
7
 
8
8
  /**
9
9
  * A custom react hook returning the current registry dispatch actions creators.
@@ -11,11 +11,11 @@ import useRegistry from '../registry-provider/use-registry';
11
11
  * Note: The component using this hook must be within the context of a
12
12
  * RegistryProvider.
13
13
  *
14
- * @param {string|WPDataStore} [storeNameOrDefinition] Optionally provide the name of the
15
- * store or its definition from which to
16
- * retrieve action creators. If not
17
- * provided, the registry.dispatch
18
- * function is returned instead.
14
+ * @param {string|StoreDescriptor} [storeNameOrDescriptor] Optionally provide the name of the
15
+ * store or its descriptor from which to
16
+ * retrieve action creators. If not
17
+ * provided, the registry.dispatch
18
+ * function is returned instead.
19
19
  *
20
20
  * @example
21
21
  * This illustrates a pattern where you may need to retrieve dynamic data from
@@ -49,11 +49,11 @@ import useRegistry from '../registry-provider/use-registry';
49
49
  * ```
50
50
  * @return {Function} A custom react hook.
51
51
  */
52
- const useDispatch = ( storeNameOrDefinition ) => {
52
+ const useDispatch = ( storeNameOrDescriptor ) => {
53
53
  const { dispatch } = useRegistry();
54
- return storeNameOrDefinition === void 0
54
+ return storeNameOrDescriptor === void 0
55
55
  ? dispatch
56
- : dispatch( storeNameOrDefinition );
56
+ : dispatch( storeNameOrDescriptor );
57
57
  };
58
58
 
59
59
  export default useDispatch;
@@ -7,7 +7,7 @@ import { useMemoOne } from 'use-memo-one';
7
7
  * WordPress dependencies
8
8
  */
9
9
  import { createQueue } from '@wordpress/priority-queue';
10
- import { useRef, useCallback, useReducer, useMemo } from '@wordpress/element';
10
+ import { useRef, useCallback, useMemo, useReducer } from '@wordpress/element';
11
11
  import isShallowEqual from '@wordpress/is-shallow-equal';
12
12
  import { useIsomorphicLayoutEffect } from '@wordpress/compose';
13
13
 
@@ -17,9 +17,10 @@ import { useIsomorphicLayoutEffect } from '@wordpress/compose';
17
17
  import useRegistry from '../registry-provider/use-registry';
18
18
  import useAsyncMode from '../async-mode-provider/use-async-mode';
19
19
 
20
+ const noop = () => {};
20
21
  const renderQueue = createQueue();
21
22
 
22
- /** @typedef {import('./types').WPDataStore} WPDataStore */
23
+ /** @typedef {import('../../types').StoreDescriptor} StoreDescriptor */
23
24
 
24
25
  /**
25
26
  * Custom react hook for retrieving props from registered selectors.
@@ -27,20 +28,20 @@ const renderQueue = createQueue();
27
28
  * In general, this custom React hook follows the
28
29
  * [rules of hooks](https://reactjs.org/docs/hooks-rules.html).
29
30
  *
30
- * @param {Function|WPDataStore|string} _mapSelect Function called on every state change. The
31
- * returned value is exposed to the component
32
- * implementing this hook. The function receives
33
- * the `registry.select` method on the first
34
- * argument and the `registry` on the second
35
- * argument.
36
- * When a store key is passed, all selectors for
37
- * the store will be returned. This is only meant
38
- * for usage of these selectors in event
39
- * callbacks, not for data needed to create the
40
- * element tree.
41
- * @param {Array} deps If provided, this memoizes the mapSelect so the
42
- * same `mapSelect` is invoked on every state
43
- * change unless the dependencies change.
31
+ * @param {Function|StoreDescriptor|string} mapSelect Function called on every state change. The
32
+ * returned value is exposed to the component
33
+ * implementing this hook. The function receives
34
+ * the `registry.select` method on the first
35
+ * argument and the `registry` on the second
36
+ * argument.
37
+ * When a store key is passed, all selectors for
38
+ * the store will be returned. This is only meant
39
+ * for usage of these selectors in event
40
+ * callbacks, not for data needed to create the
41
+ * element tree.
42
+ * @param {Array} deps If provided, this memoizes the mapSelect so the
43
+ * same `mapSelect` is invoked on every state
44
+ * change unless the dependencies change.
44
45
  *
45
46
  * @example
46
47
  * ```js
@@ -88,14 +89,27 @@ const renderQueue = createQueue();
88
89
  *
89
90
  * @return {Function} A custom react hook.
90
91
  */
91
- export default function useSelect( _mapSelect, deps ) {
92
- const isWithoutMapping = typeof _mapSelect !== 'function';
92
+ export default function useSelect( mapSelect, deps ) {
93
+ const hasMappingFunction = 'function' === typeof mapSelect;
93
94
 
94
- if ( isWithoutMapping ) {
95
+ // If we're recalling a store by its name or by
96
+ // its descriptor then we won't be caching the
97
+ // calls to `mapSelect` because we won't be calling it.
98
+ if ( ! hasMappingFunction ) {
95
99
  deps = [];
96
100
  }
97
101
 
98
- const mapSelect = useCallback( _mapSelect, deps );
102
+ // Because of the "rule of hooks" we have to call `useCallback`
103
+ // on every invocation whether or not we have a real function
104
+ // for `mapSelect`. we'll create this intermediate variable to
105
+ // fulfill that need and then reference it with our "real"
106
+ // `_mapSelect` if we can.
107
+ const callbackMapper = useCallback(
108
+ hasMappingFunction ? mapSelect : noop,
109
+ deps
110
+ );
111
+ const _mapSelect = hasMappingFunction ? callbackMapper : null;
112
+
99
113
  const registry = useRegistry();
100
114
  const isAsync = useAsyncMode();
101
115
  // React can sometimes clear the `useMemo` cache.
@@ -110,7 +124,7 @@ export default function useSelect( _mapSelect, deps ) {
110
124
  const latestMapOutputError = useRef();
111
125
  const isMountedAndNotUnsubscribing = useRef();
112
126
 
113
- // Keep track of the stores being selected in the mapSelect function,
127
+ // Keep track of the stores being selected in the _mapSelect function,
114
128
  // and only subscribe to those stores later.
115
129
  const listeningStores = useRef( [] );
116
130
  const trapSelect = useCallback(
@@ -129,39 +143,37 @@ export default function useSelect( _mapSelect, deps ) {
129
143
 
130
144
  let mapOutput;
131
145
 
132
- if ( ! isWithoutMapping ) {
133
- try {
134
- if (
135
- latestMapSelect.current !== mapSelect ||
136
- latestMapOutputError.current
137
- ) {
146
+ if ( _mapSelect ) {
147
+ mapOutput = latestMapOutput.current;
148
+ const hasReplacedMapSelect = latestMapSelect.current !== _mapSelect;
149
+ const lastMapSelectFailed = !! latestMapOutputError.current;
150
+
151
+ if ( hasReplacedMapSelect || lastMapSelectFailed ) {
152
+ try {
138
153
  mapOutput = trapSelect( () =>
139
- mapSelect( registry.select, registry )
154
+ _mapSelect( registry.select, registry )
140
155
  );
141
- } else {
142
- mapOutput = latestMapOutput.current;
143
- }
144
- } catch ( error ) {
145
- let errorMessage = `An error occurred while running 'mapSelect': ${ error.message }`;
156
+ } catch ( error ) {
157
+ let errorMessage = `An error occurred while running 'mapSelect': ${ error.message }`;
146
158
 
147
- if ( latestMapOutputError.current ) {
148
- errorMessage += `\nThe error may be correlated with this previous error:\n`;
149
- errorMessage += `${ latestMapOutputError.current.stack }\n\n`;
150
- errorMessage += 'Original stack trace:';
151
- }
159
+ if ( latestMapOutputError.current ) {
160
+ errorMessage += `\nThe error may be correlated with this previous error:\n`;
161
+ errorMessage += `${ latestMapOutputError.current.stack }\n\n`;
162
+ errorMessage += 'Original stack trace:';
163
+ }
152
164
 
153
- // eslint-disable-next-line no-console
154
- console.error( errorMessage );
155
- mapOutput = latestMapOutput.current;
165
+ // eslint-disable-next-line no-console
166
+ console.error( errorMessage );
167
+ }
156
168
  }
157
169
  }
158
170
 
159
171
  useIsomorphicLayoutEffect( () => {
160
- if ( isWithoutMapping ) {
172
+ if ( ! hasMappingFunction ) {
161
173
  return;
162
174
  }
163
175
 
164
- latestMapSelect.current = mapSelect;
176
+ latestMapSelect.current = _mapSelect;
165
177
  latestMapOutput.current = mapOutput;
166
178
  latestMapOutputError.current = undefined;
167
179
  isMountedAndNotUnsubscribing.current = true;
@@ -177,7 +189,7 @@ export default function useSelect( _mapSelect, deps ) {
177
189
  } );
178
190
 
179
191
  useIsomorphicLayoutEffect( () => {
180
- if ( isWithoutMapping ) {
192
+ if ( ! hasMappingFunction ) {
181
193
  return;
182
194
  }
183
195
 
@@ -227,7 +239,10 @@ export default function useSelect( _mapSelect, deps ) {
227
239
  unsubscribers.forEach( ( unsubscribe ) => unsubscribe?.() );
228
240
  renderQueue.flush( queueContext );
229
241
  };
230
- }, [ registry, trapSelect, depsChangedFlag, isWithoutMapping ] );
242
+ // If you're tempted to eliminate the spread dependencies below don't do it!
243
+ // We're passing these in from the calling function and want to make sure we're
244
+ // examining every individual value inside the `deps` array.
245
+ }, [ registry, trapSelect, hasMappingFunction, depsChangedFlag ] );
231
246
 
232
- return isWithoutMapping ? registry.select( _mapSelect ) : mapOutput;
247
+ return hasMappingFunction ? mapOutput : registry.select( mapSelect );
233
248
  }
@@ -723,42 +723,42 @@ describe( 'useSelect', () => {
723
723
  it( 'handles custom generic stores without a unsubscribe function', () => {
724
724
  let renderer;
725
725
 
726
- function createCustomStore() {
727
- let storeChanged = () => {};
728
- let counter = 0;
729
-
730
- const selectors = {
731
- getCounter: () => counter,
732
- };
733
-
734
- const actions = {
735
- increment: () => {
736
- counter += 1;
737
- storeChanged();
738
- },
739
- };
726
+ const customStore = {
727
+ name: 'generic-store',
728
+ instantiate() {
729
+ let storeChanged = () => {};
730
+ let counter = 0;
731
+
732
+ const selectors = {
733
+ getCounter: () => counter,
734
+ };
735
+
736
+ const actions = {
737
+ increment: () => {
738
+ counter += 1;
739
+ storeChanged();
740
+ },
741
+ };
740
742
 
741
- return {
742
- getSelectors() {
743
- return selectors;
744
- },
745
- getActions() {
746
- return actions;
747
- },
748
- subscribe( listener ) {
749
- storeChanged = listener;
750
- },
751
- };
752
- }
743
+ return {
744
+ getSelectors() {
745
+ return selectors;
746
+ },
747
+ getActions() {
748
+ return actions;
749
+ },
750
+ subscribe( listener ) {
751
+ storeChanged = listener;
752
+ },
753
+ };
754
+ },
755
+ };
753
756
 
754
- registry.registerGenericStore(
755
- 'generic-store',
756
- createCustomStore()
757
- );
757
+ registry.register( customStore );
758
758
 
759
759
  const TestComponent = jest.fn( () => {
760
760
  const state = useSelect(
761
- ( select ) => select( 'generic-store' ).getCounter(),
761
+ ( select ) => select( customStore ).getCounter(),
762
762
  []
763
763
  );
764
764
 
@@ -778,7 +778,7 @@ describe( 'useSelect', () => {
778
778
  expect( testInstance.findByType( 'div' ).props.data ).toBe( 0 );
779
779
 
780
780
  act( () => {
781
- registry.dispatch( 'generic-store' ).increment();
781
+ registry.dispatch( customStore ).increment();
782
782
  } );
783
783
 
784
784
  expect( testInstance.findByType( 'div' ).props.data ).toBe( 1 );
package/src/controls.js CHANGED
@@ -8,7 +8,7 @@ import { isObject } from 'lodash';
8
8
  */
9
9
  import { createRegistryControl } from './factory';
10
10
 
11
- /** @typedef {import('./types').WPDataStore} WPDataStore */
11
+ /** @typedef {import('./types').StoreDescriptor} StoreDescriptor */
12
12
 
13
13
  const SELECT = '@@data/SELECT';
14
14
  const RESOLVE_SELECT = '@@data/RESOLVE_SELECT';
@@ -20,9 +20,9 @@ const DISPATCH = '@@data/DISPATCH';
20
20
  * Note: This control synchronously returns the current selector value, triggering the
21
21
  * resolution, but not waiting for it.
22
22
  *
23
- * @param {string|WPDataStore} storeNameOrDefinition Unique namespace identifier for the store
24
- * @param {string} selectorName The name of the selector.
25
- * @param {Array} args Arguments for the selector.
23
+ * @param {string|StoreDescriptor} storeNameOrDescriptor Unique namespace identifier for the store
24
+ * @param {string} selectorName The name of the selector.
25
+ * @param {Array} args Arguments for the selector.
26
26
  *
27
27
  * @example
28
28
  * ```js
@@ -37,12 +37,12 @@ const DISPATCH = '@@data/DISPATCH';
37
37
  *
38
38
  * @return {Object} The control descriptor.
39
39
  */
40
- function select( storeNameOrDefinition, selectorName, ...args ) {
40
+ function select( storeNameOrDescriptor, selectorName, ...args ) {
41
41
  return {
42
42
  type: SELECT,
43
- storeKey: isObject( storeNameOrDefinition )
44
- ? storeNameOrDefinition.name
45
- : storeNameOrDefinition,
43
+ storeKey: isObject( storeNameOrDescriptor )
44
+ ? storeNameOrDescriptor.name
45
+ : storeNameOrDescriptor,
46
46
  selectorName,
47
47
  args,
48
48
  };
@@ -55,9 +55,9 @@ function select( storeNameOrDefinition, selectorName, ...args ) {
55
55
  * selectors that may have a resolver. In such case, it will return a `Promise` that resolves
56
56
  * after the selector finishes resolving, with the final result value.
57
57
  *
58
- * @param {string|WPDataStore} storeNameOrDefinition Unique namespace identifier for the store
59
- * @param {string} selectorName The name of the selector
60
- * @param {Array} args Arguments for the selector.
58
+ * @param {string|StoreDescriptor} storeNameOrDescriptor Unique namespace identifier for the store
59
+ * @param {string} selectorName The name of the selector
60
+ * @param {Array} args Arguments for the selector.
61
61
  *
62
62
  * @example
63
63
  * ```js
@@ -72,12 +72,12 @@ function select( storeNameOrDefinition, selectorName, ...args ) {
72
72
  *
73
73
  * @return {Object} The control descriptor.
74
74
  */
75
- function resolveSelect( storeNameOrDefinition, selectorName, ...args ) {
75
+ function resolveSelect( storeNameOrDescriptor, selectorName, ...args ) {
76
76
  return {
77
77
  type: RESOLVE_SELECT,
78
- storeKey: isObject( storeNameOrDefinition )
79
- ? storeNameOrDefinition.name
80
- : storeNameOrDefinition,
78
+ storeKey: isObject( storeNameOrDescriptor )
79
+ ? storeNameOrDescriptor.name
80
+ : storeNameOrDescriptor,
81
81
  selectorName,
82
82
  args,
83
83
  };
@@ -86,9 +86,9 @@ function resolveSelect( storeNameOrDefinition, selectorName, ...args ) {
86
86
  /**
87
87
  * Dispatches a control action for triggering a registry dispatch.
88
88
  *
89
- * @param {string|WPDataStore} storeNameOrDefinition Unique namespace identifier for the store
90
- * @param {string} actionName The name of the action to dispatch
91
- * @param {Array} args Arguments for the dispatch action.
89
+ * @param {string|StoreDescriptor} storeNameOrDescriptor Unique namespace identifier for the store
90
+ * @param {string} actionName The name of the action to dispatch
91
+ * @param {Array} args Arguments for the dispatch action.
92
92
  *
93
93
  * @example
94
94
  * ```js
@@ -103,12 +103,12 @@ function resolveSelect( storeNameOrDefinition, selectorName, ...args ) {
103
103
  *
104
104
  * @return {Object} The control descriptor.
105
105
  */
106
- function dispatch( storeNameOrDefinition, actionName, ...args ) {
106
+ function dispatch( storeNameOrDescriptor, actionName, ...args ) {
107
107
  return {
108
108
  type: DISPATCH,
109
- storeKey: isObject( storeNameOrDefinition )
110
- ? storeNameOrDefinition.name
111
- : storeNameOrDefinition,
109
+ storeKey: isObject( storeNameOrDescriptor )
110
+ ? storeNameOrDescriptor.name
111
+ : storeNameOrDescriptor,
112
112
  actionName,
113
113
  args,
114
114
  };
package/src/index.js CHANGED
@@ -9,7 +9,7 @@ import combineReducers from 'turbo-combine-reducers';
9
9
  import defaultRegistry from './default-registry';
10
10
  import * as plugins from './plugins';
11
11
 
12
- /** @typedef {import('./types').WPDataStore} WPDataStore */
12
+ /** @typedef {import('./types').StoreDescriptor} StoreDescriptor */
13
13
 
14
14
  export { default as withSelect } from './components/with-select';
15
15
  export { default as withDispatch } from './components/with-dispatch';
@@ -77,12 +77,12 @@ export { plugins };
77
77
  export { combineReducers };
78
78
 
79
79
  /**
80
- * Given the name or definition of a registered store, returns an object of the store's selectors.
80
+ * Given the name or descriptor of a registered store, returns an object of the store's selectors.
81
81
  * The selector functions are been pre-bound to pass the current state automatically.
82
82
  * As a consumer, you need only pass arguments of the selector, if applicable.
83
83
  *
84
- * @param {string|WPDataStore} storeNameOrDefinition Unique namespace identifier for the store
85
- * or the store definition.
84
+ * @param {string|StoreDescriptor} storeNameOrDescriptor Unique namespace identifier for the store
85
+ * or the store descriptor.
86
86
  *
87
87
  * @example
88
88
  * ```js
@@ -101,8 +101,8 @@ export const select = defaultRegistry.select;
101
101
  * and modified so that they return promises that resolve to their eventual values,
102
102
  * after any resolvers have ran.
103
103
  *
104
- * @param {string|WPDataStore} storeNameOrDefinition Unique namespace identifier for the store
105
- * or the store definition.
104
+ * @param {string|StoreDescriptor} storeNameOrDescriptor Unique namespace identifier for the store
105
+ * or the store descriptor.
106
106
  *
107
107
  * @example
108
108
  * ```js
@@ -122,8 +122,8 @@ export const resolveSelect = defaultRegistry.resolveSelect;
122
122
  * Note: Action creators returned by the dispatch will return a promise when
123
123
  * they are called.
124
124
  *
125
- * @param {string|WPDataStore} storeNameOrDefinition Unique namespace identifier for the store
126
- * or the store definition.
125
+ * @param {string|StoreDescriptor} storeNameOrDescriptor Unique namespace identifier for the store
126
+ * or the store descriptor.
127
127
  *
128
128
  * @example
129
129
  * ```js
@@ -158,12 +158,12 @@ export const dispatch = defaultRegistry.dispatch;
158
158
  export const subscribe = defaultRegistry.subscribe;
159
159
 
160
160
  /**
161
- * Registers a generic store.
161
+ * Registers a generic store instance.
162
162
  *
163
- * @deprecated Use `register` instead.
163
+ * @deprecated Use `register( storeDescriptor )` instead.
164
164
  *
165
- * @param {string} key Store registry key.
166
- * @param {Object} config Configuration (getSelectors, getActions, subscribe).
165
+ * @param {string} name Store registry name.
166
+ * @param {Object} store Store instance (`{ getSelectors, getActions, subscribe }`).
167
167
  */
168
168
  export const registerGenericStore = defaultRegistry.registerGenericStore;
169
169
 
@@ -189,7 +189,7 @@ export const registerStore = defaultRegistry.registerStore;
189
189
  export const use = defaultRegistry.use;
190
190
 
191
191
  /**
192
- * Registers a standard `@wordpress/data` store definition.
192
+ * Registers a standard `@wordpress/data` store descriptor.
193
193
  *
194
194
  * @example
195
195
  * ```js
@@ -204,6 +204,6 @@ export const use = defaultRegistry.use;
204
204
  * register( store );
205
205
  * ```
206
206
  *
207
- * @param {WPDataStore} store Store definition.
207
+ * @param {StoreDescriptor} store Store descriptor.
208
208
  */
209
209
  export const register = defaultRegistry.register;