mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-15 09:34:19 +08:00

Issue number: internal --------- <!-- Please do not submit updates to dependencies unless it fixes an issue. --> <!-- Please try to limit your pull request to one type (bugfix, feature, etc). Submit multiple pull requests if needed. --> ## What is the current behavior? <!-- Please describe the current behavior that you are modifying. --> ## What is the new behavior? <!-- Please describe the behavior or changes that are being added by this PR. --> - Updated tokens utilities to no longer add font-family to utillity-classes. That is something that should only be set at a global layer, no sense to have that on a utility-class. - Updated text token JSON as received by UX/UI Team. - Improved tokens utilities to correctly set font-style to italic with italic font tokens. - Adjusted typography Ionic scss to use the new typography classes and mixins based on tokens. - Removed old basic typography test, as it was testing utility-classes that do not exist anymore. - Added new typography test for ionic display tokens. - Added a TODO to tackle the Inter font loading scenario, as it envolves research that impact other contexts as well. ## Does this introduce a breaking change? - [x] Yes - [ ] No <!-- If this introduces a breaking change: 1. Describe the impact and migration path for existing applications below. 2. Update the BREAKING.md file with the breaking change. 3. Add "BREAKING CHANGE: [...]" to the commit description when merging. See https://github.com/ionic-team/ionic-framework/blob/main/docs/CONTRIBUTING.md#footer for more information. --> ## Other information <!-- Any other information that is important to this PR such as screenshots of how the component looks before and after the change. --> [Sample Typography Screen](https://ionic-framework-e2le05h3a-ionic1.vercel.app/src/css/test/typography/basic) --------- Co-authored-by: ionitron <hi@ionicframework.com> Co-authored-by: Maria Hutt <thetaPC@users.noreply.github.com>
192 lines
7.2 KiB
JavaScript
192 lines
7.2 KiB
JavaScript
const variablesPrefix = 'ionic'; // Variable that holds the prefix used on all css and scss variables generated
|
|
|
|
// Generates a valid rgba() color
|
|
function getRgbaValue(propValue) {
|
|
// Check if its rgba color
|
|
const isRgba = hexToRgba(propValue);
|
|
// If it is, then compose rgba() color, otherwise use the normal color
|
|
if (isRgba !== null) {
|
|
return (propValue = `rgba(${isRgba.r}, ${isRgba.g}, ${isRgba.b},${isRgba.a})`);
|
|
} else {
|
|
return propValue;
|
|
}
|
|
}
|
|
|
|
// Translates an hex color value to rgb
|
|
function hexToRgb(hex) {
|
|
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
return result
|
|
? {
|
|
r: parseInt(result[1], 16),
|
|
g: parseInt(result[2], 16),
|
|
b: parseInt(result[3], 16),
|
|
}
|
|
: null;
|
|
}
|
|
|
|
// Translates an hex color value to rgba
|
|
function hexToRgba(hex) {
|
|
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
return result
|
|
? {
|
|
r: parseInt(result[1], 16),
|
|
g: parseInt(result[2], 16),
|
|
b: parseInt(result[3], 16),
|
|
a: Math.round((parseInt(result[4], 16) * 100) / 255) / 100,
|
|
}
|
|
: null;
|
|
}
|
|
|
|
// Generates a valid box-shadow value from a shadow Design Token structure
|
|
function generateShadowValue(shadow) {
|
|
const color = getRgbaValue(shadow.color);
|
|
|
|
return `${shadow.offsetX} ${shadow.offsetY} ${shadow.blur} ${shadow.spread} ${color}`;
|
|
}
|
|
|
|
// Generates a valid font-size value from a font-size Design Token structure, while transforming the pixels to rem
|
|
function generateFontSizeValue(prop, variableType = 'css') {
|
|
return variableType === 'scss'
|
|
? `$${variablesPrefix}-${prop.name}: var(--${variablesPrefix}-${prop.name}, font.px-to-rem(${parseInt(
|
|
prop.value
|
|
)}));`
|
|
: `--${variablesPrefix}-${prop.name}: #{font.px-to-rem(${parseInt(prop.value)})};`;
|
|
}
|
|
|
|
// Generates a valid font-family value from a font-family Design Token structure
|
|
function generateFontFamilyValue(prop, variableType = 'css') {
|
|
// Remove the last word from the token, as it contains the name of the font, which we don't want to be included on the generated variables
|
|
const propName = prop.name.split('-').slice(0, -1).join('-');
|
|
return variableType === 'scss'
|
|
? `$${variablesPrefix}-${propName}: var(--${variablesPrefix}-${propName}, "${prop.value}", sans-serif);`
|
|
: `--${variablesPrefix}-${propName}: "${prop.value}", sans-serif;`;
|
|
}
|
|
|
|
// Generates a typography based scss map from a typography Design Token structure
|
|
function generateTypographyValue(prop, dictionary) {
|
|
const typography = prop.value;
|
|
const fontSizeMap = getTypeMap(dictionary, 'font-size');
|
|
const fontWeightMap = getTypeMap(dictionary, 'font-weight');
|
|
const lineHeightMap = getTypeMap(dictionary, 'line-height');
|
|
const letterSpacingMap = getTypeMap(dictionary, 'letter-spacing');
|
|
const fontStyle = prop.attributes.item?.toLowerCase() === 'italic' ? 'italic' : 'normal';
|
|
|
|
// This exact format is needed so that it compiles the tokens with the expected lint rules
|
|
return `
|
|
$${variablesPrefix}-${prop.name}: (
|
|
font-size: $ionic-font-size-${fontSizeMap[typography.fontSize]},
|
|
font-style: ${fontStyle},
|
|
font-weight: $ionic-font-weight-${fontWeightMap[typography.fontWeight]},
|
|
letter-spacing: $ionic-letter-spacing-${letterSpacingMap[typography.letterSpacing] || 0},
|
|
line-height: $ionic-line-height-${lineHeightMap[typography.lineHeight]},
|
|
text-transform: ${typography.textTransform},
|
|
text-decoration: ${typography.textDecoration}
|
|
);
|
|
`;
|
|
}
|
|
|
|
// To abstract the need to loop across all tokens from a given type
|
|
function getTypeMap(dictionary, type) {
|
|
return Object.fromEntries(
|
|
Object.entries(dictionary.properties[type]).map(([key, token]) => [token.value, token.attributes.type])
|
|
);
|
|
}
|
|
|
|
// Generates a final value, based if the Design Token is of type color or not
|
|
function generateValue(prop) {
|
|
const rgb = hexToRgb(prop.value);
|
|
|
|
let rgbDeclaration = '';
|
|
|
|
if (rgb) {
|
|
// If the token is color, also add a rgb variable using the same color
|
|
rgbDeclaration = `\n$${variablesPrefix}-${prop.name}-rgb: var(--${variablesPrefix}-${prop.name}-rgb, ${rgb.r}, ${rgb.g}, ${rgb.b});`;
|
|
}
|
|
|
|
prop.value = getRgbaValue(prop.value);
|
|
|
|
return `$${variablesPrefix}-${prop.name}: var(--${variablesPrefix}-${prop.name}, ${prop.value});${rgbDeclaration}`;
|
|
}
|
|
|
|
// Generates a typography based css utility-class from a typography Design Token structure
|
|
function generateTypographyUtilityClass(prop, dictionary) {
|
|
const typography = prop.value;
|
|
const fontSizeMap = getTypeMap(dictionary, 'font-size');
|
|
const fontWeightMap = getTypeMap(dictionary, 'font-weight');
|
|
const lineHeightMap = getTypeMap(dictionary, 'line-height');
|
|
const letterSpacingMap = getTypeMap(dictionary, 'letter-spacing');
|
|
const fontStyle = prop.attributes.item?.toLowerCase() === 'italic' ? 'italic' : 'normal';
|
|
|
|
// This exact format is needed so that it compiles the tokens with the expected lint rules
|
|
return `
|
|
.${variablesPrefix}-${prop.name} {
|
|
font-size: $ionic-font-size-${fontSizeMap[typography.fontSize]};
|
|
font-style: ${fontStyle};
|
|
font-weight: $ionic-font-weight-${fontWeightMap[typography.fontWeight]};
|
|
letter-spacing: $ionic-letter-spacing-${letterSpacingMap[typography.letterSpacing] || 0};
|
|
line-height: $ionic-line-height-${lineHeightMap[typography.lineHeight]};
|
|
text-transform: ${typography.textTransform};
|
|
text-decoration: ${typography.textDecoration};
|
|
};
|
|
`;
|
|
}
|
|
|
|
// Generates a color based css utility-class from a color Design Token structure
|
|
function generateColorUtilityClasses(prop, className) {
|
|
return `.${variablesPrefix}-${className} {\n color: $ionic-${prop.name};\n}
|
|
.${variablesPrefix}-background-${className} {\n background-color: $ionic-${prop.name};\n}`;
|
|
}
|
|
|
|
// Generates a font based css utility-class from a font Design Token structure
|
|
function generateFontUtilityClass(prop, className) {
|
|
let fontAttribute;
|
|
switch (prop.attributes.type) {
|
|
case 'size':
|
|
fontAttribute = 'font-size';
|
|
break;
|
|
case 'weight':
|
|
fontAttribute = 'font-weight';
|
|
break;
|
|
case 'line-height':
|
|
fontAttribute = 'line-height';
|
|
break;
|
|
case 'letter-spacing':
|
|
fontAttribute = 'letter-spacing';
|
|
break;
|
|
}
|
|
return `.${variablesPrefix}-${className} {\n ${fontAttribute}: $ionic-${prop.name};\n}`;
|
|
}
|
|
|
|
// Generates a margin or padding based css utility-class from a space Design Token structure
|
|
function generateSpaceUtilityClasses(prop, className) {
|
|
// This exact format is needed so that it compiles the tokens with the expected lint rules
|
|
const marginPaddingTemplate = (type) => `
|
|
.${variablesPrefix}-${type}-${className} {
|
|
--${type}-start: #{$ionic-${prop.name}};
|
|
--${type}-end: #{$ionic-${prop.name}};
|
|
--${type}-top: #{$ionic-${prop.name}};
|
|
--${type}-bottom: #{$ionic-${prop.name}};
|
|
|
|
@include ${type}($ionic-${prop.name});
|
|
};`;
|
|
|
|
return `${marginPaddingTemplate('margin')}\n${marginPaddingTemplate('padding')}`;
|
|
}
|
|
|
|
// Export all methods to be used on the tokens.js script
|
|
module.exports = {
|
|
variablesPrefix,
|
|
getRgbaValue,
|
|
hexToRgb,
|
|
hexToRgba,
|
|
generateShadowValue,
|
|
generateFontSizeValue,
|
|
generateFontFamilyValue,
|
|
generateTypographyValue,
|
|
generateRgbValue: generateValue,
|
|
generateColorUtilityClasses,
|
|
generateFontUtilityClass,
|
|
generateSpaceUtilityClasses,
|
|
generateTypographyUtilityClass,
|
|
};
|