Skip to content

Commit

Permalink
Showing 7 changed files with 103 additions and 19 deletions.
3 changes: 2 additions & 1 deletion packages/base/src/AssetRegistry.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { registerI18nLoader } from "./asset-registries/i18n.js";
import { registerLocaleDataLoader } from "./asset-registries/LocaleData.js";
import { registerThemePropertiesLoader } from "./asset-registries/Themes.js";
import { registerThemePropertiesLoader, registerCustomThemePropertiesLoader } from "./asset-registries/Themes.js";
import { registerIconLoader } from "./asset-registries/Icons.js";

export {
registerI18nLoader,
registerLocaleDataLoader,
registerThemePropertiesLoader,
registerCustomThemePropertiesLoader,
registerIconLoader,
};
19 changes: 19 additions & 0 deletions packages/base/src/ManagedStyles.ts
Original file line number Diff line number Diff line change
@@ -139,12 +139,31 @@ const createOrUpdateStyle = (data: StyleData, name: string, value = "", theme?:
}
};

const mergeStyles = (style1?: StyleData, style2?: StyleData) => {
if (style1 === undefined) {
return style2;
}
if (style2 === undefined) {
return style1;
}
const style2Content = typeof style2 === "string" ? style2 : style2.content;
if (typeof style1 === "string") {
return `${style1} ${style2Content}`;
}
return {
content: `${style1.content} ${style2Content}`,
packageName: style1.packageName,
fileName: style1.fileName,
};
};

export {
createStyle,
hasStyle,
updateStyle,
removeStyle,
createOrUpdateStyle,
mergeStyles,
};

export type {
42 changes: 31 additions & 11 deletions packages/base/src/asset-registries/Themes.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { DEFAULT_THEME } from "../generated/AssetParameters.js";
import { StyleData, StyleDataCSP } from "../types.js";
import type { StyleData, StyleDataCSP } from "../ManagedStyles.js";
import { mergeStyles } from "../ManagedStyles.js";
import { fireThemeRegistered } from "../theming/ThemeRegistered.js";

type ThemeData = {_: StyleDataCSP } | StyleDataCSP | string;
type ThemeLoader = (themeName: string) => Promise<ThemeData>;

const themeStyles = new Map<string, StyleData>();
const loaders = new Map<string, ThemeLoader>();
const customLoaders = new Map<string, ThemeLoader>();
const registeredPackages = new Set<string>();
const registeredThemes = new Set<string>();

@@ -17,10 +19,15 @@ const registerThemePropertiesLoader = (packageName: string, themeName: string, l
fireThemeRegistered(themeName);
};

const getThemeProperties = async (packageName: string, themeName: string) => {
const style = themeStyles.get(`${packageName}_${themeName}`);
if (style !== undefined) { // it's valid for style to be an empty string
return style;
const registerCustomThemePropertiesLoader = (packageName: string, themeName: string, loader: ThemeLoader) => {
customLoaders.set(`${packageName}/${themeName}`, loader);
};

const getThemeProperties = async (packageName: string, themeName: string, externalThemeName?: string) => {
const cacheKey = `${packageName}_${themeName}_${externalThemeName || ""}`;
const cachedStyleData = themeStyles.get(cacheKey);
if (cachedStyleData !== undefined) { // it's valid for style to be an empty string
return cachedStyleData;
}

if (!registeredThemes.has(themeName)) {
@@ -29,14 +36,27 @@ const getThemeProperties = async (packageName: string, themeName: string) => {
return _getThemeProperties(packageName, DEFAULT_THEME);
}

return _getThemeProperties(packageName, themeName);
const [style, customStyle] = await Promise.all([
_getThemeProperties(packageName, themeName),
externalThemeName ? _getThemeProperties(packageName, externalThemeName, true) : undefined,
]);

const styleData = mergeStyles(style, customStyle);
if (styleData) {
themeStyles.set(cacheKey, styleData);
}

return styleData;
};

const _getThemeProperties = async (packageName: string, themeName: string) => {
const loader = loaders.get(`${packageName}/${themeName}`);
const _getThemeProperties = async (packageName: string, themeName: string, forCustomTheme = false) => {
const loadersMap = forCustomTheme ? customLoaders : loaders;
const loader = loadersMap.get(`${packageName}/${themeName}`);
if (!loader) {
// no themes for package
console.error(`Theme [${themeName}] not registered for package [${packageName}]`); /* eslint-disable-line */
if (!forCustomTheme) {
console.error(`Theme [${themeName}] not registered for package [${packageName}]`); /* eslint-disable-line */
}
return;
}
let data;
@@ -47,9 +67,8 @@ const _getThemeProperties = async (packageName: string, themeName: string) => {
console.error(packageName, e.message); /* eslint-disable-line */
return;
}
const themeProps = (data as {_: StyleDataCSP})._ || data; // Refactor: remove _ everywhere

themeStyles.set(`${packageName}_${themeName}`, themeProps);
const themeProps = (data as {_: StyleDataCSP})._ || data; // Refactor: remove _ everywhere
return themeProps;
};

@@ -63,6 +82,7 @@ const isThemeRegistered = (theme: string) => {

export {
registerThemePropertiesLoader,
registerCustomThemePropertiesLoader,
getThemeProperties,
getRegisteredPackages,
isThemeRegistered,
6 changes: 3 additions & 3 deletions packages/base/src/theming/applyTheme.ts
Original file line number Diff line number Diff line change
@@ -30,15 +30,15 @@ const deleteThemeBase = () => {
removeStyle("data-ui5-theme-properties", BASE_THEME_PACKAGE);
};

const loadComponentPackages = async (theme: string) => {
const loadComponentPackages = async (theme: string, externalThemeName?: string) => {
const registeredPackages = getRegisteredPackages();

const packagesStylesPromises = [...registeredPackages].map(async packageName => {
if (packageName === BASE_THEME_PACKAGE) {
return;
}

const cssData = await getThemeProperties(packageName, theme);
const cssData = await getThemeProperties(packageName, theme, externalThemeName);
if (cssData) {
createOrUpdateStyle(cssData, `data-ui5-component-properties-${getCurrentRuntimeIndex()}`, packageName);
}
@@ -83,7 +83,7 @@ const applyTheme = async (theme: string) => {

// Always load component packages properties. For non-registered themes, try with the base theme, if any
const packagesTheme = isThemeRegistered(theme) ? theme : extTheme && extTheme.baseThemeName;
await loadComponentPackages(packagesTheme || DEFAULT_THEME);
await loadComponentPackages(packagesTheme || DEFAULT_THEME, extTheme && extTheme.themeName === theme ? theme : undefined);

fireThemeLoaded(theme);
};
9 changes: 9 additions & 0 deletions packages/main/bundle.common.js
Original file line number Diff line number Diff line change
@@ -13,6 +13,15 @@ import "@ui5/webcomponents-localization/dist/features/calendar/Persian.js";
// CLDR
import getLocaleData from "@ui5/webcomponents-localization/dist/locale/getLocaleData.js";

// import { registerCustomThemePropertiesLoader } from "@ui5/webcomponents-base/dist/AssetRegistry.js";
// import { getScopedVarName } from "@ui5/webcomponents-base/dist/CustomElementsScope.js";
// const customThemeLoader = theme => Promise.resolve(`:root {
// ${getScopedVarName("--_ui5_button_base_height")}: 4rem;
// ${getScopedVarName("--_ui5_button_base_padding")}: 2rem;
// }`);
// registerCustomThemePropertiesLoader("@ui5/webcomponents", "my_custom_theme", customThemeLoader);


// Uncomment to test the registration of custom properties and JSON bundles - use the TextArea test page
// import { registerI18nLoader } from "@ui5/webcomponents-base/dist/asset-registries/i18n.js";
// import parse from "@ui5/webcomponents-base/dist/PropertiesFileFormat.js";
4 changes: 2 additions & 2 deletions packages/main/test/pages/Kitchen.html
Original file line number Diff line number Diff line change
@@ -10,9 +10,9 @@

<link rel="stylesheet" type="text/css" href="./styles/Kitchen.css">

<!-- CUSTOM THEME: my_custom_theme
<!--
<link rel="stylesheet" type="text/css" href="./css/css_variables.css">
-->
-->

<!-- ANOTHER CUSTOM THEME: custom_belize@url
<link rel="stylesheet" type="text/css" href="./css/css_variables2.css?version=1.93.0&sap-ui-dist-version=1.93.0">
39 changes: 37 additions & 2 deletions packages/tools/lib/postcss-scope-vars/index.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,45 @@
const path = require("path");
const name = "postcss-scope-vars";

const escapeVersion = version => "v" + version?.replaceAll(/[^0-9A-Za-z\-_]/g, "-");

/**
* Tries to detect an override for a package
* @param {*} filePath For example: /my_project/src/themes/overrides/@ui5/webcomponents/my_custom_theme/parameters-bundle.css
* @returns
*/
const getOverrideVersion = filePath => {
console.log(filePath);
if (!filePath.includes(`overrides${path.sep}`)) {
return; // The "overrides/" directory is the marker
}
const override = filePath.split(`overrides${path.sep}`)[1]; // For example, this will be: @ui5/webcomponents/my_custom_theme/parameters-bundle.css
if (!override) {
return; // There must be other directories after overrides/, the path can't end with it
}
const parts = override.split(path.sep);
if (parts.length < 3) {
return; // There must be at least a directory for the theme that is being overridden (my_custom_theme) and the name of the CSS file after the name of the package that is overridden
}
const packageName = parts.slice(0, -2).join(path.sep); // After the last 2 parts are removed (my_custom_theme and parameters-bundle.css from the example), the rest is the package

let overrideVersion;
try {
overrideVersion = require(`${packageName}${path.sep}package.json`).version;
} catch (e) {
console.log(`Error requiring package ${packageName}: ${e.message}`);
}

return overrideVersion;
}

module.exports = (options) => {
const versionStr = "v" + options?.version?.replaceAll(/[^0-9A-Za-z\-_]/g, "-");
return {
postcssPlugin: name,
prepare() {
prepare(opts) {
const filePath = opts.root.source.input.file;
const versionStr = escapeVersion(getOverrideVersion(filePath) || options?.version);

return {
Declaration: (declaration) => {
if (declaration.__ui5_replaced) {

0 comments on commit c6c04c6

Please sign in to comment.