diff --git a/components/lib/themes/config/index.js b/components/lib/themes/config/index.js index 726b1ce27..5fbfc0d6d 100644 --- a/components/lib/themes/config/index.js +++ b/components/lib/themes/config/index.js @@ -5,7 +5,7 @@ export default { variable: { prefix: '', selector: ':root', - excludedKeyRegex: /^(primitive|semantic|variables|colorscheme|light|dark|common|colors|root|states)$/gi + excludedKeyRegex: /^(primitive|semantic|variables|colorscheme|light|dark|common|colors|root|states|components|directives)$/gi }, colorScheme: { light: { @@ -29,11 +29,13 @@ export default { _initialized: false, _currentColorScheme: 'light', _layerNames: new Set(), + _tokens: {}, init() { if (!this._initialized) { this.applyColorScheme(); } + this._tokens = ThemeUtils.createTokens(this.preset, this.getCurrentColorScheme(), this.defaults); this._initialized = true; }, get theme() { @@ -51,14 +53,21 @@ export default { get extend() { return this.theme?.extend || {}; }, + get tokens() { + return this._tokens; + }, getPConfig() { return this._pConfig; }, setPConfig(newValue) { this._pConfig = newValue; }, + getTokenValue(tokenPath) { + return ThemeUtils.getTokenValue(this.tokens, tokenPath, this.defaults); + }, setTheme(newValue) { this._theme = newValue; + this._tokens = ThemeUtils.createTokens(newValue, this.defaults); }, getCurrentColorScheme() { return this._currentColorScheme; diff --git a/components/lib/themes/utils/dt.js b/components/lib/themes/utils/dt.js index 38c21cd3d..3ce2cafd4 100644 --- a/components/lib/themes/utils/dt.js +++ b/components/lib/themes/utils/dt.js @@ -2,20 +2,20 @@ import Theme, { SharedUtils } from 'primevue/themes'; const VARIABLE = Theme.defaults.variable; -export const $dt = (tokenPath) => { +export const $dt = (tokenPath, type) => { const config = Theme.getPConfig(); - return dt(config?.theme, tokenPath); + return dt(config?.theme, tokenPath, type); }; -export const dt = (theme = {}, tokenPath) => { +export const dt = (theme = {}, tokenPath, type) => { if (tokenPath) { const { prefix, transform } = theme?.options || {}; const regex = /{([^}]*)}/g; const token = SharedUtils.object.test(regex, tokenPath) ? tokenPath : `{${tokenPath}}`; - const isStrictTransform = transform === 'strict'; // @todo - TRANSFORM: strict | lenient + const isStrictTransform = type === 'value' || transform === 'strict'; // @todo - TRANSFORM: strict | lenient(default) - return isStrictTransform ? SharedUtils.object.getComputedValue(theme?.preset, token, [VARIABLE.excludedKeyRegex]) : SharedUtils.object.getVariableValue(token, undefined, prefix, [VARIABLE.excludedKeyRegex]); + return isStrictTransform ? Theme.getTokenValue(tokenPath) : SharedUtils.object.getVariableValue(token, undefined, prefix, [VARIABLE.excludedKeyRegex]); } return ''; diff --git a/components/lib/themes/utils/sharedUtils.js b/components/lib/themes/utils/sharedUtils.js index bd6d66cc8..9d5826209 100644 --- a/components/lib/themes/utils/sharedUtils.js +++ b/components/lib/themes/utils/sharedUtils.js @@ -34,6 +34,9 @@ export default { .toLowerCase() : str; }, + toTokenKey(str) { + return this.isString(str) ? str.replace(/[A-Z]/g, (c, i) => (i === 0 ? c : '.' + c.toLowerCase())).toLowerCase() : str; + }, merge(value1, value2) { if (this.isArray(value1)) { value1.push(...(value2 || [])); diff --git a/components/lib/themes/utils/themeUtils.js b/components/lib/themes/utils/themeUtils.js index ef397f77f..7b32ea324 100644 --- a/components/lib/themes/utils/themeUtils.js +++ b/components/lib/themes/utils/themeUtils.js @@ -30,7 +30,7 @@ export default { )}`; } - global_css = SharedUtils.object.getItemValue(base?.components?.global?.css, { ...params, dt: (tokenPath) => dt(theme, tokenPath) }); + global_css = SharedUtils.object.getItemValue(base?.components?.global?.css, { ...params, dt: (tokenPath, type) => dt(theme, tokenPath, type) }); return { primitive: primitive_css, @@ -53,7 +53,7 @@ export default { getBaseC({ name = '', theme = {}, params, set, defaults }) { const { base, options } = theme; const { css } = base?.components?.[name] || {}; - const computed_css = SharedUtils.object.getItemValue(css, { ...params, dt: (tokenPath) => dt(theme, tokenPath) }); + const computed_css = SharedUtils.object.getItemValue(css, { ...params, dt: (tokenPath, type) => dt(theme, tokenPath, type) }); return this._transformCSS(name, computed_css, undefined, 'style', options, set, defaults); }, @@ -72,7 +72,7 @@ export default { getBaseD({ name = '', theme = {}, params, set, defaults }) { const { base, options } = theme; const { css } = base?.directives?.[name] || {}; - const computed_css = SharedUtils.object.getItemValue(css, { ...params, dt: (tokenPath) => dt(theme, tokenPath) }); + const computed_css = SharedUtils.object.getItemValue(css, { ...params, dt: (tokenPath, type) => dt(theme, tokenPath, type) }); return this._transformCSS(name, computed_css, undefined, 'style', options, set, defaults); }, @@ -190,5 +190,62 @@ export default { } return ''; + }, + createTokens(obj = {}, currentColorScheme, defaults, parentKey = '', parentPath = '', tokens = {}) { + Object.entries(obj).forEach(([key, value]) => { + const currentKey = SharedUtils.object.test(defaults.variable.excludedKeyRegex, key) ? parentKey : parentKey ? `${parentKey}.${SharedUtils.object.toTokenKey(key)}` : SharedUtils.object.toTokenKey(key); + const currentPath = parentPath ? `${parentPath}.${key}` : key; + + if (SharedUtils.object.isObject(value)) { + this.createTokens(value, currentColorScheme, defaults, currentKey, currentPath, tokens); + } else { + tokens[currentKey] ||= { + paths: [], + computed(colorScheme) { + const scheme = colorScheme || currentColorScheme; + + return this.paths.find((p) => p.scheme === scheme || p.scheme === 'none')?.computed(); + } + }; + tokens[currentKey].paths.push({ + path: currentPath, + value, + scheme: currentPath.includes('colorScheme.light') ? 'light' : currentPath.includes('colorScheme.dark') ? 'dark' : 'none', + computed(colorScheme) { + const regex = /{([^}]*)}/g; + + if (SharedUtils.object.test(regex, value)) { + const val = value.trim(); + const _val = val.replaceAll(regex, (v) => { + const path = v.replace(/{|}/g, ''); + + return tokens[path]?.computed(colorScheme); + }); + + const calculationRegex = /(\d+\w*\s+[\+\-\*\/]\s+\d+\w*)/g; + const cleanedVarRegex = /var\([^)]+\)/g; + + return SharedUtils.object.test(calculationRegex, _val.replace(cleanedVarRegex, '0')) ? `calc(${_val})` : _val; + } + + return value; + } + }); + } + }); + + return tokens; + }, + getTokenValue(tokens, path, defaults) { + const normalizePath = (str) => { + const strArr = str.split('.'); + + return strArr.filter((s) => !SharedUtils.object.test(defaults.variable.excludedKeyRegex, s.toLowerCase())).join('.'); + }; + + const token = normalizePath(path); + const colorScheme = path.includes('colorScheme.light') ? 'light' : path.includes('colorScheme.dark') ? 'dark' : undefined; + + return tokens[token]?.computed(colorScheme); } };