@wordpress/preferences 1.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.
Files changed (46) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/LICENSE.md +788 -0
  3. package/README.md +174 -0
  4. package/build/components/index.js +16 -0
  5. package/build/components/index.js.map +1 -0
  6. package/build/components/preference-toggle-menu-item/index.js +70 -0
  7. package/build/components/preference-toggle-menu-item/index.js.map +1 -0
  8. package/build/index.js +31 -0
  9. package/build/index.js.map +1 -0
  10. package/build/store/actions.js +65 -0
  11. package/build/store/actions.js.map +1 -0
  12. package/build/store/constants.js +15 -0
  13. package/build/store/constants.js.map +1 -0
  14. package/build/store/index.js +58 -0
  15. package/build/store/index.js.map +1 -0
  16. package/build/store/reducer.js +81 -0
  17. package/build/store/reducer.js.map +1 -0
  18. package/build/store/selectors.js +24 -0
  19. package/build/store/selectors.js.map +1 -0
  20. package/build-module/components/index.js +2 -0
  21. package/build-module/components/index.js.map +1 -0
  22. package/build-module/components/preference-toggle-menu-item/index.js +57 -0
  23. package/build-module/components/preference-toggle-menu-item/index.js.map +1 -0
  24. package/build-module/index.js +3 -0
  25. package/build-module/index.js.map +1 -0
  26. package/build-module/store/actions.js +54 -0
  27. package/build-module/store/actions.js.map +1 -0
  28. package/build-module/store/constants.js +7 -0
  29. package/build-module/store/constants.js.map +1 -0
  30. package/build-module/store/index.js +39 -0
  31. package/build-module/store/index.js.map +1 -0
  32. package/build-module/store/reducer.js +67 -0
  33. package/build-module/store/reducer.js.map +1 -0
  34. package/build-module/store/selectors.js +17 -0
  35. package/build-module/store/selectors.js.map +1 -0
  36. package/package.json +44 -0
  37. package/src/components/index.js +1 -0
  38. package/src/components/preference-toggle-menu-item/README.md +58 -0
  39. package/src/components/preference-toggle-menu-item/index.js +66 -0
  40. package/src/index.js +2 -0
  41. package/src/store/actions.js +49 -0
  42. package/src/store/constants.js +6 -0
  43. package/src/store/index.js +38 -0
  44. package/src/store/reducer.js +58 -0
  45. package/src/store/selectors.js +14 -0
  46. package/src/store/test/selectors.js +68 -0
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Returns an action object used in signalling that a preference should be
3
+ * toggled.
4
+ *
5
+ * @param {string} scope The preference scope (e.g. core/edit-post).
6
+ * @param {string} name The preference name.
7
+ */
8
+ export function toggle(scope, name) {
9
+ return function (_ref) {
10
+ let {
11
+ select,
12
+ dispatch
13
+ } = _ref;
14
+ const currentValue = select.get(scope, name);
15
+ dispatch.set(scope, name, !currentValue);
16
+ };
17
+ }
18
+ /**
19
+ * Returns an action object used in signalling that a preference should be set
20
+ * to a value
21
+ *
22
+ * @param {string} scope The preference scope (e.g. core/edit-post).
23
+ * @param {string} name The preference name.
24
+ * @param {*} value The value to set.
25
+ *
26
+ * @return {Object} Action object.
27
+ */
28
+
29
+ export function set(scope, name, value) {
30
+ return {
31
+ type: 'SET_PREFERENCE_VALUE',
32
+ scope,
33
+ name,
34
+ value
35
+ };
36
+ }
37
+ /**
38
+ * Returns an action object used in signalling that preference defaults should
39
+ * be set.
40
+ *
41
+ * @param {string} scope The preference scope (e.g. core/edit-post).
42
+ * @param {Object<string, *>} defaults A key/value map of preference names to values.
43
+ *
44
+ * @return {Object} Action object.
45
+ */
46
+
47
+ export function setDefaults(scope, defaults) {
48
+ return {
49
+ type: 'SET_PREFERENCE_DEFAULTS',
50
+ scope,
51
+ defaults
52
+ };
53
+ }
54
+ //# sourceMappingURL=actions.js.map
@@ -0,0 +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"]}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * The identifier for the data store.
3
+ *
4
+ * @type {string}
5
+ */
6
+ export const STORE_NAME = 'core/preferences';
7
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["@wordpress/preferences/src/store/constants.js"],"names":["STORE_NAME"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMA,UAAU,GAAG,kBAAnB","sourcesContent":["/**\n * The identifier for the data store.\n *\n * @type {string}\n */\nexport const STORE_NAME = 'core/preferences';\n"]}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { createReduxStore, registerStore } from '@wordpress/data';
5
+ /**
6
+ * Internal dependencies
7
+ */
8
+
9
+ /**
10
+ * Internal dependencies
11
+ */
12
+
13
+ import reducer from './reducer';
14
+ import * as actions from './actions';
15
+ import * as selectors from './selectors';
16
+ import { STORE_NAME } from './constants';
17
+ /**
18
+ * Store definition for the interface namespace.
19
+ *
20
+ * @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/data/README.md#createReduxStore
21
+ *
22
+ * @type {Object}
23
+ */
24
+
25
+ export const store = createReduxStore(STORE_NAME, {
26
+ reducer,
27
+ 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']
38
+ });
39
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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"]}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { combineReducers } from '@wordpress/data';
5
+ /**
6
+ * Reducer returning the defaults for user preferences.
7
+ *
8
+ * This is kept intentionally separate from the preferences
9
+ * themselves so that defaults are not persisted.
10
+ *
11
+ * @param {Object} state Current state.
12
+ * @param {Object} action Dispatched action.
13
+ *
14
+ * @return {Object} Updated state.
15
+ */
16
+
17
+ export function defaults() {
18
+ let state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
19
+ let action = arguments.length > 1 ? arguments[1] : undefined;
20
+
21
+ if (action.type === 'SET_PREFERENCE_DEFAULTS') {
22
+ const {
23
+ scope,
24
+ defaults: values
25
+ } = action;
26
+ return { ...state,
27
+ [scope]: { ...state[scope],
28
+ ...values
29
+ }
30
+ };
31
+ }
32
+
33
+ return state;
34
+ }
35
+ /**
36
+ * Reducer returning the user preferences.
37
+ *
38
+ * @param {Object} state Current state.
39
+ * @param {Object} action Dispatched action.
40
+ *
41
+ * @return {Object} Updated state.
42
+ */
43
+
44
+ export function preferences() {
45
+ let state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
46
+ let action = arguments.length > 1 ? arguments[1] : undefined;
47
+
48
+ if (action.type === 'SET_PREFERENCE_VALUE') {
49
+ const {
50
+ scope,
51
+ name,
52
+ value
53
+ } = action;
54
+ return { ...state,
55
+ [scope]: { ...state[scope],
56
+ [name]: value
57
+ }
58
+ };
59
+ }
60
+
61
+ return state;
62
+ }
63
+ export default combineReducers({
64
+ defaults,
65
+ preferences
66
+ });
67
+ //# sourceMappingURL=reducer.js.map
@@ -0,0 +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"]}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Returns a boolean indicating whether a prefer is active for a particular
3
+ * scope.
4
+ *
5
+ * @param {Object} state The store state.
6
+ * @param {string} scope The scope of the feature (e.g. core/edit-post).
7
+ * @param {string} name The name of the feature.
8
+ *
9
+ * @return {*} Is the feature enabled?
10
+ */
11
+ export function get(state, scope, name) {
12
+ var _state$preferences$sc, _state$defaults$scope;
13
+
14
+ const value = (_state$preferences$sc = state.preferences[scope]) === null || _state$preferences$sc === void 0 ? void 0 : _state$preferences$sc[name];
15
+ return value !== null && value !== void 0 ? value : (_state$defaults$scope = state.defaults[scope]) === null || _state$defaults$scope === void 0 ? void 0 : _state$defaults$scope[name];
16
+ }
17
+ //# sourceMappingURL=selectors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["@wordpress/preferences/src/store/selectors.js"],"names":["get","state","scope","name","value","preferences","defaults"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASA,GAAT,CAAcC,KAAd,EAAqBC,KAArB,EAA4BC,IAA5B,EAAmC;AAAA;;AACzC,QAAMC,KAAK,4BAAGH,KAAK,CAACI,WAAN,CAAmBH,KAAnB,CAAH,0DAAG,sBAA8BC,IAA9B,CAAd;AACA,SAAOC,KAAP,aAAOA,KAAP,cAAOA,KAAP,4BAAgBH,KAAK,CAACK,QAAN,CAAgBJ,KAAhB,CAAhB,0DAAgB,sBAA2BC,IAA3B,CAAhB;AACA","sourcesContent":["/**\n * Returns a boolean indicating whether a prefer is active for a particular\n * scope.\n *\n * @param {Object} state The store state.\n * @param {string} scope The scope of the feature (e.g. core/edit-post).\n * @param {string} name The name of the feature.\n *\n * @return {*} Is the feature enabled?\n */\nexport function get( state, scope, name ) {\n\tconst value = state.preferences[ scope ]?.[ name ];\n\treturn value ?? state.defaults[ scope ]?.[ name ];\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@wordpress/preferences",
3
+ "version": "1.0.0",
4
+ "description": "Utilities for managing WordPress preferences.",
5
+ "author": "The WordPress Contributors",
6
+ "license": "GPL-2.0-or-later",
7
+ "keywords": [
8
+ "wordpress",
9
+ "gutenberg",
10
+ "preferences",
11
+ "settings",
12
+ "options"
13
+ ],
14
+ "homepage": "https://github.com/WordPress/gutenberg/tree/HEAD/packages/preferences/README.md",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://github.com/WordPress/gutenberg.git",
18
+ "directory": "packages/preferences"
19
+ },
20
+ "bugs": {
21
+ "url": "https://github.com/WordPress/gutenberg/issues"
22
+ },
23
+ "engines": {
24
+ "node": ">=12"
25
+ },
26
+ "main": "build/index.js",
27
+ "module": "build-module/index.js",
28
+ "react-native": "src/index",
29
+ "types": "build-types",
30
+ "sideEffects": false,
31
+ "dependencies": {
32
+ "@babel/runtime": "^7.16.0",
33
+ "@wordpress/a11y": "^3.4.1",
34
+ "@wordpress/components": "^19.6.1",
35
+ "@wordpress/data": "^6.4.1",
36
+ "@wordpress/i18n": "^4.4.1",
37
+ "@wordpress/icons": "^8.0.1",
38
+ "classnames": "^2.3.1"
39
+ },
40
+ "publishConfig": {
41
+ "access": "public"
42
+ },
43
+ "gitHead": "3494eafea7cb345728166c902b3d1223c4a8db6f"
44
+ }
@@ -0,0 +1 @@
1
+ export { default as PreferenceToggleMenuItem } from './preference-toggle-menu-item';
@@ -0,0 +1,58 @@
1
+ # PreferenceToggleMenuItem
2
+
3
+ `PreferenceToggleMenuItem` renders a menu item that is connected to the preference package's store, and will toggle the value of a 'preference' between true and false.
4
+
5
+ This component implements a `MenuItem` component from the `@wordpress/components` package.
6
+
7
+ ## Props
8
+
9
+ ### scope
10
+
11
+ The 'scope' of the feature. This is usually a namespaced string that represents the name of the editor (e.g. 'core/edit-post'), and often matches the name of the store for the editor.
12
+
13
+ - Type: `String`
14
+ - Required: Yes
15
+
16
+ ### name
17
+
18
+ The name of the preference to toggle (e.g. 'fixedToolbar').
19
+
20
+ - Type: `String`
21
+ - Required: Yes
22
+
23
+ ### label
24
+
25
+ A human readable label for the feature.
26
+
27
+ - Type: `String`
28
+ - Required: Yes
29
+
30
+ ### info
31
+
32
+ A human readable description of what this toggle does.
33
+
34
+ - Type: `Object`
35
+ - Required: No
36
+
37
+ ### messageActivated
38
+
39
+ A message read by a screen reader when the feature is activated. (e.g. 'Fixed toolbar activated')
40
+
41
+ - Type: `String`
42
+ - Required: No
43
+
44
+ ### messageDeactivated
45
+
46
+ A message read by a screen reader when the feature is deactivated. (e.g. 'Fixed toolbar deactivated')
47
+
48
+ - Type: `String`
49
+ - Required: No
50
+
51
+ ### shortcut
52
+
53
+ A keyboard shortcut for the feature. This is just used for display purposes and the implementation of the shortcut should be handled separately.
54
+
55
+ Consider using the `displayShortcut` helper from the `@wordpress/keycodes` package for this prop.
56
+
57
+ - Type: `Array`
58
+ - Required: No
@@ -0,0 +1,66 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useSelect, useDispatch } from '@wordpress/data';
5
+ import { MenuItem } from '@wordpress/components';
6
+ import { __, sprintf } from '@wordpress/i18n';
7
+ import { check } from '@wordpress/icons';
8
+ import { speak } from '@wordpress/a11y';
9
+
10
+ /**
11
+ * Internal dependencies
12
+ */
13
+ import { store as preferencesStore } from '../../store';
14
+
15
+ export default function PreferenceToggleMenuItem( {
16
+ scope,
17
+ name,
18
+ label,
19
+ info,
20
+ messageActivated,
21
+ messageDeactivated,
22
+ shortcut,
23
+ } ) {
24
+ const isActive = useSelect(
25
+ ( select ) => !! select( preferencesStore ).get( scope, name ),
26
+ [ name ]
27
+ );
28
+ const { toggle } = useDispatch( preferencesStore );
29
+ const speakMessage = () => {
30
+ if ( isActive ) {
31
+ const message =
32
+ messageDeactivated ||
33
+ sprintf(
34
+ /* translators: %s: preference name, e.g. 'Fullscreen mode' */
35
+ __( 'Preference deactivated - %s' ),
36
+ label
37
+ );
38
+ speak( message );
39
+ } else {
40
+ const message =
41
+ messageActivated ||
42
+ sprintf(
43
+ /* translators: %s: preference name, e.g. 'Fullscreen mode' */
44
+ __( 'Preference activated - %s' ),
45
+ label
46
+ );
47
+ speak( message );
48
+ }
49
+ };
50
+
51
+ return (
52
+ <MenuItem
53
+ icon={ isActive && check }
54
+ isSelected={ isActive }
55
+ onClick={ () => {
56
+ toggle( scope, name );
57
+ speakMessage();
58
+ } }
59
+ role="menuitemcheckbox"
60
+ info={ info }
61
+ shortcut={ shortcut }
62
+ >
63
+ { label }
64
+ </MenuItem>
65
+ );
66
+ }
package/src/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export * from './components';
2
+ export { store } from './store';
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Returns an action object used in signalling that a preference should be
3
+ * toggled.
4
+ *
5
+ * @param {string} scope The preference scope (e.g. core/edit-post).
6
+ * @param {string} name The preference name.
7
+ */
8
+ export function toggle( scope, name ) {
9
+ return function ( { select, dispatch } ) {
10
+ const currentValue = select.get( scope, name );
11
+ dispatch.set( scope, name, ! currentValue );
12
+ };
13
+ }
14
+
15
+ /**
16
+ * Returns an action object used in signalling that a preference should be set
17
+ * to a value
18
+ *
19
+ * @param {string} scope The preference scope (e.g. core/edit-post).
20
+ * @param {string} name The preference name.
21
+ * @param {*} value The value to set.
22
+ *
23
+ * @return {Object} Action object.
24
+ */
25
+ export function set( scope, name, value ) {
26
+ return {
27
+ type: 'SET_PREFERENCE_VALUE',
28
+ scope,
29
+ name,
30
+ value,
31
+ };
32
+ }
33
+
34
+ /**
35
+ * Returns an action object used in signalling that preference defaults should
36
+ * be set.
37
+ *
38
+ * @param {string} scope The preference scope (e.g. core/edit-post).
39
+ * @param {Object<string, *>} defaults A key/value map of preference names to values.
40
+ *
41
+ * @return {Object} Action object.
42
+ */
43
+ export function setDefaults( scope, defaults ) {
44
+ return {
45
+ type: 'SET_PREFERENCE_DEFAULTS',
46
+ scope,
47
+ defaults,
48
+ };
49
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * The identifier for the data store.
3
+ *
4
+ * @type {string}
5
+ */
6
+ export const STORE_NAME = 'core/preferences';
@@ -0,0 +1,38 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { createReduxStore, registerStore } from '@wordpress/data';
5
+
6
+ /**
7
+ * Internal dependencies
8
+ */
9
+ /**
10
+ * Internal dependencies
11
+ */
12
+ import reducer from './reducer';
13
+ import * as actions from './actions';
14
+ import * as selectors from './selectors';
15
+ import { STORE_NAME } from './constants';
16
+
17
+ /**
18
+ * Store definition for the interface namespace.
19
+ *
20
+ * @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/data/README.md#createReduxStore
21
+ *
22
+ * @type {Object}
23
+ */
24
+ export const store = createReduxStore( STORE_NAME, {
25
+ reducer,
26
+ actions,
27
+ selectors,
28
+ persist: [ 'preferences' ],
29
+ } );
30
+
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
+ } );
@@ -0,0 +1,58 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { combineReducers } from '@wordpress/data';
5
+
6
+ /**
7
+ * Reducer returning the defaults for user preferences.
8
+ *
9
+ * This is kept intentionally separate from the preferences
10
+ * themselves so that defaults are not persisted.
11
+ *
12
+ * @param {Object} state Current state.
13
+ * @param {Object} action Dispatched action.
14
+ *
15
+ * @return {Object} Updated state.
16
+ */
17
+ export function defaults( state = {}, action ) {
18
+ if ( action.type === 'SET_PREFERENCE_DEFAULTS' ) {
19
+ const { scope, defaults: values } = action;
20
+ return {
21
+ ...state,
22
+ [ scope ]: {
23
+ ...state[ scope ],
24
+ ...values,
25
+ },
26
+ };
27
+ }
28
+
29
+ return state;
30
+ }
31
+
32
+ /**
33
+ * Reducer returning the user preferences.
34
+ *
35
+ * @param {Object} state Current state.
36
+ * @param {Object} action Dispatched action.
37
+ *
38
+ * @return {Object} Updated state.
39
+ */
40
+ export function preferences( state = {}, action ) {
41
+ if ( action.type === 'SET_PREFERENCE_VALUE' ) {
42
+ const { scope, name, value } = action;
43
+ return {
44
+ ...state,
45
+ [ scope ]: {
46
+ ...state[ scope ],
47
+ [ name ]: value,
48
+ },
49
+ };
50
+ }
51
+
52
+ return state;
53
+ }
54
+
55
+ export default combineReducers( {
56
+ defaults,
57
+ preferences,
58
+ } );
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Returns a boolean indicating whether a prefer is active for a particular
3
+ * scope.
4
+ *
5
+ * @param {Object} state The store state.
6
+ * @param {string} scope The scope of the feature (e.g. core/edit-post).
7
+ * @param {string} name The name of the feature.
8
+ *
9
+ * @return {*} Is the feature enabled?
10
+ */
11
+ export function get( state, scope, name ) {
12
+ const value = state.preferences[ scope ]?.[ name ];
13
+ return value ?? state.defaults[ scope ]?.[ name ];
14
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import { get } from '../selectors';
5
+
6
+ describe( 'selectors', () => {
7
+ describe( 'get', () => {
8
+ it( 'returns `undefined` if the there is no state for the preference', () => {
9
+ const emptyState = {
10
+ defaults: {},
11
+ preferences: {},
12
+ };
13
+
14
+ expect(
15
+ get( emptyState, 'test-scope', 'testPreferenceName' )
16
+ ).toBe( undefined );
17
+ } );
18
+
19
+ it( 'returns the default for a preference if the default is set and the preference has no value', () => {
20
+ const emptyState = {
21
+ defaults: {
22
+ 'test-scope': {
23
+ testPreferenceName: 'test default',
24
+ },
25
+ },
26
+ preferences: {},
27
+ };
28
+
29
+ expect(
30
+ get( emptyState, 'test-scope', 'testPreferenceName' )
31
+ ).toBe( 'test default' );
32
+ } );
33
+
34
+ it( 'returns the value for a preference if the preference is set and the default is not set', () => {
35
+ const emptyState = {
36
+ defaults: {},
37
+ preferences: {
38
+ 'test-scope': {
39
+ testPreferenceName: 'test value',
40
+ },
41
+ },
42
+ };
43
+
44
+ expect(
45
+ get( emptyState, 'test-scope', 'testPreferenceName' )
46
+ ).toBe( 'test value' );
47
+ } );
48
+
49
+ it( 'returns the value for a preference if the preference and the default are set', () => {
50
+ const emptyState = {
51
+ defaults: {
52
+ 'test-scope': {
53
+ testPreferenceName: 'test default',
54
+ },
55
+ },
56
+ preferences: {
57
+ 'test-scope': {
58
+ testPreferenceName: 'test value',
59
+ },
60
+ },
61
+ };
62
+
63
+ expect(
64
+ get( emptyState, 'test-scope', 'testPreferenceName' )
65
+ ).toBe( 'test value' );
66
+ } );
67
+ } );
68
+ } );