mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
feat(tokens): add new tokens json files (#29525)
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 new behavior? <!-- Please describe the behavior or changes that are being added by this PR. --> - Added new structure of JSON files that are generated from Figma Variables - Adjusted tokens.js script to correctly translate the new JSON format - Adjusted tokens usage on components and CSS files - Added html template to auto-generate html preview based on Design Tokens (wip) - Updated snapshots, as some tokens values changed, specially colors. ## 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. --> --------- Co-authored-by: Maria Hutt <thetaPC@users.noreply.github.com>
This commit is contained in:
@@ -1,197 +0,0 @@
|
||||
/* For generating Design Tokens, we use Style Dictionary for several reasons:
|
||||
- It's prepared to easily generate tokens for multiple types of outputs (CSS, SCSS, iOS, Android, documentation, etc.).
|
||||
- It also works very well out of the box with any kind of Design Tokens formats, like Figma Tokens, as well as APIs to adjust to more custom ones.
|
||||
- It is probably the most well-known and widely used Design Tokens tool. It has also been regularly maintained for a long time.
|
||||
- It can easily scale to different necessities we might have in the future.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const StyleDictionary = require('style-dictionary');
|
||||
|
||||
const { fileHeader } = StyleDictionary.formatHelpers;
|
||||
|
||||
// Empty for as an example of how we can add some extra variables, not from the tokens JSON
|
||||
const customVariables = ``;
|
||||
|
||||
// Prefix for all generated variables
|
||||
const variablesPrefix = 'ionic';
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// CSS vanilla :root format
|
||||
StyleDictionary.registerFormat({
|
||||
name: 'rootFormat',
|
||||
formatter({ dictionary, file }) {
|
||||
// Add a prefix to all variable names
|
||||
const prefixedVariables = dictionary.allProperties.map((prop) => {
|
||||
const rgb = hexToRgb(prop.value);
|
||||
return ` --${variablesPrefix}-${prop.name}: ${prop.value};${
|
||||
rgb ? `\n --${variablesPrefix}-${prop.name}-rgb: ${rgb.r}, ${rgb.g}, ${rgb.b};` : ``
|
||||
}`;
|
||||
});
|
||||
|
||||
return (
|
||||
fileHeader({ file }) +
|
||||
':root {\n' +
|
||||
prefixedVariables.join('\n') + // Join all prefixed variables with a newline
|
||||
customVariables +
|
||||
'\n}\n'
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
// scss variables format
|
||||
StyleDictionary.registerFormat({
|
||||
name: 'scssVariablesFormat',
|
||||
formatter({ dictionary, file }) {
|
||||
// Add a prefix to all variable names
|
||||
const prefixedVariables = dictionary.allProperties.map((prop) => {
|
||||
const rgb = hexToRgb(prop.value);
|
||||
return `$${variablesPrefix}-${prop.name}: var(--${variablesPrefix}-${prop.name}, ${prop.value});${
|
||||
rgb
|
||||
? `\n$${variablesPrefix}-${prop.name}-rgb: var(--${variablesPrefix}-${prop.name}-rgb, ${rgb.r}, ${rgb.g}, ${rgb.b});`
|
||||
: ``
|
||||
}`;
|
||||
});
|
||||
|
||||
return (
|
||||
fileHeader({ file }) +
|
||||
prefixedVariables.join('\n') + // Join all prefixed variables with a newline
|
||||
customVariables +
|
||||
'\n'
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
// Create utility-classes
|
||||
StyleDictionary.registerFormat({
|
||||
name: 'cssUtilityClassesFormat',
|
||||
formatter({ dictionary, file }) {
|
||||
const utilityClasses = dictionary.allProperties.map((prop) => {
|
||||
let tokenType = prop.attributes.category;
|
||||
const className = `${prop.name}`;
|
||||
let utilityClass = '';
|
||||
|
||||
switch (tokenType) {
|
||||
case 'color':
|
||||
utilityClass = `.${variablesPrefix}-${className} {\n color: $ionic-${prop.name};\n}
|
||||
.${variablesPrefix}-background-${className} {\n background-color: $ionic-${prop.name};\n}`;
|
||||
break;
|
||||
case 'border':
|
||||
const borderAttribute = prop.attributes.type === 'radius' ? 'border-radius' : 'border-width';
|
||||
utilityClass = `.${variablesPrefix}-${className} {\n ${borderAttribute}: $ionic-${prop.name};\n}`;
|
||||
break;
|
||||
case 'font':
|
||||
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;
|
||||
case 'family':
|
||||
return;
|
||||
}
|
||||
utilityClass = `.${variablesPrefix}-${className} {\n ${fontAttribute}: $ionic-${prop.name};\n}`;
|
||||
break;
|
||||
case 'elevation':
|
||||
utilityClass = `.${variablesPrefix}-${className} {\n box-shadow: $ionic-${prop.name};\n}`;
|
||||
break;
|
||||
case 'space':
|
||||
utilityClass = `.${variablesPrefix}-margin-${className} {\n --margin-start: #{$ionic-${prop.name}};\n --margin-end: #{$ionic-${prop.name}};\n --margin-top: #{$ionic-${prop.name}};\n --margin-bottom: #{$ionic-${prop.name}};\n\n @include margin(${prop.value});\n};\n
|
||||
.${variablesPrefix}-padding-${className} {\n --padding-start: #{$ionic-${prop.name}};\n --padding-end: #{$ionic-${prop.name}};\n --padding-top: #{$ionic-${prop.name}};\n --padding-bottom: #{$ionic-${prop.name}};\n\n @include padding(${prop.value});\n};\n`;
|
||||
break;
|
||||
default:
|
||||
utilityClass = `.${variablesPrefix}-${className} {\n ${tokenType}: $ionic-${prop.name};\n}`;
|
||||
}
|
||||
|
||||
return utilityClass;
|
||||
});
|
||||
|
||||
return [
|
||||
fileHeader({ file }),
|
||||
'@import "./ionic.vars";\n@import "../themes/mixins";\n',
|
||||
utilityClasses.join('\n'),
|
||||
].join('\n');
|
||||
},
|
||||
});
|
||||
|
||||
// Make Style Dictionary comply with the $ format on properties from W3C Guidelines
|
||||
const w3cTokenJsonParser = {
|
||||
pattern: /\.json|\.tokens\.json|\.tokens$/,
|
||||
parse({ contents }) {
|
||||
// replace $value with value so that style dictionary recognizes it
|
||||
var preparedContent = (contents || '{}')
|
||||
.replace(/"\$?value":/g, '"value":')
|
||||
// convert $description to comment
|
||||
.replace(/"\$?description":/g, '"comment":');
|
||||
//
|
||||
|
||||
return JSON.parse(preparedContent);
|
||||
},
|
||||
};
|
||||
|
||||
StyleDictionary.registerParser(w3cTokenJsonParser);
|
||||
|
||||
// Generate Tokens
|
||||
StyleDictionary.extend({
|
||||
source: ['./src/foundations/*.json'],
|
||||
platforms: {
|
||||
css: {
|
||||
buildPath: './src/foundations/',
|
||||
transformGroup: 'css',
|
||||
files: [
|
||||
{
|
||||
destination: 'ionic.root.scss',
|
||||
format: 'rootFormat',
|
||||
options: {
|
||||
outputReferences: true,
|
||||
fileHeader: `myFileHeader`,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
scss: {
|
||||
buildPath: './src/foundations/',
|
||||
transformGroup: 'scss',
|
||||
files: [
|
||||
{
|
||||
destination: 'ionic.vars.scss',
|
||||
format: 'scssVariablesFormat',
|
||||
options: {
|
||||
outputReferences: true,
|
||||
fileHeader: `myFileHeader`,
|
||||
},
|
||||
},
|
||||
{
|
||||
destination: 'ionic.utility.scss',
|
||||
format: 'cssUtilityClassesFormat',
|
||||
options: {
|
||||
outputReferences: true,
|
||||
fileHeader: `myFileHeader`,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
fileHeader: {
|
||||
myFileHeader: () => {
|
||||
return [`This is an auto-generated file, please do not change it directly.`, `Ionic Design System`];
|
||||
},
|
||||
},
|
||||
}).buildAllPlatforms();
|
||||
218
core/scripts/tokens/index.js
Normal file
218
core/scripts/tokens/index.js
Normal file
@@ -0,0 +1,218 @@
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
// For generating Design Tokens, we use Style Dictionary for several reasons:
|
||||
// - It's prepared to easily generate tokens for multiple types of outputs (CSS, SCSS, iOS, Android, documentation, etc.).
|
||||
// - It also works very well out of the box with any kind of Design Tokens formats, like Figma Tokens, as well as APIs to adjust to more custom ones.
|
||||
// - It is probably the most well-known and widely used Design Tokens tool. It has also been regularly maintained for a long time.
|
||||
// - It can easily scale to different necessities we might have in the future.
|
||||
|
||||
const StyleDictionary = require('style-dictionary');
|
||||
|
||||
const targetPath = './src/foundations/';
|
||||
|
||||
const {
|
||||
variablesPrefix,
|
||||
hexToRgb,
|
||||
generateShadowValue,
|
||||
generateFontFamilyValue,
|
||||
generateTypographyValue,
|
||||
generateRgbValue,
|
||||
generateColorUtilityClasses,
|
||||
generateFontUtilityClass,
|
||||
generateSpaceUtilityClasses,
|
||||
generateTypographyUtilityClass,
|
||||
} = require('./utilities');
|
||||
|
||||
const { fileHeader } = StyleDictionary.formatHelpers;
|
||||
|
||||
// CSS vanilla :root format
|
||||
StyleDictionary.registerFormat({
|
||||
name: 'rootFormat',
|
||||
formatter({ dictionary, file }) {
|
||||
/*
|
||||
* This will loop through all tokens and based on the type it will
|
||||
* call a utility function that will return the expected format for the CSS Variable
|
||||
*/
|
||||
const prefixedVariables = dictionary.allProperties
|
||||
.filter((prop) => prop['$type'] !== 'typography')
|
||||
.map((prop) => {
|
||||
if (prop.attributes.category.startsWith('Elevation')) {
|
||||
const cssShadow = prop.value.map(generateShadowValue).join(', ');
|
||||
return `--${variablesPrefix}-${prop.name}: ${cssShadow};`;
|
||||
} else if (prop.attributes.category.match('font-family')) {
|
||||
return generateFontFamilyValue(prop);
|
||||
} else {
|
||||
// TODO(ROU-4870): prevent colors with 8 characters to be created without a rgb transformation
|
||||
const rgb = hexToRgb(prop.value);
|
||||
return ` --${variablesPrefix}-${prop.name}: ${prop.value};${
|
||||
rgb ? `\n --${variablesPrefix}-${prop.name}-rgb: ${rgb.r}, ${rgb.g}, ${rgb.b};` : ``
|
||||
}`;
|
||||
}
|
||||
});
|
||||
|
||||
return fileHeader({ file }) + ':root {\n' + prefixedVariables.join('\n') + '\n}\n';
|
||||
},
|
||||
});
|
||||
|
||||
// SCSS variables format
|
||||
StyleDictionary.registerFormat({
|
||||
name: 'scssVariablesFormat',
|
||||
formatter({ dictionary, file }) {
|
||||
const typographyProperties = dictionary.allProperties.filter((prop) => prop['$type'] === 'typography');
|
||||
const otherProperties = dictionary.allProperties.filter((prop) => prop['$type'] !== 'typography');
|
||||
|
||||
// Make sure the reused scss variables are defined first, to avoid compilation errors
|
||||
const sortedProperties = [...otherProperties, ...typographyProperties];
|
||||
|
||||
const prefixedVariables = sortedProperties.map((prop) => {
|
||||
if (prop.attributes.category.startsWith('Elevation')) {
|
||||
const cssShadow = prop.value.map(generateShadowValue).join(', ');
|
||||
return `$${variablesPrefix}-${prop.name}: var(--${variablesPrefix}-${prop.name}, ${cssShadow});`;
|
||||
} else if (prop.attributes.category.match('font-family')) {
|
||||
return generateFontFamilyValue(prop, 'scss');
|
||||
} else if (prop['$type'] === 'typography') {
|
||||
return generateTypographyValue(prop, dictionary);
|
||||
} else {
|
||||
return generateRgbValue(prop);
|
||||
}
|
||||
});
|
||||
|
||||
return fileHeader({ file }) + prefixedVariables.join('\n') + '\n';
|
||||
},
|
||||
});
|
||||
|
||||
// Create utility-classes
|
||||
StyleDictionary.registerFormat({
|
||||
name: 'cssUtilityClassesFormat',
|
||||
formatter({ dictionary, file }) {
|
||||
const utilityClasses = dictionary.allProperties.map((prop) => {
|
||||
let tokenType = prop.attributes.category;
|
||||
const className = `${prop.name}`;
|
||||
let utilityClass = '';
|
||||
|
||||
if (tokenType.startsWith('Elevation')) {
|
||||
return `.${variablesPrefix}-${className} {\n box-shadow: $ionic-${prop.name};\n}`;
|
||||
} else if (prop['$type'] === 'typography') {
|
||||
return generateTypographyUtilityClass(prop, dictionary);
|
||||
/*
|
||||
* Not creating for the tokens below, as they make no sense to exist as utility-classes.
|
||||
* Font-family should be defined on global scope, not component.
|
||||
* Scale its an abstract token group, to be used by other tokens, like the space ones.
|
||||
*/
|
||||
} else if (prop.attributes.category.match('font-family') || tokenType === 'scale') {
|
||||
return;
|
||||
}
|
||||
|
||||
const tokenTypeLower = tokenType.toLowerCase();
|
||||
|
||||
switch (tokenTypeLower) {
|
||||
case 'color':
|
||||
case 'state':
|
||||
case 'guidelines':
|
||||
case 'disabled':
|
||||
case 'hover':
|
||||
case 'pressed':
|
||||
utilityClass = generateColorUtilityClasses(prop, className);
|
||||
break;
|
||||
case 'border-size':
|
||||
utilityClass = `.${variablesPrefix}-${className} {\n border-width: $ionic-${prop.name};\n}`;
|
||||
break;
|
||||
case 'font':
|
||||
utilityClass = generateFontUtilityClass(prop, className);
|
||||
break;
|
||||
case 'space':
|
||||
utilityClass = generateSpaceUtilityClasses(prop, className);
|
||||
break;
|
||||
default:
|
||||
utilityClass = `.${variablesPrefix}-${className} {\n ${tokenType}: $ionic-${prop.name};\n}`;
|
||||
}
|
||||
|
||||
return utilityClass;
|
||||
});
|
||||
|
||||
return [
|
||||
fileHeader({ file }),
|
||||
'@import "./ionic.vars";\n@import "../themes/mixins";\n',
|
||||
utilityClasses.join('\n'),
|
||||
].join('\n');
|
||||
},
|
||||
});
|
||||
|
||||
// Custom transform to ensure unique token names
|
||||
StyleDictionary.registerTransform({
|
||||
name: 'name/cti/kebab-unique',
|
||||
type: 'name',
|
||||
transformer: function (prop, options) {
|
||||
return [options.prefix].concat(prop.path).join('-').toLowerCase();
|
||||
},
|
||||
});
|
||||
|
||||
// Register the custom transform group for html file generation
|
||||
StyleDictionary.registerTransformGroup({
|
||||
name: 'custom',
|
||||
transforms: ['attribute/cti', 'name/cti/kebab-unique', 'size/rem', 'color/css'],
|
||||
});
|
||||
|
||||
// Make Style Dictionary comply with the $ format on properties from W3C Guidelines
|
||||
const w3cTokenJsonParser = {
|
||||
pattern: /\.json|\.tokens\.json|\.tokens$/,
|
||||
parse({ contents }) {
|
||||
// replace $value with value so that style dictionary recognizes it
|
||||
var preparedContent = (contents || '{}')
|
||||
.replace(/"\$?value":/g, '"value":')
|
||||
// convert $description to comment
|
||||
.replace(/"\$?description":/g, '"comment":');
|
||||
//
|
||||
|
||||
return JSON.parse(preparedContent);
|
||||
},
|
||||
};
|
||||
|
||||
StyleDictionary.registerParser(w3cTokenJsonParser);
|
||||
|
||||
// Generate Tokens
|
||||
StyleDictionary.extend({
|
||||
source: ['./src/foundations/tokens/*.json', './src/foundations/tokens/theme/*.json'],
|
||||
platforms: {
|
||||
css: {
|
||||
buildPath: targetPath,
|
||||
transformGroup: 'css',
|
||||
files: [
|
||||
{
|
||||
destination: 'ionic.root.scss',
|
||||
format: 'rootFormat',
|
||||
options: {
|
||||
outputReferences: true,
|
||||
fileHeader: `myFileHeader`,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
scss: {
|
||||
buildPath: targetPath,
|
||||
transformGroup: 'scss',
|
||||
files: [
|
||||
{
|
||||
destination: 'ionic.vars.scss',
|
||||
format: 'scssVariablesFormat',
|
||||
options: {
|
||||
outputReferences: true,
|
||||
fileHeader: `myFileHeader`,
|
||||
},
|
||||
},
|
||||
{
|
||||
destination: 'ionic.utility.scss',
|
||||
format: 'cssUtilityClassesFormat',
|
||||
options: {
|
||||
outputReferences: true,
|
||||
fileHeader: `myFileHeader`,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
fileHeader: {
|
||||
myFileHeader: () => {
|
||||
return [`This is an auto-generated file, please do not change it directly.`, `Ionic Design System`];
|
||||
},
|
||||
},
|
||||
}).buildAllPlatforms();
|
||||
147
core/scripts/tokens/utilities.js
Normal file
147
core/scripts/tokens/utilities.js
Normal file
@@ -0,0 +1,147 @@
|
||||
const variablesPrefix = 'ionic'; // Variable that holds the prefix used on all css and scss variables generated
|
||||
|
||||
// Generates translate 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;
|
||||
}
|
||||
|
||||
// Generates a valid box-shadow value from a shadow Design Token structure
|
||||
function generateShadowValue(shadow) {
|
||||
return `${shadow.offsetX} ${shadow.offsetY} ${shadow.blur} ${shadow.spread} ${shadow.color}`;
|
||||
}
|
||||
|
||||
// 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');
|
||||
|
||||
// This exact format is needed so that it compiles the tokens with the expected lint rules
|
||||
return `
|
||||
$${variablesPrefix}-${prop.name}: (
|
||||
font-family: $ionic-font-family,
|
||||
font-size: $ionic-font-size-${fontSizeMap[typography.fontSize]},
|
||||
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 rgb color value, based on a color Design Token
|
||||
function generateRgbValue(prop) {
|
||||
const rgb = hexToRgb(prop.value);
|
||||
let rgbDeclaration = '';
|
||||
|
||||
// If the token is color, also add a rgb variable using the same color
|
||||
if (rgb) {
|
||||
rgbDeclaration = `\n$${variablesPrefix}-${prop.name}-rgb: var(--${variablesPrefix}-${prop.name}-rgb, ${rgb.r}, ${rgb.g}, ${rgb.b});`;
|
||||
}
|
||||
|
||||
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');
|
||||
|
||||
// This exact format is needed so that it compiles the tokens with the expected lint rules
|
||||
return `
|
||||
.${variablesPrefix}-${prop.name} {
|
||||
font-family: $ionic-font-family;
|
||||
font-size: $ionic-font-size-${fontSizeMap[typography.fontSize]};
|
||||
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,
|
||||
hexToRgb,
|
||||
generateShadowValue,
|
||||
generateFontFamilyValue,
|
||||
generateTypographyValue,
|
||||
generateRgbValue,
|
||||
generateColorUtilityClasses,
|
||||
generateFontUtilityClass,
|
||||
generateSpaceUtilityClasses,
|
||||
generateTypographyUtilityClass,
|
||||
};
|
||||
Reference in New Issue
Block a user