Theming API: Refactor on $dt method and inline styles for css variables

pull/5677/head
mertsincan 2024-04-15 10:17:29 +01:00
parent ddeaab525a
commit 51110b585a
12 changed files with 129 additions and 67 deletions

View File

@ -1 +1,18 @@
export default {}; export default {
_loadedStyleNames: new Set(),
getLoadedStyleNames() {
return this._loadedStyleNames;
},
isStyleNameLoaded(name) {
return this._loadedStyleNames.has(name);
},
setLoadedStyleName(name) {
this._loadedStyleNames.add(name);
},
deleteLoadedStyleName(name) {
this._loadedStyleNames.delete(name);
},
clearLoadedStyleNames() {
this._loadedStyleNames.clear();
}
};

View File

@ -1,11 +1,8 @@
import Theme from 'primevue/themes'; import Theme, { dt } from 'primevue/themes';
import { useStyle } from 'primevue/usestyle'; import { useStyle } from 'primevue/usestyle';
import { ObjectUtils } from 'primevue/utils'; import { ObjectUtils } from 'primevue/utils';
/** const css = ({ dt }) => `
* @todo padding-right: ${$dt('scrollbar.width')};
*/
const css = `
.p-hidden-accessible { .p-hidden-accessible {
border: 0; border: 0;
clip: rect(0 0 0 0); clip: rect(0 0 0 0);
@ -24,7 +21,7 @@ const css = `
.p-overflow-hidden { .p-overflow-hidden {
overflow: hidden; overflow: hidden;
padding-right: var(--p-scrollbar-width); padding-right: ${dt('scrollbar.width')};
} }
`; `;
@ -38,7 +35,9 @@ export default {
classes, classes,
inlineStyles, inlineStyles,
loadStyle(options = {}) { loadStyle(options = {}) {
return this.css ? useStyle(ObjectUtils.minifyCSS(this.css), { name: this.name, ...options }) : {}; const css = ObjectUtils.getItemValue(this.css, { dt });
return css ? useStyle(ObjectUtils.minifyCSS(css), { name: this.name, ...options }) : {};
}, },
loadTheme(theme, options = {}) { loadTheme(theme, options = {}) {
return theme ? useStyle(ObjectUtils.minifyCSS(theme), { name: this.name, ...options }) : {}; return theme ? useStyle(ObjectUtils.minifyCSS(theme), { name: this.name, ...options }) : {};

View File

@ -1,4 +1,5 @@
<script> <script>
import Base from 'primevue/base';
import BaseStyle from 'primevue/base/style'; import BaseStyle from 'primevue/base/style';
import Theme, { ThemeService } from 'primevue/themes'; import Theme, { ThemeService } from 'primevue/themes';
import { DomHandler, ObjectUtils, UniqueComponentId } from 'primevue/utils'; import { DomHandler, ObjectUtils, UniqueComponentId } from 'primevue/utils';
@ -35,8 +36,8 @@ export default {
immediate: true, immediate: true,
handler(newValue) { handler(newValue) {
if (!newValue) { if (!newValue) {
BaseComponentStyle.loadStyle(this.$styleOptions); this._loadCoreStyles();
this.$options.style && this.$style.loadStyle(this.$styleOptions); this._themeChangeListener(this._loadCoreStyles); // update styles with theme settings
} else { } else {
// load theme // load theme
this._loadThemeStyles(); this._loadThemeStyles();
@ -107,11 +108,28 @@ export default {
return ObjectUtils.isFunction(fn) ? fn(...args) : mergeProps(...args); return ObjectUtils.isFunction(fn) ? fn(...args) : mergeProps(...args);
}, },
_loadStyles() { _loadStyles() {
const _load = () => {
// @todo
if (!Base.isStyleNameLoaded('base')) {
BaseStyle.loadStyle(this.$styleOptions); BaseStyle.loadStyle(this.$styleOptions);
this._loadGlobalStyles(); this._loadGlobalStyles();
this._loadThemeStyles();
ThemeService.on('theme:change', this._loadThemeStyles); Base.setLoadedStyleName('base');
}
this._loadThemeStyles();
};
_load();
this._themeChangeListener(_load);
},
_loadCoreStyles() {
if (!Base.isStyleNameLoaded(this.$style?.name) && this.$style?.name) {
BaseComponentStyle.loadStyle(this.$styleOptions);
this.$options.style && this.$style.loadStyle(this.$styleOptions);
Base.setLoadedStyleName(this.$style.name);
}
}, },
_loadGlobalStyles() { _loadGlobalStyles() {
/* /*
@ -167,6 +185,10 @@ export default {
this.scopedStyleEl = scopedStyle.el; this.scopedStyleEl = scopedStyle.el;
}, },
_themeChangeListener(callback = () => {}) {
Base.clearLoadedStyleNames();
ThemeService.on('theme:change', callback);
},
_getHostInstance(instance) { _getHostInstance(instance) {
return instance ? (this.$options.hostName ? (instance.$.type.name === this.$options.hostName ? instance : this._getHostInstance(instance.$parentInstance)) : instance.$parentInstance) : undefined; return instance ? (this.$options.hostName ? (instance.$.type.name === this.$options.hostName ? instance : this._getHostInstance(instance.$parentInstance)) : instance.$parentInstance) : undefined;
}, },

View File

@ -1,3 +1,4 @@
import Base from 'primevue/base';
import BaseStyle from 'primevue/base/style'; import BaseStyle from 'primevue/base/style';
import Theme, { ThemeService } from 'primevue/themes'; import Theme, { ThemeService } from 'primevue/themes';
import { ObjectUtils, UniqueComponentId } from 'primevue/utils'; import { ObjectUtils, UniqueComponentId } from 'primevue/utils';
@ -76,14 +77,21 @@ const BaseDirective = {
}, },
_loadStyles: (el, binding, vnode) => { _loadStyles: (el, binding, vnode) => {
const config = BaseDirective._getConfig(binding, vnode); const config = BaseDirective._getConfig(binding, vnode);
const useStyleOptions = { nonce: config?.csp?.nonce };
BaseStyle.loadStyle({ nonce: config?.csp?.nonce }); BaseDirective._loadCoreStyles(el.$instance, useStyleOptions);
!el.$instance?.isUnstyled() && el.$instance?.$style?.loadStyle({ nonce: config?.csp?.nonce }); BaseDirective._loadThemeStyles(el.$instance, useStyleOptions);
BaseDirective._loadScopedThemeStyles(el.$instance, useStyleOptions);
BaseDirective._loadThemeStyles(el.$instance, { nonce: config?.csp?.nonce }); BaseDirective._themeChangeListener(() => BaseDirective._loadThemeStyles(el.$instance, useStyleOptions));
ThemeService.on('theme:change', () => BaseDirective._loadThemeStyles(el.$instance, { nonce: config?.csp?.nonce })); },
_loadCoreStyles(instance = {}, useStyleOptions) {
if (!Base.isStyleNameLoaded(instance.$style?.name) && instance.$style?.name) {
BaseStyle.loadStyle(useStyleOptions);
instance.isUnstyled() && instance.$style?.loadStyle(useStyleOptions);
BaseDirective._loadScopedThemeStyles(el.$instance, { nonce: config?.csp?.nonce }); Base.setLoadedStyleName(instance.$style.name);
}
}, },
_loadThemeStyles: (instance = {}, useStyleOptions) => { _loadThemeStyles: (instance = {}, useStyleOptions) => {
if (instance?.isUnstyled()) return; if (instance?.isUnstyled()) return;
@ -128,6 +136,10 @@ const BaseDirective = {
instance.scopedStyleEl = scopedStyle.el; instance.scopedStyleEl = scopedStyle.el;
} }
}, },
_themeChangeListener(callback = () => {}) {
Base.clearLoadedStyleNames();
ThemeService.on('theme:change', callback);
},
_hook: (directiveName, hookName, el, binding, vnode, prevVnode) => { _hook: (directiveName, hookName, el, binding, vnode, prevVnode) => {
const name = `on${ObjectUtils.toCapitalCase(hookName)}`; const name = `on${ObjectUtils.toCapitalCase(hookName)}`;
const config = BaseDirective._getConfig(binding, vnode); const config = BaseDirective._getConfig(binding, vnode);

View File

@ -63,7 +63,7 @@ import ConfirmationEventBus from 'primevue/confirmationeventbus';
import FocusTrap from 'primevue/focustrap'; import FocusTrap from 'primevue/focustrap';
import OverlayEventBus from 'primevue/overlayeventbus'; import OverlayEventBus from 'primevue/overlayeventbus';
import Portal from 'primevue/portal'; import Portal from 'primevue/portal';
import { $dtp } from 'primevue/themes'; import { $dt } from 'primevue/themes';
import { ConnectedOverlayScrollHandler, DomHandler, ZIndexUtils } from 'primevue/utils'; import { ConnectedOverlayScrollHandler, DomHandler, ZIndexUtils } from 'primevue/utils';
import BaseConfirmPopup from './BaseConfirmPopup.vue'; import BaseConfirmPopup from './BaseConfirmPopup.vue';
@ -204,7 +204,7 @@ export default {
arrowLeft = targetOffset.left - containerOffset.left; arrowLeft = targetOffset.left - containerOffset.left;
} }
this.container.style.setProperty($dtp('overlay.arrow.left').name, `${arrowLeft}px`); this.container.style.setProperty($dt('overlay.arrow.left').name, `${arrowLeft}px`);
if (containerOffset.top < targetOffset.top) { if (containerOffset.top < targetOffset.top) {
this.container.setAttribute('data-p-confirm-popup-flipped', 'true'); this.container.setAttribute('data-p-confirm-popup-flipped', 'true');

View File

@ -37,15 +37,21 @@ export default {
}, },
valueColor: { valueColor: {
type: String, type: String,
default: $dt('knob.value.background') default: () => {
return $dt('knob.value.background').variable;
}
}, },
rangeColor: { rangeColor: {
type: String, type: String,
default: $dt('knob.range.background') default: () => {
return $dt('knob.range.background').variable;
}
}, },
textColor: { textColor: {
type: String, type: String,
default: $dt('knob.text.color') default: () => {
return $dt('knob.text.color').variable;
}
}, },
strokeWidth: { strokeWidth: {
type: Number, type: Number,

View File

@ -18,7 +18,7 @@ import FocusTrap from 'primevue/focustrap';
import OverlayEventBus from 'primevue/overlayeventbus'; import OverlayEventBus from 'primevue/overlayeventbus';
import Portal from 'primevue/portal'; import Portal from 'primevue/portal';
import Ripple from 'primevue/ripple'; import Ripple from 'primevue/ripple';
import { $dtp } from 'primevue/themes'; import { $dt } from 'primevue/themes';
import { ConnectedOverlayScrollHandler, DomHandler, UniqueComponentId, ZIndexUtils } from 'primevue/utils'; import { ConnectedOverlayScrollHandler, DomHandler, UniqueComponentId, ZIndexUtils } from 'primevue/utils';
import BaseOverlayPanel from './BaseOverlayPanel.vue'; import BaseOverlayPanel from './BaseOverlayPanel.vue';
@ -155,7 +155,7 @@ export default {
arrowLeft = targetOffset.left - containerOffset.left; arrowLeft = targetOffset.left - containerOffset.left;
} }
this.container.style.setProperty($dtp('overlay.arrow.left').name, `${arrowLeft}px`); this.container.style.setProperty($dt('overlay.arrow.left').name, `${arrowLeft}px`);
if (containerOffset.top < targetOffset.top) { if (containerOffset.top < targetOffset.top) {
this.container.setAttribute('data-p-overlaypanel-flipped', 'true'); this.container.setAttribute('data-p-overlaypanel-flipped', 'true');

View File

@ -67,7 +67,7 @@
import Button from 'primevue/button'; import Button from 'primevue/button';
import PlusIcon from 'primevue/icons/plus'; import PlusIcon from 'primevue/icons/plus';
import Ripple from 'primevue/ripple'; import Ripple from 'primevue/ripple';
import { $dt, $dtp } from 'primevue/themes'; import { $dt } from 'primevue/themes';
import Tooltip from 'primevue/tooltip'; import Tooltip from 'primevue/tooltip';
import { DomHandler, UniqueComponentId } from 'primevue/utils'; import { DomHandler, UniqueComponentId } from 'primevue/utils';
import BaseSpeedDial from './BaseSpeedDial.vue'; import BaseSpeedDial from './BaseSpeedDial.vue';
@ -108,8 +108,8 @@ export default {
const wDiff = Math.abs(button.offsetWidth - firstItem.offsetWidth); const wDiff = Math.abs(button.offsetWidth - firstItem.offsetWidth);
const hDiff = Math.abs(button.offsetHeight - firstItem.offsetHeight); const hDiff = Math.abs(button.offsetHeight - firstItem.offsetHeight);
this.list.style.setProperty($dtp('item.diff.x').name, `${wDiff / 2}px`); this.list.style.setProperty($dt('item.diff.x').name, `${wDiff / 2}px`);
this.list.style.setProperty($dtp('item.diff.y').name, `${hDiff / 2}px`); this.list.style.setProperty($dt('item.diff.y').name, `${hDiff / 2}px`);
} }
} }

View File

@ -1,14 +1,25 @@
import Theme, { SharedUtils } from 'primevue/themes'; import { SharedUtils } from 'primevue/themes';
import Theme from 'primevue/themes/config';
const types = ['value', 'variable']; export const $dt = (tokenPath) => {
export const $dt = (tokenPath, param1, param2) => {
const theme = Theme.getTheme(); const theme = Theme.getTheme();
return types.includes(param1) ? dt(theme, tokenPath, undefined, param1) : dt(theme, tokenPath, param1, param2); const variable = dtwt(theme, tokenPath, undefined, 'variable');
const name = variable.match(/--[\w-]+/g)?.[0];
const value = dtwt(theme, tokenPath, undefined, 'value');
return {
name,
variable,
value
};
}; };
export const dt = (theme = {}, tokenPath, fallback, type = 'variable') => { export const dt = (...args) => {
return dtwt(Theme.getTheme(), ...args);
};
export const dtwt = (theme = {}, tokenPath, fallback, type = 'variable') => {
if (tokenPath) { if (tokenPath) {
const VARIABLE = Theme.defaults.variable; const VARIABLE = Theme.defaults.variable;
const { prefix, transform } = theme?.options || {}; const { prefix, transform } = theme?.options || {};
@ -21,17 +32,3 @@ export const dt = (theme = {}, tokenPath, fallback, type = 'variable') => {
return ''; return '';
}; };
export const $dtp = (tokenPath) => {
const theme = Theme.getTheme();
const variable = dt(theme, tokenPath, undefined, 'variable');
const name = variable.match(/--[\w-]+/g)?.[0];
const value = dt(theme, tokenPath, undefined, 'value');
return {
variable,
name,
value
};
};

View File

@ -1,4 +1,4 @@
import { SharedUtils, dt, toVariables } from 'primevue/themes'; import { SharedUtils, dtwt, toVariables } from 'primevue/themes';
export default { export default {
regex: { regex: {
@ -62,7 +62,7 @@ export default {
semantic_css = `${semantic_light_css}${semantic_dark_css}`; semantic_css = `${semantic_light_css}${semantic_dark_css}`;
} }
global_css = SharedUtils.object.getItemValue(base?.global?.css, { ...params, dt: (tokenPath, fallback, type) => dt(theme, tokenPath, fallback, type) }); global_css = SharedUtils.object.getItemValue(base?.global?.css, { ...params, dt: (...args) => dtwt(theme, ...args) });
global_css = this._transformCSS(name, global_css, undefined, 'style', options, set, defaults); global_css = this._transformCSS(name, global_css, undefined, 'style', options, set, defaults);
return { return {
@ -93,7 +93,7 @@ export default {
getBaseC({ name = '', theme = {}, params, set, defaults }) { getBaseC({ name = '', theme = {}, params, set, defaults }) {
const { base, options } = theme; const { base, options } = theme;
const { css } = base?.components?.[name] || {}; const { css } = base?.components?.[name] || {};
const computed_css = SharedUtils.object.getItemValue(css, { ...params, dt: (tokenPath, fallback, type) => dt(theme, tokenPath, fallback, type) }); const computed_css = SharedUtils.object.getItemValue(css, { ...params, dt: (...args) => dtwt(theme, ...args) });
return this._transformCSS(name, computed_css, undefined, 'style', options, set, defaults); return this._transformCSS(name, computed_css, undefined, 'style', options, set, defaults);
}, },
@ -108,7 +108,7 @@ export default {
const dName = name.replace('-directive', ''); const dName = name.replace('-directive', '');
const { base, options } = theme; const { base, options } = theme;
const { css } = base?.directives?.[dName] || {}; const { css } = base?.directives?.[dName] || {};
const computed_css = SharedUtils.object.getItemValue(css, { ...params, dt: (tokenPath, fallback, type) => dt(theme, tokenPath, fallback, type) }); const computed_css = SharedUtils.object.getItemValue(css, { ...params, dt: (...args) => dtwt(theme, ...args) });
return this._transformCSS(dName, computed_css, undefined, 'style', options, set, defaults); return this._transformCSS(dName, computed_css, undefined, 'style', options, set, defaults);
}, },
@ -173,10 +173,10 @@ export default {
if (colorScheme) { if (colorScheme) {
const path = this.paths.find((p) => p.scheme === colorScheme) || this.paths.find((p) => p.scheme === 'none'); const path = this.paths.find((p) => p.scheme === colorScheme) || this.paths.find((p) => p.scheme === 'none');
return path?.computed(colorScheme, tokenPathMap['paths']); return path?.computed(colorScheme, tokenPathMap['binding']);
} }
return this.paths.map((p) => p.computed(p.scheme, tokenPathMap)); return this.paths.map((p) => p.computed(p.scheme, tokenPathMap[p.scheme]));
} }
}; };
tokens[currentKey].paths.push({ tokens[currentKey].paths.push({
@ -187,8 +187,8 @@ export default {
const regex = /{([^}]*)}/g; const regex = /{([^}]*)}/g;
let computedValue = value; let computedValue = value;
tokenPathMap['path'] = this.path; tokenPathMap['name'] = this.path;
tokenPathMap['paths'] ||= {}; tokenPathMap['binding'] ||= {};
if (SharedUtils.object.test(regex, value)) { if (SharedUtils.object.test(regex, value)) {
const val = value.trim(); const val = value.trim();
@ -204,12 +204,12 @@ export default {
computedValue = SharedUtils.object.test(calculationRegex, _val.replace(cleanedVarRegex, '0')) ? `calc(${_val})` : _val; computedValue = SharedUtils.object.test(calculationRegex, _val.replace(cleanedVarRegex, '0')) ? `calc(${_val})` : _val;
} }
SharedUtils.object.isEmpty(tokenPathMap['paths']) && delete tokenPathMap['paths']; SharedUtils.object.isEmpty(tokenPathMap['binding']) && delete tokenPathMap['binding'];
return { return {
colorScheme, colorScheme,
tokenPath: this.path, path: this.path,
tokenPathMap, paths: tokenPathMap,
value: computedValue.includes('undefined') ? undefined : computedValue value: computedValue.includes('undefined') ? undefined : computedValue
}; };
} }
@ -228,8 +228,17 @@ export default {
const token = normalizePath(path); const token = normalizePath(path);
const colorScheme = path.includes('colorScheme.light') ? 'light' : path.includes('colorScheme.dark') ? 'dark' : undefined; const colorScheme = path.includes('colorScheme.light') ? 'light' : path.includes('colorScheme.dark') ? 'dark' : undefined;
const computedValues = [tokens[token]?.computed(colorScheme)].flat().filter((computed) => computed);
return [tokens[token]?.computed(colorScheme)].flat(); return computedValues.length === 1
? computedValues[0].value
: computedValues.reduce((acc = {}, computed) => {
const { colorScheme: cs, ...rest } = computed;
acc[cs] = rest;
return acc;
}, undefined);
}, },
_toVariables(theme, options) { _toVariables(theme, options) {
return toVariables(theme, { prefix: options?.prefix }); return toVariables(theme, { prefix: options?.prefix });

View File

@ -1,4 +1,4 @@
import { $dt, $dtp } from 'primevue/themes'; import { $dt } from 'primevue/themes';
export default { export default {
innerWidth(el) { innerWidth(el) {
@ -328,7 +328,7 @@ export default {
element.style.top = top + 'px'; element.style.top = top + 'px';
element.style.left = left + 'px'; element.style.left = left + 'px';
element.style.transformOrigin = origin; element.style.transformOrigin = origin;
gutter && (element.style.marginTop = origin === 'bottom' ? $dt('{anchor.gutter} * -1') : $dt('anchor.gutter')); gutter && (element.style.marginTop = origin === 'bottom' ? $dt('{anchor.gutter} * -1').variable : $dt('anchor.gutter').variable);
} }
}, },
@ -367,7 +367,7 @@ export default {
element.style.top = top + 'px'; element.style.top = top + 'px';
element.style.left = left + 'px'; element.style.left = left + 'px';
element.style.transformOrigin = origin; element.style.transformOrigin = origin;
gutter && (element.style.marginTop = origin === 'bottom' ? $dt('{anchor.gutter} * -1') : $dt('anchor.gutter')); gutter && (element.style.marginTop = origin === 'bottom' ? $dt('{anchor.gutter} * -1').variable : $dt('anchor.gutter').variable);
} }
}, },
@ -851,12 +851,12 @@ export default {
}, },
blockBodyScroll(className = 'p-overflow-hidden') { blockBodyScroll(className = 'p-overflow-hidden') {
document.body.style.setProperty($dtp('scrollbar.width').name, this.calculateBodyScrollbarWidth() + 'px'); document.body.style.setProperty($dt('scrollbar.width').name, this.calculateBodyScrollbarWidth() + 'px');
this.addClass(document.body, className); this.addClass(document.body, className);
}, },
unblockBodyScroll(className = 'p-overflow-hidden') { unblockBodyScroll(className = 'p-overflow-hidden') {
document.body.style.removeProperty($dtp('scrollbar.width').name); document.body.style.removeProperty($dt('scrollbar.width').name);
this.removeClass(document.body, className); this.removeClass(document.body, className);
} }
}; };

View File

@ -33,7 +33,7 @@ export default {
var(--p-blue-500) var(--p-blue-500)
// With JS // With JS
$dt('blue.500', 'value') $dt('blue.500').value
` `
} }
}; };