Change theming implementation - 1/2

pull/5507/head
mertsincan 2024-03-05 09:22:33 +00:00
parent 6479cad038
commit 43bdf2c3e5
19 changed files with 474 additions and 61 deletions

View File

@ -6,6 +6,7 @@
<script> <script>
import EventBus from '@/layouts/AppEventBus'; import EventBus from '@/layouts/AppEventBus';
import { useColorMode } from 'primevue/themes';
export default { export default {
mounted() { mounted() {
@ -25,10 +26,13 @@ export default {
document.startViewTransition(() => this.applyTheme(event)); document.startViewTransition(() => this.applyTheme(event));
}, },
applyTheme(event) { applyTheme(event) {
this.$appState.darkTheme = event.dark; const { toggleColorMode } = useColorMode();
toggleColorMode();
/*this.$appState.darkTheme = event.dark;
if (event.dark) document.documentElement.classList.add('p-dark'); if (event.dark) document.documentElement.classList.add('p-dark');
else document.documentElement.classList.remove('p-dark'); else document.documentElement.classList.remove('p-dark');*/
} }
} }
}; };

View File

@ -1,3 +1,4 @@
import { SharedUtils, dt, toVariables } from 'primevue/themes';
import { useStyle } from 'primevue/usestyle'; import { useStyle } from 'primevue/usestyle';
import { ObjectUtils } from 'primevue/utils'; import { ObjectUtils } from 'primevue/utils';
@ -39,6 +40,15 @@ export default {
loadTheme(theme, options = {}) { loadTheme(theme, options = {}) {
return theme ? useStyle(ObjectUtils.minifyCSS(theme), { name: `${this.name}-style`, ...options }) : {}; return theme ? useStyle(ObjectUtils.minifyCSS(theme), { name: `${this.name}-style`, ...options }) : {};
}, },
getGlobalThemeCSS(presetTheme, baseTheme, params, globalTheme) {
return BaseThemeStyle.getGlobalThemeCSS(this.name, presetTheme, baseTheme, params, globalTheme);
},
getPresetThemeCSS(presetCTheme, globalTheme) {
return BaseThemeStyle.getPresetCThemeCSS(this.name, presetCTheme, globalTheme);
},
getBaseThemeCSS(baseCTheme, params, globalTheme) {
return BaseThemeStyle.getBaseCThemeCSS(this.name, baseCTheme, params, globalTheme);
},
getStyleSheet(extendedCSS = '', props = {}) { getStyleSheet(extendedCSS = '', props = {}) {
if (this.css) { if (this.css) {
const _css = ObjectUtils.minifyCSS(`${this.css}${extendedCSS}`); const _css = ObjectUtils.minifyCSS(`${this.css}${extendedCSS}`);
@ -51,7 +61,137 @@ export default {
return ''; return '';
}, },
getThemeStyleSheet(globalTheme = {}, params, props = {}) {
const { preset, base } = globalTheme;
const presetCTheme = preset?.components?.[this.name];
const baseCTheme = base?.components?.[this.name];
const presetCThemeCSS = this.getPresetThemeCSS(presetCTheme, globalTheme);
const baseCThemeCSS = this.getBaseThemeCSS(baseCTheme, params, globalTheme);
const _props = Object.entries(props)
.reduce((acc, [k, v]) => acc.push(`${k}="${v}"`) && acc, [])
.join(' ');
let css = [];
presetCThemeCSS && css.push(`<style type="text/css" data-primevue-style-id="${this.name}-variables" ${_props}>${ObjectUtils.minifyCSS(presetCThemeCSS)}</style>`);
baseCThemeCSS && css.push(`<style type="text/css" data-primevue-style-id="${this.name}-style" ${_props}>${ObjectUtils.minifyCSS(baseCThemeCSS)}</style>`);
return css.join('');
},
getGlobalThemeStyleSheet(globalTheme = {}, params, props = {}) {
const { preset, base } = globalTheme;
const globalThemeCSS = this.getGlobalThemeCSS(preset, base, params, globalTheme);
const _props = Object.entries(props)
.reduce((acc, [k, v]) => acc.push(`${k}="${v}"`) && acc, [])
.join(' ');
return Object.entries(globalThemeCSS || {})
.reduce((acc, [key, value]) => {
if (value) {
const _css = ObjectUtils.minifyCSS(value);
acc.push(`<style type="text/css" data-primevue-style-id="${key}" ${_props}>${_css}</style>`);
}
return acc;
}, [])
.join('');
},
extend(style) { extend(style) {
return { ...this, css: undefined, ...style }; return { ...this, css: undefined, ...style };
} }
}; };
// @todo - Create new file for it.
const BaseThemeStyle = {
getGlobalThemeCSS(name, presetTheme, baseTheme, params, globalTheme) {
let primitive_css, semantic_css, global_css;
if (ObjectUtils.isNotEmpty(presetTheme)) {
const { options } = globalTheme;
const { primitive, semantic } = presetTheme;
const { colorScheme, ...sRest } = semantic || {};
const { dark, ...csRest } = colorScheme || {};
const prim_css = ObjectUtils.isNotEmpty(primitive) ? this._toVariables({ primitive }, options).declarations : '';
const sRest_css = ObjectUtils.isNotEmpty(sRest) ? this._toVariables({ semantic: sRest }, options).declarations : '';
const csRest_css = ObjectUtils.isNotEmpty(csRest) ? this._toVariables({ light: csRest }, options).declarations : '';
const dark_css = ObjectUtils.isNotEmpty(dark) ? this._toVariables({ dark }, options).declarations : '';
primitive_css = this._transformCSS(name, prim_css, 'light', 'variable', options);
semantic_css = `${this._transformCSS(name, `${sRest_css}${csRest_css}color-scheme:light`, 'light', 'variable', options)}${this._transformCSS(name, `${dark_css}color-scheme:dark`, 'dark', 'variable', options)}`;
}
global_css = ObjectUtils.getItemValue(baseTheme?.components?.global?.css, { ...params, dt: (tokenPath) => dt(globalTheme, tokenPath) });
return {
primitive: primitive_css,
semantic: semantic_css,
global: global_css
};
},
getPresetCThemeCSS(name, presetCTheme = {}, globalTheme) {
const { options } = globalTheme;
const { colorScheme, ...vRest } = presetCTheme;
const { dark, ...csRest } = colorScheme || {};
const vRest_css = ObjectUtils.isNotEmpty(vRest) ? this._toVariables({ [name]: vRest }, options).declarations : '';
const csRest_css = ObjectUtils.isNotEmpty(csRest) ? this._toVariables({ [name]: csRest }, options).declarations : '';
const dark_css = ObjectUtils.isNotEmpty(dark) ? this._toVariables({ [name]: dark }, options).declarations : '';
return `${this._transformCSS(name, `${vRest_css}${csRest_css}`, 'light', 'variable', options)}${this._transformCSS(name, dark_css, 'dark', 'variable', options)}`;
},
getBaseCThemeCSS(name, baseCTheme = {}, params, globalTheme) {
const { options } = globalTheme;
const { css } = baseCTheme;
const computed_css = ObjectUtils.getItemValue(css, { ...params, dt: (tokenPath) => dt(globalTheme, tokenPath) });
return this._transformCSS(name, computed_css, undefined, 'style', options);
},
_toVariables(theme, options) {
return toVariables(theme, { prefix: options?.prefix });
},
_transformCSS(name, css, mode, type, options = {}) {
const { layer, colorScheme } = options;
if (type !== 'style') {
let colorSchemeOption = {
light: {
class: '',
rule: `:root{[CSS]}`,
default: false
},
dark: {
class: 'p-dark',
rule: `.p-dark{[CSS]}`,
default: false
}
};
if (colorScheme) {
if (ObjectUtils.isObject(colorScheme)) {
colorSchemeOption.light = { ...colorSchemeOption.light, ...colorScheme.light };
colorSchemeOption.dark = { ...colorSchemeOption.dark, ...colorScheme.dark };
} else {
colorSchemeOption.light = { ...colorSchemeOption.light, default: colorScheme !== 'auto' && colorScheme !== 'dark' };
colorSchemeOption.dark = { ...colorSchemeOption.dark, default: colorScheme === 'dark' };
}
}
mode = mode === 'dark' ? 'dark' : 'light';
css = colorSchemeOption[mode]?.rule?.replace('[CSS]', css);
}
if (layer) {
let layerOptions = {
name: 'primevue'
//order: '@layer'
};
const _layer = ObjectUtils.isObject(layer) ? layer.name : layer;
layerOptions.name = ObjectUtils.getItemValue(_layer, { name, type });
css = ObjectUtils.isNotEmpty(layerOptions.name) ? SharedUtils.object.getRule(`@layer ${layerOptions.name}`, css) : css;
}
return css;
}
};

View File

@ -1,7 +1,7 @@
<script> <script>
import BaseStyle from 'primevue/base/style'; import BaseStyle from 'primevue/base/style';
import { toVariables } from 'primevue/themes'; import Theme from 'primevue/themes';
import { ObjectUtils } from 'primevue/utils'; import { DomHandler, ObjectUtils } from 'primevue/utils';
import { mergeProps } from 'vue'; import { mergeProps } from 'vue';
import BaseComponentStyle from './style/BaseComponentStyle'; import BaseComponentStyle from './style/BaseComponentStyle';
@ -36,28 +36,36 @@ export default {
} }
} }
}, },
$globalPresetCTheme: { $globalPresetTheme: {
deep: true,
immediate: true, immediate: true,
handler(newValue, oldValue) { handler(newValue) {
if (newValue && newValue !== oldValue) { const { primitive, semantic, global } = this.$style?.getGlobalThemeCSS(newValue, this.$globalBaseTheme, this.$themeParams, this.$globalTheme);
const { colorScheme, ...vRest } = newValue;
const { dark, ...csRest } = colorScheme || {}; BaseStyle.loadTheme(primitive, { name: 'primitive-variables', useStyleOptions: this.$styleOptions });
const vRest_css = ObjectUtils.isNotEmpty(vRest) ? toVariables({ [this.$style.name]: vRest }).css : ''; BaseStyle.loadTheme(semantic, { name: 'semantic-variables', useStyleOptions: this.$styleOptions });
const csRest_css = ObjectUtils.isNotEmpty(csRest) ? toVariables({ [this.$style.name]: csRest }).css : ''; BaseComponentStyle.loadGlobalTheme(global, this.$styleOptions);
const dark_css = ObjectUtils.isNotEmpty(dark) ? toVariables({ [this.$style.name]: dark }, { selector: '.p-dark' }).css : ''; }
const variables_css = `${vRest_css}${csRest_css}${dark_css}`; },
$globalPresetCTheme: {
deep: true,
immediate: true,
handler(newValue) {
if (newValue) {
const variables_css = this.$style?.getPresetThemeCSS(newValue, this.$globalTheme);
this.$style?.loadTheme(`${variables_css}`, { name: `${this.$style.name}-variables`, useStyleOptions: this.$styleOptions }); this.$style?.loadTheme(`${variables_css}`, { name: `${this.$style.name}-variables`, useStyleOptions: this.$styleOptions });
} }
} }
}, },
$globalBaseCTheme: { $globalBaseCTheme: {
deep: true,
immediate: true, immediate: true,
handler(newValue, oldValue) { handler(newValue) {
if (newValue && newValue !== oldValue) { if (newValue) {
const { css } = newValue; const style_css = this.$style?.getBaseThemeCSS(newValue, this.$themeParams, this.$globalTheme);
this.$style?.loadTheme(`${css}`, { useStyleOptions: this.$styleOptions }); this.$style?.loadTheme(style_css, { useStyleOptions: this.$styleOptions });
} }
} }
} }
@ -81,8 +89,41 @@ export default {
beforeMount() { beforeMount() {
BaseStyle.loadStyle(this.$styleOptions); BaseStyle.loadStyle(this.$styleOptions);
this._loadGlobalStyles(); this._loadGlobalStyles();
this._loadGlobalThemeStyles();
this._hook('onBeforeMount'); this._hook('onBeforeMount');
// @todo
const { colorScheme } = this.$globalThemeOptions || {};
let colorSchemeOption = {
light: {
class: '',
default: false
},
dark: {
class: 'p-dark',
default: false
}
};
if (colorScheme) {
if (ObjectUtils.isObject(colorScheme)) {
colorSchemeOption.light = { ...colorSchemeOption.light, ...colorScheme.light };
colorSchemeOption.dark = { ...colorSchemeOption.dark, ...colorScheme.dark };
} else {
colorSchemeOption.light = { ...colorSchemeOption.light, default: colorScheme !== 'auto' && colorScheme !== 'dark' };
colorSchemeOption.dark = { ...colorSchemeOption.dark, default: colorScheme === 'dark' };
}
const isAuto = !colorSchemeOption.light?.default && !colorSchemeOption.dark?.default;
const isDark = isAuto ? window.matchMedia('(prefers-color-scheme: dark)') : colorSchemeOption.dark?.default;
const defaultDocument = DomHandler.isClient() ? window.document : undefined;
Theme.setColorMode(isDark ? 'dark' : 'light');
if (isDark && defaultDocument) {
DomHandler.addClass(defaultDocument.documentElement, colorSchemeOption.dark?.class);
}
}
}, },
mounted() { mounted() {
this._hook('onMounted'); this._hook('onMounted');
@ -127,23 +168,6 @@ export default {
ObjectUtils.isNotEmpty(globalCSS) && BaseComponentStyle.loadGlobalStyle(globalCSS, this.$styleOptions); ObjectUtils.isNotEmpty(globalCSS) && BaseComponentStyle.loadGlobalStyle(globalCSS, this.$styleOptions);
}, },
_loadGlobalThemeStyles() {
if (ObjectUtils.isNotEmpty(this.$globalPresetTheme)) {
const { primitive, semantic } = this.$globalPresetTheme;
const { colorScheme, ...sRest } = semantic || {};
const { dark, ...csRest } = colorScheme || {};
const primitive_css = ObjectUtils.isNotEmpty(primitive) ? toVariables({ primitive }).css : '';
const sRest_css = ObjectUtils.isNotEmpty(sRest) ? toVariables({ semantic: sRest }).css : '';
const csRest_css = ObjectUtils.isNotEmpty(csRest) ? toVariables({ light: csRest }).css : '';
const dark_css = ObjectUtils.isNotEmpty(dark) ? toVariables({ dark }, { selector: '.p-dark' }).css : '';
const semantic_css = `${sRest_css}${csRest_css}${dark_css}`;
BaseStyle.loadTheme(primitive_css, { name: 'primitive-variables', useStyleOptions: this.$styleOptions });
BaseStyle.loadTheme(semantic_css, { name: 'semantic-variables', useStyleOptions: this.$styleOptions });
}
BaseComponentStyle.loadGlobalTheme(this.$globalBaseTheme?.components?.global?.css, this.$styleOptions);
},
_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;
}, },
@ -271,17 +295,20 @@ export default {
$globalTheme() { $globalTheme() {
return this.$config?.theme; return this.$config?.theme;
}, },
$globalThemeOptions() {
return this.$globalTheme?.options;
},
$globalBaseTheme() { $globalBaseTheme() {
return ObjectUtils.getItemValue(this.$globalTheme?.base); return ObjectUtils.getItemValue(this.$globalTheme?.base);
}, },
$globalBaseCTheme() { $globalBaseCTheme() {
return ObjectUtils.getItemValue(this.$globalBaseTheme?.components?.[this.$style.name], this.$params); return ObjectUtils.getItemValue(this.$globalBaseTheme?.components?.[this.$style.name], this.$themeParams);
}, },
$globalPresetTheme() { $globalPresetTheme() {
return ObjectUtils.getItemValue(this.$globalTheme?.preset, this.$globalTheme?.options); return ObjectUtils.getItemValue(this.$globalTheme?.preset, { options: { ...this.$globalThemeOptions } });
}, },
$globalPresetCTheme() { $globalPresetCTheme() {
return ObjectUtils.getItemValue(this.$globalPresetTheme?.components?.[this.$style.name], this.$params); return ObjectUtils.getItemValue(this.$globalPresetTheme?.components?.[this.$style.name], this.$themeParams);
}, },
$style() { $style() {
return { classes: undefined, inlineStyles: undefined, loadStyle: () => {}, loadCustomStyle: () => {}, loadTheme: () => {}, ...(this._getHostInstance(this) || {}).$style, ...this.$options.style }; return { classes: undefined, inlineStyles: undefined, loadStyle: () => {}, loadCustomStyle: () => {}, loadTheme: () => {}, ...(this._getHostInstance(this) || {}).$style, ...this.$options.style };
@ -313,6 +340,16 @@ export default {
parentInstance parentInstance
}; };
}, },
$themeParams() {
return {
...this.$params,
globalTheme: {
base: { ...this.$globalBaseTheme },
preset: { ...this.$globalPresetTheme },
options: { ...this.$globalThemeOptions }
}
};
},
$_attrsPT() { $_attrsPT() {
return Object.entries(this.$attrs || {}) return Object.entries(this.$attrs || {})
.filter(([key]) => key?.startsWith('pt:')) .filter(([key]) => key?.startsWith('pt:'))

View File

@ -1,7 +1,8 @@
import { FilterMatchMode } from 'primevue/api'; import { FilterMatchMode } from 'primevue/api';
import Theme from 'primevue/themes';
import PrimeOne from 'primevue/themes/primeone'; import PrimeOne from 'primevue/themes/primeone';
import Aura from 'primevue/themes/primeone/aura'; import Aura from 'primevue/themes/primeone/aura';
import { inject, reactive } from 'vue'; import { inject, reactive, watch } from 'vue';
export const defaultOptions = { export const defaultOptions = {
ripple: false, ripple: false,
@ -138,7 +139,35 @@ export const defaultOptions = {
theme: { theme: {
base: PrimeOne, base: PrimeOne,
preset: Aura, preset: Aura,
options: undefined options: {
prefix: 'p',
colorScheme: {
dark: {
class: 'p-dark',
rule: `.p-dark { [CSS] }`
//default: false
}
},
layer: false
/*colorScheme: {
// mode: 'light' | 'dark' | 'auto' | object // default: auto
light: {
class: '',
rule: `:root { [CSS] }`
//default: true
},
dark: {
class: 'p-dark',
rule: `.p-dark { [CSS] }`
//default: false
}
},
layer: {
// layer: true | false | undefined | object // default: undefined
name: '', // (component_name, type=variable|style) => layer_names // default: primevue
order: '' // (layer_names) => layer_order // default: @layer primevue
}*/
}
}, },
pt: undefined, pt: undefined,
ptOptions: { ptOptions: {
@ -194,6 +223,14 @@ export default {
changeTheme: switchTheme changeTheme: switchTheme
}; };
watch(
PrimeVue.config,
(newValue) => {
Theme.setPConfig(newValue);
},
{ immediate: true }
);
app.config.globalProperties.$primevue = PrimeVue; app.config.globalProperties.$primevue = PrimeVue;
app.provide(PrimeVueSymbol, PrimeVue); app.provide(PrimeVueSymbol, PrimeVue);
} }

View File

@ -0,0 +1,36 @@
import { SharedUtils, ThemeService } from 'primevue/themes';
const ServiceSymbol = Symbol();
export default {
_pConfig: undefined,
_colorMode: 'dark',
getPConfig() {
return this._pConfig;
},
setPConfig(newValue) {
this._pConfig = newValue;
ThemeService.emit(ServiceSymbol, this._pConfig);
},
onPConfigChange(callback) {
ThemeService.on(ServiceSymbol, callback);
},
getColorMode() {
return this._colorMode;
},
setColorMode(newValue) {
this._colorMode = newValue;
},
toggleColorMode() {
this._colorMode = this._colorMode === 'dark' ? 'light' : 'dark';
const defaultDocument = SharedUtils.dom.isClient() ? window.document : undefined;
if (defaultDocument) {
const className = 'p-dark'; // @todo
this._colorMode !== 'dark' ? SharedUtils.dom.removeClass(defaultDocument.documentElement, className) : SharedUtils.dom.addClass(defaultDocument.documentElement, className);
}
return this._colorMode;
}
};

View File

@ -0,0 +1,6 @@
{
"main": "./index.cjs.js",
"module": "./index.esm.js",
"unpkg": "./index.min.js",
"types": "./index.d.ts"
}

View File

@ -1 +1,2 @@
export { default } from 'primevue/themes/config';
export * from './utils'; export * from './utils';

View File

@ -1,10 +1,10 @@
export default { export default {
css: ` css: ({ dt }) => `
.p-panel { .p-panel {
border: 1px solid var(--p-panel-border-color); border: 1px solid ${dt('panel.border.color')};
border-radius: var(--p-rounded-base); border-radius: ${dt('{rounded.base} * 2')};
background: var(--p-panel-background); background: ${dt('panel.background')};
color: var(--p-panel-text-color); color: ${dt('panel.text.color')};
} }
.p-panel-header { .p-panel-header {
@ -31,22 +31,22 @@ export default {
width: 1.75rem; width: 1.75rem;
height: 1.75rem; height: 1.75rem;
position: relative; position: relative;
color: var(--p-panel-header-icon-color); color: ${dt('panel.header.icon.color')};
border: 0 none; border: 0 none;
background: transparent; background: transparent;
border-radius: 50%; border-radius: 50%;
transition: background-color var(--p-transition-duration), color var(--p-transition-duration), outline-color var(--p-transition-duration); transition: background-color ${dt('transition.duration')}, color ${dt('transition.duration')}, outline-color ${dt('transition.duration')};
outline-color: transparent; outline-color: transparent;
} }
.p-panel-header-icon:enabled:hover { .p-panel-header-icon:enabled:hover {
color: var(--p-panel-header-icon-color-hover); color: ${dt('panel.header.icon.color.hover')};
background: var(--p-panel-header-icon-background-hover); background: ${dt('panel.header.icon.background.hover')};
} }
.p-panel-header-icon:focus-visible { .p-panel-header-icon:focus-visible {
outline: var(--p-focus-ring-width) var(--p-focus-ring-style) var(--p-focus-ring-color); outline: ${dt('focus.ring.width')} ${dt('focus.ring.style')} ${dt('focus.ring.color')};
outline-offset: var(--p-focus-ring-offset); outline-offset: ${dt('focus.ring.offset')};
} }
.p-panel-content { .p-panel-content {

View File

@ -0,0 +1,22 @@
import Theme, { SharedUtils } from 'primevue/themes';
const EXCLUDED_KEY_REGEX = /^(primitive|semantic|variables|colorscheme|light|dark|common|colors|root|states)$/gi;
export const $dt = (tokenPath) => {
const config = Theme.getPConfig();
return dt(config?.theme, tokenPath);
};
export const dt = (theme = {}, tokenPath) => {
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
return isStrictTransform ? SharedUtils.object.getComputedValue(theme?.preset, token, [EXCLUDED_KEY_REGEX]) : SharedUtils.object.getVariableValue(token, undefined, prefix, [EXCLUDED_KEY_REGEX]);
}
return '';
};

View File

@ -1,3 +1,6 @@
export * from './color'; export * from './color';
export { default as sharedUtils } from './sharedUtils'; export * from './dt';
export { default as ThemeService } from './service';
export { default as SharedUtils } from './sharedUtils';
export { default as toVariables } from './toVariables'; export { default as toVariables } from './toVariables';
export { default as useColorMode } from './useColorMode';

View File

@ -0,0 +1,36 @@
function createService() {
const allHandlers = new Map();
return {
on(type, handler) {
let handlers = allHandlers.get(type);
if (!handlers) handlers = [handler];
else handlers.push(handler);
allHandlers.set(type, handlers);
},
off(type, handler) {
let handlers = allHandlers.get(type);
if (handlers) {
handlers.splice(handlers.indexOf(handler) >>> 0, 1);
}
},
emit(type, evt) {
let handlers = allHandlers.get(type);
if (handlers) {
handlers.slice().map((handler) => {
handler(evt);
});
}
}
};
}
const ThemeService = createService();
export default ThemeService;

View File

@ -41,6 +41,19 @@ export default {
Object.assign(value1, value2); Object.assign(value1, value2);
} }
}, },
getItemValue(obj, ...params) {
return this.isFunction(obj) ? obj(...params) : obj;
},
getOptionValue(options, key = '', params = {}) {
const fKeys = this.toFlatCase(key).split('.');
const fKey = fKeys.shift();
return fKey
? this.isObject(options)
? this.getOptionValue(this.getItemValue(options[Object.keys(options).find((k) => this.toFlatCase(k) === fKey) || ''], params), fKeys.join('.'), params)
: undefined
: this.getItemValue(options, params);
},
test(regex, str) { test(regex, str) {
if (regex) { if (regex) {
const match = regex.test(str); const match = regex.test(str);
@ -70,19 +83,23 @@ export default {
toNormalizePrefix(prefix) { toNormalizePrefix(prefix) {
return prefix.replaceAll(/ /g, '').replace(/[^\w]/g, '-'); return prefix.replaceAll(/ /g, '').replace(/[^\w]/g, '-');
}, },
toNormalizeVariable(prefix = '', variable = '') {
return this.toNormalizePrefix(`${this.isString(prefix, false) && this.isString(variable, false) ? `${prefix}-` : prefix}${variable}`);
},
getVariableName(prefix = '', variable = '') {
return `--${this.toNormalizeVariable(prefix, variable)}`;
},
getVariableValue(value, variable = '', prefix = '', excludedKeyRegexes = []) { getVariableValue(value, variable = '', prefix = '', excludedKeyRegexes = []) {
if (this.isString(value)) { if (this.isString(value)) {
const regex = /{([^}]*)}/g; const regex = /{([^}]*)}/g;
const val = value.trim(); const val = value.trim();
const px = prefix.trim();
if (this.test(regex, val)) { if (this.test(regex, val)) {
const computedPx = this.isNotEmpty(px) ? `${px}-` : px;
const _val = val.replaceAll(regex, (v) => { const _val = val.replaceAll(regex, (v) => {
const path = v.replace(/{|}/g, ''); const path = v.replace(/{|}/g, '');
const keys = path.split('.').filter((_v) => !excludedKeyRegexes.some((_r) => this.test(_r, _v))); const keys = path.split('.').filter((_v) => !excludedKeyRegexes.some((_r) => this.test(_r, _v)));
return `var(--${computedPx}${this.toKebabCase(keys.join('-'))})`; return `var(${this.getVariableName(prefix, this.toKebabCase(keys.join('-')))})`;
}); });
const calculationRegex = /(\d+\s+[\+\-\*\/]\s+\d+)/g; const calculationRegex = /(\d+\s+[\+\-\*\/]\s+\d+)/g;
@ -98,6 +115,18 @@ export default {
return undefined; return undefined;
}, },
getComputedValue(obj = {}, value) {
if (this.isString(value)) {
const regex = /{([^}]*)}/g;
const val = value.trim();
return this.test(regex, val) ? val.replaceAll(regex, (v) => this.getOptionValue(obj, v.replace(/{|}/g, ''))) : val;
} else if (this.isNumber(value)) {
return value;
}
return undefined;
},
setProperty(properties, key, value) { setProperty(properties, key, value) {
if (this.isString(key, false)) { if (this.isString(key, false)) {
properties.push(`${key}:${value};`); properties.push(`${key}:${value};`);
@ -110,5 +139,30 @@ export default {
return ''; return '';
} }
},
dom: {
isClient() {
return !!(typeof window !== 'undefined' && window.document && window.document.createElement);
},
addClass(element, className) {
if (element && className && !this.hasClass(element, className)) {
if (element.classList) element.classList.add(className);
else element.className += ' ' + className;
}
},
removeClass(element, className) {
if (element && className) {
if (element.classList) element.classList.remove(className);
else element.className = element.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
}
},
hasClass(element, className) {
if (element) {
if (element.classList) return element.classList.contains(className);
else return new RegExp('(^| )' + className + '( |$)', 'gi').test(element.className);
}
return false;
}
} }
}; };

View File

@ -1,7 +1,7 @@
import SharedUtils from './sharedUtils'; import SharedUtils from './sharedUtils';
const VARIABLE = { const VARIABLE = {
PREFIX: 'p', PREFIX: '',
SELECTOR: ':root', SELECTOR: ':root',
EXCLUDED_KEY_REGEX: /^(primitive|semantic|variables|colorscheme|light|dark|common|colors|root|states)$/gi EXCLUDED_KEY_REGEX: /^(primitive|semantic|variables|colorscheme|light|dark|common|colors|root|states)$/gi
}; };
@ -11,7 +11,7 @@ export default function (theme, options = {}) {
const _toVariables = (_theme, _prefix = '') => { const _toVariables = (_theme, _prefix = '') => {
return Object.entries(_theme).reduce((acc, [key, value]) => { return Object.entries(_theme).reduce((acc, [key, value]) => {
const px = SharedUtils.object.toNormalizePrefix(SharedUtils.object.test(excludedKeyRegex, key) ? _prefix : `${_prefix}-${SharedUtils.object.toKebabCase(key)}`); const px = SharedUtils.object.test(excludedKeyRegex, key) ? SharedUtils.object.toNormalizeVariable(_prefix) : SharedUtils.object.toNormalizeVariable(_prefix, SharedUtils.object.toKebabCase(key));
const v = SharedUtils.object.toValue(value); const v = SharedUtils.object.toValue(value);
if (SharedUtils.object.isObject(v)) { if (SharedUtils.object.isObject(v)) {
@ -19,7 +19,7 @@ export default function (theme, options = {}) {
SharedUtils.object.merge(acc, variables); SharedUtils.object.merge(acc, variables);
} else { } else {
SharedUtils.object.setProperty(acc, `--${px}`, SharedUtils.object.getVariableValue(v, px, prefix, [excludedKeyRegex])); SharedUtils.object.setProperty(acc, SharedUtils.object.getVariableName(px), SharedUtils.object.getVariableValue(v, px, prefix, [excludedKeyRegex]));
} }
return acc; return acc;
@ -30,6 +30,7 @@ export default function (theme, options = {}) {
return { return {
value, value,
declarations: value.join(''),
css: SharedUtils.object.getRule(selector, value.join('')) css: SharedUtils.object.getRule(selector, value.join(''))
}; };
} }

View File

@ -0,0 +1,12 @@
import Theme from 'primevue/themes';
export default () => {
return {
colorMode: Theme.getColorMode(),
toggleColorMode() {
this.colorMode = Theme.toggleColorMode();
return this.colorMode;
}
};
};

View File

@ -14,6 +14,7 @@ export default defineNuxtModule({
resolvePath: undefined, resolvePath: undefined,
layerOrder: 'tailwind-base, primevue, tailwind-utilities', layerOrder: 'tailwind-base, primevue, tailwind-utilities',
importPT: undefined, importPT: undefined,
importTheme: undefined,
options: {}, options: {},
components: { components: {
prefix: '', prefix: '',
@ -38,7 +39,7 @@ export default defineNuxtModule({
setup(moduleOptions, nuxt) { setup(moduleOptions, nuxt) {
const resolver = createResolver(import.meta.url); const resolver = createResolver(import.meta.url);
const registered = register(moduleOptions); const registered = register(moduleOptions);
const { importPT, options } = moduleOptions; const { importPT, importTheme, options } = moduleOptions;
nuxt.options.runtimeConfig.public.primevue = { nuxt.options.runtimeConfig.public.primevue = {
...moduleOptions, ...moduleOptions,
@ -50,6 +51,8 @@ export default defineNuxtModule({
const styleContent = () => ` const styleContent = () => `
${registered.styles.map((style) => `import ${style.as} from '${style.from}';`).join('\n')} ${registered.styles.map((style) => `import ${style.as} from '${style.from}';`).join('\n')}
${importTheme ? `import ${importTheme.as} from '${importTheme.from}';\n` : ''}
const styleProps = { const styleProps = {
${options?.csp?.nonce ? `nonce: ${options?.csp?.nonce}` : ''} ${options?.csp?.nonce ? `nonce: ${options?.csp?.nonce}` : ''}
} }
@ -58,7 +61,12 @@ const styles = [
${registered.styles.map((item) => `${item.as} && ${item.as}.getStyleSheet ? ${item.as}.getStyleSheet(undefined, styleProps) : ''`).join(',')} ${registered.styles.map((item) => `${item.as} && ${item.as}.getStyleSheet ? ${item.as}.getStyleSheet(undefined, styleProps) : ''`).join(',')}
].join(''); ].join('');
export { styles }; const themes = [
${importTheme ? `${registered.styles[0].as} && ${registered.styles[0].as}.getGlobalThemeStyleSheet ? ${registered.styles[0].as}.getGlobalThemeStyleSheet(${importTheme?.as}, undefined, styleProps) : ''` : ''},
${importTheme ? registered.styles.map((item) => `${item.as} && ${item.as}.getThemeStyleSheet ? ${item.as}.getThemeStyleSheet(${importTheme?.as}, undefined, styleProps) : ''`).join(',') : ''}
].join('');
export { styles, themes };
`; `;
nuxt.options.alias['#primevue-style'] = addTemplate({ nuxt.options.alias['#primevue-style'] = addTemplate({
@ -77,14 +85,16 @@ ${registered.config.map((config) => `import ${config.as} from '${config.from}';`
${registered.services.map((service) => `import ${service.as} from '${service.from}';`).join('\n')} ${registered.services.map((service) => `import ${service.as} from '${service.from}';`).join('\n')}
${registered.directives.map((directive) => `import ${directive.as} from '${directive.from}';`).join('\n')} ${registered.directives.map((directive) => `import ${directive.as} from '${directive.from}';`).join('\n')}
${importPT ? `import ${importPT.as} from '${importPT.from}';\n` : ''} ${importPT ? `import ${importPT.as} from '${importPT.from}';\n` : ''}
${importTheme ? `import ${importTheme.as} from '${importTheme.from}';\n` : ''}
export default defineNuxtPlugin(({ vueApp }) => { export default defineNuxtPlugin(({ vueApp }) => {
const runtimeConfig = useRuntimeConfig(); const runtimeConfig = useRuntimeConfig();
const config = runtimeConfig?.public?.primevue ?? {}; const config = runtimeConfig?.public?.primevue ?? {};
const { usePrimeVue = true, options = {} } = config; const { usePrimeVue = true, options = {} } = config;
const pt = ${importPT ? `{ pt: ${importPT.as} }` : `{}`}; const pt = ${importPT ? `{ pt: ${importPT.as} }` : `{}`};
const theme = ${importTheme ? `{ theme: ${importTheme.as} }` : `{}`};
usePrimeVue && vueApp.use(PrimeVue, { ...options, ...pt }); usePrimeVue && vueApp.use(PrimeVue, { ...options, ...pt, ...theme });
${registered.services.map((service) => `vueApp.use(${service.as});`).join('\n')} ${registered.services.map((service) => `vueApp.use(${service.as});`).join('\n')}
${registered.directives.map((directive) => `vueApp.directive('${directive.name}', ${directive.as});`).join('\n')} ${registered.directives.map((directive) => `vueApp.directive('${directive.name}', ${directive.as});`).join('\n')}
}); });

View File

@ -7,5 +7,7 @@ const defineNitroPlugin = (def) => def;
export default defineNitroPlugin(async (nitroApp) => { export default defineNitroPlugin(async (nitroApp) => {
nitroApp.hooks.hook('render:html', (html) => { nitroApp.hooks.hook('render:html', (html) => {
html.head.push(styles); html.head.push(styles);
//html.head.push(themes);
//html.htmlAttrs.push('class="p-dark"'); // @todo
}); });
}); });

10
mytheme.js Normal file
View File

@ -0,0 +1,10 @@
import PrimeOne from 'primevue/themes/primeone';
import Aura from 'primevue/themes/primeone/aura';
export default {
base: PrimeOne,
preset: Aura,
options: {
prefix: 'p'
}
};

View File

@ -258,6 +258,7 @@ const THEME_ALIAS = {
'primevue/themes/primeone/presets': path.resolve(__dirname, './components/lib/themes/primeone/presets/index.js'), 'primevue/themes/primeone/presets': path.resolve(__dirname, './components/lib/themes/primeone/presets/index.js'),
'primevue/themes/primeone/aura': path.resolve(__dirname, './components/lib/themes/primeone/aura/index.js'), 'primevue/themes/primeone/aura': path.resolve(__dirname, './components/lib/themes/primeone/aura/index.js'),
'primevue/themes/primeone': path.resolve(__dirname, './components/lib/themes/primeone/index.js'), 'primevue/themes/primeone': path.resolve(__dirname, './components/lib/themes/primeone/index.js'),
'primevue/themes/config': path.resolve(__dirname, './components/lib/themes/config/index.js'),
'primevue/themes': path.resolve(__dirname, './components/lib/themes/index.js') 'primevue/themes': path.resolve(__dirname, './components/lib/themes/index.js')
}; };

View File

@ -26,6 +26,7 @@ export default defineNuxtConfig({
ripple: true ripple: true
}, },
layerOrder: 'primevue', layerOrder: 'primevue',
//importTheme: { from: '@/mytheme.js' },
resolvePath: function ({ as, from, type }) { resolvePath: function ({ as, from, type }) {
const resolvedPath = from.replace('primevue', '@/components/lib'); const resolvedPath = from.replace('primevue', '@/components/lib');