diff --git a/core/src/components.d.ts b/core/src/components.d.ts index 80be04dd02..63242ed45e 100644 --- a/core/src/components.d.ts +++ b/core/src/components.d.ts @@ -890,10 +890,10 @@ export namespace Components { */ "shape"?: 'soft' | 'round' | 'rectangular'; /** - * Set to `"small"` for a chip with less height and padding. Defaults to `"medium"`. - * @default 'medium' + * Set to `"small"` for a chip with less height and padding. Defaults to `"small"`. + * @default 'large' */ - "size"?: 'small' | 'medium' | 'large'; + "size"?: 'small' | 'large'; /** * The theme determines the visual appearance of the component. */ @@ -6861,10 +6861,10 @@ declare namespace LocalJSX { */ "shape"?: 'soft' | 'round' | 'rectangular'; /** - * Set to `"small"` for a chip with less height and padding. Defaults to `"medium"`. - * @default 'medium' + * Set to `"small"` for a chip with less height and padding. Defaults to `"small"`. + * @default 'large' */ - "size"?: 'small' | 'medium' | 'large'; + "size"?: 'small' | 'large'; /** * The theme determines the visual appearance of the component. */ diff --git a/core/src/components/chip/chip.base.scss b/core/src/components/chip/chip.base.scss index 6aeb293058..601fcef814 100644 --- a/core/src/components/chip/chip.base.scss +++ b/core/src/components/chip/chip.base.scss @@ -1,6 +1,7 @@ @use "../../themes/mixins" as mixins; @use "../../themes/functions.color" as colors; @use "./chip.base.vars.scss" as vars; +@use "sass:meta"; // Chip: Common Styles // -------------------------------------------------- @@ -20,6 +21,7 @@ @include mixins.border-radius(var(--border-radius)); @include mixins.margin(vars.$chip-margin); @include mixins.padding(vars.$chip-padding-vertical, vars.$chip-padding-horizontal); + @include mixins.typography(vars.$chip-typography); display: inline-flex; position: relative; @@ -49,12 +51,6 @@ font-size: vars.$chip-size-small-font-size; } -:host(.chip-medium) { - min-height: vars.$chip-size-medium-height; - - font-size: vars.$chip-size-medium-font-size; -} - :host(.chip-large) { min-height: vars.$chip-size-large-height; @@ -110,6 +106,8 @@ :host(.ion-color.chip-bold.chip-outline) { border-color: vars.$chip-hue-bold-semantic-outline-border-color; + + background: vars.$chip-outline-bold-semantic-bg; //native would be transparent, else it would be whatevers in ion-color.chip-bold } // Subtle @@ -120,6 +118,8 @@ :host(.ion-color.chip-subtle.chip-outline) { border-color: colors.current-color(shade, $subtle: true); + + background: vars.$chip-outline-subtle-semantic-bg; } // Outline Chip @@ -130,11 +130,6 @@ border-style: solid; } -:host(.chip-outline), -:host(.chip-outline.ion-color) { - background: vars.$chip-outline-bg; -} - // Chip States // --------------------------------------------- @@ -210,10 +205,14 @@ // Avatar ::slotted(ion-avatar) { + // width: vars.$chip-avatar-size; + // height: vars.$chip-avatar-size; + // @error vars.$chip-avatar-size; + @if vars.$chip-avatar-size != "unset" { + width: vars.$chip-avatar-size; + height: vars.$chip-avatar-size; + } flex-shrink: 0; - - width: vars.$chip-avatar-size; - height: vars.$chip-avatar-size; } ::slotted(ion-avatar:first-child) { diff --git a/core/src/components/chip/chip.base.vars.scss b/core/src/components/chip/chip.base.vars.scss index 412121e44d..3251393d08 100644 --- a/core/src/components/chip/chip.base.vars.scss +++ b/core/src/components/chip/chip.base.vars.scss @@ -76,8 +76,14 @@ $chip-hue-bold-semantic-outline-border-color: var(--ion-chip-hue-bold-semantic-o /// @prop - Outline border width $chip-outline-border-width: var(--ion-chip-variant-outline-border-width); -/// @prop - Outline chip background color -$chip-outline-bg: var(--ion-chip-variant-outline-bg); +/// @prop - Outline bold chip background color for semantic colors +$chip-outline-bold-semantic-bg: var(--ion-chip-hue-bold-semantic-outline-bg); + +/// @prop - Subtle chip background color for semantic colors +$chip-hue-subtle-semantic-bg: var(--ion-chip-hue-subtle-semantic-bg); + +/// @prop - Outline subtle chip background color for semantic colors +$chip-outline-subtle-semantic-bg: var(--ion-chip-hue-subtle-semantic-outline-bg); /// @prop - Focus ring color $chip-focus-ring-color: var(--ion-chip-state-focus-ring-color); @@ -128,7 +134,7 @@ $chip-icon-last-child-margin: var(--ion-chip-icon-last-child-margin); $chip-icon-last-child-margin-start: var(--ion-chip-icon-last-child-margin-start); /// @prop - Avatar size -$chip-avatar-size: var(--ion-chip-avatar-size); +$chip-avatar-size: var(--ion-chip-avatar-size, revert-layer); /// @prop - Avatar margin vertical for first child $chip-avatar-first-child-margin-vertical: var(--ion-chip-avatar-first-child-margin-vertical); @@ -147,3 +153,14 @@ $chip-avatar-last-child-margin-start: var(--ion-chip-avatar-last-child-margin-st /// @prop - Avatar margin end for last child $chip-avatar-last-child-margin-end: var(--ion-chip-avatar-last-child-margin-end); + +/// @prop - Typography styles for the chip +$chip-typography: ( + font-family: var(--ion-chip-typography-font-family), + font-size: var(--ion-chip-typography-font-size), + font-weight: var(--ion-chip-typography-font-weight), + letter-spacing: var(--ion-chip-typography-letter-spacing), + line-height: var(--ion-chip-typography-line-height), + text-decoration: var(--ion-chip-typography-text-decoration), + text-transform: var(--ion-chip-typography-text-transform), +); diff --git a/core/src/components/chip/chip.tsx b/core/src/components/chip/chip.tsx index 9584c8b536..6c92dfafa0 100644 --- a/core/src/components/chip/chip.tsx +++ b/core/src/components/chip/chip.tsx @@ -64,9 +64,9 @@ export class Chip implements ComponentInterface { /** * Set to `"small"` for a chip with less height and padding. * - * Defaults to `"medium"`. + * Defaults to `"small"`. */ - @Prop() size?: 'small' | 'medium' | 'large' = 'medium'; + @Prop() size?: 'small' | 'large' = 'large'; render() { const { hue, size } = this; diff --git a/core/src/themes/ionic/default.tokens.ts b/core/src/themes/ionic/default.tokens.ts index debcac4092..a132208d6f 100644 --- a/core/src/themes/ionic/default.tokens.ts +++ b/core/src/themes/ionic/default.tokens.ts @@ -1,9 +1,22 @@ +import * as colorTokens from 'outsystems-design-tokens/tokens/color scheme.json'; +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 { currentColor, cachedResolveOsToken } from '../../utils/theme'; import { defaultTheme as baseDefaultTheme } from '../base/default.tokens'; import type { DefaultTheme } from '../themes.interfaces'; import { darkTheme } from './dark.tokens'; import { lightTheme } from './light.tokens'; +const tokenMap = { + colorTokens, + primitiveTokens, + lightTokens, + typographyTokens, +}; + export const defaultTheme: DefaultTheme = { ...baseDefaultTheme, @@ -76,4 +89,102 @@ export const defaultTheme: DefaultTheme = { xxxl: 'var(--ion-radii-1000)', xxxxl: 'var(--ion-radii-full)', }, + + components: { + IonChip: { + margin: '0px', + padding: { + vertical: primitiveTokens.scale['150'].$value, + horizontal: primitiveTokens.scale['200'].$value, + }, + typography: cachedResolveOsToken(typographyTokens.body.sm.medium.$value, tokenMap), + lineHeight: primitiveTokens.font['line-height']['full'].$value, + + // Sizes + size: { + small: { + height: primitiveTokens.scale['600'].$value, + fontSize: primitiveTokens.font['font-size']['300'].$value, + }, + large: { + height: primitiveTokens.scale['800'].$value, + fontSize: primitiveTokens.font['font-size']['350'].$value, + }, + }, + + // States + state: { + disabled: { + opacity: '0.4', + }, + focus: { + ring: { + color: lightTokens.primitives.blue['400'].$value, + width: primitiveTokens.scale['050'].$value, + }, + }, + }, + + // Shapes + shape: { + soft: { + borderRadius: primitiveTokens.scale['100'].$value, + }, + round: { + borderRadius: primitiveTokens.scale['400'].$value, + }, + rectangular: { + borderRadius: primitiveTokens.scale['0'].$value, + }, + }, + + // Hues + hue: { + bold: { + bg: cachedResolveOsToken(colorTokens.bg.neutral.bold.default, tokenMap), + color: lightTokens.primitives.base.white.$value, + + outline: { + borderColor: lightTokens.primitives.neutral['1200'].$value, + }, + + // Any of the semantic colors like primary, secondary, etc. + semantic: { + color: currentColor('contrast'), + + outline: { + borderColor: currentColor('shade'), + bg: currentColor('base'), + }, + }, + }, + subtle: { + bg: cachedResolveOsToken(lightTokens.primitives.neutral['100'], tokenMap), + color: lightTokens.primitives.neutral['800'].$value, + + outline: { + borderColor: lightTokens.primitives.neutral['300'].$value, + }, + + semantic: { + outline: { + borderColor: currentColor('shade', null, true), + bg: currentColor('base', null, true), + }, + }, + }, + }, + + // Variants + variant: { + outline: { + borderWidth: primitiveTokens.scale['025'].$value, + }, + }, + + icon: { + size: primitiveTokens.font['font-size']['400'].$value, + }, + }, + }, }; diff --git a/core/src/themes/ionic/light.tokens.ts b/core/src/themes/ionic/light.tokens.ts index 94c96baeb9..6c63c2410d 100644 --- a/core/src/themes/ionic/light.tokens.ts +++ b/core/src/themes/ionic/light.tokens.ts @@ -1,9 +1,172 @@ +import * as colorTokens from 'outsystems-design-tokens/tokens/color scheme.json'; +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, +}; +console.log( + 'cachedResolveOsToken(colorTokens.bg.primary.base.default, tokenMap)', + cachedResolveOsToken(colorTokens.bg.primary.base.default, tokenMap) +); export const lightTheme: LightTheme = { backgroundColor: '#ffffff', textColor: '#000000', + color: { + primary: { + bold: { + base: cachedResolveOsToken(colorTokens.bg.primary.base.default, tokenMap), + 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.inverse, tokenMap), + foreground: cachedResolveOsToken(colorTokens.text.warning, tokenMap), + shade: cachedResolveOsToken(colorTokens.bg.warning.base.press, tokenMap), + tint: cachedResolveOsToken(colorTokens.semantics.warning['800'], 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(colorTokens.semantics.warning['200'], 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', diff --git a/core/src/themes/ios/default.tokens.ts b/core/src/themes/ios/default.tokens.ts index 6ee0f5c9d0..b46a7a910c 100644 --- a/core/src/themes/ios/default.tokens.ts +++ b/core/src/themes/ios/default.tokens.ts @@ -98,10 +98,6 @@ export const defaultTheme: DefaultTheme = { height: '24px', fontSize: clamp('12px', `${(fontSizes.chipBase - 2) / 16}rem`, '20px'), }, - medium: { - height: '32px', - fontSize: clamp('13px', `${fontSizes.chipBase / 16}rem`, '22px'), - }, large: { height: '32px', fontSize: clamp('14px', `${(fontSizes.chipBase + 2) / 16}rem`, '24px'), @@ -159,6 +155,7 @@ export const defaultTheme: DefaultTheme = { outline: { borderColor: currentColor('base', 0.32), + bg: 'transparent', }, }, }, @@ -169,6 +166,13 @@ export const defaultTheme: DefaultTheme = { outline: { borderColor: rgba(colors.textColorRgb, 0.32), }, + + semantic: { + outline: { + borderColor: currentColor('shade'), + bg: 'transparent', + }, + }, }, }, @@ -176,7 +180,6 @@ export const defaultTheme: DefaultTheme = { variant: { outline: { borderWidth: '1px', - bg: 'transparent', }, }, diff --git a/core/src/themes/md/default.tokens.ts b/core/src/themes/md/default.tokens.ts index 97538172b0..bcd6e5d8a4 100644 --- a/core/src/themes/md/default.tokens.ts +++ b/core/src/themes/md/default.tokens.ts @@ -103,10 +103,6 @@ export const defaultTheme: DefaultTheme = { height: '24px', fontSize: `${(fontSizes.chipBase - 2) / 16}rem`, }, - medium: { - height: '32px', - fontSize: `${fontSizes.chipBase / 16}rem`, - }, large: { height: '32px', fontSize: `${(fontSizes.chipBase + 2) / 16}rem`, @@ -164,6 +160,7 @@ export const defaultTheme: DefaultTheme = { outline: { borderColor: currentColor('base', 0.32), + bg: 'transparent', }, }, }, @@ -174,6 +171,13 @@ export const defaultTheme: DefaultTheme = { outline: { borderColor: rgba(colors.textColorRgb, 0.32), }, + + semantic: { + outline: { + borderColor: currentColor('shade'), + bg: 'transparent', + }, + }, }, }, @@ -181,7 +185,6 @@ export const defaultTheme: DefaultTheme = { variant: { outline: { borderWidth: '1px', - bg: 'transparent', }, }, diff --git a/core/src/themes/mixins.scss b/core/src/themes/mixins.scss index 1a2afeb58e..85fdfabd4e 100644 --- a/core/src/themes/mixins.scss +++ b/core/src/themes/mixins.scss @@ -632,3 +632,20 @@ } } } + +// Typography mixin to be used with typography scss variables (ionic.vars.scss) +// +// ex: @include typography($ion-heading-h3-medium); +// +// -------------------------------------------------- +@mixin typography($properties) { + font-family: map-get($properties, font-family); + font-size: map-get($properties, font-size); + font-weight: map-get($properties, font-weight); + + letter-spacing: map-get($properties, letter-spacing); + line-height: map-get($properties, line-height); + + text-decoration: map-get($properties, text-decoration); + text-transform: map-get($properties, text-transform); +} diff --git a/core/src/themes/themes.interfaces.ts b/core/src/themes/themes.interfaces.ts index 1a40f09706..3b785010d8 100644 --- a/core/src/themes/themes.interfaces.ts +++ b/core/src/themes/themes.interfaces.ts @@ -269,6 +269,9 @@ type Components = { gap?: string | number; lineHeight?: string | number; + typography?: { + [key: string]: string | number; + }; // Sizes size: { @@ -276,10 +279,6 @@ type Components = { height: string | number; fontSize: string | number; }; - medium: { - height: string | number; - fontSize?: string | number; - }; large: { height: string | number; fontSize: string | number; @@ -292,17 +291,19 @@ type Components = { opacity: string | number; }; focus: { - ringColor?: string; - ringWidth?: string | number; - bg: string; - semanticBg: string; - outlineBg: string; + ring?: { + color: string; + width?: string | number; + }; + bg?: string; + semanticBg?: string; + outlineBg?: string; }; - activated: { + activated?: { bg: string; semanticBg: string; }; - hover: { + hover?: { bg: string; semanticBg: string; outlineBg: string; @@ -334,11 +335,12 @@ type Components = { // Any of the semantic colors like primary, secondary, etc. semantic: { - bgAlpha: string; + bgAlpha?: string; color: string; outline: { borderColor: string; + bg?: string; }; }; }; @@ -348,6 +350,14 @@ type Components = { outline: { borderColor: string; + bg?: string; + }; + + semantic: { + outline: { + borderColor: string; + bg?: string; + }; }; }; }; @@ -356,27 +366,26 @@ type Components = { variant: { outline: { borderWidth: string | number; - bg: string; }; }; icon: { size: string | number; - color: string; - firstChildMargin: string | number; - firstChildMarginEnd: string | number; - lastChildMargin: string | number; - lastChildMarginStart: string | number; + color?: string; + firstChildMargin?: string | number; + firstChildMarginEnd?: string | number; + lastChildMargin?: string | number; + lastChildMarginStart?: string | number; }; - avatar: { - size: string | number; - firstChildMarginVertical: string | number; - firstChildMarginStart: string | number; - firstChildMarginEnd: string | number; - lastChildMarginVertical: string | number; - lastChildMarginStart: string | number; - lastChildMarginEnd: string | number; + avatar?: { + size: string | number | null; + firstChildMarginVertical?: string | number; + firstChildMarginStart?: string | number; + firstChildMarginEnd?: string | number; + lastChildMarginVertical?: string | number; + lastChildMarginStart?: string | number; + lastChildMarginEnd?: string | number; }; }; diff --git a/core/src/utils/theme.ts b/core/src/utils/theme.ts index 310d5a2f16..e2247169da 100644 --- a/core/src/utils/theme.ts +++ b/core/src/utils/theme.ts @@ -589,3 +589,87 @@ export function currentColor(variation: string, alpha: number | string | null = export function clamp(min: number | string, val: number | string, max: number | string): string { return `clamp(${min}, ${val}, ${max})`; } + +// Create a cache to store results +const cache = new Map(); + +export const cachedResolveOsToken = (tokenPath: any, tokenMap: Record): any => { + // 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): 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 = {}; + 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; + + // As requested, keeping refCategory in the path + 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; +}; diff --git a/core/tsconfig.json b/core/tsconfig.json index 6e2271dfde..5cefdae651 100644 --- a/core/tsconfig.json +++ b/core/tsconfig.json @@ -34,7 +34,8 @@ "@utils/*": ["src/utils/*"], "@utils/test": ["src/utils/test/utils"], "@global/*": ["src/global/*"] - } + }, + "resolveJsonModule": true, }, "include": [ "src",