@wordpress/edit-site 5.28.8 → 5.28.10
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/build/components/global-styles/font-library-modal/context.js +80 -23
- package/build/components/global-styles/font-library-modal/context.js.map +1 -1
- package/build/components/global-styles/font-library-modal/font-collection.js +1 -0
- package/build/components/global-styles/font-library-modal/font-collection.js.map +1 -1
- package/build/components/global-styles/font-library-modal/index.js +1 -1
- package/build/components/global-styles/font-library-modal/index.js.map +1 -1
- package/build/components/global-styles/font-library-modal/installed-fonts.js +5 -2
- package/build/components/global-styles/font-library-modal/installed-fonts.js.map +1 -1
- package/build/components/global-styles/font-library-modal/utils/index.js +20 -2
- package/build/components/global-styles/font-library-modal/utils/index.js.map +1 -1
- package/build/hooks/push-changes-to-global-styles/index.js +4 -40
- package/build/hooks/push-changes-to-global-styles/index.js.map +1 -1
- package/build/utils/set-nested-value.js +44 -0
- package/build/utils/set-nested-value.js.map +1 -0
- package/build-module/components/global-styles/font-library-modal/context.js +79 -23
- package/build-module/components/global-styles/font-library-modal/context.js.map +1 -1
- package/build-module/components/global-styles/font-library-modal/font-collection.js +1 -0
- package/build-module/components/global-styles/font-library-modal/font-collection.js.map +1 -1
- package/build-module/components/global-styles/font-library-modal/index.js +2 -2
- package/build-module/components/global-styles/font-library-modal/index.js.map +1 -1
- package/build-module/components/global-styles/font-library-modal/installed-fonts.js +5 -2
- package/build-module/components/global-styles/font-library-modal/installed-fonts.js.map +1 -1
- package/build-module/components/global-styles/font-library-modal/utils/index.js +20 -2
- package/build-module/components/global-styles/font-library-modal/utils/index.js.map +1 -1
- package/build-module/hooks/push-changes-to-global-styles/index.js +1 -38
- package/build-module/hooks/push-changes-to-global-styles/index.js.map +1 -1
- package/build-module/utils/set-nested-value.js +38 -0
- package/build-module/utils/set-nested-value.js.map +1 -0
- package/package.json +16 -16
- package/src/components/global-styles/font-library-modal/context.js +95 -41
- package/src/components/global-styles/font-library-modal/font-collection.js +1 -0
- package/src/components/global-styles/font-library-modal/index.js +2 -2
- package/src/components/global-styles/font-library-modal/installed-fonts.js +4 -1
- package/src/components/global-styles/font-library-modal/utils/index.js +17 -4
- package/src/hooks/push-changes-to-global-styles/index.js +1 -40
- package/src/utils/set-nested-value.js +39 -0
|
@@ -35,12 +35,12 @@ import {
|
|
|
35
35
|
checkFontFaceInstalled,
|
|
36
36
|
} from './utils';
|
|
37
37
|
import { toggleFont } from './utils/toggleFont';
|
|
38
|
+
import setNestedValue from '../../../utils/set-nested-value';
|
|
38
39
|
|
|
39
40
|
export const FontLibraryContext = createContext( {} );
|
|
40
41
|
|
|
41
42
|
function FontLibraryProvider( { children } ) {
|
|
42
|
-
const {
|
|
43
|
-
useDispatch( coreStore );
|
|
43
|
+
const { saveEntityRecord } = useDispatch( coreStore );
|
|
44
44
|
const { globalStylesId } = useSelect( ( select ) => {
|
|
45
45
|
const { __experimentalGetCurrentGlobalStylesId } = select( coreStore );
|
|
46
46
|
return { globalStylesId: __experimentalGetCurrentGlobalStylesId() };
|
|
@@ -94,29 +94,61 @@ function FontLibraryProvider( { children } ) {
|
|
|
94
94
|
'base'
|
|
95
95
|
);
|
|
96
96
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
97
|
+
/*
|
|
98
|
+
* Save the font families to the database.
|
|
99
|
+
|
|
100
|
+
* This function is called when the user activates or deactivates a font family.
|
|
101
|
+
* It only updates the global styles post content in the database for new font families.
|
|
102
|
+
* This avoids saving other styles/settings changed by the user using other parts of the editor.
|
|
103
|
+
*
|
|
104
|
+
* It uses the font families from the param to avoid using the font families from an outdated state.
|
|
105
|
+
*
|
|
106
|
+
* @param {Array} fonts - The font families that will be saved to the database.
|
|
107
|
+
*/
|
|
108
|
+
const saveFontFamilies = async ( fonts ) => {
|
|
109
|
+
// Gets the global styles database post content.
|
|
110
|
+
const updatedGlobalStyles = globalStyles.record;
|
|
111
|
+
|
|
112
|
+
// Updates the database version of global styles with the edited font families in the client.
|
|
113
|
+
setNestedValue(
|
|
114
|
+
updatedGlobalStyles,
|
|
115
|
+
[ 'settings', 'typography', 'fontFamilies' ],
|
|
116
|
+
fonts
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
// Saves a new version of the global styles in the database.
|
|
120
|
+
await saveEntityRecord( 'root', 'globalStyles', updatedGlobalStyles );
|
|
102
121
|
};
|
|
103
122
|
|
|
104
123
|
// Library Fonts
|
|
105
124
|
const [ modalTabOpen, setModalTabOpen ] = useState( false );
|
|
106
125
|
const [ libraryFontSelected, setLibraryFontSelected ] = useState( null );
|
|
107
126
|
|
|
108
|
-
|
|
109
|
-
? baseFontFamilies.theme
|
|
110
|
-
.map( ( f ) => setUIValuesNeeded( f, { source: 'theme' } ) )
|
|
111
|
-
.sort( ( a, b ) => a.name.localeCompare( b.name ) )
|
|
112
|
-
: [];
|
|
113
|
-
|
|
127
|
+
// Themes Fonts are the fonts defined in the global styles (database persisted theme.json data).
|
|
114
128
|
const themeFonts = fontFamilies?.theme
|
|
115
129
|
? fontFamilies.theme
|
|
116
130
|
.map( ( f ) => setUIValuesNeeded( f, { source: 'theme' } ) )
|
|
117
131
|
.sort( ( a, b ) => a.name.localeCompare( b.name ) )
|
|
118
132
|
: [];
|
|
119
133
|
|
|
134
|
+
const themeFontsSlugs = new Set( themeFonts.map( ( f ) => f.slug ) );
|
|
135
|
+
|
|
136
|
+
/*
|
|
137
|
+
* Base Theme Fonts are the fonts defined in the theme.json *file*.
|
|
138
|
+
*
|
|
139
|
+
* Uses the fonts from global styles + the ones from the theme.json file that hasn't repeated slugs.
|
|
140
|
+
* Avoids incosistencies with the fonts listed in the font library modal as base (unactivated).
|
|
141
|
+
* These inconsistencies can happen when the active theme fonts in global styles aren't defined in theme.json file as when a theme style variation is applied.
|
|
142
|
+
*/
|
|
143
|
+
const baseThemeFonts = baseFontFamilies?.theme
|
|
144
|
+
? themeFonts.concat(
|
|
145
|
+
baseFontFamilies.theme
|
|
146
|
+
.filter( ( f ) => ! themeFontsSlugs.has( f.slug ) )
|
|
147
|
+
.map( ( f ) => setUIValuesNeeded( f, { source: 'theme' } ) )
|
|
148
|
+
.sort( ( a, b ) => a.name.localeCompare( b.name ) )
|
|
149
|
+
)
|
|
150
|
+
: [];
|
|
151
|
+
|
|
120
152
|
const customFonts = fontFamilies?.custom
|
|
121
153
|
? fontFamilies.custom
|
|
122
154
|
.map( ( f ) => setUIValuesNeeded( f, { source: 'custom' } ) )
|
|
@@ -144,8 +176,7 @@ function FontLibraryProvider( { children } ) {
|
|
|
144
176
|
return;
|
|
145
177
|
}
|
|
146
178
|
|
|
147
|
-
const fonts =
|
|
148
|
-
font.source === 'theme' ? baseThemeFonts : baseCustomFonts;
|
|
179
|
+
const fonts = font.source === 'theme' ? themeFonts : baseCustomFonts;
|
|
149
180
|
|
|
150
181
|
// Tries to find the font in the installed fonts
|
|
151
182
|
const fontSelected = fonts.find( ( f ) => f.slug === font.slug );
|
|
@@ -269,11 +300,13 @@ function FontLibraryProvider( { children } ) {
|
|
|
269
300
|
sucessfullyInstalledFontFaces?.length > 0 ||
|
|
270
301
|
alreadyInstalledFontFaces?.length > 0
|
|
271
302
|
) {
|
|
272
|
-
|
|
303
|
+
// Use font data from REST API not from client to ensure
|
|
304
|
+
// correct font information is used.
|
|
305
|
+
installedFontFamily.fontFace = [
|
|
273
306
|
...sucessfullyInstalledFontFaces,
|
|
274
|
-
...alreadyInstalledFontFaces,
|
|
275
307
|
];
|
|
276
|
-
|
|
308
|
+
|
|
309
|
+
fontFamiliesToActivate.push( installedFontFamily );
|
|
277
310
|
}
|
|
278
311
|
|
|
279
312
|
// If it's a system font but was installed successfully, activate it.
|
|
@@ -308,15 +341,11 @@ function FontLibraryProvider( { children } ) {
|
|
|
308
341
|
|
|
309
342
|
if ( fontFamiliesToActivate.length > 0 ) {
|
|
310
343
|
// Activate the font family (add the font family to the global styles).
|
|
311
|
-
activateCustomFontFamilies(
|
|
312
|
-
|
|
313
|
-
// Save the global styles to the database.
|
|
314
|
-
await saveSpecifiedEntityEdits(
|
|
315
|
-
'root',
|
|
316
|
-
'globalStyles',
|
|
317
|
-
globalStylesId,
|
|
318
|
-
[ 'settings.typography.fontFamilies' ]
|
|
344
|
+
const activeFonts = activateCustomFontFamilies(
|
|
345
|
+
fontFamiliesToActivate
|
|
319
346
|
);
|
|
347
|
+
// Save the global styles to the database.
|
|
348
|
+
await saveFontFamilies( activeFonts );
|
|
320
349
|
|
|
321
350
|
refreshLibrary();
|
|
322
351
|
}
|
|
@@ -346,14 +375,11 @@ function FontLibraryProvider( { children } ) {
|
|
|
346
375
|
// Deactivate the font family if delete request is successful
|
|
347
376
|
// (Removes the font family from the global styles).
|
|
348
377
|
if ( uninstalledFontFamily.deleted ) {
|
|
349
|
-
deactivateFontFamily(
|
|
350
|
-
|
|
351
|
-
await saveSpecifiedEntityEdits(
|
|
352
|
-
'root',
|
|
353
|
-
'globalStyles',
|
|
354
|
-
globalStylesId,
|
|
355
|
-
[ 'settings.typography.fontFamilies' ]
|
|
378
|
+
const activeFonts = deactivateFontFamily(
|
|
379
|
+
fontFamilyToUninstall
|
|
356
380
|
);
|
|
381
|
+
// Save the global styles to the database.
|
|
382
|
+
await saveFontFamilies( activeFonts );
|
|
357
383
|
}
|
|
358
384
|
|
|
359
385
|
// Refresh the library (the library font families from database).
|
|
@@ -377,27 +403,54 @@ function FontLibraryProvider( { children } ) {
|
|
|
377
403
|
const newCustomFonts = initialCustomFonts.filter(
|
|
378
404
|
( f ) => f.slug !== font.slug
|
|
379
405
|
);
|
|
380
|
-
|
|
406
|
+
const activeFonts = {
|
|
381
407
|
...fontFamilies,
|
|
382
408
|
[ font.source ]: newCustomFonts,
|
|
383
|
-
}
|
|
409
|
+
};
|
|
410
|
+
setFontFamilies( activeFonts );
|
|
384
411
|
|
|
385
412
|
if ( font.fontFace ) {
|
|
386
413
|
font.fontFace.forEach( ( face ) => {
|
|
387
414
|
unloadFontFaceInBrowser( face, 'all' );
|
|
388
415
|
} );
|
|
389
416
|
}
|
|
417
|
+
return activeFonts;
|
|
390
418
|
};
|
|
391
419
|
|
|
392
420
|
const activateCustomFontFamilies = ( fontsToAdd ) => {
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
421
|
+
const fontsToActivate = cleanFontsForSave( fontsToAdd );
|
|
422
|
+
|
|
423
|
+
const activeFonts = {
|
|
396
424
|
...fontFamilies,
|
|
397
|
-
|
|
398
|
-
|
|
425
|
+
// Merge the existing custom fonts with the new fonts.
|
|
426
|
+
custom: mergeFontFamilies( fontFamilies?.custom, fontsToActivate ),
|
|
427
|
+
};
|
|
428
|
+
|
|
429
|
+
// Activate the fonts by set the new custom fonts array.
|
|
430
|
+
setFontFamilies( activeFonts );
|
|
431
|
+
|
|
432
|
+
loadFontsInBrowser( fontsToActivate );
|
|
433
|
+
|
|
434
|
+
return activeFonts;
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
// Removes the id from the families and faces to avoid saving that to global styles post content.
|
|
438
|
+
const cleanFontsForSave = ( fonts ) => {
|
|
439
|
+
return fonts.map( ( { id: _familyDbId, fontFace, ...font } ) => ( {
|
|
440
|
+
...font,
|
|
441
|
+
...( fontFace && fontFace.length > 0
|
|
442
|
+
? {
|
|
443
|
+
fontFace: fontFace.map(
|
|
444
|
+
( { id: _faceDbId, ...face } ) => face
|
|
445
|
+
),
|
|
446
|
+
}
|
|
447
|
+
: {} ),
|
|
448
|
+
} ) );
|
|
449
|
+
};
|
|
450
|
+
|
|
451
|
+
const loadFontsInBrowser = ( fonts ) => {
|
|
399
452
|
// Add custom fonts to the browser.
|
|
400
|
-
|
|
453
|
+
fonts.forEach( ( font ) => {
|
|
401
454
|
if ( font.fontFace ) {
|
|
402
455
|
font.fontFace.forEach( ( face ) => {
|
|
403
456
|
// Load font faces just in the iframe because they already are in the document.
|
|
@@ -489,6 +542,7 @@ function FontLibraryProvider( { children } ) {
|
|
|
489
542
|
value={ {
|
|
490
543
|
libraryFontSelected,
|
|
491
544
|
handleSetLibraryFontSelected,
|
|
545
|
+
fontFamilies,
|
|
492
546
|
themeFonts,
|
|
493
547
|
baseThemeFonts,
|
|
494
548
|
customFonts,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* WordPress dependencies
|
|
3
3
|
*/
|
|
4
|
-
import { __ } from '@wordpress/i18n';
|
|
4
|
+
import { __, _x } from '@wordpress/i18n';
|
|
5
5
|
import {
|
|
6
6
|
Modal,
|
|
7
7
|
privateApis as componentsPrivateApis,
|
|
@@ -23,7 +23,7 @@ const { Tabs } = unlock( componentsPrivateApis );
|
|
|
23
23
|
|
|
24
24
|
const DEFAULT_TAB = {
|
|
25
25
|
id: 'installed-fonts',
|
|
26
|
-
title:
|
|
26
|
+
title: _x( 'Library', 'Font library' ),
|
|
27
27
|
};
|
|
28
28
|
|
|
29
29
|
const UPLOAD_TAB = {
|
|
@@ -49,6 +49,7 @@ function InstalledFonts() {
|
|
|
49
49
|
fontFamiliesHasChanges,
|
|
50
50
|
notice,
|
|
51
51
|
setNotice,
|
|
52
|
+
fontFamilies,
|
|
52
53
|
} = useContext( FontLibraryContext );
|
|
53
54
|
const [ isConfirmDeleteOpen, setIsConfirmDeleteOpen ] = useState( false );
|
|
54
55
|
const customFontFamilyId =
|
|
@@ -262,7 +263,9 @@ function InstalledFonts() {
|
|
|
262
263
|
) }
|
|
263
264
|
<Button
|
|
264
265
|
variant="primary"
|
|
265
|
-
onClick={
|
|
266
|
+
onClick={ () => {
|
|
267
|
+
saveFontFamilies( fontFamilies );
|
|
268
|
+
} }
|
|
266
269
|
disabled={ ! fontFamiliesHasChanges }
|
|
267
270
|
__experimentalIsFocusable
|
|
268
271
|
>
|
|
@@ -234,10 +234,23 @@ export function makeFontFacesFormData( font ) {
|
|
|
234
234
|
}
|
|
235
235
|
|
|
236
236
|
export async function batchInstallFontFaces( fontFamilyId, fontFacesData ) {
|
|
237
|
-
const
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
237
|
+
const responses = [];
|
|
238
|
+
|
|
239
|
+
/*
|
|
240
|
+
* Uses the same response format as Promise.allSettled, but executes requests in sequence to work
|
|
241
|
+
* around a race condition that can cause an error when the fonts directory doesn't exist yet.
|
|
242
|
+
*/
|
|
243
|
+
for ( const faceData of fontFacesData ) {
|
|
244
|
+
try {
|
|
245
|
+
const response = await fetchInstallFontFace(
|
|
246
|
+
fontFamilyId,
|
|
247
|
+
faceData
|
|
248
|
+
);
|
|
249
|
+
responses.push( { status: 'fulfilled', value: response } );
|
|
250
|
+
} catch ( error ) {
|
|
251
|
+
responses.push( { status: 'rejected', reason: error } );
|
|
252
|
+
}
|
|
253
|
+
}
|
|
241
254
|
|
|
242
255
|
const results = {
|
|
243
256
|
errors: [],
|
|
@@ -26,6 +26,7 @@ import { store as coreStore } from '@wordpress/core-data';
|
|
|
26
26
|
*/
|
|
27
27
|
import { useSupportedStyles } from '../../components/global-styles/hooks';
|
|
28
28
|
import { unlock } from '../../lock-unlock';
|
|
29
|
+
import setNestedValue from '../../utils/set-nested-value';
|
|
29
30
|
|
|
30
31
|
const { cleanEmptyObject, GlobalStylesContext } = unlock(
|
|
31
32
|
blockEditorPrivateApis
|
|
@@ -235,46 +236,6 @@ function useChangesToPush( name, attributes, userConfig ) {
|
|
|
235
236
|
}, [ supports, attributes, blockUserConfig ] );
|
|
236
237
|
}
|
|
237
238
|
|
|
238
|
-
/**
|
|
239
|
-
* Sets the value at path of object.
|
|
240
|
-
* If a portion of path doesn’t exist, it’s created.
|
|
241
|
-
* Arrays are created for missing index properties while objects are created
|
|
242
|
-
* for all other missing properties.
|
|
243
|
-
*
|
|
244
|
-
* This function intentionally mutates the input object.
|
|
245
|
-
*
|
|
246
|
-
* Inspired by _.set().
|
|
247
|
-
*
|
|
248
|
-
* @see https://lodash.com/docs/4.17.15#set
|
|
249
|
-
*
|
|
250
|
-
* @todo Needs to be deduplicated with its copy in `@wordpress/core-data`.
|
|
251
|
-
*
|
|
252
|
-
* @param {Object} object Object to modify
|
|
253
|
-
* @param {Array} path Path of the property to set.
|
|
254
|
-
* @param {*} value Value to set.
|
|
255
|
-
*/
|
|
256
|
-
function setNestedValue( object, path, value ) {
|
|
257
|
-
if ( ! object || typeof object !== 'object' ) {
|
|
258
|
-
return object;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
path.reduce( ( acc, key, idx ) => {
|
|
262
|
-
if ( acc[ key ] === undefined ) {
|
|
263
|
-
if ( Number.isInteger( path[ idx + 1 ] ) ) {
|
|
264
|
-
acc[ key ] = [];
|
|
265
|
-
} else {
|
|
266
|
-
acc[ key ] = {};
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
if ( idx === path.length - 1 ) {
|
|
270
|
-
acc[ key ] = value;
|
|
271
|
-
}
|
|
272
|
-
return acc[ key ];
|
|
273
|
-
}, object );
|
|
274
|
-
|
|
275
|
-
return object;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
239
|
function cloneDeep( object ) {
|
|
279
240
|
return ! object ? {} : JSON.parse( JSON.stringify( object ) );
|
|
280
241
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sets the value at path of object.
|
|
3
|
+
* If a portion of path doesn’t exist, it’s created.
|
|
4
|
+
* Arrays are created for missing index properties while objects are created
|
|
5
|
+
* for all other missing properties.
|
|
6
|
+
*
|
|
7
|
+
* This function intentionally mutates the input object.
|
|
8
|
+
*
|
|
9
|
+
* Inspired by _.set().
|
|
10
|
+
*
|
|
11
|
+
* @see https://lodash.com/docs/4.17.15#set
|
|
12
|
+
*
|
|
13
|
+
* @todo Needs to be deduplicated with its copy in `@wordpress/core-data`.
|
|
14
|
+
*
|
|
15
|
+
* @param {Object} object Object to modify
|
|
16
|
+
* @param {Array} path Path of the property to set.
|
|
17
|
+
* @param {*} value Value to set.
|
|
18
|
+
*/
|
|
19
|
+
export default function setNestedValue( object, path, value ) {
|
|
20
|
+
if ( ! object || typeof object !== 'object' ) {
|
|
21
|
+
return object;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
path.reduce( ( acc, key, idx ) => {
|
|
25
|
+
if ( acc[ key ] === undefined ) {
|
|
26
|
+
if ( Number.isInteger( path[ idx + 1 ] ) ) {
|
|
27
|
+
acc[ key ] = [];
|
|
28
|
+
} else {
|
|
29
|
+
acc[ key ] = {};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if ( idx === path.length - 1 ) {
|
|
33
|
+
acc[ key ] = value;
|
|
34
|
+
}
|
|
35
|
+
return acc[ key ];
|
|
36
|
+
}, object );
|
|
37
|
+
|
|
38
|
+
return object;
|
|
39
|
+
}
|