Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions docs/2-advanced/01-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ There are several configuration settings that affect all UI5 Web Components glob
| [fetchDefaultLanguage](#fetchDefaultLanguage) | `true`, `false` | `false` | Whether to fetch assets even for the default language | Framework |
| [defaultFontLoading](#defaultFontLoading) | `true`, `false` | `true` | Whether to fetch default font faces | Framework |
| [enableDefaultTooltips](#enableDefaultTooltips) | `true`, `false` | `true` | Whether to display default tooltips | Components (Icon, Button, RatingIndicator, etc.) |
| [skipThemeBase](#skipThemeBase) | `true`, `false` | `false` | Whether to skip loading current theme base | Framework |
| [timezone](#timezone) | `Asia/Tokyo`, `Pacific/Apia`, `Asia/Kolkata`, `Europe/Sofia` and etc. | Your local time zone. | Allows to override your local time zone. | Date/time components (`ui5-date-picker`, etc.) |
| [themeRoot](#themeRoot) | String to a URL - see the [themeRoot](#themeRoot) section below | N/A | Allows to set a URL to a Theme-designer-created custom theme. | All components |

Expand Down Expand Up @@ -253,6 +254,39 @@ Example:
</script>
```

### skipThemeBase
<a name="skipThemeBase"></a>

This configuration option controls whether the framework should skip loading its theme base CSS variables (`--sap*`).

By default, the framework loads both:
- **Base theme variables** (`--sap*`) - global SAP Fiori design tokens

When `skipThemeBase` is set to `true`, the framework skips loading the base `--sap*` variables This is useful when your application provides theme variables externally and handles theming independently from the framework.

Typically, you would not need to modify this setting. However, if your application manages SAP Fiori theme variables externally (e.g., through a separate theming system), you can set `skipThemeBase` to `true` to avoid loading duplicate variables.

Example:
```html
<script data-ui5-config type="application/json">
{
"skipThemeBase": true
}
</script>
```

You can also control this setting programmatically:
```js
import { setSkipThemeBase } from "@ui5/webcomponents-base/dist/config/ThemeLoading.js";
import { setTheme, getTheme } from "@ui5/webcomponents-base/dist/config/Theme.js";

// Skip framework's base theme loading
setSkipThemeBase(true);

// Re-apply theme to take effect immediately
await setTheme(getTheme());
```

### timezone
<a name="timezone"></a>

Expand Down Expand Up @@ -395,6 +429,12 @@ import { getDefaultFontLoading, setDefaultFontLoading } from "@ui5/webcomponents

```js
import { getEnableDefaultTooltips, setEnableDefaultTooltips } from "@ui5/webcomponents-base/dist/config/Tooltips.js";
```

- `skipThemeBase`

```js
import { getSkipThemeBase, setSkipThemeBase } from "@ui5/webcomponents-base/dist/config/ThemeLoading.js";
```

- `timezone` - can only be set initially in the configuration script.
Expand Down
12 changes: 12 additions & 0 deletions packages/base/src/InitialConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type InitialConfig = {
fetchDefaultLanguage: boolean,
defaultFontLoading: boolean,
enableDefaultTooltips: boolean,
skipThemeBase: boolean,
};

let initialConfig: InitialConfig = {
Expand All @@ -41,6 +42,7 @@ let initialConfig: InitialConfig = {
fetchDefaultLanguage: false,
defaultFontLoading: true,
enableDefaultTooltips: true,
skipThemeBase: false,
};

/* General settings */
Expand Down Expand Up @@ -127,6 +129,15 @@ const getFormatSettings = () => {
return initialConfig.formatSettings;
};

/**
* Returns if theme base loading should be skipped.
* @returns { boolean } true if theme base loading should be skipped
*/
const getSkipThemeBase = () => {
initConfiguration();
return initialConfig.skipThemeBase;
};

const booleanMapping = new Map();
booleanMapping.set("true", true);
booleanMapping.set("false", false);
Expand Down Expand Up @@ -257,4 +268,5 @@ export {
getDefaultFontLoading,
resetConfiguration,
getEnableDefaultTooltips,
getSkipThemeBase,
};
50 changes: 50 additions & 0 deletions packages/base/src/config/ThemeLoading.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { getSkipThemeBase as getConfiguredSkipThemeBase } from "../InitialConfiguration.js";
import { attachConfigurationReset } from "./ConfigurationReset.js";

let skipThemeBase: boolean | undefined;

attachConfigurationReset(() => {
skipThemeBase = undefined;
});

/**
* Returns if theme base loading should be skipped.
*
* When set to "true", the framework will skip loading the base theme CSS variables (--sap*).
* When set to "false" (default), both base (--sap*) are loaded.
*
* This is useful when the application provides theme variables externally
* and handles theming independently from the framework.
*
* @public
* @since 2.20.0
* @returns { boolean }
*/
const getSkipThemeBase = (): boolean => {
if (skipThemeBase === undefined) {
skipThemeBase = getConfiguredSkipThemeBase();
}

return skipThemeBase;
};

/**
* Sets whether theme base loading should be skipped.
*
* - When set to "true", the framework will skip loading base theme CSS variables (--sap*).
* - When set to "false" (default), both base (--sap*) variables will be loaded.
*
* **Note:** This setting should be used as early as possible in the application lifecycle, ideally before any theme is applied, to ensure it takes effect.
*
* @public
* @since 2.20.0
* @param { boolean } skip - whether to skip loading base theme variables
*/
const setSkipThemeBase = (skip: boolean) => {
skipThemeBase = skip;
};

export {
getSkipThemeBase,
setSkipThemeBase,
};
44 changes: 36 additions & 8 deletions packages/base/src/theming/applyTheme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type OpenUI5Support from "../features/OpenUI5Support.js";
import { DEFAULT_THEME } from "../generated/AssetParameters.js";
import { getCurrentRuntimeIndex } from "../Runtimes.js";
import { updateComponentStyles } from "./componentStyles.js";
import { getSkipThemeBase } from "../config/ThemeLoading.js";

// eslint-disable-next-line
export let _lib = "ui5";
Expand All @@ -27,9 +28,30 @@ const loadThemeBase = async (theme: string) => {
return;
}

const cssData = await getThemeProperties(BASE_THEME_PACKAGE, theme);
if (cssData) {
createOrUpdateStyle(cssData, "data-ui5-theme-properties", BASE_THEME_PACKAGE, theme);
// Load default properties (--sap*) to avoid conflicts
const [defaultCss] = await Promise.all([
getThemeProperties(BASE_THEME_PACKAGE, theme),
]);

// Apply default variables (--sap*)
if (defaultCss) {
createOrUpdateStyle(defaultCss, "data-ui5-theme-properties", BASE_THEME_PACKAGE, theme);
}
};

const loadThemeBaseScoped = async (theme: string) => {
if (!isThemeBaseRegistered()) {
return;
}

// Load scoped properties (--ui5-sap* framework-scoped)
const [scopedCss] = await Promise.all([
getThemeProperties(BASE_THEME_PACKAGE, `${theme}-scoped`),
]);

// Apply scoped variables (--ui5-sap* framework-scoped)
if (scopedCss) {
createOrUpdateStyle(scopedCss, "data-ui5-theme-properties-scoped", BASE_THEME_PACKAGE, theme);
}
};

Expand Down Expand Up @@ -84,16 +106,22 @@ const detectExternalTheme = async (theme: string) => {

const applyTheme = async (theme: string) => {
const extTheme = await detectExternalTheme(theme);
const hasExternalTheme = extTheme && theme === extTheme.themeName;

// Only load theme_base properties if there is no externally loaded theme, or there is, but it is not being loaded
if (!extTheme || theme !== extTheme.themeName) {
await loadThemeBase(theme);
} else {
const skipBase = getSkipThemeBase();

// If an external theme is detected or skipBase is true, do not load the base theme to avoid conflicts.
if (hasExternalTheme || skipBase) {
deleteThemeBase();
} else if (!skipBase) {
await loadThemeBase(theme);
}

// Always load scoped --ui5-sap* variables
await loadThemeBaseScoped(theme);

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

Expand Down
42 changes: 42 additions & 0 deletions packages/main/test/pages/theming/2.16.0-latest-default.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<!doctype html>
<html lang="en">

<head>
<meta charset="utf-8" />
<title>2.16.0 × Custom × Latest - Default Theme</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script src="./bundle.2.16.0.js" type="module"></script>
<script src="../%VITE_BUNDLE_PATH%" type="module"></script>
</head>

<body style="background: var(--sapAccentBackgroundColor1);">
<h1>2.16.0 × Custom × Latest - Default Theme</h1>

<h2>Cozy</h2>
<div>
<ui5-button-demo>2.16.0</ui5-button-demo>
<ui5-button>current</ui5-button>
</div>

<h2>sapUiSizeCompact</h2>
<div class="sapUiSizeCompact">
<ui5-button-demo>2.16.0</ui5-button-demo>
<ui5-button>current</ui5-button>
</div>

<h2>ui5-content-density-compact</h2>
<div class="ui5-content-density-compact">
<ui5-button-demo>2.16.0</ui5-button-demo>
<ui5-button>current</ui5-button>
</div>

<h2>data-ui5-compact-size</h2>
<div data-ui5-compact-size>
<ui5-button-demo>2.16.0</ui5-button-demo>
<ui5-button>current</ui5-button>
</div>


</body>

</html>
51 changes: 51 additions & 0 deletions packages/main/test/pages/theming/2.16.0-latest-delayed.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<!doctype html>
<html lang="en">

<head>
<meta charset="utf-8" />
<title>2.16.0 × Custom × Latest - Delayed External Theme</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script src="./bundle.2.16.0.js" type="module"></script>
<script src="../%VITE_BUNDLE_PATH%" type="module"></script>
</head>

<body style="background: var(--sapAccentBackgroundColor1);">
<h1>2.16.0 × Custom × Latest - Delayed External Theme</h1>

<h2>Cozy</h2>
<div>
<ui5-button-demo>2.16.0</ui5-button-demo>
<ui5-button>current</ui5-button>
</div>

<h2>sapUiSizeCompact</h2>
<div class="sapUiSizeCompact">
<ui5-button-demo>2.16.0</ui5-button-demo>
<ui5-button>current</ui5-button>
</div>

<h2>ui5-content-density-compact</h2>
<div class="ui5-content-density-compact">
<ui5-button-demo>2.16.0</ui5-button-demo>
<ui5-button>current</ui5-button>
</div>

<h2>data-ui5-compact-size</h2>
<div data-ui5-compact-size>
<ui5-button-demo>2.16.0</ui5-button-demo>
<ui5-button>current</ui5-button>
</div>



<script>
setTimeout(() => {
const link = document.documentElement.createElement("link");
link.rel = "stylesheet";
link.href = "https://cdn.jsdelivr.net/npm/@sap-theming/theming-base-content/content/Base/baseLib/sap_horizon/css_variables.css";
document.documentElement.head.appendChild(link);
}, 3000);
</script>
</body>

</html>
44 changes: 44 additions & 0 deletions packages/main/test/pages/theming/2.16.0-latest-preloaded.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<!doctype html>
<html lang="en">

<head>
<meta charset="utf-8" />
<title>2.16.0 × Custom × Latest - Preloaded External Theme</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@sap-theming/theming-base-content/content/Base/baseLib/sap_horizon/css_variables.css">
<script src="./bundle.2.16.0.js" type="module"></script>
<script src="../%VITE_BUNDLE_PATH%" type="module"></script>
</head>

<body style="background: var(--sapAccentBackgroundColor1);">
<h1>2.16.0 × Custom × Latest - Preloaded External Theme</h1>

<h2>Cozy</h2>
<div>
<ui5-button-demo>2.16.0</ui5-button-demo>
<ui5-button>current</ui5-button>
</div>

<h2>sapUiSizeCompact</h2>
<div class="sapUiSizeCompact">
<ui5-button-demo>2.16.0</ui5-button-demo>
<ui5-button>current</ui5-button>
</div>

<h2>ui5-content-density-compact</h2>
<div class="ui5-content-density-compact">
<ui5-button-demo>2.16.0</ui5-button-demo>
<ui5-button>current</ui5-button>
</div>

<h2>data-ui5-compact-size</h2>
<div data-ui5-compact-size>
<ui5-button-demo>2.16.0</ui5-button-demo>
<ui5-button>current</ui5-button>
</div>


</body>

</html>
Loading
Loading