From 5b0a939e4fd5f0797371f7bccc6886305f0a5596 Mon Sep 17 00:00:00 2001 From: Stefano Baldan Date: Mon, 22 Jul 2024 10:44:20 +0200 Subject: [PATCH 1/2] Add the ability to override OS reduced motion settings --- README.md | 22 +++++++--------------- packages/flip-toolkit/src/flip/index.ts | 18 +++++++++--------- packages/react-flip-toolkit/src/index.ts | 2 +- 3 files changed, 17 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 54dcad1..0bdd525 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,7 @@ - [Transform props](#transform-props) - [Advanced props](#advanced-props) - [`Spring`](#spring) +- [`Global configuration`](#global-configuration) - [Library details](#library-details) - [Troubleshooting](#troubleshooting) - [Problem #1: Nothing is happening](#problem-1-nothing-is-happening) @@ -468,22 +469,13 @@ spring({ -## Global configuration functions +## Global configuration -You can programmatically call the following functions if you need to disable (or re-enable) FLIP animations everywhere. - -#### `disableFlip()` - -Global switch to disable all animations in all `Flipper` containers. - -#### `enableFlip()` - -Global switch to (re-)enable all animations in all `Flipper` containers. Animations are enabled by default. Calling this function is needed only if animations were previously disabled with `disableFlip()`. - -#### `isFlipEnabled()` - -Returns a boolean indicating whether animations are globally enabled or disabled. +By default, FLIP animations respect the reduced motion preferences as defined in the operating system. This means that they are enabled if the operating system's reduced motion setting is turned off, and disabled when it is turned on. You can programmatically call `setFlipToggle(value)` if you need to disable (or re-enable) FLIP animations everywhere, and `getFlipToggle()` to know whether FLIP animations are currently enabled or not. The toggle accepts the following values: +- `'system'` (default): respects the reduced motion preferences of the operating system, +- `'on'`: enables all animations, +- `'off'`: disables all animations. ## Library details @@ -503,7 +495,7 @@ Returns a boolean indicating whether animations are globally enabled or disabled - If one of your `Flipped` components is wrapping another React component rather than a DOM element, [use a render prop to get the Flipped props](#wrapping-a-react-component) and pass down to the necessary DOM element. - Is the element that's receiving props from `Flipped` visible in the DOM? `react-flip-toolkit` attempts to optimize performance by not animating elements that are off-screen or elements that have no width or height. - `display:inline` elements cannot be animated. If you want an `inline` element to animate, set `display:inline-block`. -- Do you have the [prefers-reduced-motion](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion) setting turned on? As of v7.1.0 that setting will disable all animations. +- Do you have the [prefers-reduced-motion](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion) setting turned on? As of v7.1.0 that setting will disable all animations. From v7.3.0 you can use `setFlipToggle('on')` to override the OS reduced motion settings. ### Problem #2: Things look weird / animations aren't behaving diff --git a/packages/flip-toolkit/src/flip/index.ts b/packages/flip-toolkit/src/flip/index.ts index 93268f5..c1732f4 100644 --- a/packages/flip-toolkit/src/flip/index.ts +++ b/packages/flip-toolkit/src/flip/index.ts @@ -15,13 +15,12 @@ import { ScopedSelector } from './animateFlippedElements/types' -let enabled = true +export type FlipToggleOptions = 'system' | 'on' | 'off' -export const disableFlip = () => (enabled = false) +let toggle: FlipToggleOptions = 'system' -export const enableFlip = () => (enabled = true) - -export const isFlipEnabled = () => enabled +export const getFlipToggle = () => toggle +export const setFlipToggle = (value: FlipToggleOptions) => (toggle = value) const createPortalScopedSelector = (portalKey: string) => (selector: string) => { @@ -81,9 +80,11 @@ export const onFlipKeyUpdate = ({ onComplete, onStart }: OnFlipKeyUpdateArgs) => { - if (!enabled) return - const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)') - if (mediaQuery.matches) return + if (toggle === 'off') return + if (toggle === 'system') { + const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)') + if (mediaQuery.matches) return + } const flippedElementPositionsAfterUpdate = getFlippedElementPositionsAfterUpdate({ element: containerEl, @@ -158,4 +159,3 @@ export const onFlipKeyUpdate = ({ flip() } } - diff --git a/packages/react-flip-toolkit/src/index.ts b/packages/react-flip-toolkit/src/index.ts index ec812cb..f0390ea 100644 --- a/packages/react-flip-toolkit/src/index.ts +++ b/packages/react-flip-toolkit/src/index.ts @@ -1,4 +1,4 @@ -export { disableFlip, enableFlip, isFlipEnabled } from 'flip-toolkit' +export { FlipToggleOptions, getFlipToggle, setFlipToggle } from 'flip-toolkit' export { default as Flipper } from './Flipper' export { default as Flipped } from './Flipped' export { default as ExitContainer } from './ExitContainer' From f79cefb81d0cbe317e78a1260e9cca5b942b8234 Mon Sep 17 00:00:00 2001 From: Stefano Baldan Date: Mon, 22 Jul 2024 15:12:44 +0200 Subject: [PATCH 2/2] Executing start and complete callbacks when animations are disabled --- packages/flip-toolkit/src/flip/index.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/flip-toolkit/src/flip/index.ts b/packages/flip-toolkit/src/flip/index.ts index c1732f4..32f89b8 100644 --- a/packages/flip-toolkit/src/flip/index.ts +++ b/packages/flip-toolkit/src/flip/index.ts @@ -80,11 +80,14 @@ export const onFlipKeyUpdate = ({ onComplete, onStart }: OnFlipKeyUpdateArgs) => { - if (toggle === 'off') return - if (toggle === 'system') { - const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)') - if (mediaQuery.matches) return + const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)') + + if (toggle === 'off' || (toggle === 'system' && mediaQuery.matches)) { + onStart?.(containerEl, decisionData) + onComplete?.(containerEl, decisionData) + return } + const flippedElementPositionsAfterUpdate = getFlippedElementPositionsAfterUpdate({ element: containerEl,