Compare commits
16 Commits
test-layou
...
ionic-colo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
36dfc50fa3 | ||
|
|
3b93bb4a9b | ||
|
|
b4ce7129b2 | ||
|
|
1ded2c5191 | ||
|
|
c8679f8b1b | ||
|
|
6f089c0536 | ||
|
|
7f8be3e18c | ||
|
|
fea59b73aa | ||
|
|
b9af47ae0d | ||
|
|
b21f95cced | ||
|
|
1c035af1a2 | ||
|
|
258dabfb9e | ||
|
|
15f8c55046 | ||
|
|
5c0b5c32d0 | ||
|
|
888b0c8284 | ||
|
|
b6325e49be |
@@ -15,6 +15,7 @@ ignoreFiles:
|
||||
- src/themes/functions.string.scss
|
||||
- src/themes/native.theme.default.scss
|
||||
- src/css/themes/*.scss
|
||||
- scripts/tokens/*.css
|
||||
|
||||
indentation: 2
|
||||
|
||||
|
||||
@@ -184,6 +184,7 @@ ion-app,prop,theme,"ios" | "md" | "ionic",undefined,false,false
|
||||
|
||||
ion-avatar,shadow
|
||||
ion-avatar,prop,mode,"ios" | "md",undefined,false,false
|
||||
ion-avatar,prop,size,"large" | "medium" | "small" | "xsmall" | undefined,undefined,false,false
|
||||
ion-avatar,prop,theme,"ios" | "md" | "ionic",undefined,false,false
|
||||
ion-avatar,css-prop,--border-radius,ionic
|
||||
ion-avatar,css-prop,--border-radius,ios
|
||||
@@ -310,6 +311,7 @@ ion-backdrop,event,ionBackdropTap,void,true
|
||||
ion-badge,shadow
|
||||
ion-badge,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
|
||||
ion-badge,prop,mode,"ios" | "md",undefined,false,false
|
||||
ion-badge,prop,size,"large" | "medium" | "small" | "xlarge" | undefined,undefined,false,false
|
||||
ion-badge,prop,theme,"ios" | "md" | "ionic",undefined,false,false
|
||||
ion-badge,css-prop,--background,ionic
|
||||
ion-badge,css-prop,--background,ios
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
"build.css": "npm run css.sass && npm run css.minify",
|
||||
"build.debug": "npm run clean && stencil build --debug",
|
||||
"build.docs.json": "stencil build --docs-json dist/docs.json",
|
||||
"build.tokens": "node ./scripts/tokens.js && npm run lint.sass.fix && npm run prettier.tokens",
|
||||
"build.tokens": "node ./scripts/tokens/index.js && npm run lint.fix && npm run prettier.tokens",
|
||||
"clean": "node scripts/clean.js",
|
||||
"css.minify": "cleancss -O2 -o ./css/ionic.bundle.css ./css/ionic.bundle.css",
|
||||
"css.sass": "sass --embed-sources --style compressed src/css:./css",
|
||||
@@ -90,7 +90,7 @@
|
||||
"lint.ts.fix": "npm run eslint -- --fix",
|
||||
"prerender.e2e": "node scripts/testing/prerender.js",
|
||||
"prettier": "prettier \"./src/**/*.{html,ts,tsx,js,jsx,scss}\"",
|
||||
"prettier.tokens": "prettier \"./src/foundations/*.scss\" --write --cache",
|
||||
"prettier.tokens": "prettier \"./src/foundations/*.{scss, html}\" --write --cache",
|
||||
"start": "npm run build.css && stencil build --dev --watch --serve",
|
||||
"test": "npm run test.spec && npm run test.e2e",
|
||||
"test.spec": "stencil test --spec --max-workers=2",
|
||||
|
||||
@@ -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();
|
||||
362
core/scripts/tokens/index.js
Normal file
@@ -0,0 +1,362 @@
|
||||
/* 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 fs = require('fs');
|
||||
const path = require('path');
|
||||
const StyleDictionary = require('style-dictionary');
|
||||
|
||||
const targetPath = './src/foundations/';
|
||||
|
||||
const {
|
||||
variablesPrefix,
|
||||
getRgbaValue,
|
||||
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 {
|
||||
const rgb = hexToRgb(prop.value);
|
||||
prop.value = getRgbaValue(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');
|
||||
},
|
||||
});
|
||||
|
||||
// Register the custom format to generate HTML
|
||||
// Load the HTML template
|
||||
const template = fs.readFileSync(path.join(__dirname, 'preview.template.html'), 'utf8');
|
||||
|
||||
StyleDictionary.registerFormat({
|
||||
name: 'html/tokens',
|
||||
formatter: function ({ dictionary }) {
|
||||
// Function to extract numerical value from token name
|
||||
const extractValue = (tokenName) => {
|
||||
const match = tokenName.match(/-([0-9]+)/);
|
||||
return match ? parseInt(match[1], 10) : Number.MAX_SAFE_INTEGER;
|
||||
};
|
||||
|
||||
let colorTokens = `
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Color</th>
|
||||
<th>Hex</th>
|
||||
<th>Token Name</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
`;
|
||||
let fontSizeTokens = '';
|
||||
let boxShadowTokens = '';
|
||||
let borderSizeTokens = '';
|
||||
let borderRadiusTokens = '';
|
||||
let borderStyleTokens = '';
|
||||
let fontWeightTokens = '';
|
||||
let letterSpacingTokens = '';
|
||||
let spaceTokens = '';
|
||||
|
||||
// Collect border-radius and space tokens for separate sorting
|
||||
let borderRadiusTokenList = [];
|
||||
let spaceTokenList = [];
|
||||
|
||||
dictionary.allProperties.forEach((token) => {
|
||||
if (token.attributes.category === 'color') {
|
||||
colorTokens += `
|
||||
<tr>
|
||||
<td><div class="color-swatch" style="background-color: ${token.value};"></div></td>
|
||||
<td>${token.value}</td>
|
||||
<td>${token.name}</td>
|
||||
</tr>
|
||||
`;
|
||||
} else if (token.attributes.category === 'font-size') {
|
||||
fontSizeTokens += `
|
||||
<div class="font-size-token" style="font-size: ${token.value};">
|
||||
${token.name} (${token.value})
|
||||
</div>
|
||||
`;
|
||||
} else if (token.attributes.category.startsWith('Elevation')) {
|
||||
const cssShadow = token.value.map(generateShadowValue).join(', ');
|
||||
boxShadowTokens += `
|
||||
<div class="shadow-token" style="box-shadow: ${cssShadow};">
|
||||
${token.name}
|
||||
</div>
|
||||
`;
|
||||
} else if (token.attributes.category === 'border-size' || token.attributes.category === 'border-width') {
|
||||
borderSizeTokens += `
|
||||
<div class="border-token" style="border-width: ${token.value};">
|
||||
${token.name} (${token.value})
|
||||
</div>
|
||||
`;
|
||||
} else if (token.attributes.category === 'border-radius') {
|
||||
borderRadiusTokenList.push(token); // Collect border-radius tokens
|
||||
} else if (token.attributes.category === 'border-style') {
|
||||
borderStyleTokens += `
|
||||
<div class="border-token" style="border: 1px ${token.value} #000;">
|
||||
${token.name} (${token.value})
|
||||
</div>
|
||||
`;
|
||||
} else if (token.attributes.category === 'font-weight') {
|
||||
fontWeightTokens += `
|
||||
<div class="weight-token" style="font-weight: ${token.value};">
|
||||
${token.name} (${token.value})
|
||||
</div>
|
||||
`;
|
||||
} else if (token.attributes.category === 'letter-spacing') {
|
||||
// Convert % to px
|
||||
const letterSpacingValue = token.value.replace('%', '') + 'px';
|
||||
letterSpacingTokens += `
|
||||
<div class="letter-spacing-token" style="letter-spacing: ${letterSpacingValue};">
|
||||
${token.name} (${letterSpacingValue})
|
||||
</div>
|
||||
`;
|
||||
} else if (token.attributes.category === 'space') {
|
||||
spaceTokenList.push(token); // Collect space tokens
|
||||
}
|
||||
});
|
||||
|
||||
// Sort border-radius and space tokens
|
||||
borderRadiusTokenList.sort((a, b) => extractValue(a.name) - extractValue(b.name));
|
||||
spaceTokenList.sort((a, b) => extractValue(a.name) - extractValue(b.name));
|
||||
|
||||
// Generate HTML for sorted border-radius tokens
|
||||
borderRadiusTokenList.forEach((token) => {
|
||||
borderRadiusTokens += `
|
||||
<div class="border-token" style="border-radius: ${token.value};">
|
||||
${token.name} (${token.value})
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
|
||||
// Generate HTML for sorted space tokens
|
||||
spaceTokenList.forEach((token) => {
|
||||
spaceTokens += `
|
||||
<div class="spacing-wrapper">
|
||||
<div class="space-token" style="margin: ${token.value};">
|
||||
${token.name} (${token.value})
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
|
||||
colorTokens += '</tbody></table>';
|
||||
|
||||
return template
|
||||
.replace('{{colorTokens}}', colorTokens)
|
||||
.replace('{{fontSizeTokens}}', fontSizeTokens)
|
||||
.replace('{{boxShadowTokens}}', boxShadowTokens)
|
||||
.replace('{{borderSizeTokens}}', borderSizeTokens)
|
||||
.replace('{{borderRadiusTokens}}', borderRadiusTokens)
|
||||
.replace('{{borderStyleTokens}}', borderStyleTokens)
|
||||
.replace('{{fontWeightTokens}}', fontWeightTokens)
|
||||
.replace('{{letterSpacingTokens}}', letterSpacingTokens)
|
||||
.replace('{{spaceTokens}}', spaceTokens);
|
||||
},
|
||||
});
|
||||
|
||||
// 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`,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
html: {
|
||||
transformGroup: 'custom',
|
||||
buildPath: targetPath,
|
||||
files: [
|
||||
{
|
||||
destination: 'tokens.preview.html',
|
||||
format: 'html/tokens',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
fileHeader: {
|
||||
myFileHeader: () => {
|
||||
return [`This is an auto-generated file, please do not change it directly.`, `Ionic Design System`];
|
||||
},
|
||||
},
|
||||
}).buildAllPlatforms();
|
||||
63
core/scripts/tokens/preview.styles.css
Normal file
@@ -0,0 +1,63 @@
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
padding: 10px;
|
||||
border: 1px solid #ccc;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
|
||||
thead th {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
background-color: #f4f4f4;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.color-swatch {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.font-size-token,
|
||||
.weight-token,
|
||||
.letter-spacing-token {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.border-token,
|
||||
.shadow-token {
|
||||
margin: 10px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.border-token {
|
||||
border: 1px solid #000;
|
||||
}
|
||||
|
||||
.spacing-wrapper {
|
||||
background-color: lightblue;
|
||||
}
|
||||
|
||||
.spacing-wrapper > div {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.token-wrapper:has(.spacing-wrapper) {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
hr {
|
||||
background-color: #ccc;
|
||||
margin: 20px 0;
|
||||
}
|
||||
52
core/scripts/tokens/preview.template.html
Normal file
@@ -0,0 +1,52 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
|
||||
/>
|
||||
<title>Design Tokens</title>
|
||||
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet" />
|
||||
<script nomodule src="../../../../../dist/ionic/ionic.js"></script>
|
||||
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
|
||||
<link rel="stylesheet" href="../../scripts/tokens/preview.styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<ion-app>
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Design Tokens - Preview</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content class="ion-padding-horizontal">
|
||||
<h1>Color Tokens</h1>
|
||||
<div class="token-wrapper">{{colorTokens}}</div>
|
||||
<hr />
|
||||
<h1>Font Size Tokens</h1>
|
||||
<div class="token-wrapper">{{fontSizeTokens}}</div>
|
||||
<hr />
|
||||
<h1>Font Weight Tokens</h1>
|
||||
<div class="token-wrapper">{{fontWeightTokens}}</div>
|
||||
<hr />
|
||||
<h1>Letter Spacing Tokens</h1>
|
||||
<div class="token-wrapper">{{letterSpacingTokens}}</div>
|
||||
<hr />
|
||||
<h1>Box Shadow Tokens</h1>
|
||||
<div class="token-wrapper">{{boxShadowTokens}}</div>
|
||||
<hr />
|
||||
<h1>Border Size Tokens</h1>
|
||||
<div class="token-wrapper">{{borderSizeTokens}}</div>
|
||||
<hr />
|
||||
<h1>Border Radius Tokens</h1>
|
||||
<div class="token-wrapper">{{borderRadiusTokens}}</div>
|
||||
<hr />
|
||||
<h1>Border Style Tokens</h1>
|
||||
<div class="token-wrapper">{{borderStyleTokens}}</div>
|
||||
<hr />
|
||||
<h1>Space Tokens</h1>
|
||||
<div class="token-wrapper">{{spaceTokens}}</div>
|
||||
</ion-content>
|
||||
</ion-app>
|
||||
</body>
|
||||
</html>
|
||||
179
core/scripts/tokens/utilities.js
Normal file
@@ -0,0 +1,179 @@
|
||||
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-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 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');
|
||||
|
||||
// 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: $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,
|
||||
generateFontFamilyValue,
|
||||
generateTypographyValue,
|
||||
generateRgbValue: generateValue,
|
||||
generateColorUtilityClasses,
|
||||
generateFontUtilityClass,
|
||||
generateSpaceUtilityClasses,
|
||||
generateTypographyUtilityClass,
|
||||
};
|
||||
16
core/src/components.d.ts
vendored
@@ -335,6 +335,10 @@ export namespace Components {
|
||||
* The mode determines the platform behaviors of the component.
|
||||
*/
|
||||
"mode"?: "ios" | "md";
|
||||
/**
|
||||
* Set to `"xsmall"` for the smallest size, `"small"` for a compact size, `"medium"` for the default height and width, or to `"large"` for a larger size. Defaults to `"medium"` for the `ionic` theme, undefined for all other themes.
|
||||
*/
|
||||
"size"?: `xsmall` | 'small' | 'medium' | 'large';
|
||||
/**
|
||||
* The theme determines the visual appearance of the component.
|
||||
*/
|
||||
@@ -409,6 +413,10 @@ export namespace Components {
|
||||
* The mode determines the platform behaviors of the component.
|
||||
*/
|
||||
"mode"?: "ios" | "md";
|
||||
/**
|
||||
* Set to `"small"` for less height and width. Set to "medium" for slightly larger dimensions. Set to "large" for even greater height and width. Set to `"xlarge"` for the largest badge. Defaults to `"small"` for the `ionic` theme, undefined for all other themes.
|
||||
*/
|
||||
"size"?: 'small' | 'medium' | 'large' | 'xlarge';
|
||||
/**
|
||||
* The theme determines the visual appearance of the component.
|
||||
*/
|
||||
@@ -5559,6 +5567,10 @@ declare namespace LocalJSX {
|
||||
* The mode determines the platform behaviors of the component.
|
||||
*/
|
||||
"mode"?: "ios" | "md";
|
||||
/**
|
||||
* Set to `"xsmall"` for the smallest size, `"small"` for a compact size, `"medium"` for the default height and width, or to `"large"` for a larger size. Defaults to `"medium"` for the `ionic` theme, undefined for all other themes.
|
||||
*/
|
||||
"size"?: `xsmall` | 'small' | 'medium' | 'large';
|
||||
/**
|
||||
* The theme determines the visual appearance of the component.
|
||||
*/
|
||||
@@ -5637,6 +5649,10 @@ declare namespace LocalJSX {
|
||||
* The mode determines the platform behaviors of the component.
|
||||
*/
|
||||
"mode"?: "ios" | "md";
|
||||
/**
|
||||
* Set to `"small"` for less height and width. Set to "medium" for slightly larger dimensions. Set to "large" for even greater height and width. Set to `"xlarge"` for the largest badge. Defaults to `"small"` for the `ionic` theme, undefined for all other themes.
|
||||
*/
|
||||
"size"?: 'small' | 'medium' | 'large' | 'xlarge';
|
||||
/**
|
||||
* The theme determines the visual appearance of the component.
|
||||
*/
|
||||
|
||||
73
core/src/components/avatar/avatar.ionic.scss
Normal file
@@ -0,0 +1,73 @@
|
||||
@use "../../themes/ionic/ionic.globals.scss" as globals;
|
||||
@import "./avatar";
|
||||
|
||||
// Ionic Avatar
|
||||
// --------------------------------------------------
|
||||
|
||||
:host {
|
||||
--padding-top: #{globals.$ionic-space-0};
|
||||
--padding-bottom: #{globals.$ionic-space-0};
|
||||
|
||||
display: flex;
|
||||
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
background: globals.$ionic-color-neutral-100;
|
||||
color: globals.$ionic-color-neutral-800;
|
||||
|
||||
font-weight: globals.$ionic-font-weight-regular;
|
||||
|
||||
line-height: globals.$ionic-line-height-600;
|
||||
}
|
||||
|
||||
:host(:not(.avatar-image)) {
|
||||
border: globals.$ionic-border-size-025 solid globals.$ionic-color-neutral-800;
|
||||
}
|
||||
|
||||
// Avatar Sizes
|
||||
// --------------------------------------------------
|
||||
|
||||
:host(.avatar-xsmall) {
|
||||
--padding-end: #{globals.$ionic-space-050};
|
||||
--padding-start: #{globals.$ionic-space-050};
|
||||
|
||||
width: globals.$ionic-scale-600;
|
||||
height: globals.$ionic-scale-600;
|
||||
|
||||
font-size: globals.$ionic-font-size-300;
|
||||
|
||||
font-weight: globals.$ionic-font-weight-medium;
|
||||
|
||||
line-height: globals.$ionic-line-height-500;
|
||||
}
|
||||
|
||||
:host(.avatar-small) {
|
||||
--padding-end: #{globals.$ionic-space-150};
|
||||
--padding-start: #{globals.$ionic-space-150};
|
||||
|
||||
width: globals.$ionic-scale-800;
|
||||
height: globals.$ionic-scale-800;
|
||||
|
||||
font-size: globals.$ionic-font-size-350;
|
||||
}
|
||||
|
||||
:host(.avatar-medium) {
|
||||
--padding-end: #{globals.$ionic-space-200};
|
||||
--padding-start: #{globals.$ionic-space-200};
|
||||
|
||||
width: globals.$ionic-scale-1000;
|
||||
height: globals.$ionic-scale-1000;
|
||||
|
||||
font-size: globals.$ionic-font-size-400;
|
||||
}
|
||||
|
||||
:host(.avatar-large) {
|
||||
--padding-end: #{globals.$ionic-space-250};
|
||||
--padding-start: #{globals.$ionic-space-250};
|
||||
|
||||
width: globals.$ionic-scale-1200;
|
||||
height: globals.$ionic-scale-1200;
|
||||
|
||||
font-size: globals.$ionic-font-size-450;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { ComponentInterface } from '@stencil/core';
|
||||
import { Component, Host, h } from '@stencil/core';
|
||||
import { Component, Element, Host, Prop, h } from '@stencil/core';
|
||||
|
||||
import { getIonTheme } from '../../global/ionic-global';
|
||||
|
||||
@@ -12,17 +12,51 @@ import { getIonTheme } from '../../global/ionic-global';
|
||||
styleUrls: {
|
||||
ios: 'avatar.ios.scss',
|
||||
md: 'avatar.md.scss',
|
||||
ionic: 'avatar.md.scss',
|
||||
ionic: 'avatar.ionic.scss',
|
||||
},
|
||||
shadow: true,
|
||||
})
|
||||
export class Avatar implements ComponentInterface {
|
||||
@Element() el!: HTMLElement;
|
||||
|
||||
/**
|
||||
* Set to `"xsmall"` for the smallest size, `"small"` for a compact size, `"medium"`
|
||||
* for the default height and width, or to `"large"` for a larger size.
|
||||
*
|
||||
* Defaults to `"medium"` for the `ionic` theme, undefined for all other themes.
|
||||
*/
|
||||
@Prop() size?: `xsmall` | 'small' | 'medium' | 'large';
|
||||
|
||||
get hasImage() {
|
||||
return !!this.el.querySelector('ion-img') || !!this.el.querySelector('img');
|
||||
}
|
||||
|
||||
private getSize(): string | undefined {
|
||||
const theme = getIonTheme(this);
|
||||
const { size } = this;
|
||||
|
||||
// TODO(ROU-10752): Remove theme check when sizes are defined for all themes.
|
||||
if (theme !== 'ionic') {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (size === undefined) {
|
||||
return 'medium';
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
render() {
|
||||
const theme = getIonTheme(this);
|
||||
const size = this.getSize();
|
||||
|
||||
return (
|
||||
<Host
|
||||
class={{
|
||||
[theme]: true,
|
||||
[`avatar-${size}`]: size !== undefined,
|
||||
[`avatar-image`]: this.hasImage,
|
||||
}}
|
||||
>
|
||||
<slot></slot>
|
||||
|
||||
189
core/src/components/avatar/test/size/avatar.e2e.ts
Normal file
@@ -0,0 +1,189 @@
|
||||
import { expect } from '@playwright/test';
|
||||
import { configs, test } from '@utils/test/playwright';
|
||||
|
||||
/**
|
||||
* This behavior does not vary across directions.
|
||||
*/
|
||||
configs({ directions: ['ltr'], modes: ['ionic-md'] }).forEach(({ config, screenshot, title }) => {
|
||||
test.describe(title('avatar: size'), () => {
|
||||
test.describe('xsmall', () => {
|
||||
test('should not have visual regressions when containing text', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-avatar size="xsmall">AB</ion-avatar>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const avatar = page.locator('ion-avatar');
|
||||
|
||||
await expect(avatar).toHaveScreenshot(screenshot(`avatar-size-xsmall-text`));
|
||||
});
|
||||
|
||||
test('should not have visual regressions when containing an icon', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-avatar size="xsmall">
|
||||
<ion-icon name="person-outline"></ion-icon>
|
||||
</ion-avatar>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const avatar = page.locator('ion-avatar');
|
||||
|
||||
await expect(avatar).toHaveScreenshot(screenshot(`avatar-size-xsmall-icon`));
|
||||
});
|
||||
|
||||
test('should not have visual regressions when containing an image', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-avatar size="xsmall">
|
||||
<img src="/src/components/avatar/test/avatar.svg"/>
|
||||
</ion-avatar>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const avatar = page.locator('ion-avatar');
|
||||
|
||||
await expect(avatar).toHaveScreenshot(screenshot(`avatar-size-xsmall-image`));
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('small', () => {
|
||||
test('should not have visual regressions when containing text', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-avatar size="small">AB</ion-avatar>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const avatar = page.locator('ion-avatar');
|
||||
|
||||
await expect(avatar).toHaveScreenshot(screenshot(`avatar-size-small-text`));
|
||||
});
|
||||
|
||||
test('should not have visual regressions when containing an icon', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-avatar size="small">
|
||||
<ion-icon name="person-outline"></ion-icon>
|
||||
</ion-avatar>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const avatar = page.locator('ion-avatar');
|
||||
|
||||
await expect(avatar).toHaveScreenshot(screenshot(`avatar-size-small-icon`));
|
||||
});
|
||||
|
||||
test('should not have visual regressions when containing an image', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-avatar size="small">
|
||||
<img src="/src/components/avatar/test/avatar.svg"/>
|
||||
</ion-avatar>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const avatar = page.locator('ion-avatar');
|
||||
|
||||
await expect(avatar).toHaveScreenshot(screenshot(`avatar-size-small-image`));
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('medium', () => {
|
||||
test('should not have visual regressions when containing text', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-avatar size="medium">AB</ion-avatar>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const avatar = page.locator('ion-avatar');
|
||||
|
||||
await expect(avatar).toHaveScreenshot(screenshot(`avatar-size-medium-text`));
|
||||
});
|
||||
|
||||
test('should not have visual regressions when containing an icon', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-avatar size="medium">
|
||||
<ion-icon name="person-outline"></ion-icon>
|
||||
</ion-avatar>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const avatar = page.locator('ion-avatar');
|
||||
|
||||
await expect(avatar).toHaveScreenshot(screenshot(`avatar-size-medium-icon`));
|
||||
});
|
||||
|
||||
test('should not have visual regressions when containing an image', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-avatar size="medium">
|
||||
<img src="/src/components/avatar/test/avatar.svg"/>
|
||||
</ion-avatar>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const avatar = page.locator('ion-avatar');
|
||||
|
||||
await expect(avatar).toHaveScreenshot(screenshot(`avatar-size-medium-image`));
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('large', () => {
|
||||
test('should not have visual regressions when containing text', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-avatar size="large">AB</ion-avatar>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const avatar = page.locator('ion-avatar');
|
||||
|
||||
await expect(avatar).toHaveScreenshot(screenshot(`avatar-size-large-text`));
|
||||
});
|
||||
|
||||
test('should not have visual regressions when containing an icon', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-avatar size="large">
|
||||
<ion-icon name="person-outline"></ion-icon>
|
||||
</ion-avatar>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const avatar = page.locator('ion-avatar');
|
||||
|
||||
await expect(avatar).toHaveScreenshot(screenshot(`avatar-size-large-icon`));
|
||||
});
|
||||
|
||||
test('should not have visual regressions when containing an image', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-avatar size="large">
|
||||
<img src="/src/components/avatar/test/avatar.svg"/>
|
||||
</ion-avatar>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const avatar = page.locator('ion-avatar');
|
||||
|
||||
await expect(avatar).toHaveScreenshot(screenshot(`avatar-size-large-image`));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
After Width: | Height: | Size: 652 B |
|
After Width: | Height: | Size: 578 B |
|
After Width: | Height: | Size: 592 B |
|
After Width: | Height: | Size: 740 B |
|
After Width: | Height: | Size: 688 B |
|
After Width: | Height: | Size: 728 B |
|
After Width: | Height: | Size: 798 B |
|
After Width: | Height: | Size: 819 B |
|
After Width: | Height: | Size: 721 B |
|
After Width: | Height: | Size: 540 B |
|
After Width: | Height: | Size: 521 B |
|
After Width: | Height: | Size: 500 B |
|
After Width: | Height: | Size: 627 B |
|
After Width: | Height: | Size: 585 B |
|
After Width: | Height: | Size: 624 B |
|
After Width: | Height: | Size: 695 B |
|
After Width: | Height: | Size: 717 B |
|
After Width: | Height: | Size: 637 B |
|
After Width: | Height: | Size: 465 B |
|
After Width: | Height: | Size: 460 B |
|
After Width: | Height: | Size: 462 B |
|
After Width: | Height: | Size: 501 B |
|
After Width: | Height: | Size: 481 B |
|
After Width: | Height: | Size: 480 B |
|
After Width: | Height: | Size: 586 B |
|
After Width: | Height: | Size: 590 B |
|
After Width: | Height: | Size: 562 B |
|
After Width: | Height: | Size: 390 B |
|
After Width: | Height: | Size: 396 B |
|
After Width: | Height: | Size: 384 B |
|
After Width: | Height: | Size: 438 B |
|
After Width: | Height: | Size: 376 B |
|
After Width: | Height: | Size: 418 B |
|
After Width: | Height: | Size: 490 B |
|
After Width: | Height: | Size: 525 B |
|
After Width: | Height: | Size: 456 B |
86
core/src/components/avatar/test/size/index.html
Normal file
@@ -0,0 +1,86 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" dir="ltr">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Avatar - Size</title>
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
|
||||
/>
|
||||
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet" />
|
||||
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet" />
|
||||
<script src="../../../../../scripts/testing/scripts.js"></script>
|
||||
<script nomodule src="../../../../../dist/ionic/ionic.js"></script>
|
||||
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
|
||||
|
||||
<style>
|
||||
.container {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<ion-app>
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Avatar - Size</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content class="ion-padding" id="content" no-bounce>
|
||||
<h2>Default</h2>
|
||||
<div class="container">
|
||||
<ion-avatar>AB</ion-avatar>
|
||||
<ion-avatar>
|
||||
<ion-icon name="person-outline"></ion-icon>
|
||||
</ion-avatar>
|
||||
<ion-avatar>
|
||||
<img src="/src/components/avatar/test/avatar.svg" />
|
||||
</ion-avatar>
|
||||
</div>
|
||||
|
||||
<h2>Text</h2>
|
||||
<div class="container">
|
||||
<ion-avatar size="xsmall">AB</ion-avatar>
|
||||
<ion-avatar size="small">AB</ion-avatar>
|
||||
<ion-avatar size="medium">AB</ion-avatar>
|
||||
<ion-avatar size="large">AB</ion-avatar>
|
||||
</div>
|
||||
|
||||
<h2>Icons</h2>
|
||||
<div class="container">
|
||||
<ion-avatar size="xsmall">
|
||||
<ion-icon name="person-outline"></ion-icon>
|
||||
</ion-avatar>
|
||||
<ion-avatar size="small">
|
||||
<ion-icon name="person-outline"></ion-icon>
|
||||
</ion-avatar>
|
||||
<ion-avatar size="medium">
|
||||
<ion-icon name="person-outline"></ion-icon>
|
||||
</ion-avatar>
|
||||
<ion-avatar size="large">
|
||||
<ion-icon name="person-outline"></ion-icon>
|
||||
</ion-avatar>
|
||||
</div>
|
||||
|
||||
<h2>Images</h2>
|
||||
<div class="container">
|
||||
<ion-avatar size="xsmall">
|
||||
<img src="/src/components/avatar/test/avatar.svg" />
|
||||
</ion-avatar>
|
||||
<ion-avatar size="small">
|
||||
<img src="/src/components/avatar/test/avatar.svg" />
|
||||
</ion-avatar>
|
||||
<ion-avatar size="medium">
|
||||
<img src="/src/components/avatar/test/avatar.svg" />
|
||||
</ion-avatar>
|
||||
<ion-avatar size="large">
|
||||
<img src="/src/components/avatar/test/avatar.svg" />
|
||||
</ion-avatar>
|
||||
</div>
|
||||
</ion-content>
|
||||
</ion-app>
|
||||
</body>
|
||||
</html>
|
||||
68
core/src/components/badge/badge.ionic.scss
Normal file
@@ -0,0 +1,68 @@
|
||||
@use "../../themes/ionic/ionic.globals.scss" as globals;
|
||||
@import "./badge";
|
||||
|
||||
// Ionic Badge
|
||||
// --------------------------------------------------
|
||||
|
||||
:host {
|
||||
--padding-start: #{globals.$ionic-space-100};
|
||||
--padding-end: #{globals.$ionic-space-100};
|
||||
--padding-top: #{globals.$ionic-space-0};
|
||||
--padding-bottom: #{globals.$ionic-space-0};
|
||||
|
||||
display: inline-flex;
|
||||
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
font-weight: globals.$ionic-font-weight-medium;
|
||||
}
|
||||
|
||||
// Badge Sizes
|
||||
// --------------------------------------------------
|
||||
|
||||
/* Small Badge */
|
||||
:host(.badge-small) {
|
||||
min-width: globals.$ionic-scale-800;
|
||||
height: globals.$ionic-scale-800;
|
||||
|
||||
font-size: globals.$ionic-font-size-400;
|
||||
|
||||
line-height: globals.$ionic-line-height-600;
|
||||
}
|
||||
|
||||
/* Medium Badge */
|
||||
:host(.badge-medium) {
|
||||
min-width: globals.$ionic-scale-1000;
|
||||
height: globals.$ionic-scale-1000;
|
||||
|
||||
font-size: globals.$ionic-font-size-450;
|
||||
|
||||
line-height: globals.$ionic-line-height-700;
|
||||
}
|
||||
|
||||
/* Large Badge */
|
||||
:host(.badge-large) {
|
||||
--padding-start: #{globals.$ionic-space-200};
|
||||
--padding-end: #{globals.$ionic-space-200};
|
||||
|
||||
min-width: globals.$ionic-scale-1200;
|
||||
height: globals.$ionic-scale-1200;
|
||||
|
||||
font-size: globals.$ionic-font-size-500;
|
||||
|
||||
line-height: globals.$ionic-line-height-700;
|
||||
}
|
||||
|
||||
/* Extra Large Badge */
|
||||
:host(.badge-xlarge) {
|
||||
--padding-start: #{globals.$ionic-space-200};
|
||||
--padding-end: #{globals.$ionic-space-200};
|
||||
|
||||
min-width: globals.$ionic-scale-1400;
|
||||
height: globals.$ionic-scale-1400;
|
||||
|
||||
font-size: globals.$ionic-font-size-550;
|
||||
|
||||
line-height: globals.$ionic-line-height-700;
|
||||
}
|
||||
@@ -14,7 +14,7 @@ import type { Color } from '../../interface';
|
||||
styleUrls: {
|
||||
ios: 'badge.ios.scss',
|
||||
md: 'badge.md.scss',
|
||||
ionic: 'badge.md.scss',
|
||||
ionic: 'badge.ionic.scss',
|
||||
},
|
||||
shadow: true,
|
||||
})
|
||||
@@ -26,12 +26,36 @@ export class Badge implements ComponentInterface {
|
||||
*/
|
||||
@Prop({ reflect: true }) color?: Color;
|
||||
|
||||
/**
|
||||
* Set to `"small"` for less height and width. Set to "medium" for slightly larger dimensions. Set to "large" for even greater height and width. Set to `"xlarge"` for the largest badge.
|
||||
* Defaults to `"small"` for the `ionic` theme, undefined for all other themes.
|
||||
*/
|
||||
@Prop() size?: 'small' | 'medium' | 'large' | 'xlarge';
|
||||
|
||||
private getSize(): string | undefined {
|
||||
const theme = getIonTheme(this);
|
||||
const { size } = this;
|
||||
|
||||
// TODO(ROU-10747): Remove theme check when sizes are defined for all themes.
|
||||
if (theme !== 'ionic') {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (size === undefined) {
|
||||
return 'small';
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
render() {
|
||||
const size = this.getSize();
|
||||
const theme = getIonTheme(this);
|
||||
return (
|
||||
<Host
|
||||
class={createColorClasses(this.color, {
|
||||
[theme]: true,
|
||||
[`badge-${size}`]: size !== undefined,
|
||||
})}
|
||||
>
|
||||
<slot></slot>
|
||||
|
||||
61
core/src/components/badge/test/size/badge.e2e.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { expect } from '@playwright/test';
|
||||
import { configs, test } from '@utils/test/playwright';
|
||||
|
||||
/**
|
||||
* This behavior does not vary across directions.
|
||||
*/
|
||||
configs({ directions: ['ltr'], modes: ['ionic-md'] }).forEach(({ config, screenshot, title }) => {
|
||||
test.describe(title('badge: size'), () => {
|
||||
test('should render small badges', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-badge size="small">00</ion-badge>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const badge = page.locator('ion-badge');
|
||||
|
||||
await expect(badge).toHaveScreenshot(screenshot(`badge-size-small`));
|
||||
});
|
||||
|
||||
test('should render medium badges', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-badge size="medium">00</ion-badge>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const badge = page.locator('ion-badge');
|
||||
|
||||
await expect(badge).toHaveScreenshot(screenshot(`badge-size-medium`));
|
||||
});
|
||||
|
||||
test('should render large badges', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-badge size="large">00</ion-badge>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const badge = page.locator('ion-badge');
|
||||
|
||||
await expect(badge).toHaveScreenshot(screenshot(`badge-size-large`));
|
||||
});
|
||||
|
||||
test('should render xlarge badges', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-badge size="xlarge">00</ion-badge>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const badge = page.locator('ion-badge');
|
||||
|
||||
await expect(badge).toHaveScreenshot(screenshot(`badge-size-xlarge`));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
After Width: | Height: | Size: 561 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 546 B |
|
After Width: | Height: | Size: 501 B |
|
After Width: | Height: | Size: 924 B |
|
After Width: | Height: | Size: 473 B |
|
After Width: | Height: | Size: 459 B |
|
After Width: | Height: | Size: 536 B |
|
After Width: | Height: | Size: 440 B |
|
After Width: | Height: | Size: 632 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 607 B |
51
core/src/components/badge/test/size/index.html
Normal file
@@ -0,0 +1,51 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" dir="ltr">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Badge - Size</title>
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
|
||||
/>
|
||||
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet" />
|
||||
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet" />
|
||||
<script src="../../../../../scripts/testing/scripts.js"></script>
|
||||
<script nomodule src="../../../../../dist/ionic/ionic.js"></script>
|
||||
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<ion-app>
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Button - Size</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content class="ion-padding" id="content" no-bounce>
|
||||
<ion-list>
|
||||
<ion-item>
|
||||
<ion-label>Default</ion-label>
|
||||
<ion-badge slot="end">00</ion-badge>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label>Small</ion-label>
|
||||
<ion-badge slot="end" size="small">00</ion-badge>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label>Medium</ion-label>
|
||||
<ion-badge slot="end" size="medium">00</ion-badge>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label>Large</ion-label>
|
||||
<ion-badge slot="end" size="large">00</ion-badge>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label>XLarge</ion-label>
|
||||
<ion-badge slot="end" size="xlarge">00</ion-badge>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
</ion-content>
|
||||
</ion-app>
|
||||
</body>
|
||||
</html>
|
||||
@@ -132,20 +132,20 @@
|
||||
// -------------------------------------------------------------------------------
|
||||
|
||||
:host(.button-soft) {
|
||||
--border-radius: #{globals.$ionic-border-radius-rounded-medium};
|
||||
--border-radius: #{globals.$ionic-border-radius-200};
|
||||
}
|
||||
|
||||
:host(.button-soft.button-xsmall),
|
||||
:host(.button-soft.button-small) {
|
||||
--border-radius: #{globals.$ionic-border-radius-rounded-small};
|
||||
--border-radius: #{globals.$ionic-border-radius-100};
|
||||
}
|
||||
|
||||
:host(.button-round) {
|
||||
--border-radius: #{globals.$ionic-border-radius-rounded-full};
|
||||
--border-radius: #{globals.$ionic-border-radius-full};
|
||||
}
|
||||
|
||||
:host(.button-rectangular) {
|
||||
--border-radius: #{globals.$ionic-border-radius-square};
|
||||
--border-radius: #{globals.$ionic-border-radius-0};
|
||||
}
|
||||
|
||||
// Button Focused
|
||||
|
||||
|
Before Width: | Height: | Size: 105 KiB After Width: | Height: | Size: 104 KiB |
|
Before Width: | Height: | Size: 129 KiB After Width: | Height: | Size: 132 KiB |
|
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 92 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
@@ -4,15 +4,15 @@
|
||||
// --------------------------------------------------
|
||||
|
||||
:host {
|
||||
--background: #{globals.$ionic-color-neutral-0};
|
||||
--border-radius: #{globals.$ionic-border-radius-rounded-small};
|
||||
--background: #{globals.$ionic-color-base-white};
|
||||
--border-radius: #{globals.$ionic-border-radius-100};
|
||||
|
||||
@include globals.padding(globals.$ionic-space-base);
|
||||
@include globals.padding(globals.$ionic-space-400);
|
||||
@include globals.border-radius(var(--border-radius));
|
||||
|
||||
display: block;
|
||||
|
||||
border: #{globals.$ionic-border-size-small} solid #{globals.$ionic-color-neutral-50};
|
||||
border: #{globals.$ionic-border-size-025} solid #{globals.$ionic-color-neutral-500};
|
||||
|
||||
background: var(--background);
|
||||
color: var(--color);
|
||||
@@ -22,9 +22,9 @@
|
||||
// ---------------------------------------------
|
||||
|
||||
:host(.card-round) {
|
||||
--border-radius: #{globals.$ionic-border-radius-rounded-large};
|
||||
--border-radius: #{globals.$ionic-border-radius-400};
|
||||
}
|
||||
|
||||
:host(.card-rectangular) {
|
||||
--border-radius: #{globals.$ionic-border-radius-square};
|
||||
--border-radius: #{globals.$ionic-border-radius-0};
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
@@ -9,13 +9,13 @@ $ionic-states-focus-primary: #9ec4fd;
|
||||
$ionic-states-hover: #{rgba(#05080f, 0.16)}; // We should review how to make this in the future, as we are setting scss variables with a var() and fallback, and it doesn't work inside a rgba().
|
||||
|
||||
:host {
|
||||
--background: #{globals.$ionic-color-neutral-10};
|
||||
--background: #{globals.$ionic-color-neutral-100};
|
||||
--color: #{globals.$ionic-color-neutral-900};
|
||||
--focus-ring-color: #{$ionic-states-focus-primary};
|
||||
--focus-ring-width: #{globals.$ionic-border-size-medium};
|
||||
--focus-ring-width: #{globals.$ionic-border-size-050};
|
||||
|
||||
@include globals.font-smoothing;
|
||||
@include globals.padding(globals.$ionic-space-xxs, globals.$ionic-space-xs);
|
||||
@include globals.padding(globals.$ionic-space-150, globals.$ionic-space-200);
|
||||
@include globals.border-radius(var(--border-radius));
|
||||
|
||||
display: inline-flex;
|
||||
@@ -25,7 +25,7 @@ $ionic-states-hover: #{rgba(#05080f, 0.16)}; // We should review how to make thi
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
gap: globals.$ionic-space-xxxs;
|
||||
gap: globals.$ionic-space-100;
|
||||
|
||||
background: var(--background);
|
||||
color: var(--color);
|
||||
@@ -33,7 +33,7 @@ $ionic-states-hover: #{rgba(#05080f, 0.16)}; // We should review how to make thi
|
||||
font-family: globals.$ionic-font-family;
|
||||
font-weight: globals.$ionic-font-weight-medium;
|
||||
|
||||
line-height: globals.$ionic-font-line-height-full;
|
||||
line-height: globals.$ionic-line-height-full;
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
@@ -49,7 +49,7 @@ $ionic-states-hover: #{rgba(#05080f, 0.16)}; // We should review how to make thi
|
||||
|
||||
:host(.chip-outline) {
|
||||
--background: transparent;
|
||||
border-width: globals.$ionic-border-size-small;
|
||||
border-width: globals.$ionic-border-size-025;
|
||||
|
||||
border-color: globals.$ionic-color-neutral-100;
|
||||
}
|
||||
@@ -83,21 +83,21 @@ $ionic-states-hover: #{rgba(#05080f, 0.16)}; // We should review how to make thi
|
||||
// ---------------------------------------------
|
||||
|
||||
:host(.chip-soft) {
|
||||
--border-radius: #{globals.$ionic-border-radius-rounded-small};
|
||||
--border-radius: #{globals.$ionic-border-radius-100};
|
||||
}
|
||||
|
||||
:host(.chip-round) {
|
||||
--border-radius: #{globals.$ionic-border-radius-rounded-large};
|
||||
--border-radius: #{globals.$ionic-border-radius-400};
|
||||
}
|
||||
|
||||
:host(.chip-rectangular) {
|
||||
--border-radius: #{globals.$ionic-border-radius-square};
|
||||
--border-radius: #{globals.$ionic-border-radius-0};
|
||||
}
|
||||
|
||||
// Chip Icon
|
||||
// ---------------------------------------------
|
||||
::slotted(ion-icon) {
|
||||
font-size: globals.$ionic-font-size-l;
|
||||
font-size: globals.$ionic-font-size-400;
|
||||
}
|
||||
|
||||
// Size
|
||||
@@ -106,11 +106,11 @@ $ionic-states-hover: #{rgba(#05080f, 0.16)}; // We should review how to make thi
|
||||
:host(.chip-small) {
|
||||
min-height: 24px;
|
||||
|
||||
font-size: #{tokens.$ionic-font-size-s};
|
||||
font-size: #{tokens.$ionic-font-size-300};
|
||||
}
|
||||
|
||||
:host(.chip-large) {
|
||||
min-height: 32px;
|
||||
|
||||
font-size: globals.$ionic-font-size-m;
|
||||
font-size: globals.$ionic-font-size-350;
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 965 B |
|
Before Width: | Height: | Size: 1010 B After Width: | Height: | Size: 898 B |
|
Before Width: | Height: | Size: 888 B After Width: | Height: | Size: 854 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1020 B After Width: | Height: | Size: 1.2 KiB |