Skip to content
Merged
5 changes: 5 additions & 0 deletions core/scripts/testing/scripts.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@
linkTag.setAttribute('href', '/css/ionic/bundle.ionic.css');
document.head.appendChild(linkTag);
}

const defaultThemeLinkTag = document.querySelector('link[href*="css/ionic.bundle.css"]');
if (defaultThemeLinkTag) {
defaultThemeLinkTag.remove();
}
}

window.Ionic = window.Ionic || {};
Expand Down
257 changes: 130 additions & 127 deletions core/scripts/tokens/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
generateTypographyOutput,
generateValue,
generateColorUtilityClasses,
generateDefaultSpaceUtilityClasses,
generateSpaceUtilityClasses,
removeConsecutiveRepeatedWords,
setPrefixValue,
Expand All @@ -23,136 +24,138 @@
} = require('./utils.js');

const StyleDictionary = (await import('style-dictionary')).default;

// Set the prefix for variables and classes
setPrefixValue('ion');

// Register a custom file header
StyleDictionary.registerFileHeader({
name: 'custom-header',
fileHeader: async (defaultMessages = []) => {
return [...defaultMessages, 'Do not edit directly, this file was auto-generated.'];
},
name: 'custom-header',
fileHeader: async (defaultMessages = []) => {
return [...defaultMessages, 'Do not edit directly, this file was auto-generated.'];
},
});

// SCSS variables format
StyleDictionary.registerFormat({
name: 'scssVariablesFormat',
format: async function({ dictionary, file}) {
format: async function ({ dictionary, file }) {

console.log('Generating SCSS variables...');

// Separate typography tokens from the rest
const typographyProperties = dictionary.allTokens.filter((prop) => prop.$type === 'typography');
const otherProperties = dictionary.allTokens.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) => {
// Remove consecutive repeated words from the token name, like border-border-color
const propName = removeConsecutiveRepeatedWords(prop.name);

switch (prop.$type) {
case 'boxShadow':
return generateShadowValue(prop, propName);
case 'fontFamilies':
return generateFontFamilyValue(prop, propName, 'scss');
case 'fontSizes':
return generateFontSizeValue(prop, propName, 'scss');
case 'typography':
return generateTypographyOutput(prop, propName, true);
default:
return generateValue(prop, propName);
}
});

const fileHeader = await file.options.fileHeader();
return [
`/*\n${fileHeader.join('\n')}\n*/`,
'@use "../themes/functions.sizes" as font;\n',
prefixedVariables.join('\n') + '\n',
].join('\n');
// Separate typography tokens from the rest
const typographyProperties = dictionary.allTokens.filter((prop) => prop.$type === 'typography');
const otherProperties = dictionary.allTokens.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) => {
// Remove consecutive repeated words from the token name, like border-border-color
const propName = removeConsecutiveRepeatedWords(prop.name);

switch (prop.$type) {
case 'boxShadow':
return generateShadowValue(prop, propName);
case 'fontFamilies':
return generateFontFamilyValue(prop, propName, 'scss');
case 'fontSizes':
return generateFontSizeValue(prop, propName, 'scss');
case 'typography':
return generateTypographyOutput(prop, propName, true);
default:
return generateValue(prop, propName);
}
});

const fileHeader = await file.options.fileHeader();

return [
`/*\n${fileHeader.join('\n')}\n*/`,
'@use "../themes/functions.sizes" as font;\n',
prefixedVariables.join('\n') + '\n',
].join('\n');
},
});

// Create utility-classes
StyleDictionary.registerFormat({
name: 'cssUtilityClassesFormat',
format: async function({ dictionary, file}) {

console.log('Generating Utility-Classes...');

// Arrays to store specific utility classes
const typographyUtilityClasses = [];
const otherUtilityClasses = [];

// Generate utility classes for each token
dictionary.allTokens.map((prop) => {

const tokenCategory = prop.attributes.category;

if (prop.$type === 'fontFamilies' || tokenCategory === 'scale' || tokenCategory === 'backdrop') {
// Not creating for the tokens below, as they make no sense to exist as utility-classes.
return;
}

// Remove consecutive repeated words from the token name, like border-border-color
const propName = removeConsecutiveRepeatedWords(prop.name);

if (prop.$type === 'typography') {
// Typography tokens are handled differently, as each might have a different tokenType
return typographyUtilityClasses.push(generateTypographyOutput(prop, propName, false));

} else if(tokenCategory.startsWith('round') || tokenCategory.startsWith('rectangular') || tokenCategory.startsWith('soft')) {
// Generate utility classes for border-radius shape tokens, as they have their own token json file, based on primitive tokens
return otherUtilityClasses.push(generateRadiusUtilityClasses(propName));

}

let utilityClass = '';

switch (tokenCategory) {
case 'color':
case 'primitives':
case 'semantics':
case 'text':
case 'bg':
case 'icon':
case 'state':
utilityClass = generateColorUtilityClasses(prop, propName);
break;
case 'border-size':
utilityClass = generateBorderSizeUtilityClasses(propName);
break;
case 'font':
utilityClass = generateFontUtilityClasses(prop, propName);
break;
case 'space':
utilityClass = generateSpaceUtilityClasses(prop, propName);
break;
case 'shadow':
case 'elevation':
utilityClass = generateShadowUtilityClasses(propName);
break;
default:
utilityClass = generateUtilityClasses(tokenCategory, propName);
}

return otherUtilityClasses.push(utilityClass);
});

// Concatenate typography utility classes at the beginning
const finalOutput = typographyUtilityClasses.concat(otherUtilityClasses).join('\n');

const fileHeader = await file.options.fileHeader();

return [
`/*\n${fileHeader.join('\n')}\n*/`,
'@import "./ionic.vars";\n@import "../themes/mixins";\n',
finalOutput,
].join('\n');
format: async function ({ dictionary, file }) {

console.log('Generating Utility-Classes...');

// Arrays to store specific utility classes
const typographyUtilityClasses = [];
const otherUtilityClasses = [];

// Generate utility classes for each token
dictionary.allTokens.map((prop) => {

const tokenCategory = prop.attributes.category;

if (prop.$type === 'fontFamilies' || tokenCategory === 'scale' || tokenCategory === 'backdrop') {
// Not creating for the tokens below, as they make no sense to exist as utility-classes.
return;
}

// Remove consecutive repeated words from the token name, like border-border-color
const propName = removeConsecutiveRepeatedWords(prop.name);

if (prop.$type === 'typography') {
// Typography tokens are handled differently, as each might have a different tokenType
return typographyUtilityClasses.push(generateTypographyOutput(prop, propName, false));

} else if (tokenCategory.startsWith('round') || tokenCategory.startsWith('rectangular') || tokenCategory.startsWith('soft')) {
// Generate utility classes for border-radius shape tokens, as they have their own token json file, based on primitive tokens
return otherUtilityClasses.push(generateRadiusUtilityClasses(propName));
}

let utilityClass = '';

switch (tokenCategory) {
case 'color':
case 'primitives':
case 'semantics':
case 'text':
case 'bg':
case 'icon':
case 'state':
utilityClass = generateColorUtilityClasses(prop, propName);
break;
case 'border-size':
utilityClass = generateBorderSizeUtilityClasses(propName);
break;
case 'font':
utilityClass = generateFontUtilityClasses(prop, propName);
break;
case 'space':
utilityClass = generateSpaceUtilityClasses(prop, propName);
break;
case 'shadow':
case 'elevation':
utilityClass = generateShadowUtilityClasses(propName);
break;
default:
utilityClass = generateUtilityClasses(tokenCategory, propName);
}

return otherUtilityClasses.push(utilityClass);
});

const defaultSpaceUtilityClasses = generateDefaultSpaceUtilityClasses();
otherUtilityClasses.push(defaultSpaceUtilityClasses);
Comment on lines +146 to +147
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These were the only lines added - the rest is formatting


// Concatenate typography utility classes at the beginning
const finalOutput = typographyUtilityClasses.concat(otherUtilityClasses).join('\n');

const fileHeader = await file.options.fileHeader();

return [
`/*\n${fileHeader.join('\n')}\n*/`,
'@import "./ionic.vars";\n@import "../themes/mixins";\n',
finalOutput,
].join('\n');
},
});

Expand All @@ -163,24 +166,24 @@ module.exports = {
source: ["node_modules/outsystems-design-tokens/tokens/**/*.json"],
platforms: {
scss: {
transformGroup: "scss",
buildPath: './src/foundations/',
files: [
{
destination: "ionic.vars.scss",
format: "scssVariablesFormat",
options: {
fileHeader: `custom-header`,
},
transformGroup: "scss",
buildPath: './src/foundations/',
files: [
{
destination: "ionic.vars.scss",
format: "scssVariablesFormat",
options: {
fileHeader: `custom-header`,
},
{
destination: "ionic.utility.scss",
format: "cssUtilityClassesFormat",
options: {
fileHeader: `custom-header`
}
},
{
destination: "ionic.utility.scss",
format: "cssUtilityClassesFormat",
options: {
fileHeader: `custom-header`
}
]
}
]
}
}
};
68 changes: 68 additions & 0 deletions core/scripts/tokens/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,73 @@ function generateColorUtilityClasses(prop, className) {
.${variablesPrefix}-background-${className} {\n background-color: $${variablesPrefix}-${prop.name};\n}`;
}

// Generates margin and padding utility classes to match the token-agnostic
// utilities provided by the Ionic Framework
function generateDefaultSpaceUtilityClasses() {
const zeroMarginPaddingToken = 'space-0';
const defaultMarginPaddingToken = 'space-400';

const marginPaddingTemplate = (type) => `
.${variablesPrefix}-no-${type} {
--${type}-top: #{$${variablesPrefix}-${zeroMarginPaddingToken}};
--${type}-end: #{$${variablesPrefix}-${zeroMarginPaddingToken}};
--${type}-bottom: #{$${variablesPrefix}-${zeroMarginPaddingToken}};
--${type}-start: #{$${variablesPrefix}-${zeroMarginPaddingToken}};

@include ${type}($${variablesPrefix}-${zeroMarginPaddingToken});
};

.${variablesPrefix}-${type} {
--${type}-top: #{$${variablesPrefix}-${defaultMarginPaddingToken}};
--${type}-end: #{$${variablesPrefix}-${defaultMarginPaddingToken}};
--${type}-bottom: #{$${variablesPrefix}-${defaultMarginPaddingToken}};
--${type}-start: #{$${variablesPrefix}-${defaultMarginPaddingToken}};

@include ${type}($${variablesPrefix}-${defaultMarginPaddingToken});
};

.${variablesPrefix}-${type}-top {
--${type}-top: #{$${variablesPrefix}-${defaultMarginPaddingToken}};

@include ${type}($${variablesPrefix}-${defaultMarginPaddingToken}, null, null, null);
};

.${variablesPrefix}-${type}-end {
--${type}-end: #{$${variablesPrefix}-${defaultMarginPaddingToken}};

@include ${type}(null, $${variablesPrefix}-${defaultMarginPaddingToken}, null, null);
};

.${variablesPrefix}-${type}-bottom {
--${type}-bottom: #{$${variablesPrefix}-${defaultMarginPaddingToken}};

@include ${type}(null, null, $${variablesPrefix}-${defaultMarginPaddingToken}, null);
};

.${variablesPrefix}-${type}-start {
--${type}-start: #{$${variablesPrefix}-${defaultMarginPaddingToken}};

@include ${type}(null, null, null, $${variablesPrefix}-${defaultMarginPaddingToken});
};

.${variablesPrefix}-${type}-vertical {
--${type}-top: #{$${variablesPrefix}-${defaultMarginPaddingToken}};
--${type}-bottom: #{$${variablesPrefix}-${defaultMarginPaddingToken}};

@include ${type}($${variablesPrefix}-${defaultMarginPaddingToken}, null, $${variablesPrefix}-${defaultMarginPaddingToken}, null);
};

.${variablesPrefix}-${type}-horizontal {
--${type}-start: #{$${variablesPrefix}-${defaultMarginPaddingToken}};
--${type}-end: #{$${variablesPrefix}-${defaultMarginPaddingToken}};

@include ${type}(null, $${variablesPrefix}-${defaultMarginPaddingToken}, null, $${variablesPrefix}-${defaultMarginPaddingToken});
};
`;

return `${marginPaddingTemplate('margin')}\n${marginPaddingTemplate('padding')}`;
}

// 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
Expand Down Expand Up @@ -203,6 +270,7 @@ module.exports = {
setPrefixValue,
generateRadiusUtilityClasses,
generateColorUtilityClasses,
generateDefaultSpaceUtilityClasses,
generateSpaceUtilityClasses,
removeConsecutiveRepeatedWords,
generateBorderSizeUtilityClasses,
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading