⚠ This page is served via a proxy. Original site: https://github.com
This service does not collect credentials or authentication data.
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.
160 changes: 160 additions & 0 deletions core/src/themes/ionic/light.tokens.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,169 @@
import * as colorTokens from 'outsystems-design-tokens/tokens/color scheme.json';
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The OS package does not export these tokens to be consumed in a JS/TS file. The package only provides Sass files to be consumed. As a workaround, I was able to access the original JSON files. I'll be reaching out to Bernardo requesting JS/TS exports once he comes back from vacation. In the mean time, consider this as a temporary solution in order to not be blocked.

Copy link
Member

Choose a reason for hiding this comment

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

The plan was to remove this package from ionic-framework and have them set the token file on mobile UI. Is exporting these tokens part of the plan?

import * as primitiveTokens from 'outsystems-design-tokens/tokens/primitives.json';
import * as lightTokens from 'outsystems-design-tokens/tokens/theme/light.json';
import * as typographyTokens from 'outsystems-design-tokens/tokens/typography.json';

import { cachedResolveOsToken } from '../../utils/theme';
import type { LightTheme } from '../themes.interfaces';

const tokenMap = {
colorTokens,
lightTokens,
primitiveTokens,
typographyTokens,
};

export const lightTheme: LightTheme = {
backgroundColor: '#ffffff',
textColor: '#000000',

color: {
primary: {
bold: {
base: cachedResolveOsToken(colorTokens.bg.primary.base.default, tokenMap),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

If the export request is approved, then we can simply replace this with the correct tokens.

contrast: cachedResolveOsToken(colorTokens.text.inverse, tokenMap),
foreground: cachedResolveOsToken(colorTokens.text.primary, tokenMap),
shade: cachedResolveOsToken(colorTokens.bg.primary.base.press, tokenMap),
tint: cachedResolveOsToken(colorTokens.semantics.primary['600'], tokenMap),
},
subtle: {
base: cachedResolveOsToken(colorTokens.bg.primary.subtle.default, tokenMap),
contrast: cachedResolveOsToken(colorTokens.text.primary, tokenMap),
foreground: cachedResolveOsToken(colorTokens.text.primary, tokenMap),
shade: cachedResolveOsToken(colorTokens.bg.primary.subtle.press, tokenMap),
tint: cachedResolveOsToken(colorTokens.semantics.primary['200'], tokenMap),
},
},
secondary: {
bold: {
base: cachedResolveOsToken(colorTokens.bg.info.base.default, tokenMap),
contrast: cachedResolveOsToken(colorTokens.text.inverse, tokenMap),
foreground: cachedResolveOsToken(colorTokens.text.primary, tokenMap),
shade: cachedResolveOsToken(colorTokens.bg.info.base.press, tokenMap),
tint: cachedResolveOsToken(colorTokens.semantics.info['700'], tokenMap),
},
subtle: {
base: cachedResolveOsToken(colorTokens.bg.info.subtle.default, tokenMap),
contrast: cachedResolveOsToken(colorTokens.text.info, tokenMap),
foreground: cachedResolveOsToken(colorTokens.text.info, tokenMap),
shade: cachedResolveOsToken(colorTokens.bg.info.subtle.press, tokenMap),
tint: cachedResolveOsToken(colorTokens.semantics.info['200'], tokenMap),
},
},
tertiary: {
bold: {
base: cachedResolveOsToken(lightTokens.primitives.violet['700'], tokenMap),
contrast: cachedResolveOsToken(colorTokens.text.inverse, tokenMap),
foreground: cachedResolveOsToken(lightTokens.primitives.violet['700'], tokenMap),
shade: cachedResolveOsToken(lightTokens.primitives.violet['800'], tokenMap),
tint: cachedResolveOsToken(colorTokens.semantics.primary['600'], tokenMap),
},
subtle: {
base: cachedResolveOsToken(lightTokens.primitives.violet['100'], tokenMap),
contrast: cachedResolveOsToken(lightTokens.primitives.violet['700'], tokenMap),
foreground: cachedResolveOsToken(lightTokens.primitives.violet['700'], tokenMap),
shade: cachedResolveOsToken(lightTokens.primitives.violet['300'], tokenMap),
tint: cachedResolveOsToken(lightTokens.primitives.violet['200'], tokenMap),
},
},
success: {
bold: {
base: cachedResolveOsToken(colorTokens.bg.success.base.default, tokenMap),
contrast: cachedResolveOsToken(colorTokens.text.inverse, tokenMap),
foreground: cachedResolveOsToken(colorTokens.text.success, tokenMap),
shade: cachedResolveOsToken(colorTokens.bg.success.base.press, tokenMap),
tint: cachedResolveOsToken(colorTokens.semantics.success['800'], tokenMap),
},
subtle: {
base: cachedResolveOsToken(colorTokens.bg.success.subtle.default, tokenMap),
contrast: cachedResolveOsToken(colorTokens.text.success, tokenMap),
foreground: cachedResolveOsToken(colorTokens.text.success, tokenMap),
shade: cachedResolveOsToken(colorTokens.bg.success.subtle.press, tokenMap),
tint: cachedResolveOsToken(colorTokens.semantics.success['200'], tokenMap),
},
},
warning: {
bold: {
base: cachedResolveOsToken(colorTokens.bg.warning.base.default, tokenMap),
contrast: cachedResolveOsToken(colorTokens.text.default, tokenMap),
foreground: cachedResolveOsToken(colorTokens.text.warning, tokenMap),
shade: cachedResolveOsToken(colorTokens.bg.warning.base.press, tokenMap),
tint: cachedResolveOsToken(lightTokens.primitives.yellow['300'], tokenMap),
},
subtle: {
base: cachedResolveOsToken(colorTokens.bg.warning.subtle.default, tokenMap),
contrast: cachedResolveOsToken(colorTokens.text.warning, tokenMap),
foreground: cachedResolveOsToken(colorTokens.text.warning, tokenMap),
shade: cachedResolveOsToken(colorTokens.bg.warning.subtle.press, tokenMap),
tint: cachedResolveOsToken(lightTokens.primitives.yellow['100'], tokenMap),
},
},
danger: {
bold: {
base: cachedResolveOsToken(colorTokens.bg.danger.base.default, tokenMap),
contrast: cachedResolveOsToken(colorTokens.text.inverse, tokenMap),
foreground: cachedResolveOsToken(colorTokens.text.danger, tokenMap),
shade: cachedResolveOsToken(colorTokens.bg.danger.base.press, tokenMap),
tint: cachedResolveOsToken(colorTokens.semantics.danger['700'], tokenMap),
},
subtle: {
base: cachedResolveOsToken(colorTokens.bg.danger.subtle.default, tokenMap),
contrast: cachedResolveOsToken(colorTokens.text.danger, tokenMap),
foreground: cachedResolveOsToken(colorTokens.text.danger, tokenMap),
shade: cachedResolveOsToken(colorTokens.bg.danger.subtle.press, tokenMap),
tint: cachedResolveOsToken(colorTokens.semantics.danger['200'], tokenMap),
},
},
light: {
bold: {
base: cachedResolveOsToken(lightTokens.primitives.base.white, tokenMap),
contrast: cachedResolveOsToken(colorTokens.text.default, tokenMap),
foreground: cachedResolveOsToken(colorTokens.text.default, tokenMap),
shade: cachedResolveOsToken(lightTokens.primitives.neutral['600'], tokenMap),
tint: cachedResolveOsToken(lightTokens.primitives.neutral['400'], tokenMap),
},
subtle: {
base: cachedResolveOsToken(colorTokens.bg.neutral.subtlest.default, tokenMap),
contrast: cachedResolveOsToken(colorTokens.text.default, tokenMap),
foreground: cachedResolveOsToken(colorTokens.text.default, tokenMap),
shade: cachedResolveOsToken(colorTokens.bg.neutral.subtlest.press, tokenMap),
tint: cachedResolveOsToken(lightTokens.primitives.neutral['100'], tokenMap),
},
},
medium: {
bold: {
base: cachedResolveOsToken(colorTokens.bg.neutral.bold.default, tokenMap),
contrast: cachedResolveOsToken(colorTokens.text.inverse, tokenMap),
foreground: cachedResolveOsToken(colorTokens.text.default, tokenMap),
shade: cachedResolveOsToken(colorTokens.bg.neutral.bold.press, tokenMap),
tint: cachedResolveOsToken(lightTokens.primitives.neutral['900'], tokenMap),
},
subtle: {
base: cachedResolveOsToken(colorTokens.bg.neutral.subtle.default, tokenMap),
contrast: cachedResolveOsToken(colorTokens.text.subtlest, tokenMap),
foreground: cachedResolveOsToken(colorTokens.text.default, tokenMap),
shade: cachedResolveOsToken(colorTokens.bg.neutral.subtle.press, tokenMap),
tint: cachedResolveOsToken(lightTokens.primitives.neutral['100'], tokenMap),
},
},
dark: {
bold: {
base: cachedResolveOsToken(colorTokens.bg.neutral.boldest.default, tokenMap),
contrast: cachedResolveOsToken(colorTokens.text.inverse, tokenMap),
foreground: cachedResolveOsToken(colorTokens.text.default, tokenMap),
shade: cachedResolveOsToken(colorTokens.bg.neutral.boldest.press, tokenMap),
tint: cachedResolveOsToken(lightTokens.primitives.neutral['1100'], tokenMap),
},
subtle: {
base: cachedResolveOsToken(colorTokens.bg.neutral.subtle.default, tokenMap),
contrast: cachedResolveOsToken(colorTokens.text.subtle, tokenMap),
foreground: cachedResolveOsToken(colorTokens.text.default, tokenMap),
shade: cachedResolveOsToken(colorTokens.bg.neutral.subtle.press, tokenMap),
tint: cachedResolveOsToken(lightTokens.primitives.neutral['100'], tokenMap),
},
},
},

components: {
IonCard: {
background: '#ffffff',
Expand Down
83 changes: 83 additions & 0 deletions core/src/utils/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -471,3 +471,86 @@ export const mix = (baseColor: string, mixColor: string, weight: string): string
const toHex = (n: number) => n.toString(16).padStart(2, '0');
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
};

// Create a cache to store results
const cache = new Map<any, any>();

export const cachedResolveOsToken = (tokenPath: any, tokenMap: Record<string, any>): any => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

As mentioned in my previous comment, we only have the JSON files to access the ionic tokens. However, those tokens are not fully mapped to their correct values. This function makes sure to retrieve the right values and saves them to a map so we're not iterating so many times. If the export request is approved, then this function can be removed.

// Use the path/object as the key
// (Note: For objects, this caches by reference)
if (cache.has(tokenPath)) {
return cache.get(tokenPath);
}

// Use your existing resolveOsToken function with the global tokenMap
const result = resolveOsToken(tokenPath, tokenMap);

cache.set(tokenPath, result);
return result;
};

export const resolveOsToken = (tokenPath: any, tokenMap: Record<string, any>): any => {
// 1. Handle Objects (like Typography maps)
if (typeof tokenPath === 'object' && tokenPath !== null) {
// If it's a leaf-node token object, unwrap the $value immediately
if ('$value' in tokenPath) {
return resolveOsToken(tokenPath.$value, tokenMap);
}

// Otherwise, it's a map of multiple tokens, resolve each key
const resolvedObject: Record<string, any> = {};
for (const [key, val] of Object.entries(tokenPath)) {
resolvedObject[key] = resolveOsToken(val, tokenMap);
}
return resolvedObject;
}

// 2. Handle Reference Strings: "{category.path.item}"
let lookupPath = tokenPath;
let isPath = false;

if (typeof tokenPath === 'string' && tokenPath.startsWith('{') && tokenPath.endsWith('}')) {
const reference = tokenPath.slice(1, -1).trim();
const [refCategory, ...refPath] = reference.split('.');

let rootKey: string | null = null;
switch (refCategory) {
case 'semantics':
rootKey = 'colorTokens';
break;
case 'font':
rootKey = 'primitiveTokens';
break;
case 'primitives':
rootKey = 'lightTokens';
break;
case 'typography':
rootKey = 'typographyTokens';
break;
case 'scale':
rootKey = 'primitiveTokens';
break; // Added 'scale' based on your example
}

if (!rootKey) return tokenPath;

lookupPath = `${rootKey}.${refCategory}.${refPath.join('.')}`;
isPath = true;
}

// 3. ONLY run the reduce if we have confirmed this is a path to be searched
if (isPath) {
const value = lookupPath.split('.').reduce((acc: any, key: string) => {
if (acc && typeof acc === 'object' && key in acc) {
return acc[key];
}
return undefined;
}, tokenMap);

// Recursively resolve the result of the lookup
return resolveOsToken(value, tokenMap);
}

// 4. If it's not a path or a reference, it's a Literal Value (Hex, Font-stack, etc.)
return tokenPath;
};
3 changes: 2 additions & 1 deletion core/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
"@utils/*": ["src/utils/*"],
"@utils/test": ["src/utils/test/utils"],
"@global/*": ["src/global/*"]
}
},
"resolveJsonModule": true,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

As mentioned in my previous comment, we only have the JSON files to access the ionic tokens. This needs to be added in order to import the JSON files to light.tokens.ts or an error will be given.

},
"include": [
"src",
Expand Down
Loading