Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Font Library: fixes installed font families not rendering in the editor or frontend. #59019

Merged
merged 15 commits into from
Feb 14, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
improving fontFontFamily and add formatFontFaceName functions to ensu…
…re that CSS properties are valid
  • Loading branch information
matiasbenedetto committed Feb 14, 2024
commit 16899544ab451c3d51fd0c42257e935a65b6d92a
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { privateApis as componentsPrivateApis } from '@wordpress/components';
import { FONT_WEIGHTS, FONT_STYLES } from './constants';
import { unlock } from '../../../../lock-unlock';
import { fetchInstallFontFace } from '../resolvers';
import { formatFontFamily } from './preview-styles';
import { formatFontFaceName } from './preview-styles';

/**
* Browser dependencies
Expand Down Expand Up @@ -99,7 +99,7 @@ export async function loadFontFaceInBrowser( fontFace, source, addTo = 'all' ) {
}

const newFont = new window.FontFace(
formatFontFamily( fontFace.fontFamily ),
formatFontFaceName( fontFace.fontFamily ),
dataSource,
{
style: fontFace.fontStyle,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,76 @@ function extractFontWeights( fontFaces ) {
return result;
}

/*
* Format the font family to use in the CSS font-family property of a CSS rule.
*
* The input can be a string with the font family name or a string with multiple font family names separated by commas.
* It follows the recommendations from the CSS Fonts Module Level 4.
* https://www.w3.org/TR/css-fonts-4/#font-family-prop
*
* @param {string} input - The font family.
* @return {string} The formatted font family.
*
* Example:
* formatFontFamily( "Open Sans, Font+Name, sans-serif" ) => '"Open Sans", "Font+Name", sans-serif'
* formatFontFamily( "'Open Sans', sans-serif" ) => '"Open Sans", sans-serif'
* formatFontFamily( "DotGothic16, Slabo 27px, serif" ) => '"DotGothic16","Slabo 27px",serif'
* formatFontFamily( "Mine's, Moe's Typography" ) => `"mine's","Moe's Typography"`
*/
export function formatFontFamily( input ) {
return input
.split( ',' )
.map( ( font ) => {
font = font.trim(); // Remove any leading or trailing white spaces
// If the font doesn't start with quotes and contains a space, then wrap in quotes.
// Check that string starts with a single or double quote and not a space
if (
! ( font.startsWith( '"' ) || font.startsWith( "'" ) ) &&
font.indexOf( ' ' ) !== -1
) {
return `"${ font }"`;
}
return font; // Return font as is if no transformation is needed
} )
.join( ', ' );
// Matchs any non alphabetic characters (a-zA-Z), dashes - , or parenthesis ()
const regex = /[^a-zA-Z\-()]+/;
const output = input.trim();

const formatItem = ( item ) => {
item = item.trim();
if ( item.match( regex ) ) {
// removes leading and trailing quotes.
item = item.replace( /^["']|["']$/g, '' );
return `"${ item }"`;
}
return item;
};

if ( output.includes( ',' ) ) {
return output
.split( ',' )
.map( formatItem )
.filter( ( item ) => item !== '' )
.join( ', ' );
}

return formatItem( output );
}

/*
* Format the font face name to use in the font-family property of a font face.
*
* The input can be a string with the font face name or a string with multiple font face names separated by commas.
* It removes the leading and trailing quotes from the font face name.
*
* @param {string} input - The font face name.
* @return {string} The formatted font face name.
*
* Example:
* formatFontFaceName("Open Sans") => "Open Sans"
* formatFontFaceName("'Open Sans', sans-serif") => "Open Sans"
* formatFontFaceName("'Open Sans', 'Helvetica Neue', sans-serif") => "Open Sans"
*/
export function formatFontFaceName( input ) {
const output = input.trim();
if ( output.includes( ',' ) ) {
return (
output
.split( ',' )
.find( ( item ) => item.trim() !== '' )
.trim()
// removes leading and trailing quotes.
.replace( /^["']|["']$/g, '' )
);
}
// removes leading and trailing quotes.
return output.replace( /^["']|["']$/g, '' );
}

export function getFamilyPreviewStyle( family ) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
/**
* Internal dependencies
*/
import { getFamilyPreviewStyle, formatFontFamily } from '../preview-styles';
import {
getFamilyPreviewStyle,
formatFontFamily,
formatFontFaceName,
} from '../preview-styles';

describe( 'getFamilyPreviewStyle', () => {
it( 'should return default fontStyle and fontWeight if fontFace is not provided', () => {
Expand Down Expand Up @@ -139,7 +143,7 @@ describe( 'formatFontFamily', () => {
"Seravek, 'Gill Sans Nova', Ubuntu, Calibri, 'DejaVu Sans', source-sans-pro, sans-serif"
)
).toBe(
"Seravek, 'Gill Sans Nova', Ubuntu, Calibri, 'DejaVu Sans', source-sans-pro, sans-serif"
'Seravek, "Gill Sans Nova", Ubuntu, Calibri, "DejaVu Sans", source-sans-pro, sans-serif'
);
} );

Expand All @@ -153,9 +157,37 @@ describe( 'formatFontFamily', () => {
);
} );

it( 'should wrap only those font names with spaces which are not already quoted', () => {
expect( formatFontFamily( 'Baloo Bhai 2, Arial' ) ).toBe(
'"Baloo Bhai 2", Arial'
it( 'should wrap names with special characters in quotes', () => {
expect(
formatFontFamily(
'Font+Name, Font*Name, _Font_Name_, generic(kai), sans-serif'
)
).toBe(
'"Font+Name", "Font*Name", "_Font_Name_", generic(kai), sans-serif'
);
} );

it( 'should fix empty wrong formatted font family', () => {
expect( formatFontFamily( ', Abril Fatface,Times,serif' ) ).toBe(
'"Abril Fatface", Times, serif'
);
} );
} );

describe( 'formatFontFaceName', () => {
it( 'should remove leading and trailing quotes', () => {
expect( formatFontFaceName( '"Open Sans"' ) ).toBe( 'Open Sans' );
} );

it( 'should remove leading and trailing quotes from multiple font face names', () => {
expect(
formatFontFaceName( "'Open Sans', 'Helvetica Neue', sans-serif" )
).toBe( 'Open Sans' );
} );

it( 'should remove leading and trailing quotes even from names with spaces and special characters', () => {
expect( formatFontFaceName( "'Font+Name 24', sans-serif" ) ).toBe(
'Font+Name 24'
);
} );
} );
Loading