Skip to content

Commit

Permalink
refactor: font feature (#1061)
Browse files Browse the repository at this point in the history
  • Loading branch information
jadutter committed Apr 30, 2024
1 parent 5983cf0 commit 282c7fe
Show file tree
Hide file tree
Showing 13 changed files with 131 additions and 133 deletions.
4 changes: 2 additions & 2 deletions src/server/locale/AU/validOptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ export default {
color: [Types.STRING, ['black', 'white', 'monochrome', 'grayscale|greyscale']],
size: [Types.NUMBER, [12, 10, 11, 13, 14, 15, 16]],
align: [Types.STRING, ['left', 'right', 'center']],
fontFamily: [Types.STRING],
fontFamily: [Types.ANY],
fontSource: [Types.ANY]
}
},
flex: {
color: [Types.STRING, ['blue', 'black', 'white', 'gray|grey', 'monochrome', 'grayscale|greyscale']],
ratio: [Types.STRING, ['1x1', '1x4', '8x1', '20x1']],
text: {
fontFamily: [Types.STRING],
fontFamily: [Types.ANY],
fontSource: [Types.ANY]
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/server/locale/DE/GPL/validOptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ export default {
color: [Types.STRING, ['black', 'white', 'monochrome', 'grayscale|greyscale']],
size: [Types.NUMBER, [12, 10, 11, 13, 14, 15, 16]],
align: [Types.STRING, ['left', 'right', 'center']],
fontFamily: [Types.STRING],
fontFamily: [Types.ANY],
fontSource: [Types.ANY]
}
},
flex: {
color: [Types.STRING, ['blue', 'black', 'white', 'gray|grey', 'monochrome', 'grayscale|greyscale']],
ratio: [Types.STRING, ['1x1', '1x4', '8x1', '20x1']],
text: {
fontFamily: [Types.STRING],
fontFamily: [Types.ANY],
fontSource: [Types.ANY]
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/server/locale/DE/Pi30/validOptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default {
color: [Types.STRING, ['black', 'white', 'monochrome', 'grayscale|greyscale']],
size: [Types.NUMBER, [12, 10, 11, 13, 14, 15, 16]],
align: [Types.STRING, ['left', 'right', 'center']],
fontFamily: [Types.STRING],
fontFamily: [Types.ANY],
fontSource: [Types.ANY]
},
preset: [Types.STRING, [undefined, 'smallest']]
Expand All @@ -19,7 +19,7 @@ export default {
color: [Types.STRING, ['blue', 'black', 'white', 'gray|grey', 'monochrome', 'grayscale|greyscale']],
ratio: [Types.STRING, ['1x1', '1x4', '8x1', '20x1']],
text: {
fontFamily: [Types.STRING],
fontFamily: [Types.ANY],
fontSource: [Types.ANY]
}
},
Expand Down
4 changes: 2 additions & 2 deletions src/server/locale/ES/validOptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ export default {
color: [Types.STRING, ['black', 'white', 'monochrome', 'grayscale|greyscale']],
size: [Types.NUMBER, [12, 10, 11, 13, 14, 15, 16]],
align: [Types.STRING, ['left', 'right', 'center']],
fontFamily: [Types.STRING],
fontFamily: [Types.ANY],
fontSource: [Types.ANY]
}
},
flex: {
color: [Types.STRING, ['blue', 'black', 'white', 'gray|grey', 'monochrome', 'grayscale|greyscale']],
ratio: [Types.STRING, ['1x1', '1x4', '8x1', '20x1']],
text: {
fontFamily: [Types.STRING],
fontFamily: [Types.ANY],
fontSource: [Types.ANY]
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/server/locale/FR/validOptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default {
color: [Types.STRING, ['black', 'white', 'monochrome', 'grayscale|greyscale']],
size: [Types.NUMBER, [12, 10, 11, 13, 14, 15, 16]],
align: [Types.STRING, ['left', 'right', 'center']],
fontFamily: [Types.STRING]
fontFamily: [Types.ANY]
}
},
flex: {
Expand Down
4 changes: 2 additions & 2 deletions src/server/locale/GB/validOptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ export default {
color: [Types.STRING, ['black', 'white', 'monochrome', 'grayscale|greyscale']],
size: [Types.NUMBER, [12, 10, 11, 13, 14, 15, 16]],
align: [Types.STRING, ['left', 'right', 'center']],
fontFamily: [Types.STRING],
fontFamily: [Types.ANY],
fontSource: [Types.ANY]
}
},
flex: {
color: [Types.STRING, ['blue', 'black', 'white', 'gray|grey', 'monochrome', 'grayscale|greyscale']],
ratio: [Types.STRING, ['1x1', '1x4', '8x1', '20x1']],
text: {
fontFamily: [Types.STRING],
fontFamily: [Types.ANY],
fontSource: [Types.ANY]
}
},
Expand Down
4 changes: 2 additions & 2 deletions src/server/locale/IT/validOptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ export default {
color: [Types.STRING, ['black', 'white', 'monochrome', 'grayscale|greyscale']],
size: [Types.NUMBER, [12, 10, 11, 13, 14, 15, 16]],
align: [Types.STRING, ['left', 'right', 'center']],
fontFamily: [Types.STRING],
fontFamily: [Types.ANY],
fontSource: [Types.ANY]
}
},
flex: {
color: [Types.STRING, ['blue', 'black', 'white', 'gray|grey', 'monochrome', 'grayscale|greyscale']],
ratio: [Types.STRING, ['1x1', '1x4', '8x1', '20x1']],
text: {
fontFamily: [Types.STRING],
fontFamily: [Types.ANY],
fontSource: [Types.ANY]
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/server/locale/US/PAYPAL_CREDIT/validOptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default {
color: [Types.STRING, ['black', 'white', 'monochrome', 'grayscale|greyscale']],
size: [Types.NUMBER, [12, 10, 11, 13, 14, 15, 16]],
align: [Types.STRING, ['left', 'right', 'center']],
fontFamily: [Types.STRING],
fontFamily: [Types.ANY],
fontSource: [Types.ANY]
}
},
Expand All @@ -21,7 +21,7 @@ export default {
],
ratio: [Types.STRING, ['1x1', '1x4', '8x1', '20x1']],
text: {
fontFamily: [Types.STRING],
fontFamily: [Types.ANY],
fontSource: [Types.ANY]
}
},
Expand Down
4 changes: 2 additions & 2 deletions src/server/locale/US/PAY_LATER_LONG_TERM/validOptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default {
color: [Types.STRING, ['black', 'white', 'monochrome', 'grayscale|greyscale']],
size: [Types.NUMBER, [12, 10, 11, 13, 14, 15, 16]],
align: [Types.STRING, ['left', 'right', 'center']],
fontFamily: [Types.STRING],
fontFamily: [Types.ANY],
fontSource: [Types.ANY]
}
},
Expand All @@ -21,7 +21,7 @@ export default {
],
ratio: [Types.STRING, ['1x1', '1x4', '8x1', '20x1']],
text: {
fontFamily: [Types.STRING],
fontFamily: [Types.ANY],
fontSource: [Types.ANY]
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/server/locale/US/PAY_LATER_SHORT_TERM/validOptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default {
color: [Types.STRING, ['black', 'white', 'monochrome', 'grayscale|greyscale']],
size: [Types.NUMBER, [12, 10, 11, 13, 14, 15, 16]],
align: [Types.STRING, ['left', 'right', 'center']],
fontFamily: [Types.STRING],
fontFamily: [Types.ANY],
fontSource: [Types.ANY]
}
},
Expand All @@ -21,7 +21,7 @@ export default {
],
ratio: [Types.STRING, ['1x1', '1x4', '8x1', '20x1']],
text: {
fontFamily: [Types.STRING],
fontFamily: [Types.ANY],
fontSource: [Types.ANY]
}
},
Expand Down
92 changes: 92 additions & 0 deletions src/server/message/font.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
let customFontCounter = 1;

/**
* Create a font-face css rule for a given value fontSource value
* @param {string} val - the fontSource value the merchant wishes to use
* @returns {string} result
*/
const generateFontFaceRule = value => {
const name = `Merchant Custom Font ${customFontCounter}`;
customFontCounter += 1;
return {
name: `'${name}'`,
rule: `@font-face {
font-family: '${name}';
src: url('${value}');
}`
};
};

/**
* Format a fontFamily value
* @param {string} val - the font-family value the merchant wishes to use
* @returns {string} result
*/
const formatFontFamilyName = val => {
// using a generic family requires the value not be quoted
const genericFamilies = {
serif: 'serif',
'sans-serif': 'sans-serif',
monospace: 'monospace',
cursive: 'cursive',
fantasy: 'fantasy',
'system-ui': 'system-ui',
'ui-serif': 'ui-serif',
'ui-sans-serif': 'ui-sans-serif',
'ui-monospace': 'ui-monospace'
};
return genericFamilies[val] ?? `'${val}'`;
};

/**
* Parse the style.text.size option
* @param {Object} options
* @param {string} layout - the layout style
* @param {number} size - the font size
* @returns {undefined|string} result
*/
const parseTextSize = ({ layout, size }) => {
if (layout !== 'flex' && typeof size !== 'undefined' && !Number.isNaN(size) && size >= 10 && size <= 16) {
return `${size}`;
}
return undefined;
};

/**
* Return the css to stylize the text used for the message
* @param {Object} style - the style query parameter (after the server has validated it)
* @returns {string[]} result - an array of the css rules to customize the font
*/
export const getFontRules = style => {
customFontCounter = 0;
const fontFamilyFallbacks = ['Helvetica', 'Arial', 'sans-serif'];
const fontSelector = [
'.message__messaging', // text layout
'.message__messaging .message__headline span', // flex layout
'.message__messaging .message__sub-headline span',
'.message__messaging .message__disclaimer span'
].join(',\n');
const rules = [];
const { layout, text: { size, fontSource: fontSourceStyle, fontFamily: fontFamilyStyle } = {} } = style;
const textSize = parseTextSize({ layout, size });
const fontSource = Array.isArray(fontSourceStyle) ? fontSourceStyle : [];
const fontFamily = Array.isArray(fontFamilyStyle) ? fontFamilyStyle : [];

const customFontSourceNames = fontSource.map(value => {
const { name, rule } = generateFontFaceRule(value);
rules.push(rule);
return name;
});

const customFontFamilyNames = [...customFontSourceNames, ...fontFamily.map(val => formatFontFamilyName(val))];

if (customFontFamilyNames || textSize) {
const fontFamilyRule =
customFontFamilyNames.length === 0
? ''
: `font-family: ${[...customFontFamilyNames, ...fontFamilyFallbacks].join(', ')};\n`;
const textSizeRule = typeof textSize !== 'undefined' ? `font-size: ${textSize}px;` : '';
rules.push(`${fontSelector}{ ${fontFamilyRule}${textSizeRule} }`);
}
return rules;
};
102 changes: 4 additions & 98 deletions src/server/message/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,9 @@ import Logo from './parts/Logo';
import MutatedText from './parts/MutatedText';
import Styles from './parts/Styles';
import CustomMessage from './parts/CustomMessage';
import { getFontRules } from './font';

const DEFAULT_FONT_SIZE = 12;
const logMessage = val => (val !== 'string' ? JSON.stringify(val) : val);
const logInfo = (addLog, val) => addLog('info', 'render_markup', `${logMessage(val)}`);
const logError = (addLog, val) => addLog('error', 'render_markup', `${logMessage(val)}`);

/**
* Get all applicable rules based on user flattened options
Expand Down Expand Up @@ -45,100 +43,8 @@ const applyCascade = curry((style, flattened, type, rules) =>
type === Array ? [] : {}
)
);
const getfontSourceRule = (addLog, fontSource) => {
if (!fontSource) {
return '';
}
const fontFormats = {
woff: 'woff', // woff
woff2: 'woff2', // woff2
ttf: 'ttf', // truetype
otf: 'otf', // opentype
eot: 'eot', // embedded opentype
svg: 'svg' // svg
};
const urlPattern = RegExp(`^(https?://.+?.(${[...Object.values(fontFormats)].join('|')}))$`);
const payload = {
fontSource,
validValues: []
};
try {
const ruleVal = (Array.isArray(fontSource) ? fontSource : [fontSource])
.map(url => {
const extension = urlPattern.exec(url)?.[2];
const format = fontFormats[extension];
if (format) {
payload.validValues.push(url);
return `url('${url}') format('${format}')`;
}
return '';
})
.filter(Boolean)
.join(', ');
logInfo(addLog, payload);
return ruleVal ? `src: ${ruleVal};` : '';
} catch (err) {
payload.error = err.stack;
logError(addLog, payload);
return '';
}
};
const getFontFamilyRule = (addLog, val) => {
if (!val) {
return '';
}
const payload = {
fontFamily: val,
validValue: null
};
const genericFamilies = {
// using a generic family requires the value not be quoted
serif: 'serif',
'sans-serif': 'sans-serif',
monospace: 'monospace',
cursive: 'cursive',
fantasy: 'fantasy',
'system-ui': 'system-ui',
'ui-serif': 'ui-serif',
'ui-sans-serif': 'ui-sans-serif',
'ui-monospace': 'ui-monospace'
};
const fontFamily = genericFamilies[val] ?? `'${val}'`;
if (fontFamily) {
payload.validValue = fontFamily;
logInfo(addLog, payload);
return `font-family: ${fontFamily}, Helvetica, Arial, sans-serif; `;
}
payload.validValue = '';
logInfo(addLog, payload);
return '';
};
const getFontRules = (addLog, style) => {
const rules = [];
const textSize = style.layout === 'flex' ? undefined : style?.text?.size;
const fontSource = style?.text?.fontSource;
const fontFamily = fontSource ? 'MerchantCustomFont' : style?.text?.fontFamily;

const fontSelector = [
'.message__messaging', // text layout
'.message__messaging .message__headline span', // flex layout
'.message__messaging .message__sub-headline span',
'.message__messaging .message__disclaimer span'
].join(',\n');

const textSizeRule = Number.isNaN(textSize) ? '' : `font-size: ${textSize}px; `;
const fontFamilyRule = getFontFamilyRule(addLog, fontFamily);
const fontSourceRule = getfontSourceRule(addLog, fontSource);

if (fontSource) {
rules.push(`@font-face {font-family: '${fontFamily}'; ${fontSourceRule}}`);
}
if (fontFamilyRule || textSizeRule) {
rules.push(`${fontSelector}{ ${fontFamilyRule}${textSizeRule} }`);
}
return rules;
};
export default ({ addLog, options, markup, locale }) => {

export default ({ options, markup, locale }) => {
const offerType = markup?.meta?.offerType;
const { style, contextualComponents } = options;

Expand All @@ -163,7 +69,7 @@ export default ({ addLog, options, markup, locale }) => {
getLocaleStyles(locale, layoutProp, offerType, contextualComponents)
).map(rule => rule.replace(/\.message/g, `.${localeClass} .message`));
const mutationStyleRules = mutationRules.styles ?? [];
const customFontStyleRules = getFontRules(addLog, style);
const customFontStyleRules = getFontRules(style);
const miscStyleRules = [];

// Set boundaries on the width of the message text to ensure proper line counts
Expand Down
Loading

0 comments on commit 282c7fe

Please sign in to comment.