@wordpress/preferences-persistence 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 (58) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/LICENSE.md +788 -0
  3. package/README.md +59 -0
  4. package/build/create/debounce-async.js +80 -0
  5. package/build/create/debounce-async.js.map +1 -0
  6. package/build/create/index.js +115 -0
  7. package/build/create/index.js.map +1 -0
  8. package/build/index.js +61 -0
  9. package/build/index.js.map +1 -0
  10. package/build/migrations/legacy-local-storage-data/convert-edit-post-panels.js +60 -0
  11. package/build/migrations/legacy-local-storage-data/convert-edit-post-panels.js.map +1 -0
  12. package/build/migrations/legacy-local-storage-data/index.js +111 -0
  13. package/build/migrations/legacy-local-storage-data/index.js.map +1 -0
  14. package/build/migrations/legacy-local-storage-data/move-feature-preferences.js +135 -0
  15. package/build/migrations/legacy-local-storage-data/move-feature-preferences.js.map +1 -0
  16. package/build/migrations/legacy-local-storage-data/move-individual-preference.js +91 -0
  17. package/build/migrations/legacy-local-storage-data/move-individual-preference.js.map +1 -0
  18. package/build/migrations/legacy-local-storage-data/move-interface-enable-items.js +114 -0
  19. package/build/migrations/legacy-local-storage-data/move-interface-enable-items.js.map +1 -0
  20. package/build/migrations/legacy-local-storage-data/move-third-party-feature-preferences.js +99 -0
  21. package/build/migrations/legacy-local-storage-data/move-third-party-feature-preferences.js.map +1 -0
  22. package/build-module/create/debounce-async.js +73 -0
  23. package/build-module/create/debounce-async.js.map +1 -0
  24. package/build-module/create/index.js +104 -0
  25. package/build-module/create/index.js.map +1 -0
  26. package/build-module/index.js +45 -0
  27. package/build-module/index.js.map +1 -0
  28. package/build-module/migrations/legacy-local-storage-data/convert-edit-post-panels.js +53 -0
  29. package/build-module/migrations/legacy-local-storage-data/convert-edit-post-panels.js.map +1 -0
  30. package/build-module/migrations/legacy-local-storage-data/index.js +95 -0
  31. package/build-module/migrations/legacy-local-storage-data/index.js.map +1 -0
  32. package/build-module/migrations/legacy-local-storage-data/move-feature-preferences.js +128 -0
  33. package/build-module/migrations/legacy-local-storage-data/move-feature-preferences.js.map +1 -0
  34. package/build-module/migrations/legacy-local-storage-data/move-individual-preference.js +84 -0
  35. package/build-module/migrations/legacy-local-storage-data/move-individual-preference.js.map +1 -0
  36. package/build-module/migrations/legacy-local-storage-data/move-interface-enable-items.js +107 -0
  37. package/build-module/migrations/legacy-local-storage-data/move-interface-enable-items.js.map +1 -0
  38. package/build-module/migrations/legacy-local-storage-data/move-third-party-feature-preferences.js +92 -0
  39. package/build-module/migrations/legacy-local-storage-data/move-third-party-feature-preferences.js.map +1 -0
  40. package/package.json +37 -0
  41. package/src/create/debounce-async.js +75 -0
  42. package/src/create/index.js +112 -0
  43. package/src/create/test/debounce-async.js +129 -0
  44. package/src/create/test/index.js +178 -0
  45. package/src/index.js +49 -0
  46. package/src/migrations/legacy-local-storage-data/README.md +42 -0
  47. package/src/migrations/legacy-local-storage-data/convert-edit-post-panels.js +50 -0
  48. package/src/migrations/legacy-local-storage-data/index.js +102 -0
  49. package/src/migrations/legacy-local-storage-data/move-feature-preferences.js +135 -0
  50. package/src/migrations/legacy-local-storage-data/move-individual-preference.js +90 -0
  51. package/src/migrations/legacy-local-storage-data/move-interface-enable-items.js +120 -0
  52. package/src/migrations/legacy-local-storage-data/move-third-party-feature-preferences.js +98 -0
  53. package/src/migrations/legacy-local-storage-data/test/convert-edit-post-panels.js +47 -0
  54. package/src/migrations/legacy-local-storage-data/test/index.js +229 -0
  55. package/src/migrations/legacy-local-storage-data/test/move-feature-preferences.js +260 -0
  56. package/src/migrations/legacy-local-storage-data/test/move-individual-preference.js +188 -0
  57. package/src/migrations/legacy-local-storage-data/test/move-interface-enable-items.js +118 -0
  58. package/src/migrations/legacy-local-storage-data/test/move-third-party-feature-preferences.js +107 -0
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Migrates interface 'enableItems' data to the preferences store.
3
+ *
4
+ * The interface package stores this data in this format:
5
+ * ```js
6
+ * {
7
+ * enableItems: {
8
+ * singleEnableItems: {
9
+ * complementaryArea: {
10
+ * 'core/edit-post': 'edit-post/document',
11
+ * 'core/edit-site': 'edit-site/global-styles',
12
+ * }
13
+ * },
14
+ * multipleEnableItems: {
15
+ * pinnedItems: {
16
+ * 'core/edit-post': {
17
+ * 'plugin-1': true,
18
+ * },
19
+ * 'core/edit-site': {
20
+ * 'plugin-2': true,
21
+ * },
22
+ * },
23
+ * }
24
+ * }
25
+ * }
26
+ * ```
27
+ *
28
+ * and it should be converted it to:
29
+ * ```js
30
+ * {
31
+ * 'core/edit-post': {
32
+ * complementaryArea: 'edit-post/document',
33
+ * pinnedItems: {
34
+ * 'plugin-1': true,
35
+ * },
36
+ * },
37
+ * 'core/edit-site': {
38
+ * complementaryArea: 'edit-site/global-styles',
39
+ * pinnedItems: {
40
+ * 'plugin-2': true,
41
+ * },
42
+ * },
43
+ * }
44
+ * ```
45
+ *
46
+ * @param {Object} state The local storage state.
47
+ */
48
+ export default function moveInterfaceEnableItems( state ) {
49
+ const interfaceStoreName = 'core/interface';
50
+ const preferencesStoreName = 'core/preferences';
51
+ const sourceEnableItems = state?.[ interfaceStoreName ]?.enableItems;
52
+
53
+ // There's nothing to migrate, exit early.
54
+ if ( ! sourceEnableItems ) {
55
+ return state;
56
+ }
57
+
58
+ const allPreferences = state?.[ preferencesStoreName ]?.preferences ?? {};
59
+
60
+ // First convert complementaryAreas into the right format.
61
+ // Use the existing preferences as the accumulator so that the data is
62
+ // merged.
63
+ const sourceComplementaryAreas =
64
+ sourceEnableItems?.singleEnableItems?.complementaryArea ?? {};
65
+
66
+ const preferencesWithConvertedComplementaryAreas = Object.keys(
67
+ sourceComplementaryAreas
68
+ ).reduce( ( accumulator, scope ) => {
69
+ const data = sourceComplementaryAreas[ scope ];
70
+
71
+ // Don't overwrite any existing data in the preferences store.
72
+ if ( accumulator?.[ scope ]?.complementaryArea ) {
73
+ return accumulator;
74
+ }
75
+
76
+ return {
77
+ ...accumulator,
78
+ [ scope ]: {
79
+ ...accumulator[ scope ],
80
+ complementaryArea: data,
81
+ },
82
+ };
83
+ }, allPreferences );
84
+
85
+ // Next feed the converted complementary areas back into a reducer that
86
+ // converts the pinned items, resulting in the fully migrated data.
87
+ const sourcePinnedItems =
88
+ sourceEnableItems?.multipleEnableItems?.pinnedItems ?? {};
89
+ const allConvertedData = Object.keys( sourcePinnedItems ).reduce(
90
+ ( accumulator, scope ) => {
91
+ const data = sourcePinnedItems[ scope ];
92
+ // Don't overwrite any existing data in the preferences store.
93
+ if ( accumulator?.[ scope ]?.pinnedItems ) {
94
+ return accumulator;
95
+ }
96
+
97
+ return {
98
+ ...accumulator,
99
+ [ scope ]: {
100
+ ...accumulator[ scope ],
101
+ pinnedItems: data,
102
+ },
103
+ };
104
+ },
105
+ preferencesWithConvertedComplementaryAreas
106
+ );
107
+
108
+ const otherInterfaceItems = state[ interfaceStoreName ];
109
+
110
+ return {
111
+ ...state,
112
+ [ preferencesStoreName ]: {
113
+ preferences: allConvertedData,
114
+ },
115
+ [ interfaceStoreName ]: {
116
+ ...otherInterfaceItems,
117
+ enableItems: undefined,
118
+ },
119
+ };
120
+ }
@@ -0,0 +1,98 @@
1
+ /**
2
+ * The interface package previously had a public API that could be used by
3
+ * plugins to set persisted boolean 'feature' preferences.
4
+ *
5
+ * While usage was likely non-existent or very small, this function ensures
6
+ * those are migrated to the preferences data structure. The interface
7
+ * package's APIs have now been deprecated and use the preferences store.
8
+ *
9
+ * This will convert data that looks like this:
10
+ * ```js
11
+ * {
12
+ * 'core/interface': {
13
+ * preferences: {
14
+ * features: {
15
+ * 'my-plugin': {
16
+ * myPluginFeature: true
17
+ * }
18
+ * }
19
+ * }
20
+ * }
21
+ * }
22
+ * ```
23
+ *
24
+ * To this:
25
+ * ```js
26
+ * * {
27
+ * 'core/preferences': {
28
+ * preferences: {
29
+ * 'my-plugin': {
30
+ * myPluginFeature: true
31
+ * }
32
+ * }
33
+ * }
34
+ * }
35
+ * ```
36
+ *
37
+ * @param {Object} state The local storage state
38
+ *
39
+ * @return {Object} The state with third party preferences moved to the
40
+ * preferences data structure.
41
+ */
42
+ export default function moveThirdPartyFeaturePreferencesToPreferences( state ) {
43
+ const interfaceStoreName = 'core/interface';
44
+ const preferencesStoreName = 'core/preferences';
45
+
46
+ const interfaceScopes =
47
+ state?.[ interfaceStoreName ]?.preferences?.features;
48
+ const interfaceScopeKeys = interfaceScopes
49
+ ? Object.keys( interfaceScopes )
50
+ : [];
51
+
52
+ if ( ! interfaceScopeKeys?.length ) {
53
+ return state;
54
+ }
55
+
56
+ return interfaceScopeKeys.reduce( function ( convertedState, scope ) {
57
+ if ( scope.startsWith( 'core' ) ) {
58
+ return convertedState;
59
+ }
60
+
61
+ const featuresToMigrate = interfaceScopes?.[ scope ];
62
+ if ( ! featuresToMigrate ) {
63
+ return convertedState;
64
+ }
65
+
66
+ const existingMigratedData =
67
+ convertedState?.[ preferencesStoreName ]?.preferences?.[ scope ];
68
+
69
+ if ( existingMigratedData ) {
70
+ return convertedState;
71
+ }
72
+
73
+ const otherPreferencesScopes =
74
+ convertedState?.[ preferencesStoreName ]?.preferences;
75
+ const otherInterfaceState = convertedState?.[ interfaceStoreName ];
76
+ const otherInterfaceScopes =
77
+ convertedState?.[ interfaceStoreName ]?.preferences?.features;
78
+
79
+ return {
80
+ ...convertedState,
81
+ [ preferencesStoreName ]: {
82
+ preferences: {
83
+ ...otherPreferencesScopes,
84
+ [ scope ]: featuresToMigrate,
85
+ },
86
+ },
87
+ [ interfaceStoreName ]: {
88
+ ...otherInterfaceState,
89
+ preferences: {
90
+ features: {
91
+ ...otherInterfaceScopes,
92
+ [ scope ]: undefined,
93
+ },
94
+ },
95
+ },
96
+ };
97
+ }, state );
98
+ }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import convertEditPostPanels from '../convert-edit-post-panels';
5
+
6
+ describe( 'convertEditPostPanels', () => {
7
+ it( 'converts from one format to another', () => {
8
+ expect(
9
+ convertEditPostPanels( {
10
+ panels: {
11
+ tags: {
12
+ enabled: true,
13
+ opened: true,
14
+ },
15
+ permalinks: {
16
+ enabled: false,
17
+ opened: false,
18
+ },
19
+ categories: {
20
+ enabled: true,
21
+ opened: false,
22
+ },
23
+ excerpt: {
24
+ enabled: false,
25
+ opened: true,
26
+ },
27
+ discussion: {
28
+ enabled: false,
29
+ },
30
+ template: {
31
+ opened: true,
32
+ },
33
+ },
34
+ } )
35
+ ).toEqual( {
36
+ inactivePanels: [ 'permalinks', 'excerpt', 'discussion' ],
37
+ openPanels: [ 'tags', 'excerpt', 'template' ],
38
+ } );
39
+ } );
40
+
41
+ it( 'returns empty arrays when there is no data to convert', () => {
42
+ expect( convertEditPostPanels( {} ) ).toEqual( {
43
+ inactivePanels: [],
44
+ openPanels: [],
45
+ } );
46
+ } );
47
+ } );
@@ -0,0 +1,229 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import { convertLegacyData } from '..';
5
+
6
+ const legacyData = {
7
+ 'core/interface': {
8
+ enableItems: {
9
+ singleEnableItems: {
10
+ complementaryArea: {
11
+ 'core/edit-post': 'edit-post/document',
12
+ 'core/edit-site': 'edit-site/global-styles',
13
+ 'core/edit-widgets': 'edit-widgets/block-areas',
14
+ },
15
+ },
16
+ multipleEnableItems: {
17
+ pinnedItems: {
18
+ 'core/edit-post': {
19
+ 'my-sidebar-plugin/title-sidebar': false,
20
+ },
21
+ },
22
+ },
23
+ },
24
+ preferences: {
25
+ features: {
26
+ 'core/edit-post': { welcomeGuide: false, fixedToolbar: true },
27
+ 'core/edit-widgets': {
28
+ welcomeGuide: false,
29
+ fixedToolbar: true,
30
+ keepCaretInsideBlock: true,
31
+ },
32
+ 'core/customize-widgets': {
33
+ welcomeGuide: false,
34
+ fixedToolbar: true,
35
+ keepCaretInsideBlock: true,
36
+ },
37
+ 'third-party-plugin': {
38
+ thirdPartyFeature: true,
39
+ },
40
+ },
41
+ },
42
+ },
43
+ 'core/edit-post': {
44
+ preferences: {
45
+ panels: {
46
+ 'post-status': { opened: true },
47
+ 'post-excerpt': { enabled: false },
48
+ 'taxonomy-panel-category': { opened: true },
49
+ },
50
+ editorMode: 'text',
51
+ hiddenBlockTypes: [ 'core/heading', 'core/list' ],
52
+ preferredStyleVariations: { 'core/quote': 'plain' },
53
+ localAutosaveInterval: 15,
54
+ },
55
+ },
56
+ 'core/edit-site': {
57
+ preferences: {
58
+ features: {
59
+ welcomeGuide: false,
60
+ welcomeGuideStyles: false,
61
+ fixedToolbar: true,
62
+ focusMode: true,
63
+ },
64
+ },
65
+ },
66
+ };
67
+
68
+ const alreadyConvertedData = {
69
+ 'core/block-editor': {
70
+ preferences: {
71
+ insertUsage: {
72
+ 'core/paragraph': {
73
+ time: 1649320988011,
74
+ count: 2,
75
+ insert: {
76
+ name: 'core/paragraph',
77
+ },
78
+ },
79
+ 'core/quote': {
80
+ time: 1649320934860,
81
+ count: 1,
82
+ insert: {
83
+ name: 'core/quote',
84
+ },
85
+ },
86
+ 'core/image': {
87
+ time: 1649321017053,
88
+ count: 1,
89
+ insert: {
90
+ name: 'core/image',
91
+ },
92
+ },
93
+ 'core/group': {
94
+ time: 1649321017077,
95
+ count: 1,
96
+ insert: {
97
+ name: 'core/group',
98
+ },
99
+ },
100
+ },
101
+ },
102
+ },
103
+ 'core/preferences': {
104
+ preferences: {
105
+ 'core/edit-widgets': {
106
+ welcomeGuide: false,
107
+ fixedToolbar: true,
108
+ showBlockBreadcrumbs: false,
109
+ complementaryArea: 'edit-widgets/block-areas',
110
+ },
111
+ 'core/edit-post': {
112
+ welcomeGuide: false,
113
+ fixedToolbar: true,
114
+ fullscreenMode: false,
115
+ hiddenBlockTypes: [ 'core/audio', 'core/cover' ],
116
+ editorMode: 'visual',
117
+ preferredStyleVariations: {
118
+ 'core/quote': 'large',
119
+ },
120
+ inactivePanels: [],
121
+ openPanels: [ 'post-status' ],
122
+ complementaryArea: 'edit-post/block',
123
+ pinnedItems: {
124
+ 'my-sidebar-plugin/title-sidebar': false,
125
+ },
126
+ },
127
+ 'core/edit-site': {
128
+ welcomeGuide: false,
129
+ welcomeGuideStyles: false,
130
+ fixedToolbar: true,
131
+ complementaryArea: 'edit-site/global-styles',
132
+ },
133
+ },
134
+ },
135
+ };
136
+
137
+ describe( 'convertLegacyData', () => {
138
+ it( 'converts to the expected format', () => {
139
+ expect( convertLegacyData( legacyData ) ).toMatchInlineSnapshot( `
140
+ Object {
141
+ "core/customize-widgets": Object {
142
+ "fixedToolbar": true,
143
+ "keepCaretInsideBlock": true,
144
+ "welcomeGuide": false,
145
+ },
146
+ "core/edit-post": Object {
147
+ "complementaryArea": "edit-post/document",
148
+ "editorMode": "text",
149
+ "fixedToolbar": true,
150
+ "hiddenBlockTypes": Array [
151
+ "core/heading",
152
+ "core/list",
153
+ ],
154
+ "inactivePanels": Array [
155
+ "post-excerpt",
156
+ ],
157
+ "openPanels": Array [
158
+ "post-status",
159
+ "taxonomy-panel-category",
160
+ ],
161
+ "pinnedItems": Object {
162
+ "my-sidebar-plugin/title-sidebar": false,
163
+ },
164
+ "preferredStyleVariations": Object {
165
+ "core/quote": "plain",
166
+ },
167
+ "welcomeGuide": false,
168
+ },
169
+ "core/edit-site": Object {
170
+ "complementaryArea": "edit-site/global-styles",
171
+ "fixedToolbar": true,
172
+ "focusMode": true,
173
+ "welcomeGuide": false,
174
+ "welcomeGuideStyles": false,
175
+ },
176
+ "core/edit-widgets": Object {
177
+ "complementaryArea": "edit-widgets/block-areas",
178
+ "fixedToolbar": true,
179
+ "keepCaretInsideBlock": true,
180
+ "welcomeGuide": false,
181
+ },
182
+ "third-party-plugin": Object {
183
+ "thirdPartyFeature": true,
184
+ },
185
+ }
186
+ ` );
187
+ } );
188
+
189
+ it( 'retains already converted data', () => {
190
+ expect( convertLegacyData( alreadyConvertedData ) )
191
+ .toMatchInlineSnapshot( `
192
+ Object {
193
+ "core/edit-post": Object {
194
+ "complementaryArea": "edit-post/block",
195
+ "editorMode": "visual",
196
+ "fixedToolbar": true,
197
+ "fullscreenMode": false,
198
+ "hiddenBlockTypes": Array [
199
+ "core/audio",
200
+ "core/cover",
201
+ ],
202
+ "inactivePanels": Array [],
203
+ "openPanels": Array [
204
+ "post-status",
205
+ ],
206
+ "pinnedItems": Object {
207
+ "my-sidebar-plugin/title-sidebar": false,
208
+ },
209
+ "preferredStyleVariations": Object {
210
+ "core/quote": "large",
211
+ },
212
+ "welcomeGuide": false,
213
+ },
214
+ "core/edit-site": Object {
215
+ "complementaryArea": "edit-site/global-styles",
216
+ "fixedToolbar": true,
217
+ "welcomeGuide": false,
218
+ "welcomeGuideStyles": false,
219
+ },
220
+ "core/edit-widgets": Object {
221
+ "complementaryArea": "edit-widgets/block-areas",
222
+ "fixedToolbar": true,
223
+ "showBlockBreadcrumbs": false,
224
+ "welcomeGuide": false,
225
+ },
226
+ }
227
+ ` );
228
+ } );
229
+ } );