Skip to content

Commit

Permalink
improving fontFontFamily and add formatFontFaceName functions to ensu…
Browse files Browse the repository at this point in the history
…re that CSS properties are valid
  • Loading branch information
matiasbenedetto committed Feb 14, 2024
1 parent b1d335d commit 1689954
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 22 deletions.
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'
);
} );
} );

0 comments on commit 1689954

Please sign in to comment.