diff --git a/packages/base/cypress/specs/AnimationMode.cy.tsx b/packages/base/cypress/specs/AnimationMode.cy.tsx
new file mode 100644
index 0000000000000..912005addd8dd
--- /dev/null
+++ b/packages/base/cypress/specs/AnimationMode.cy.tsx
@@ -0,0 +1,41 @@
+import { setAnimationMode } from "../../src/config/AnimationMode.js";
+import { duration } from "../../src/animations/animate.js";
+import { getComponentStyles } from "../../src/theming/componentStyles.js";
+import Generic from "../../test/test-elements/Generic.js";
+
+describe("AnimationMode - duration", () => {
+ it("is 0 when animation mode is none", () => {
+ cy.wrap({ setAnimationMode }).invoke("setAnimationMode", "none");
+
+ cy.wrap({ duration }).invoke("duration").should("equal", 0);
+ });
+
+ it("is 400 when animation mode is full", () => {
+ cy.wrap({ setAnimationMode }).invoke("setAnimationMode", "full");
+
+ cy.wrap({ duration }).invoke("duration").should("equal", 400);
+ });
+});
+
+describe("AnimationMode - CommonStyles", () => {
+ it("common styles sheet exists in the shadow root of a component", () => {
+ cy.mount();
+
+ cy.get("[ui5-test-generic]").shadow().should($shadow => {
+ const shadowRoot = $shadow[0].getRootNode() as ShadowRoot;
+ const componentStylesSheet = getComponentStyles();
+ expect(shadowRoot.adoptedStyleSheets).to.include(componentStylesSheet);
+ expect(componentStylesSheet.cssRules).not.be.empty;
+ });
+ });
+
+ it("common styles sheet contains the animation-mode rule", () => {
+ cy.mount();
+
+ cy.wrap(null).should(() => {
+ const sheet = getComponentStyles();
+ const rules = Array.from(sheet.cssRules).map(r => r.cssText);
+ expect(rules.some(r => r.includes("--_ui5-animation-mode"))).to.be.true;
+ })
+ });
+});
diff --git a/packages/base/cypress/specs/ConfigurationChange.cy.tsx b/packages/base/cypress/specs/ConfigurationChange.cy.tsx
index b79d914510631..9d034146174de 100644
--- a/packages/base/cypress/specs/ConfigurationChange.cy.tsx
+++ b/packages/base/cypress/specs/ConfigurationChange.cy.tsx
@@ -2,6 +2,7 @@ import "../../test/test-elements/Accessor.js";
import { setTheme, getTheme } from "../../src/config/Theme.js";
import { setThemeRoot, getThemeRoot } from "../../src/config/ThemeRoot.js";
import { setNoConflict, getNoConflict } from "../../src/config/NoConflict.js";
+import { setAnimationMode, getAnimationMode } from "../../src/config/AnimationMode.js";
describe("Some configuration options can be changed at runtime", () => {
it("Tests that theme can be changed", () => {
@@ -238,3 +239,24 @@ describe("ThemeRoot validation at runtime", () => {
});
});
});
+
+describe("AnimationMode CSS variable", () => {
+ const getCSSVar = () => {
+ return cy.window().then(win => {
+ return win.getComputedStyle(win.document.documentElement).getPropertyValue("--_ui5-animation-mode").trim();
+ });
+ };
+
+ it("sets the CSS variable on getAnimationMode", () => {
+ cy.wrap({ getAnimationMode }).invoke("getAnimationMode");
+ getCSSVar().should("not.be.empty");
+ });
+
+ it("updates the CSS variable when setAnimationMode is called", () => {
+ cy.wrap({ setAnimationMode }).invoke("setAnimationMode", "none");
+ getCSSVar().should("equal", "none");
+
+ cy.wrap({ setAnimationMode }).invoke("setAnimationMode", "full");
+ getCSSVar().should("equal", "full");
+ });
+});
diff --git a/packages/base/cypress/specs/ConfigurationScript.cy.tsx b/packages/base/cypress/specs/ConfigurationScript.cy.tsx
index 255ee8d5a36bb..ba5ebe8c50818 100644
--- a/packages/base/cypress/specs/ConfigurationScript.cy.tsx
+++ b/packages/base/cypress/specs/ConfigurationScript.cy.tsx
@@ -105,6 +105,11 @@ describe("Configuration script", () => {
cy.wrap({ getAnimationMode })
.invoke("getAnimationMode")
.should("equal", configurationObject.animationMode);
+
+ cy.window().should(win => {
+ const value = win.getComputedStyle(win.document.documentElement).getPropertyValue("--_ui5-animation-mode").trim();
+ expect(value).to.equal(configurationObject.animationMode);
+ });
});
it("getEnableDefaultTooltips", () => {
diff --git a/packages/base/cypress/specs/ConfigurationURL.cy.tsx b/packages/base/cypress/specs/ConfigurationURL.cy.tsx
index 8fcd3221a3b71..1777bcc893b27 100644
--- a/packages/base/cypress/specs/ConfigurationURL.cy.tsx
+++ b/packages/base/cypress/specs/ConfigurationURL.cy.tsx
@@ -50,6 +50,11 @@ describe("Some settings can be set via SAP UI URL params", () => {
cy.wrap({ getAnimationMode })
.invoke("getAnimationMode")
.should("equal", AnimationMode.Basic);
+
+ cy.window().should(win => {
+ const value = win.getComputedStyle(win.document.documentElement).getPropertyValue("--_ui5-animation-mode").trim();
+ expect(value).to.equal(AnimationMode.Basic);
+ });
});
});
@@ -573,5 +578,10 @@ describe("URL parameters are ignored when ignoreUrlParams is set", () => {
cy.wrap({ getAnimationMode })
.invoke("getAnimationMode")
.should("equal", AnimationMode.Basic);
+
+ cy.window().should(win => {
+ const value = win.getComputedStyle(win.document.documentElement).getPropertyValue("--_ui5-animation-mode").trim();
+ expect(value).to.equal(AnimationMode.Basic);
+ });
});
});
diff --git a/packages/base/src/animations/animate.ts b/packages/base/src/animations/animate.ts
index 872cd1e88dddd..a18cc65775987 100644
--- a/packages/base/src/animations/animate.ts
+++ b/packages/base/src/animations/animate.ts
@@ -1,3 +1,4 @@
+import { getAnimationMode } from "../config/AnimationMode.js";
import AnimationQueue from "./AnimationQueue.js";
type AnimateOptions = {
@@ -57,7 +58,10 @@ const animate = (options: AnimateOptions) => {
stop: () => stop,
};
};
-const duration = 400;
+
+const duration = () => {
+ return getAnimationMode() === "none" ? 0 : 400;
+};
export { duration };
export type { AnimateOptions };
diff --git a/packages/base/src/animations/scroll.ts b/packages/base/src/animations/scroll.ts
index d4bc159451415..4b77075cc881b 100644
--- a/packages/base/src/animations/scroll.ts
+++ b/packages/base/src/animations/scroll.ts
@@ -9,7 +9,7 @@ const scroll = (element: HTMLElement, dx: number, dy: number) => {
scrollLeft = element.scrollLeft;
scrollTop = element.scrollTop;
},
- duration,
+ duration: duration(),
element,
advance: progress => {
element.scrollLeft = scrollLeft + (progress * dx); // easing - linear
diff --git a/packages/base/src/animations/slideDown.ts b/packages/base/src/animations/slideDown.ts
index 2aa7a986d22a8..edbd47a05ce93 100644
--- a/packages/base/src/animations/slideDown.ts
+++ b/packages/base/src/animations/slideDown.ts
@@ -42,7 +42,7 @@ const slideDown = (element: HTMLElement) => {
element.style.marginBottom = "0";
element.style.height = "0";
},
- duration,
+ duration: duration(),
element,
advance: progress => {
// WORKAROUND
diff --git a/packages/base/src/animations/slideUp.ts b/packages/base/src/animations/slideUp.ts
index 968eaacd3a575..a1091233296b2 100644
--- a/packages/base/src/animations/slideUp.ts
+++ b/packages/base/src/animations/slideUp.ts
@@ -38,7 +38,7 @@ const slideUp = (element: HTMLElement) => {
el.style.overflow = "hidden";
},
- duration,
+ duration: duration(),
element,
advance: progress => {
element.style.paddingTop = `${paddingTop - (paddingTop * progress)}px`;
diff --git a/packages/base/src/config/AnimationMode.ts b/packages/base/src/config/AnimationMode.ts
index 69af240ca87f6..66ed86aa544cd 100644
--- a/packages/base/src/config/AnimationMode.ts
+++ b/packages/base/src/config/AnimationMode.ts
@@ -1,9 +1,14 @@
import { getAnimationMode as getConfiguredAnimationMode } from "../InitialConfiguration.js";
import AnimationMode from "../types/AnimationMode.js";
import { attachConfigurationReset } from "./ConfigurationReset.js";
+import { createOrUpdateStyle } from "../ManagedStyles.js";
let curAnimationMode: `${AnimationMode}` | undefined;
+const applyAnimationMode = (animationMode: `${AnimationMode}`) => {
+ createOrUpdateStyle(`:root { --_ui5-animation-mode: ${animationMode}; }`, "data-ui5-animation-mode");
+};
+
attachConfigurationReset(() => {
curAnimationMode = undefined;
});
@@ -16,6 +21,7 @@ attachConfigurationReset(() => {
const getAnimationMode = (): `${AnimationMode}` => {
if (curAnimationMode === undefined) {
curAnimationMode = getConfiguredAnimationMode();
+ applyAnimationMode(curAnimationMode);
}
return curAnimationMode;
@@ -30,6 +36,7 @@ const setAnimationMode = (animationMode: `${AnimationMode}`) => {
const options: string[] = Object.values(AnimationMode);
if (options.includes(animationMode)) {
curAnimationMode = animationMode;
+ applyAnimationMode(curAnimationMode);
}
};
diff --git a/packages/base/src/css/CommonStyles.css b/packages/base/src/css/CommonStyles.css
new file mode 100644
index 0000000000000..9e63d6a4576b0
--- /dev/null
+++ b/packages/base/src/css/CommonStyles.css
@@ -0,0 +1,6 @@
+@container style(--_ui5-animation-mode: none) {
+ * {
+ transition-duration: 0s !important;
+ animation-duration: 0s !important;
+ }
+}
\ No newline at end of file
diff --git a/packages/base/src/theming/componentStyles.ts b/packages/base/src/theming/componentStyles.ts
index 32d96d6e44eee..4499097c9df37 100644
--- a/packages/base/src/theming/componentStyles.ts
+++ b/packages/base/src/theming/componentStyles.ts
@@ -1,9 +1,15 @@
+import CommonStylesCss from "../generated/css/CommonStyles.css.js";
+
const packageMap = new Map();
+
+packageMap.set("ui5-common-component-styles", CommonStylesCss);
+
let componentsStyleSheet: CSSStyleSheet;
const getComponentStyles = () => {
if (!componentsStyleSheet) {
componentsStyleSheet = new CSSStyleSheet();
+ componentsStyleSheet.replaceSync(Array.from(packageMap.values()).join("\n"));
}
return componentsStyleSheet;
diff --git a/packages/compat/cypress/specs/Table.cy.tsx b/packages/compat/cypress/specs/Table.cy.tsx
index 516307524dc46..31b4c1bc4a916 100644
--- a/packages/compat/cypress/specs/Table.cy.tsx
+++ b/packages/compat/cypress/specs/Table.cy.tsx
@@ -509,7 +509,6 @@ describe("Table general interaction", () => {
cy.get("@popinChange")
.should(stub => {
expect(stub).to.have.been.calledTwice;
- debugger
// @ts-ignore
expect(stub.args.slice(-1)[0][0].detail.poppedColumns.length).to.equal(2);
})