@atlaskit/motion
Advanced tools
Comparing version 1.7.0 to 1.7.1
# @atlaskit/motion | ||
## 1.7.1 | ||
### Patch Changes | ||
- [#113947](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/113947) | ||
[`169747d542a4f`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/169747d542a4f) - | ||
Support exiting animation in strict mode. | ||
## 1.7.0 | ||
@@ -4,0 +12,0 @@ |
"use strict"; | ||
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); | ||
var _typeof = require("@babel/runtime/helpers/typeof"); | ||
@@ -7,6 +8,7 @@ Object.defineProperty(exports, "__esModule", { | ||
}); | ||
exports.useExitingPersistence = exports.default = void 0; | ||
exports.wrapChildWithContextProvider = exports.useExitingPersistence = exports.spliceNewElementsIntoPrevious = exports.emptyContext = exports.default = exports.childrenToObj = exports.childrenToArray = exports.ExitingContext = void 0; | ||
var _react = _interopRequireWildcard(require("react")); | ||
var _accessibility = require("../utils/accessibility"); | ||
var _useForceRender = require("../utils/use-force-render"); | ||
var _platformFeatureFlags = require("@atlaskit/platform-feature-flags"); | ||
var _exitMotionNew = _interopRequireDefault(require("./exit-motion-new")); | ||
var _exitMotionOld = _interopRequireDefault(require("./exit-motion-old")); | ||
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); } | ||
@@ -23,3 +25,3 @@ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } | ||
// We define empty context here so the object doesn't change. | ||
var emptyContext = { | ||
var emptyContext = exports.emptyContext = { | ||
// Motions will always appear if not inside a exiting persistence component. | ||
@@ -29,15 +31,11 @@ appear: true, | ||
}; | ||
var ExitingContext = /*#__PURE__*/(0, _react.createContext)(emptyContext); | ||
var isAnyPreviousKeysMissingFromCurrent = function isAnyPreviousKeysMissingFromCurrent(currentMap, previous) { | ||
for (var i = 0; i < previous.length; i++) { | ||
var element = previous[i]; | ||
var _key = element.key; | ||
if (!currentMap[_key]) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
}; | ||
/** | ||
* __Exiting context__ | ||
* | ||
* An exiting context. | ||
*/ | ||
var ExitingContext = exports.ExitingContext = /*#__PURE__*/(0, _react.createContext)(emptyContext); | ||
/** | ||
* This method will wrap any React element with a context provider. We're using context (instead of | ||
@@ -47,3 +45,3 @@ * cloneElement) so we can communicate between multiple elements without the need of prop drilling | ||
*/ | ||
var wrapChildWithContextProvider = function wrapChildWithContextProvider(child) { | ||
var wrapChildWithContextProvider = exports.wrapChildWithContextProvider = function wrapChildWithContextProvider(child) { | ||
var value = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : emptyContext; | ||
@@ -55,21 +53,2 @@ return /*#__PURE__*/_react.default.createElement(ExitingContext.Provider, { | ||
}; | ||
var childrenToObj = function childrenToObj(children) { | ||
return children.reduce(function (acc, child) { | ||
acc[child.key] = child; | ||
return acc; | ||
}, {}); | ||
}; | ||
var spliceNewElementsIntoPrevious = function spliceNewElementsIntoPrevious(current, previous) { | ||
var splicedChildren = previous.concat([]); | ||
var previousMap = childrenToObj(previous); | ||
for (var i = 0; i < current.length; i++) { | ||
var child = current[i]; | ||
var childIsNew = !previousMap[child.key]; | ||
if (childIsNew) { | ||
// This will insert the new element after the previous element. | ||
splicedChildren.splice(i + 1, 0, child); | ||
} | ||
} | ||
return splicedChildren; | ||
}; | ||
@@ -79,3 +58,3 @@ /** | ||
*/ | ||
var childrenToArray = function childrenToArray(children) { | ||
var childrenToArray = exports.childrenToArray = function childrenToArray(children) { | ||
var childrenAsArray = []; | ||
@@ -95,17 +74,21 @@ | ||
}; | ||
/** | ||
* This handles the case when a render updates during an exit motion. | ||
* If any child is mounted again we removed them from the exiting children object and return true. | ||
*/ | ||
var hasAnyExitingChildMountedAgain = function hasAnyExitingChildMountedAgain(exitingChildren, children) { | ||
var exitingChildMountedAgain = false; | ||
children.forEach(function (child) { | ||
if (exitingChildren.current[child.key]) { | ||
exitingChildMountedAgain = true; | ||
delete exitingChildren.current[child.key]; | ||
var spliceNewElementsIntoPrevious = exports.spliceNewElementsIntoPrevious = function spliceNewElementsIntoPrevious(current, previous) { | ||
var splicedChildren = previous.concat([]); | ||
var previousMap = childrenToObj(previous); | ||
for (var i = 0; i < current.length; i++) { | ||
var child = current[i]; | ||
var childIsNew = !previousMap[child.key]; | ||
if (childIsNew) { | ||
// This will insert the new element after the previous element. | ||
splicedChildren.splice(i + 1, 0, child); | ||
} | ||
}); | ||
return exitingChildMountedAgain; | ||
} | ||
return splicedChildren; | ||
}; | ||
var childrenToObj = exports.childrenToObj = function childrenToObj(children) { | ||
return children.reduce(function (acc, child) { | ||
acc[child.key] = child; | ||
return acc; | ||
}, {}); | ||
}; | ||
@@ -121,78 +104,13 @@ /** | ||
var _ref$appear = _ref.appear, | ||
appearFromProp = _ref$appear === void 0 ? false : _ref$appear, | ||
childs = _ref.children, | ||
appear = _ref$appear === void 0 ? false : _ref$appear, | ||
children = _ref.children, | ||
exitThenEnter = _ref.exitThenEnter; | ||
var children = childrenToArray(childs); | ||
var childrenObj = childrenToObj(children); | ||
var previousChildren = (0, _react.useRef)([]); | ||
var persistedChildren = (0, _react.useRef)([]); | ||
var forceRender = (0, _useForceRender.useForceRender)(); | ||
var exitingChildren = (0, _react.useRef)({}); | ||
var appear = (0, _react.useRef)(appearFromProp); | ||
var defaultContextValue = (0, _react.useMemo)(function () { | ||
return { | ||
appear: appear.current, | ||
isExiting: false | ||
}; | ||
}, | ||
// React rules of hooks says this isn't needed because mutating appear won't cause a re-render. | ||
// While technically true - it will trigger this to make a new object on the _next_ render which is what we want. | ||
// Remove this or use appear instead of appear.current and you will notice a test breaks. | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
[appear.current]); | ||
if ((0, _accessibility.isReducedMotion)()) { | ||
return children; | ||
} | ||
if (!appear.current) { | ||
// We always want child motions to appear after the initial mount. | ||
appear.current = true; | ||
} | ||
// This entire block can't be an effect because we need it to run synchronously during a render | ||
// else when elements are being removed they will be remounted instead of being updated. | ||
if (previousChildren.current.length && isAnyPreviousKeysMissingFromCurrent(childrenObj, previousChildren.current)) { | ||
if (persistedChildren.current.length === 0 || hasAnyExitingChildMountedAgain(exitingChildren, children)) { | ||
persistedChildren.current = previousChildren.current; | ||
} | ||
// We have persisted children now set from previous children. | ||
// Let's update previous children so we have it available next render. | ||
previousChildren.current = children; | ||
return (exitThenEnter ? persistedChildren.current : spliceNewElementsIntoPrevious(children, persistedChildren.current)).map(function (child) { | ||
// eslint-disable-next-line @repo/internal/react/no-children-properties-access | ||
var currentChild = childrenObj[child.key]; | ||
if (!currentChild) { | ||
// We've found an exiting child - mark it! | ||
exitingChildren.current[child.key] = true; | ||
return wrapChildWithContextProvider(child, { | ||
isExiting: true, | ||
appear: true, | ||
onFinish: function onFinish() { | ||
delete exitingChildren.current[child.key]; | ||
// We will only remove the exiting elements when any subsequent exiting elements have also finished. | ||
// Think of removing many items from a todo list - when removing a few over a few clicks we don't | ||
// want the list jumping around when they exit. | ||
if (Object.keys(exitingChildren.current).length === 0) { | ||
// Set previous children to nothing. | ||
// This let's us skip the next render check as it's assumed children and previous will be the same. | ||
previousChildren.current = []; | ||
persistedChildren.current = []; | ||
// Re-render after the element(s) have animated away which will end up rendering the latest children. | ||
forceRender(); | ||
} | ||
} | ||
}); | ||
} | ||
// This element isn't exiting. | ||
// Wrap context and let's continue on our way. | ||
return wrapChildWithContextProvider(currentChild, defaultContextValue); | ||
}); | ||
} else { | ||
previousChildren.current = children; | ||
} | ||
return children.map(function (child) { | ||
return wrapChildWithContextProvider(child, defaultContextValue); | ||
return (0, _platformFeatureFlags.getBooleanFF)('platform.design-system-team.update-motion-for-strict-mode_p6qs0') ? /*#__PURE__*/_react.default.createElement(_exitMotionNew.default, { | ||
appear: appear, | ||
children: children, | ||
exitThenEnter: exitThenEnter | ||
}) : /*#__PURE__*/_react.default.createElement(_exitMotionOld.default, { | ||
appear: appear, | ||
children: children, | ||
exitThenEnter: exitThenEnter | ||
}); | ||
@@ -199,0 +117,0 @@ }); |
@@ -1,4 +0,5 @@ | ||
import React, { Children, createContext, memo, useContext, useMemo, useRef } from 'react'; | ||
import { isReducedMotion } from '../utils/accessibility'; | ||
import { useForceRender } from '../utils/use-force-render'; | ||
import React, { Children, createContext, memo, useContext } from 'react'; | ||
import { getBooleanFF } from '@atlaskit/platform-feature-flags'; | ||
import WithStrictModeSupport from './exit-motion-new'; | ||
import WithoutStrictModeSupport from './exit-motion-old'; | ||
@@ -14,3 +15,3 @@ /** | ||
// We define empty context here so the object doesn't change. | ||
const emptyContext = { | ||
export const emptyContext = { | ||
// Motions will always appear if not inside a exiting persistence component. | ||
@@ -20,15 +21,11 @@ appear: true, | ||
}; | ||
const ExitingContext = /*#__PURE__*/createContext(emptyContext); | ||
const isAnyPreviousKeysMissingFromCurrent = (currentMap, previous) => { | ||
for (let i = 0; i < previous.length; i++) { | ||
const element = previous[i]; | ||
const key = element.key; | ||
if (!currentMap[key]) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
}; | ||
/** | ||
* __Exiting context__ | ||
* | ||
* An exiting context. | ||
*/ | ||
export const ExitingContext = /*#__PURE__*/createContext(emptyContext); | ||
/** | ||
* This method will wrap any React element with a context provider. We're using context (instead of | ||
@@ -38,3 +35,3 @@ * cloneElement) so we can communicate between multiple elements without the need of prop drilling | ||
*/ | ||
const wrapChildWithContextProvider = (child, value = emptyContext) => { | ||
export const wrapChildWithContextProvider = (child, value = emptyContext) => { | ||
return /*#__PURE__*/React.createElement(ExitingContext.Provider, { | ||
@@ -45,21 +42,2 @@ key: `${child.key}-provider`, | ||
}; | ||
const childrenToObj = children => { | ||
return children.reduce((acc, child) => { | ||
acc[child.key] = child; | ||
return acc; | ||
}, {}); | ||
}; | ||
const spliceNewElementsIntoPrevious = (current, previous) => { | ||
const splicedChildren = previous.concat([]); | ||
const previousMap = childrenToObj(previous); | ||
for (let i = 0; i < current.length; i++) { | ||
const child = current[i]; | ||
const childIsNew = !previousMap[child.key]; | ||
if (childIsNew) { | ||
// This will insert the new element after the previous element. | ||
splicedChildren.splice(i + 1, 0, child); | ||
} | ||
} | ||
return splicedChildren; | ||
}; | ||
@@ -69,3 +47,3 @@ /** | ||
*/ | ||
const childrenToArray = children => { | ||
export const childrenToArray = children => { | ||
const childrenAsArray = []; | ||
@@ -85,17 +63,21 @@ | ||
}; | ||
/** | ||
* This handles the case when a render updates during an exit motion. | ||
* If any child is mounted again we removed them from the exiting children object and return true. | ||
*/ | ||
const hasAnyExitingChildMountedAgain = (exitingChildren, children) => { | ||
let exitingChildMountedAgain = false; | ||
children.forEach(child => { | ||
if (exitingChildren.current[child.key]) { | ||
exitingChildMountedAgain = true; | ||
delete exitingChildren.current[child.key]; | ||
export const spliceNewElementsIntoPrevious = (current, previous) => { | ||
const splicedChildren = previous.concat([]); | ||
const previousMap = childrenToObj(previous); | ||
for (let i = 0; i < current.length; i++) { | ||
const child = current[i]; | ||
const childIsNew = !previousMap[child.key]; | ||
if (childIsNew) { | ||
// This will insert the new element after the previous element. | ||
splicedChildren.splice(i + 1, 0, child); | ||
} | ||
}); | ||
return exitingChildMountedAgain; | ||
} | ||
return splicedChildren; | ||
}; | ||
export const childrenToObj = children => { | ||
return children.reduce((acc, child) => { | ||
acc[child.key] = child; | ||
return acc; | ||
}, {}); | ||
}; | ||
@@ -110,76 +92,15 @@ /** | ||
const ExitingPersistence = /*#__PURE__*/memo(({ | ||
appear: appearFromProp = false, | ||
children: childs, | ||
appear = false, | ||
children, | ||
exitThenEnter | ||
}) => { | ||
const children = childrenToArray(childs); | ||
const childrenObj = childrenToObj(children); | ||
const previousChildren = useRef([]); | ||
const persistedChildren = useRef([]); | ||
const forceRender = useForceRender(); | ||
const exitingChildren = useRef({}); | ||
const appear = useRef(appearFromProp); | ||
const defaultContextValue = useMemo(() => ({ | ||
appear: appear.current, | ||
isExiting: false | ||
}), | ||
// React rules of hooks says this isn't needed because mutating appear won't cause a re-render. | ||
// While technically true - it will trigger this to make a new object on the _next_ render which is what we want. | ||
// Remove this or use appear instead of appear.current and you will notice a test breaks. | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
[appear.current]); | ||
if (isReducedMotion()) { | ||
return children; | ||
} | ||
if (!appear.current) { | ||
// We always want child motions to appear after the initial mount. | ||
appear.current = true; | ||
} | ||
// This entire block can't be an effect because we need it to run synchronously during a render | ||
// else when elements are being removed they will be remounted instead of being updated. | ||
if (previousChildren.current.length && isAnyPreviousKeysMissingFromCurrent(childrenObj, previousChildren.current)) { | ||
if (persistedChildren.current.length === 0 || hasAnyExitingChildMountedAgain(exitingChildren, children)) { | ||
persistedChildren.current = previousChildren.current; | ||
} | ||
// We have persisted children now set from previous children. | ||
// Let's update previous children so we have it available next render. | ||
previousChildren.current = children; | ||
return (exitThenEnter ? persistedChildren.current : spliceNewElementsIntoPrevious(children, persistedChildren.current)).map(child => { | ||
// eslint-disable-next-line @repo/internal/react/no-children-properties-access | ||
const currentChild = childrenObj[child.key]; | ||
if (!currentChild) { | ||
// We've found an exiting child - mark it! | ||
exitingChildren.current[child.key] = true; | ||
return wrapChildWithContextProvider(child, { | ||
isExiting: true, | ||
appear: true, | ||
onFinish: () => { | ||
delete exitingChildren.current[child.key]; | ||
// We will only remove the exiting elements when any subsequent exiting elements have also finished. | ||
// Think of removing many items from a todo list - when removing a few over a few clicks we don't | ||
// want the list jumping around when they exit. | ||
if (Object.keys(exitingChildren.current).length === 0) { | ||
// Set previous children to nothing. | ||
// This let's us skip the next render check as it's assumed children and previous will be the same. | ||
previousChildren.current = []; | ||
persistedChildren.current = []; | ||
// Re-render after the element(s) have animated away which will end up rendering the latest children. | ||
forceRender(); | ||
} | ||
} | ||
}); | ||
} | ||
// This element isn't exiting. | ||
// Wrap context and let's continue on our way. | ||
return wrapChildWithContextProvider(currentChild, defaultContextValue); | ||
}); | ||
} else { | ||
previousChildren.current = children; | ||
} | ||
return children.map(child => wrapChildWithContextProvider(child, defaultContextValue)); | ||
return getBooleanFF('platform.design-system-team.update-motion-for-strict-mode_p6qs0') ? /*#__PURE__*/React.createElement(WithStrictModeSupport, { | ||
appear: appear, | ||
children: children, | ||
exitThenEnter: exitThenEnter | ||
}) : /*#__PURE__*/React.createElement(WithoutStrictModeSupport, { | ||
appear: appear, | ||
children: children, | ||
exitThenEnter: exitThenEnter | ||
}); | ||
}); | ||
@@ -186,0 +107,0 @@ export const useExitingPersistence = () => { |
@@ -1,4 +0,5 @@ | ||
import React, { Children, createContext, memo, useContext, useMemo, useRef } from 'react'; | ||
import { isReducedMotion } from '../utils/accessibility'; | ||
import { useForceRender } from '../utils/use-force-render'; | ||
import React, { Children, createContext, memo, useContext } from 'react'; | ||
import { getBooleanFF } from '@atlaskit/platform-feature-flags'; | ||
import WithStrictModeSupport from './exit-motion-new'; | ||
import WithoutStrictModeSupport from './exit-motion-old'; | ||
@@ -14,3 +15,3 @@ /** | ||
// We define empty context here so the object doesn't change. | ||
var emptyContext = { | ||
export var emptyContext = { | ||
// Motions will always appear if not inside a exiting persistence component. | ||
@@ -20,15 +21,11 @@ appear: true, | ||
}; | ||
var ExitingContext = /*#__PURE__*/createContext(emptyContext); | ||
var isAnyPreviousKeysMissingFromCurrent = function isAnyPreviousKeysMissingFromCurrent(currentMap, previous) { | ||
for (var i = 0; i < previous.length; i++) { | ||
var element = previous[i]; | ||
var _key = element.key; | ||
if (!currentMap[_key]) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
}; | ||
/** | ||
* __Exiting context__ | ||
* | ||
* An exiting context. | ||
*/ | ||
export var ExitingContext = /*#__PURE__*/createContext(emptyContext); | ||
/** | ||
* This method will wrap any React element with a context provider. We're using context (instead of | ||
@@ -38,3 +35,3 @@ * cloneElement) so we can communicate between multiple elements without the need of prop drilling | ||
*/ | ||
var wrapChildWithContextProvider = function wrapChildWithContextProvider(child) { | ||
export var wrapChildWithContextProvider = function wrapChildWithContextProvider(child) { | ||
var value = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : emptyContext; | ||
@@ -46,21 +43,2 @@ return /*#__PURE__*/React.createElement(ExitingContext.Provider, { | ||
}; | ||
var childrenToObj = function childrenToObj(children) { | ||
return children.reduce(function (acc, child) { | ||
acc[child.key] = child; | ||
return acc; | ||
}, {}); | ||
}; | ||
var spliceNewElementsIntoPrevious = function spliceNewElementsIntoPrevious(current, previous) { | ||
var splicedChildren = previous.concat([]); | ||
var previousMap = childrenToObj(previous); | ||
for (var i = 0; i < current.length; i++) { | ||
var child = current[i]; | ||
var childIsNew = !previousMap[child.key]; | ||
if (childIsNew) { | ||
// This will insert the new element after the previous element. | ||
splicedChildren.splice(i + 1, 0, child); | ||
} | ||
} | ||
return splicedChildren; | ||
}; | ||
@@ -70,3 +48,3 @@ /** | ||
*/ | ||
var childrenToArray = function childrenToArray(children) { | ||
export var childrenToArray = function childrenToArray(children) { | ||
var childrenAsArray = []; | ||
@@ -86,17 +64,21 @@ | ||
}; | ||
/** | ||
* This handles the case when a render updates during an exit motion. | ||
* If any child is mounted again we removed them from the exiting children object and return true. | ||
*/ | ||
var hasAnyExitingChildMountedAgain = function hasAnyExitingChildMountedAgain(exitingChildren, children) { | ||
var exitingChildMountedAgain = false; | ||
children.forEach(function (child) { | ||
if (exitingChildren.current[child.key]) { | ||
exitingChildMountedAgain = true; | ||
delete exitingChildren.current[child.key]; | ||
export var spliceNewElementsIntoPrevious = function spliceNewElementsIntoPrevious(current, previous) { | ||
var splicedChildren = previous.concat([]); | ||
var previousMap = childrenToObj(previous); | ||
for (var i = 0; i < current.length; i++) { | ||
var child = current[i]; | ||
var childIsNew = !previousMap[child.key]; | ||
if (childIsNew) { | ||
// This will insert the new element after the previous element. | ||
splicedChildren.splice(i + 1, 0, child); | ||
} | ||
}); | ||
return exitingChildMountedAgain; | ||
} | ||
return splicedChildren; | ||
}; | ||
export var childrenToObj = function childrenToObj(children) { | ||
return children.reduce(function (acc, child) { | ||
acc[child.key] = child; | ||
return acc; | ||
}, {}); | ||
}; | ||
@@ -112,78 +94,13 @@ /** | ||
var _ref$appear = _ref.appear, | ||
appearFromProp = _ref$appear === void 0 ? false : _ref$appear, | ||
childs = _ref.children, | ||
appear = _ref$appear === void 0 ? false : _ref$appear, | ||
children = _ref.children, | ||
exitThenEnter = _ref.exitThenEnter; | ||
var children = childrenToArray(childs); | ||
var childrenObj = childrenToObj(children); | ||
var previousChildren = useRef([]); | ||
var persistedChildren = useRef([]); | ||
var forceRender = useForceRender(); | ||
var exitingChildren = useRef({}); | ||
var appear = useRef(appearFromProp); | ||
var defaultContextValue = useMemo(function () { | ||
return { | ||
appear: appear.current, | ||
isExiting: false | ||
}; | ||
}, | ||
// React rules of hooks says this isn't needed because mutating appear won't cause a re-render. | ||
// While technically true - it will trigger this to make a new object on the _next_ render which is what we want. | ||
// Remove this or use appear instead of appear.current and you will notice a test breaks. | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
[appear.current]); | ||
if (isReducedMotion()) { | ||
return children; | ||
} | ||
if (!appear.current) { | ||
// We always want child motions to appear after the initial mount. | ||
appear.current = true; | ||
} | ||
// This entire block can't be an effect because we need it to run synchronously during a render | ||
// else when elements are being removed they will be remounted instead of being updated. | ||
if (previousChildren.current.length && isAnyPreviousKeysMissingFromCurrent(childrenObj, previousChildren.current)) { | ||
if (persistedChildren.current.length === 0 || hasAnyExitingChildMountedAgain(exitingChildren, children)) { | ||
persistedChildren.current = previousChildren.current; | ||
} | ||
// We have persisted children now set from previous children. | ||
// Let's update previous children so we have it available next render. | ||
previousChildren.current = children; | ||
return (exitThenEnter ? persistedChildren.current : spliceNewElementsIntoPrevious(children, persistedChildren.current)).map(function (child) { | ||
// eslint-disable-next-line @repo/internal/react/no-children-properties-access | ||
var currentChild = childrenObj[child.key]; | ||
if (!currentChild) { | ||
// We've found an exiting child - mark it! | ||
exitingChildren.current[child.key] = true; | ||
return wrapChildWithContextProvider(child, { | ||
isExiting: true, | ||
appear: true, | ||
onFinish: function onFinish() { | ||
delete exitingChildren.current[child.key]; | ||
// We will only remove the exiting elements when any subsequent exiting elements have also finished. | ||
// Think of removing many items from a todo list - when removing a few over a few clicks we don't | ||
// want the list jumping around when they exit. | ||
if (Object.keys(exitingChildren.current).length === 0) { | ||
// Set previous children to nothing. | ||
// This let's us skip the next render check as it's assumed children and previous will be the same. | ||
previousChildren.current = []; | ||
persistedChildren.current = []; | ||
// Re-render after the element(s) have animated away which will end up rendering the latest children. | ||
forceRender(); | ||
} | ||
} | ||
}); | ||
} | ||
// This element isn't exiting. | ||
// Wrap context and let's continue on our way. | ||
return wrapChildWithContextProvider(currentChild, defaultContextValue); | ||
}); | ||
} else { | ||
previousChildren.current = children; | ||
} | ||
return children.map(function (child) { | ||
return wrapChildWithContextProvider(child, defaultContextValue); | ||
return getBooleanFF('platform.design-system-team.update-motion-for-strict-mode_p6qs0') ? /*#__PURE__*/React.createElement(WithStrictModeSupport, { | ||
appear: appear, | ||
children: children, | ||
exitThenEnter: exitThenEnter | ||
}) : /*#__PURE__*/React.createElement(WithoutStrictModeSupport, { | ||
appear: appear, | ||
children: children, | ||
exitThenEnter: exitThenEnter | ||
}); | ||
@@ -190,0 +107,0 @@ }); |
import React, { type ReactNode } from 'react'; | ||
/** | ||
* Internally we will be playing with an element that will always have a key defined. | ||
*/ | ||
export type ElementWithKey = JSX.Element & { | ||
key: string; | ||
}; | ||
export interface ExitingPersistenceProps { | ||
@@ -23,3 +29,3 @@ /** | ||
*/ | ||
interface ExitingChildContext { | ||
export interface ExitingChildContext { | ||
/** | ||
@@ -38,3 +44,24 @@ * Will perform an exit animation instead of an enter animation. | ||
} | ||
export declare const emptyContext: ExitingChildContext; | ||
/** | ||
* __Exiting context__ | ||
* | ||
* An exiting context. | ||
*/ | ||
export declare const ExitingContext: React.Context<ExitingChildContext>; | ||
/** | ||
* This method will wrap any React element with a context provider. We're using context (instead of | ||
* cloneElement) so we can communicate between multiple elements without the need of prop drilling | ||
* (results in a better API for consumers). | ||
*/ | ||
export declare const wrapChildWithContextProvider: (child: JSX.Element, value?: ExitingChildContext) => JSX.Element; | ||
/** | ||
* This function will convert all children types to an array while also filtering out non-valid React elements. | ||
*/ | ||
export declare const childrenToArray: (children?: ReactNode) => ElementWithKey[]; | ||
export declare const spliceNewElementsIntoPrevious: (current: ElementWithKey[], previous: ElementWithKey[]) => ElementWithKey[]; | ||
export declare const childrenToObj: (children: ElementWithKey[]) => { | ||
[key: string]: ElementWithKey; | ||
}; | ||
/** | ||
* __ExitingPersistence__ | ||
@@ -46,4 +73,4 @@ * | ||
*/ | ||
declare const ExitingPersistence: React.MemoExoticComponent<({ appear: appearFromProp, children: childs, exitThenEnter, }: ExitingPersistenceProps) => any>; | ||
declare const ExitingPersistence: React.MemoExoticComponent<({ appear, children, exitThenEnter }: ExitingPersistenceProps) => any>; | ||
export declare const useExitingPersistence: () => ExitingChildContext; | ||
export default ExitingPersistence; |
import React, { type ReactNode } from 'react'; | ||
/** | ||
* Internally we will be playing with an element that will always have a key defined. | ||
*/ | ||
export type ElementWithKey = JSX.Element & { | ||
key: string; | ||
}; | ||
export interface ExitingPersistenceProps { | ||
@@ -23,3 +29,3 @@ /** | ||
*/ | ||
interface ExitingChildContext { | ||
export interface ExitingChildContext { | ||
/** | ||
@@ -38,3 +44,24 @@ * Will perform an exit animation instead of an enter animation. | ||
} | ||
export declare const emptyContext: ExitingChildContext; | ||
/** | ||
* __Exiting context__ | ||
* | ||
* An exiting context. | ||
*/ | ||
export declare const ExitingContext: React.Context<ExitingChildContext>; | ||
/** | ||
* This method will wrap any React element with a context provider. We're using context (instead of | ||
* cloneElement) so we can communicate between multiple elements without the need of prop drilling | ||
* (results in a better API for consumers). | ||
*/ | ||
export declare const wrapChildWithContextProvider: (child: JSX.Element, value?: ExitingChildContext) => JSX.Element; | ||
/** | ||
* This function will convert all children types to an array while also filtering out non-valid React elements. | ||
*/ | ||
export declare const childrenToArray: (children?: ReactNode) => ElementWithKey[]; | ||
export declare const spliceNewElementsIntoPrevious: (current: ElementWithKey[], previous: ElementWithKey[]) => ElementWithKey[]; | ||
export declare const childrenToObj: (children: ElementWithKey[]) => { | ||
[key: string]: ElementWithKey; | ||
}; | ||
/** | ||
* __ExitingPersistence__ | ||
@@ -46,4 +73,4 @@ * | ||
*/ | ||
declare const ExitingPersistence: React.MemoExoticComponent<({ appear: appearFromProp, children: childs, exitThenEnter, }: ExitingPersistenceProps) => any>; | ||
declare const ExitingPersistence: React.MemoExoticComponent<({ appear, children, exitThenEnter }: ExitingPersistenceProps) => any>; | ||
export declare const useExitingPersistence: () => ExitingChildContext; | ||
export default ExitingPersistence; |
{ | ||
"name": "@atlaskit/motion", | ||
"version": "1.7.0", | ||
"version": "1.7.1", | ||
"description": "A set of utilities to apply motion in your application.", | ||
@@ -52,2 +52,3 @@ "publishConfig": { | ||
"@atlaskit/ds-lib": "^2.3.0", | ||
"@atlaskit/platform-feature-flags": "^0.2.5", | ||
"@babel/runtime": "^7.0.0", | ||
@@ -98,3 +99,8 @@ "@emotion/react": "^11.7.1", | ||
}, | ||
"homepage": "https://atlassian.design/components/motion/" | ||
"homepage": "https://atlassian.design/components/motion/", | ||
"platform-feature-flags": { | ||
"platform.design-system-team.update-motion-for-strict-mode_p6qs0": { | ||
"type": "boolean" | ||
} | ||
} | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
230809
171
4655
6
+ Added@atlaskit/platform-feature-flags@0.2.6(transitive)