framer-motion 12.11.4 → 12.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/client.js +1 -1
- package/dist/cjs/{create-t9legXtK.js → create-DCF2FFGK.js} +76 -84
- package/dist/cjs/dom-mini.js +1 -3
- package/dist/cjs/dom.js +18 -24
- package/dist/cjs/index.js +21 -57
- package/dist/cjs/m.js +113 -115
- package/dist/dom.js +1 -1
- package/dist/es/animation/animate/single-value.mjs +1 -2
- package/dist/es/animation/animate/subject.mjs +1 -1
- package/dist/es/animation/sequence/create.mjs +1 -2
- package/dist/es/animation/utils/create-visual-element.mjs +2 -2
- package/dist/es/components/AnimatePresence/PopChild.mjs +4 -1
- package/dist/es/components/Reorder/Item.mjs +1 -1
- package/dist/es/index.mjs +0 -1
- package/dist/es/projection/node/create-projection-node.mjs +2 -3
- package/dist/es/render/VisualElement.mjs +1 -2
- package/dist/es/render/dom/DOMVisualElement.mjs +1 -2
- package/dist/es/render/dom/resize/handle-element.mjs +2 -2
- package/dist/es/render/dom/scroll/offsets/inset.mjs +3 -1
- package/dist/es/render/dom/use-render.mjs +2 -2
- package/dist/es/render/html/use-props.mjs +1 -1
- package/dist/es/render/html/utils/scrape-motion-values.mjs +1 -1
- package/dist/es/render/svg/utils/scrape-motion-values.mjs +1 -2
- package/dist/es/render/utils/motion-values.mjs +1 -2
- package/dist/es/value/use-motion-template.mjs +1 -1
- package/dist/es/value/use-spring.mjs +12 -52
- package/dist/es/value/use-will-change/is.mjs +1 -1
- package/dist/es/value/utils/resolve-motion-value.mjs +1 -1
- package/dist/framer-motion.dev.js +768 -710
- package/dist/framer-motion.js +1 -1
- package/dist/m.d.ts +4 -4
- package/dist/size-rollup-animate.js +1 -1
- package/dist/size-rollup-dom-animation-assets.js +1 -1
- package/dist/size-rollup-dom-animation-m.js +1 -1
- package/dist/size-rollup-dom-animation.js +1 -1
- package/dist/size-rollup-dom-max-assets.js +1 -1
- package/dist/size-rollup-dom-max.js +1 -1
- package/dist/size-rollup-m.js +1 -1
- package/dist/size-rollup-motion.js +1 -1
- package/dist/size-rollup-scroll.js +1 -1
- package/dist/types/client.d.ts +2 -2
- package/dist/types/index.d.ts +11 -13
- package/dist/{types.d-CQt5spQA.d.ts → types.d-CtuPurYT.d.ts} +3 -3
- package/package.json +4 -4
- package/dist/es/render/dom/utils/is-svg-element.mjs +0 -5
- package/dist/es/value/utils/is-motion-value.mjs +0 -3
|
@@ -83,591 +83,216 @@
|
|
|
83
83
|
const PresenceContext =
|
|
84
84
|
/* @__PURE__ */ React$1.createContext(null);
|
|
85
85
|
|
|
86
|
+
function addUniqueItem(arr, item) {
|
|
87
|
+
if (arr.indexOf(item) === -1)
|
|
88
|
+
arr.push(item);
|
|
89
|
+
}
|
|
90
|
+
function removeItem(arr, item) {
|
|
91
|
+
const index = arr.indexOf(item);
|
|
92
|
+
if (index > -1)
|
|
93
|
+
arr.splice(index, 1);
|
|
94
|
+
}
|
|
95
|
+
// Adapted from array-move
|
|
96
|
+
function moveItem([...arr], fromIndex, toIndex) {
|
|
97
|
+
const startIndex = fromIndex < 0 ? arr.length + fromIndex : fromIndex;
|
|
98
|
+
if (startIndex >= 0 && startIndex < arr.length) {
|
|
99
|
+
const endIndex = toIndex < 0 ? arr.length + toIndex : toIndex;
|
|
100
|
+
const [item] = arr.splice(fromIndex, 1);
|
|
101
|
+
arr.splice(endIndex, 0, item);
|
|
102
|
+
}
|
|
103
|
+
return arr;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const clamp = (min, max, v) => {
|
|
107
|
+
if (v > max)
|
|
108
|
+
return max;
|
|
109
|
+
if (v < min)
|
|
110
|
+
return min;
|
|
111
|
+
return v;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
exports.warning = () => { };
|
|
115
|
+
exports.invariant = () => { };
|
|
116
|
+
{
|
|
117
|
+
exports.warning = (check, message) => {
|
|
118
|
+
if (!check && typeof console !== "undefined") {
|
|
119
|
+
console.warn(message);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
exports.invariant = (check, message) => {
|
|
123
|
+
if (!check) {
|
|
124
|
+
throw new Error(message);
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const MotionGlobalConfig = {};
|
|
130
|
+
|
|
86
131
|
/**
|
|
87
|
-
*
|
|
132
|
+
* Check if value is a numerical string, ie a string that is purely a number eg "100" or "-100.1"
|
|
88
133
|
*/
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
134
|
+
const isNumericalString = (v) => /^-?(?:\d+(?:\.\d+)?|\.\d+)$/u.test(v);
|
|
135
|
+
|
|
136
|
+
function isObject(value) {
|
|
137
|
+
return typeof value === "object" && value !== null;
|
|
138
|
+
}
|
|
94
139
|
|
|
95
140
|
/**
|
|
96
|
-
*
|
|
97
|
-
* to leverage snapshot lifecycle.
|
|
141
|
+
* Check if the value is a zero value string like "0px" or "0%"
|
|
98
142
|
*/
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
143
|
+
const isZeroValueString = (v) => /^0[^.\s]+$/u.test(v);
|
|
144
|
+
|
|
145
|
+
/*#__NO_SIDE_EFFECTS__*/
|
|
146
|
+
function memo(callback) {
|
|
147
|
+
let result;
|
|
148
|
+
return () => {
|
|
149
|
+
if (result === undefined)
|
|
150
|
+
result = callback();
|
|
151
|
+
return result;
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/*#__NO_SIDE_EFFECTS__*/
|
|
156
|
+
const noop = (any) => any;
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Pipe
|
|
160
|
+
* Compose other transformers to run linearily
|
|
161
|
+
* pipe(min(20), max(40))
|
|
162
|
+
* @param {...functions} transformers
|
|
163
|
+
* @return {function}
|
|
164
|
+
*/
|
|
165
|
+
const combineFunctions = (a, b) => (v) => b(a(v));
|
|
166
|
+
const pipe = (...transformers) => transformers.reduce(combineFunctions);
|
|
167
|
+
|
|
168
|
+
/*
|
|
169
|
+
Progress within given range
|
|
170
|
+
|
|
171
|
+
Given a lower limit and an upper limit, we return the progress
|
|
172
|
+
(expressed as a number 0-1) represented by the given value, and
|
|
173
|
+
limit that progress to within 0-1.
|
|
174
|
+
|
|
175
|
+
@param [number]: Lower limit
|
|
176
|
+
@param [number]: Upper limit
|
|
177
|
+
@param [number]: Value to find progress within given range
|
|
178
|
+
@return [number]: Progress of value within range as expressed 0-1
|
|
179
|
+
*/
|
|
180
|
+
/*#__NO_SIDE_EFFECTS__*/
|
|
181
|
+
const progress = (from, to, value) => {
|
|
182
|
+
const toFromDifference = to - from;
|
|
183
|
+
return toFromDifference === 0 ? 1 : (value - from) / toFromDifference;
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
class SubscriptionManager {
|
|
187
|
+
constructor() {
|
|
188
|
+
this.subscriptions = [];
|
|
113
189
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
componentDidUpdate() { }
|
|
118
|
-
render() {
|
|
119
|
-
return this.props.children;
|
|
190
|
+
add(handler) {
|
|
191
|
+
addUniqueItem(this.subscriptions, handler);
|
|
192
|
+
return () => removeItem(this.subscriptions, handler);
|
|
120
193
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
const ref = React$1.useRef(null);
|
|
125
|
-
const size = React$1.useRef({
|
|
126
|
-
width: 0,
|
|
127
|
-
height: 0,
|
|
128
|
-
top: 0,
|
|
129
|
-
left: 0,
|
|
130
|
-
right: 0,
|
|
131
|
-
});
|
|
132
|
-
const { nonce } = React$1.useContext(MotionConfigContext);
|
|
133
|
-
/**
|
|
134
|
-
* We create and inject a style block so we can apply this explicit
|
|
135
|
-
* sizing in a non-destructive manner by just deleting the style block.
|
|
136
|
-
*
|
|
137
|
-
* We can't apply size via render as the measurement happens
|
|
138
|
-
* in getSnapshotBeforeUpdate (post-render), likewise if we apply the
|
|
139
|
-
* styles directly on the DOM node, we might be overwriting
|
|
140
|
-
* styles set via the style prop.
|
|
141
|
-
*/
|
|
142
|
-
React$1.useInsertionEffect(() => {
|
|
143
|
-
const { width, height, top, left, right } = size.current;
|
|
144
|
-
if (isPresent || !ref.current || !width || !height)
|
|
194
|
+
notify(a, b, c) {
|
|
195
|
+
const numSubscriptions = this.subscriptions.length;
|
|
196
|
+
if (!numSubscriptions)
|
|
145
197
|
return;
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
document.head.appendChild(style);
|
|
152
|
-
if (style.sheet) {
|
|
153
|
-
style.sheet.insertRule(`
|
|
154
|
-
[data-motion-pop-id="${id}"] {
|
|
155
|
-
position: absolute !important;
|
|
156
|
-
width: ${width}px !important;
|
|
157
|
-
height: ${height}px !important;
|
|
158
|
-
${x}px !important;
|
|
159
|
-
top: ${top}px !important;
|
|
160
|
-
}
|
|
161
|
-
`);
|
|
198
|
+
if (numSubscriptions === 1) {
|
|
199
|
+
/**
|
|
200
|
+
* If there's only a single handler we can just call it without invoking a loop.
|
|
201
|
+
*/
|
|
202
|
+
this.subscriptions[0](a, b, c);
|
|
162
203
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
204
|
+
else {
|
|
205
|
+
for (let i = 0; i < numSubscriptions; i++) {
|
|
206
|
+
/**
|
|
207
|
+
* Check whether the handler exists before firing as it's possible
|
|
208
|
+
* the subscriptions were modified during this loop running.
|
|
209
|
+
*/
|
|
210
|
+
const handler = this.subscriptions[i];
|
|
211
|
+
handler && handler(a, b, c);
|
|
166
212
|
}
|
|
167
|
-
}
|
|
168
|
-
}, [isPresent]);
|
|
169
|
-
return (jsx(PopChildMeasure, { isPresent: isPresent, childRef: ref, sizeRef: size, children: React__namespace.cloneElement(children, { ref }) }));
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const PresenceChild = ({ children, initial, isPresent, onExitComplete, custom, presenceAffectsLayout, mode, anchorX, }) => {
|
|
173
|
-
const presenceChildren = useConstant(newChildrenMap);
|
|
174
|
-
const id = React$1.useId();
|
|
175
|
-
let isReusedContext = true;
|
|
176
|
-
let context = React$1.useMemo(() => {
|
|
177
|
-
isReusedContext = false;
|
|
178
|
-
return {
|
|
179
|
-
id,
|
|
180
|
-
initial,
|
|
181
|
-
isPresent,
|
|
182
|
-
custom,
|
|
183
|
-
onExitComplete: (childId) => {
|
|
184
|
-
presenceChildren.set(childId, true);
|
|
185
|
-
for (const isComplete of presenceChildren.values()) {
|
|
186
|
-
if (!isComplete)
|
|
187
|
-
return; // can stop searching when any is incomplete
|
|
188
|
-
}
|
|
189
|
-
onExitComplete && onExitComplete();
|
|
190
|
-
},
|
|
191
|
-
register: (childId) => {
|
|
192
|
-
presenceChildren.set(childId, false);
|
|
193
|
-
return () => presenceChildren.delete(childId);
|
|
194
|
-
},
|
|
195
|
-
};
|
|
196
|
-
}, [isPresent, presenceChildren, onExitComplete]);
|
|
197
|
-
/**
|
|
198
|
-
* If the presence of a child affects the layout of the components around it,
|
|
199
|
-
* we want to make a new context value to ensure they get re-rendered
|
|
200
|
-
* so they can detect that layout change.
|
|
201
|
-
*/
|
|
202
|
-
if (presenceAffectsLayout && isReusedContext) {
|
|
203
|
-
context = { ...context };
|
|
213
|
+
}
|
|
204
214
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
* component immediately.
|
|
211
|
-
*/
|
|
212
|
-
React__namespace.useEffect(() => {
|
|
213
|
-
!isPresent &&
|
|
214
|
-
!presenceChildren.size &&
|
|
215
|
-
onExitComplete &&
|
|
216
|
-
onExitComplete();
|
|
217
|
-
}, [isPresent]);
|
|
218
|
-
if (mode === "popLayout") {
|
|
219
|
-
children = (jsx(PopChild, { isPresent: isPresent, anchorX: anchorX, children: children }));
|
|
215
|
+
getSize() {
|
|
216
|
+
return this.subscriptions.length;
|
|
217
|
+
}
|
|
218
|
+
clear() {
|
|
219
|
+
this.subscriptions.length = 0;
|
|
220
220
|
}
|
|
221
|
-
return (jsx(PresenceContext.Provider, { value: context, children: children }));
|
|
222
|
-
};
|
|
223
|
-
function newChildrenMap() {
|
|
224
|
-
return new Map();
|
|
225
221
|
}
|
|
226
222
|
|
|
227
223
|
/**
|
|
228
|
-
*
|
|
229
|
-
* to access information about whether it's still present in the React tree.
|
|
230
|
-
*
|
|
231
|
-
* ```jsx
|
|
232
|
-
* import { usePresence } from "framer-motion"
|
|
233
|
-
*
|
|
234
|
-
* export const Component = () => {
|
|
235
|
-
* const [isPresent, safeToRemove] = usePresence()
|
|
224
|
+
* Converts seconds to milliseconds
|
|
236
225
|
*
|
|
237
|
-
*
|
|
238
|
-
*
|
|
239
|
-
* }, [isPresent])
|
|
240
|
-
*
|
|
241
|
-
* return <div />
|
|
242
|
-
* }
|
|
243
|
-
* ```
|
|
244
|
-
*
|
|
245
|
-
* If `isPresent` is `false`, it means that a component has been removed the tree, but
|
|
246
|
-
* `AnimatePresence` won't really remove it until `safeToRemove` has been called.
|
|
247
|
-
*
|
|
248
|
-
* @public
|
|
226
|
+
* @param seconds - Time in seconds.
|
|
227
|
+
* @return milliseconds - Converted time in milliseconds.
|
|
249
228
|
*/
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
const safeToRemove = React$1.useCallback(() => subscribe && onExitComplete && onExitComplete(id), [id, onExitComplete, subscribe]);
|
|
264
|
-
return !isPresent && onExitComplete ? [false, safeToRemove] : [true];
|
|
229
|
+
/*#__NO_SIDE_EFFECTS__*/
|
|
230
|
+
const secondsToMilliseconds = (seconds) => seconds * 1000;
|
|
231
|
+
/*#__NO_SIDE_EFFECTS__*/
|
|
232
|
+
const millisecondsToSeconds = (milliseconds) => milliseconds / 1000;
|
|
233
|
+
|
|
234
|
+
/*
|
|
235
|
+
Convert velocity into velocity per second
|
|
236
|
+
|
|
237
|
+
@param [number]: Unit per frame
|
|
238
|
+
@param [number]: Frame duration in ms
|
|
239
|
+
*/
|
|
240
|
+
function velocityPerSecond(velocity, frameDuration) {
|
|
241
|
+
return frameDuration ? velocity * (1000 / frameDuration) : 0;
|
|
265
242
|
}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
* ```jsx
|
|
271
|
-
* import { useIsPresent } from "framer-motion"
|
|
272
|
-
*
|
|
273
|
-
* export const Component = () => {
|
|
274
|
-
* const isPresent = useIsPresent()
|
|
275
|
-
*
|
|
276
|
-
* useEffect(() => {
|
|
277
|
-
* !isPresent && console.log("I've been removed!")
|
|
278
|
-
* }, [isPresent])
|
|
279
|
-
*
|
|
280
|
-
* return <div />
|
|
281
|
-
* }
|
|
282
|
-
* ```
|
|
283
|
-
*
|
|
284
|
-
* @public
|
|
285
|
-
*/
|
|
286
|
-
function useIsPresent() {
|
|
287
|
-
return isPresent(React$1.useContext(PresenceContext));
|
|
243
|
+
|
|
244
|
+
const warned = new Set();
|
|
245
|
+
function hasWarned$1(message) {
|
|
246
|
+
return warned.has(message);
|
|
288
247
|
}
|
|
289
|
-
function
|
|
290
|
-
|
|
248
|
+
function warnOnce(condition, message, element) {
|
|
249
|
+
if (condition || warned.has(message))
|
|
250
|
+
return;
|
|
251
|
+
console.warn(message);
|
|
252
|
+
if (element)
|
|
253
|
+
console.warn(element);
|
|
254
|
+
warned.add(message);
|
|
291
255
|
}
|
|
292
256
|
|
|
293
|
-
const
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
React$1.Children.forEach(children, (child) => {
|
|
298
|
-
if (React$1.isValidElement(child))
|
|
299
|
-
filtered.push(child);
|
|
300
|
-
});
|
|
301
|
-
return filtered;
|
|
302
|
-
}
|
|
257
|
+
const wrap = (min, max, v) => {
|
|
258
|
+
const rangeSize = max - min;
|
|
259
|
+
return ((((v - min) % rangeSize) + rangeSize) % rangeSize) + min;
|
|
260
|
+
};
|
|
303
261
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
* @public
|
|
336
|
-
*/
|
|
337
|
-
const AnimatePresence = ({ children, custom, initial = true, onExitComplete, presenceAffectsLayout = true, mode = "sync", propagate = false, anchorX = "left", }) => {
|
|
338
|
-
const [isParentPresent, safeToRemove] = usePresence(propagate);
|
|
339
|
-
/**
|
|
340
|
-
* Filter any children that aren't ReactElements. We can only track components
|
|
341
|
-
* between renders with a props.key.
|
|
342
|
-
*/
|
|
343
|
-
const presentChildren = React$1.useMemo(() => onlyElements(children), [children]);
|
|
344
|
-
/**
|
|
345
|
-
* Track the keys of the currently rendered children. This is used to
|
|
346
|
-
* determine which children are exiting.
|
|
347
|
-
*/
|
|
348
|
-
const presentKeys = propagate && !isParentPresent ? [] : presentChildren.map(getChildKey);
|
|
349
|
-
/**
|
|
350
|
-
* If `initial={false}` we only want to pass this to components in the first render.
|
|
351
|
-
*/
|
|
352
|
-
const isInitialRender = React$1.useRef(true);
|
|
353
|
-
/**
|
|
354
|
-
* A ref containing the currently present children. When all exit animations
|
|
355
|
-
* are complete, we use this to re-render the component with the latest children
|
|
356
|
-
* *committed* rather than the latest children *rendered*.
|
|
357
|
-
*/
|
|
358
|
-
const pendingPresentChildren = React$1.useRef(presentChildren);
|
|
359
|
-
/**
|
|
360
|
-
* Track which exiting children have finished animating out.
|
|
361
|
-
*/
|
|
362
|
-
const exitComplete = useConstant(() => new Map());
|
|
363
|
-
/**
|
|
364
|
-
* Save children to render as React state. To ensure this component is concurrent-safe,
|
|
365
|
-
* we check for exiting children via an effect.
|
|
366
|
-
*/
|
|
367
|
-
const [diffedChildren, setDiffedChildren] = React$1.useState(presentChildren);
|
|
368
|
-
const [renderedChildren, setRenderedChildren] = React$1.useState(presentChildren);
|
|
369
|
-
useIsomorphicLayoutEffect(() => {
|
|
370
|
-
isInitialRender.current = false;
|
|
371
|
-
pendingPresentChildren.current = presentChildren;
|
|
372
|
-
/**
|
|
373
|
-
* Update complete status of exiting children.
|
|
374
|
-
*/
|
|
375
|
-
for (let i = 0; i < renderedChildren.length; i++) {
|
|
376
|
-
const key = getChildKey(renderedChildren[i]);
|
|
377
|
-
if (!presentKeys.includes(key)) {
|
|
378
|
-
if (exitComplete.get(key) !== true) {
|
|
379
|
-
exitComplete.set(key, false);
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
else {
|
|
383
|
-
exitComplete.delete(key);
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
}, [renderedChildren, presentKeys.length, presentKeys.join("-")]);
|
|
387
|
-
const exitingChildren = [];
|
|
388
|
-
if (presentChildren !== diffedChildren) {
|
|
389
|
-
let nextChildren = [...presentChildren];
|
|
390
|
-
/**
|
|
391
|
-
* Loop through all the currently rendered components and decide which
|
|
392
|
-
* are exiting.
|
|
393
|
-
*/
|
|
394
|
-
for (let i = 0; i < renderedChildren.length; i++) {
|
|
395
|
-
const child = renderedChildren[i];
|
|
396
|
-
const key = getChildKey(child);
|
|
397
|
-
if (!presentKeys.includes(key)) {
|
|
398
|
-
nextChildren.splice(i, 0, child);
|
|
399
|
-
exitingChildren.push(child);
|
|
400
|
-
}
|
|
262
|
+
/*
|
|
263
|
+
Bezier function generator
|
|
264
|
+
This has been modified from Gaëtan Renaudeau's BezierEasing
|
|
265
|
+
https://github.com/gre/bezier-easing/blob/master/src/index.js
|
|
266
|
+
https://github.com/gre/bezier-easing/blob/master/LICENSE
|
|
267
|
+
|
|
268
|
+
I've removed the newtonRaphsonIterate algo because in benchmarking it
|
|
269
|
+
wasn't noticiably faster than binarySubdivision, indeed removing it
|
|
270
|
+
usually improved times, depending on the curve.
|
|
271
|
+
I also removed the lookup table, as for the added bundle size and loop we're
|
|
272
|
+
only cutting ~4 or so subdivision iterations. I bumped the max iterations up
|
|
273
|
+
to 12 to compensate and this still tended to be faster for no perceivable
|
|
274
|
+
loss in accuracy.
|
|
275
|
+
Usage
|
|
276
|
+
const easeOut = cubicBezier(.17,.67,.83,.67);
|
|
277
|
+
const x = easeOut(0.5); // returns 0.627...
|
|
278
|
+
*/
|
|
279
|
+
// Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
|
|
280
|
+
const calcBezier = (t, a1, a2) => (((1.0 - 3.0 * a2 + 3.0 * a1) * t + (3.0 * a2 - 6.0 * a1)) * t + 3.0 * a1) *
|
|
281
|
+
t;
|
|
282
|
+
const subdivisionPrecision = 0.0000001;
|
|
283
|
+
const subdivisionMaxIterations = 12;
|
|
284
|
+
function binarySubdivide(x, lowerBound, upperBound, mX1, mX2) {
|
|
285
|
+
let currentX;
|
|
286
|
+
let currentT;
|
|
287
|
+
let i = 0;
|
|
288
|
+
do {
|
|
289
|
+
currentT = lowerBound + (upperBound - lowerBound) / 2.0;
|
|
290
|
+
currentX = calcBezier(currentT, mX1, mX2) - x;
|
|
291
|
+
if (currentX > 0.0) {
|
|
292
|
+
upperBound = currentT;
|
|
401
293
|
}
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
* only render these until they've all exited.
|
|
405
|
-
*/
|
|
406
|
-
if (mode === "wait" && exitingChildren.length) {
|
|
407
|
-
nextChildren = exitingChildren;
|
|
408
|
-
}
|
|
409
|
-
setRenderedChildren(onlyElements(nextChildren));
|
|
410
|
-
setDiffedChildren(presentChildren);
|
|
411
|
-
/**
|
|
412
|
-
* Early return to ensure once we've set state with the latest diffed
|
|
413
|
-
* children, we can immediately re-render.
|
|
414
|
-
*/
|
|
415
|
-
return null;
|
|
416
|
-
}
|
|
417
|
-
if (mode === "wait" &&
|
|
418
|
-
renderedChildren.length > 1) {
|
|
419
|
-
console.warn(`You're attempting to animate multiple children within AnimatePresence, but its mode is set to "wait". This will lead to odd visual behaviour.`);
|
|
420
|
-
}
|
|
421
|
-
/**
|
|
422
|
-
* If we've been provided a forceRender function by the LayoutGroupContext,
|
|
423
|
-
* we can use it to force a re-render amongst all surrounding components once
|
|
424
|
-
* all components have finished animating out.
|
|
425
|
-
*/
|
|
426
|
-
const { forceRender } = React$1.useContext(LayoutGroupContext);
|
|
427
|
-
return (jsx(Fragment, { children: renderedChildren.map((child) => {
|
|
428
|
-
const key = getChildKey(child);
|
|
429
|
-
const isPresent = propagate && !isParentPresent
|
|
430
|
-
? false
|
|
431
|
-
: presentChildren === renderedChildren ||
|
|
432
|
-
presentKeys.includes(key);
|
|
433
|
-
const onExit = () => {
|
|
434
|
-
if (exitComplete.has(key)) {
|
|
435
|
-
exitComplete.set(key, true);
|
|
436
|
-
}
|
|
437
|
-
else {
|
|
438
|
-
return;
|
|
439
|
-
}
|
|
440
|
-
let isEveryExitComplete = true;
|
|
441
|
-
exitComplete.forEach((isExitComplete) => {
|
|
442
|
-
if (!isExitComplete)
|
|
443
|
-
isEveryExitComplete = false;
|
|
444
|
-
});
|
|
445
|
-
if (isEveryExitComplete) {
|
|
446
|
-
forceRender?.();
|
|
447
|
-
setRenderedChildren(pendingPresentChildren.current);
|
|
448
|
-
propagate && safeToRemove?.();
|
|
449
|
-
onExitComplete && onExitComplete();
|
|
450
|
-
}
|
|
451
|
-
};
|
|
452
|
-
return (jsx(PresenceChild, { isPresent: isPresent, initial: !isInitialRender.current || initial
|
|
453
|
-
? undefined
|
|
454
|
-
: false, custom: custom, presenceAffectsLayout: presenceAffectsLayout, mode: mode, onExitComplete: isPresent ? undefined : onExit, anchorX: anchorX, children: child }, key));
|
|
455
|
-
}) }));
|
|
456
|
-
};
|
|
457
|
-
|
|
458
|
-
/**
|
|
459
|
-
* Note: Still used by components generated by old versions of Framer
|
|
460
|
-
*
|
|
461
|
-
* @deprecated
|
|
462
|
-
*/
|
|
463
|
-
const DeprecatedLayoutGroupContext = React$1.createContext(null);
|
|
464
|
-
|
|
465
|
-
function addUniqueItem(arr, item) {
|
|
466
|
-
if (arr.indexOf(item) === -1)
|
|
467
|
-
arr.push(item);
|
|
468
|
-
}
|
|
469
|
-
function removeItem(arr, item) {
|
|
470
|
-
const index = arr.indexOf(item);
|
|
471
|
-
if (index > -1)
|
|
472
|
-
arr.splice(index, 1);
|
|
473
|
-
}
|
|
474
|
-
// Adapted from array-move
|
|
475
|
-
function moveItem([...arr], fromIndex, toIndex) {
|
|
476
|
-
const startIndex = fromIndex < 0 ? arr.length + fromIndex : fromIndex;
|
|
477
|
-
if (startIndex >= 0 && startIndex < arr.length) {
|
|
478
|
-
const endIndex = toIndex < 0 ? arr.length + toIndex : toIndex;
|
|
479
|
-
const [item] = arr.splice(fromIndex, 1);
|
|
480
|
-
arr.splice(endIndex, 0, item);
|
|
481
|
-
}
|
|
482
|
-
return arr;
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
const clamp = (min, max, v) => {
|
|
486
|
-
if (v > max)
|
|
487
|
-
return max;
|
|
488
|
-
if (v < min)
|
|
489
|
-
return min;
|
|
490
|
-
return v;
|
|
491
|
-
};
|
|
492
|
-
|
|
493
|
-
exports.warning = () => { };
|
|
494
|
-
exports.invariant = () => { };
|
|
495
|
-
{
|
|
496
|
-
exports.warning = (check, message) => {
|
|
497
|
-
if (!check && typeof console !== "undefined") {
|
|
498
|
-
console.warn(message);
|
|
499
|
-
}
|
|
500
|
-
};
|
|
501
|
-
exports.invariant = (check, message) => {
|
|
502
|
-
if (!check) {
|
|
503
|
-
throw new Error(message);
|
|
504
|
-
}
|
|
505
|
-
};
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
const MotionGlobalConfig = {};
|
|
509
|
-
|
|
510
|
-
/**
|
|
511
|
-
* Check if value is a numerical string, ie a string that is purely a number eg "100" or "-100.1"
|
|
512
|
-
*/
|
|
513
|
-
const isNumericalString = (v) => /^-?(?:\d+(?:\.\d+)?|\.\d+)$/u.test(v);
|
|
514
|
-
|
|
515
|
-
/**
|
|
516
|
-
* Check if the value is a zero value string like "0px" or "0%"
|
|
517
|
-
*/
|
|
518
|
-
const isZeroValueString = (v) => /^0[^.\s]+$/u.test(v);
|
|
519
|
-
|
|
520
|
-
/*#__NO_SIDE_EFFECTS__*/
|
|
521
|
-
function memo(callback) {
|
|
522
|
-
let result;
|
|
523
|
-
return () => {
|
|
524
|
-
if (result === undefined)
|
|
525
|
-
result = callback();
|
|
526
|
-
return result;
|
|
527
|
-
};
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
/*#__NO_SIDE_EFFECTS__*/
|
|
531
|
-
const noop = (any) => any;
|
|
532
|
-
|
|
533
|
-
/**
|
|
534
|
-
* Pipe
|
|
535
|
-
* Compose other transformers to run linearily
|
|
536
|
-
* pipe(min(20), max(40))
|
|
537
|
-
* @param {...functions} transformers
|
|
538
|
-
* @return {function}
|
|
539
|
-
*/
|
|
540
|
-
const combineFunctions = (a, b) => (v) => b(a(v));
|
|
541
|
-
const pipe = (...transformers) => transformers.reduce(combineFunctions);
|
|
542
|
-
|
|
543
|
-
/*
|
|
544
|
-
Progress within given range
|
|
545
|
-
|
|
546
|
-
Given a lower limit and an upper limit, we return the progress
|
|
547
|
-
(expressed as a number 0-1) represented by the given value, and
|
|
548
|
-
limit that progress to within 0-1.
|
|
549
|
-
|
|
550
|
-
@param [number]: Lower limit
|
|
551
|
-
@param [number]: Upper limit
|
|
552
|
-
@param [number]: Value to find progress within given range
|
|
553
|
-
@return [number]: Progress of value within range as expressed 0-1
|
|
554
|
-
*/
|
|
555
|
-
/*#__NO_SIDE_EFFECTS__*/
|
|
556
|
-
const progress = (from, to, value) => {
|
|
557
|
-
const toFromDifference = to - from;
|
|
558
|
-
return toFromDifference === 0 ? 1 : (value - from) / toFromDifference;
|
|
559
|
-
};
|
|
560
|
-
|
|
561
|
-
class SubscriptionManager {
|
|
562
|
-
constructor() {
|
|
563
|
-
this.subscriptions = [];
|
|
564
|
-
}
|
|
565
|
-
add(handler) {
|
|
566
|
-
addUniqueItem(this.subscriptions, handler);
|
|
567
|
-
return () => removeItem(this.subscriptions, handler);
|
|
568
|
-
}
|
|
569
|
-
notify(a, b, c) {
|
|
570
|
-
const numSubscriptions = this.subscriptions.length;
|
|
571
|
-
if (!numSubscriptions)
|
|
572
|
-
return;
|
|
573
|
-
if (numSubscriptions === 1) {
|
|
574
|
-
/**
|
|
575
|
-
* If there's only a single handler we can just call it without invoking a loop.
|
|
576
|
-
*/
|
|
577
|
-
this.subscriptions[0](a, b, c);
|
|
578
|
-
}
|
|
579
|
-
else {
|
|
580
|
-
for (let i = 0; i < numSubscriptions; i++) {
|
|
581
|
-
/**
|
|
582
|
-
* Check whether the handler exists before firing as it's possible
|
|
583
|
-
* the subscriptions were modified during this loop running.
|
|
584
|
-
*/
|
|
585
|
-
const handler = this.subscriptions[i];
|
|
586
|
-
handler && handler(a, b, c);
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
getSize() {
|
|
591
|
-
return this.subscriptions.length;
|
|
592
|
-
}
|
|
593
|
-
clear() {
|
|
594
|
-
this.subscriptions.length = 0;
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
/**
|
|
599
|
-
* Converts seconds to milliseconds
|
|
600
|
-
*
|
|
601
|
-
* @param seconds - Time in seconds.
|
|
602
|
-
* @return milliseconds - Converted time in milliseconds.
|
|
603
|
-
*/
|
|
604
|
-
/*#__NO_SIDE_EFFECTS__*/
|
|
605
|
-
const secondsToMilliseconds = (seconds) => seconds * 1000;
|
|
606
|
-
/*#__NO_SIDE_EFFECTS__*/
|
|
607
|
-
const millisecondsToSeconds = (milliseconds) => milliseconds / 1000;
|
|
608
|
-
|
|
609
|
-
/*
|
|
610
|
-
Convert velocity into velocity per second
|
|
611
|
-
|
|
612
|
-
@param [number]: Unit per frame
|
|
613
|
-
@param [number]: Frame duration in ms
|
|
614
|
-
*/
|
|
615
|
-
function velocityPerSecond(velocity, frameDuration) {
|
|
616
|
-
return frameDuration ? velocity * (1000 / frameDuration) : 0;
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
const warned = new Set();
|
|
620
|
-
function hasWarned$1(message) {
|
|
621
|
-
return warned.has(message);
|
|
622
|
-
}
|
|
623
|
-
function warnOnce(condition, message, element) {
|
|
624
|
-
if (condition || warned.has(message))
|
|
625
|
-
return;
|
|
626
|
-
console.warn(message);
|
|
627
|
-
if (element)
|
|
628
|
-
console.warn(element);
|
|
629
|
-
warned.add(message);
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
const wrap = (min, max, v) => {
|
|
633
|
-
const rangeSize = max - min;
|
|
634
|
-
return ((((v - min) % rangeSize) + rangeSize) % rangeSize) + min;
|
|
635
|
-
};
|
|
636
|
-
|
|
637
|
-
/*
|
|
638
|
-
Bezier function generator
|
|
639
|
-
This has been modified from Gaëtan Renaudeau's BezierEasing
|
|
640
|
-
https://github.com/gre/bezier-easing/blob/master/src/index.js
|
|
641
|
-
https://github.com/gre/bezier-easing/blob/master/LICENSE
|
|
642
|
-
|
|
643
|
-
I've removed the newtonRaphsonIterate algo because in benchmarking it
|
|
644
|
-
wasn't noticiably faster than binarySubdivision, indeed removing it
|
|
645
|
-
usually improved times, depending on the curve.
|
|
646
|
-
I also removed the lookup table, as for the added bundle size and loop we're
|
|
647
|
-
only cutting ~4 or so subdivision iterations. I bumped the max iterations up
|
|
648
|
-
to 12 to compensate and this still tended to be faster for no perceivable
|
|
649
|
-
loss in accuracy.
|
|
650
|
-
Usage
|
|
651
|
-
const easeOut = cubicBezier(.17,.67,.83,.67);
|
|
652
|
-
const x = easeOut(0.5); // returns 0.627...
|
|
653
|
-
*/
|
|
654
|
-
// Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
|
|
655
|
-
const calcBezier = (t, a1, a2) => (((1.0 - 3.0 * a2 + 3.0 * a1) * t + (3.0 * a2 - 6.0 * a1)) * t + 3.0 * a1) *
|
|
656
|
-
t;
|
|
657
|
-
const subdivisionPrecision = 0.0000001;
|
|
658
|
-
const subdivisionMaxIterations = 12;
|
|
659
|
-
function binarySubdivide(x, lowerBound, upperBound, mX1, mX2) {
|
|
660
|
-
let currentX;
|
|
661
|
-
let currentT;
|
|
662
|
-
let i = 0;
|
|
663
|
-
do {
|
|
664
|
-
currentT = lowerBound + (upperBound - lowerBound) / 2.0;
|
|
665
|
-
currentX = calcBezier(currentT, mX1, mX2) - x;
|
|
666
|
-
if (currentX > 0.0) {
|
|
667
|
-
upperBound = currentT;
|
|
668
|
-
}
|
|
669
|
-
else {
|
|
670
|
-
lowerBound = currentT;
|
|
294
|
+
else {
|
|
295
|
+
lowerBound = currentT;
|
|
671
296
|
}
|
|
672
297
|
} while (Math.abs(currentX) > subdivisionPrecision &&
|
|
673
298
|
++i < subdivisionMaxIterations);
|
|
@@ -1883,7 +1508,7 @@
|
|
|
1883
1508
|
* mixColor(0.5) // 'rgba(128, 128, 128, 1)'
|
|
1884
1509
|
* ```
|
|
1885
1510
|
*
|
|
1886
|
-
* TODO
|
|
1511
|
+
* TODO Revisit this approach once we've moved to data models for values,
|
|
1887
1512
|
* probably not needed to pregenerate mixer functions.
|
|
1888
1513
|
*
|
|
1889
1514
|
* @public
|
|
@@ -3055,6 +2680,14 @@
|
|
|
3055
2680
|
((type === "spring" || isGenerator(type)) && velocity));
|
|
3056
2681
|
}
|
|
3057
2682
|
|
|
2683
|
+
/**
|
|
2684
|
+
* Checks if an element is an HTML element in a way
|
|
2685
|
+
* that works across iframes
|
|
2686
|
+
*/
|
|
2687
|
+
function isHTMLElement(element) {
|
|
2688
|
+
return isObject(element) && "offsetHeight" in element;
|
|
2689
|
+
}
|
|
2690
|
+
|
|
3058
2691
|
/**
|
|
3059
2692
|
* A list of values that can be hardware-accelerated.
|
|
3060
2693
|
*/
|
|
@@ -3063,16 +2696,13 @@
|
|
|
3063
2696
|
"clipPath",
|
|
3064
2697
|
"filter",
|
|
3065
2698
|
"transform",
|
|
3066
|
-
// TODO:
|
|
3067
|
-
// or until we implement support for linear() easing.
|
|
2699
|
+
// TODO: Could be re-enabled now we have support for linear() easing
|
|
3068
2700
|
// "background-color"
|
|
3069
2701
|
]);
|
|
3070
2702
|
const supportsWaapi = /*@__PURE__*/ memo(() => Object.hasOwnProperty.call(Element.prototype, "animate"));
|
|
3071
2703
|
function supportsBrowserAnimation(options) {
|
|
3072
2704
|
const { motionValue, name, repeatDelay, repeatType, damping, type } = options;
|
|
3073
|
-
if (!motionValue
|
|
3074
|
-
!motionValue.owner ||
|
|
3075
|
-
!(motionValue.owner.current instanceof HTMLElement)) {
|
|
2705
|
+
if (!isHTMLElement(motionValue?.owner?.current)) {
|
|
3076
2706
|
return false;
|
|
3077
2707
|
}
|
|
3078
2708
|
const { onUpdate, transformTemplate } = motionValue.owner.getProps();
|
|
@@ -4488,7 +4118,7 @@
|
|
|
4488
4118
|
targets.forEach((target) => {
|
|
4489
4119
|
const pointerDownTarget = options.useGlobalTarget ? window : target;
|
|
4490
4120
|
pointerDownTarget.addEventListener("pointerdown", startPress, eventOptions);
|
|
4491
|
-
if (target
|
|
4121
|
+
if (isHTMLElement(target)) {
|
|
4492
4122
|
target.addEventListener("focus", (event) => enableKeyboardPress(event, eventOptions));
|
|
4493
4123
|
if (!isElementKeyboardAccessible(target) &&
|
|
4494
4124
|
!target.hasAttribute("tabindex")) {
|
|
@@ -4633,6 +4263,22 @@
|
|
|
4633
4263
|
return reportStats;
|
|
4634
4264
|
}
|
|
4635
4265
|
|
|
4266
|
+
/**
|
|
4267
|
+
* Checks if an element is an SVG element in a way
|
|
4268
|
+
* that works across iframes
|
|
4269
|
+
*/
|
|
4270
|
+
function isSVGElement(element) {
|
|
4271
|
+
return isObject(element) && "ownerSVGElement" in element;
|
|
4272
|
+
}
|
|
4273
|
+
|
|
4274
|
+
/**
|
|
4275
|
+
* Checks if an element is specifically an SVGSVGElement (the root SVG element)
|
|
4276
|
+
* in a way that works across iframes
|
|
4277
|
+
*/
|
|
4278
|
+
function isSVGSVGElement(element) {
|
|
4279
|
+
return isSVGElement(element) && element.tagName === "svg";
|
|
4280
|
+
}
|
|
4281
|
+
|
|
4636
4282
|
function transform(...args) {
|
|
4637
4283
|
const useImmediate = !Array.isArray(args[0]);
|
|
4638
4284
|
const argOffset = useImmediate ? 0 : -1;
|
|
@@ -4727,12 +4373,80 @@
|
|
|
4727
4373
|
return transformValue(() => map(inputValue.get()));
|
|
4728
4374
|
}
|
|
4729
4375
|
|
|
4376
|
+
const isMotionValue = (value) => Boolean(value && value.getVelocity);
|
|
4377
|
+
|
|
4730
4378
|
/**
|
|
4731
|
-
*
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
*
|
|
4379
|
+
* Create a `MotionValue` that animates to its latest value using a spring.
|
|
4380
|
+
* Can either be a value or track another `MotionValue`.
|
|
4381
|
+
*
|
|
4382
|
+
* ```jsx
|
|
4383
|
+
* const x = motionValue(0)
|
|
4384
|
+
* const y = transformValue(() => x.get() * 2) // double x
|
|
4385
|
+
* ```
|
|
4386
|
+
*
|
|
4387
|
+
* @param transformer - A transform function. This function must be pure with no side-effects or conditional statements.
|
|
4388
|
+
* @returns `MotionValue`
|
|
4389
|
+
*
|
|
4390
|
+
* @public
|
|
4391
|
+
*/
|
|
4392
|
+
function springValue(source, options) {
|
|
4393
|
+
const initialValue = isMotionValue(source) ? source.get() : source;
|
|
4394
|
+
const value = motionValue(initialValue);
|
|
4395
|
+
attachSpring(value, source, options);
|
|
4396
|
+
return value;
|
|
4397
|
+
}
|
|
4398
|
+
function attachSpring(value, source, options) {
|
|
4399
|
+
const initialValue = value.get();
|
|
4400
|
+
let activeAnimation = null;
|
|
4401
|
+
let latestValue = initialValue;
|
|
4402
|
+
let latestSetter;
|
|
4403
|
+
const unit = typeof initialValue === "string"
|
|
4404
|
+
? initialValue.replace(/[\d.-]/g, "")
|
|
4405
|
+
: undefined;
|
|
4406
|
+
const stopAnimation = () => {
|
|
4407
|
+
if (activeAnimation) {
|
|
4408
|
+
activeAnimation.stop();
|
|
4409
|
+
activeAnimation = null;
|
|
4410
|
+
}
|
|
4411
|
+
};
|
|
4412
|
+
const startAnimation = () => {
|
|
4413
|
+
stopAnimation();
|
|
4414
|
+
activeAnimation = new JSAnimation({
|
|
4415
|
+
keyframes: [asNumber$1(value.get()), asNumber$1(latestValue)],
|
|
4416
|
+
velocity: value.getVelocity(),
|
|
4417
|
+
type: "spring",
|
|
4418
|
+
restDelta: 0.001,
|
|
4419
|
+
restSpeed: 0.01,
|
|
4420
|
+
...options,
|
|
4421
|
+
onUpdate: latestSetter,
|
|
4422
|
+
});
|
|
4423
|
+
};
|
|
4424
|
+
value.attach((v, set) => {
|
|
4425
|
+
latestValue = v;
|
|
4426
|
+
latestSetter = (latest) => set(parseValue(latest, unit));
|
|
4427
|
+
frame.postRender(startAnimation);
|
|
4428
|
+
return value.get();
|
|
4429
|
+
}, stopAnimation);
|
|
4430
|
+
let unsubscribe = undefined;
|
|
4431
|
+
if (isMotionValue(source)) {
|
|
4432
|
+
unsubscribe = source.on("change", (v) => value.set(parseValue(v, unit)));
|
|
4433
|
+
value.on("destroy", unsubscribe);
|
|
4434
|
+
}
|
|
4435
|
+
return unsubscribe;
|
|
4436
|
+
}
|
|
4437
|
+
function parseValue(v, unit) {
|
|
4438
|
+
return unit ? v + unit : v;
|
|
4439
|
+
}
|
|
4440
|
+
function asNumber$1(v) {
|
|
4441
|
+
return typeof v === "number" ? v : parseFloat(v);
|
|
4442
|
+
}
|
|
4443
|
+
|
|
4444
|
+
/**
|
|
4445
|
+
* A list of all ValueTypes
|
|
4446
|
+
*/
|
|
4447
|
+
const valueTypes = [...dimensionValueTypes, color, complex];
|
|
4448
|
+
/**
|
|
4449
|
+
* Tests a value against the list of ValueTypes
|
|
4736
4450
|
*/
|
|
4737
4451
|
const findValueType = (v) => valueTypes.find(testValueType(v));
|
|
4738
4452
|
|
|
@@ -5036,32 +4750,413 @@
|
|
|
5036
4750
|
if (!targets.has(currentTarget)) {
|
|
5037
4751
|
targets.set(currentTarget, {});
|
|
5038
4752
|
}
|
|
5039
|
-
const targetData = targets.get(currentTarget);
|
|
5040
|
-
targetData[target] = { keyframes, options };
|
|
4753
|
+
const targetData = targets.get(currentTarget);
|
|
4754
|
+
targetData[target] = { keyframes, options };
|
|
4755
|
+
}
|
|
4756
|
+
then(resolve, reject) {
|
|
4757
|
+
return this.readyPromise.then(resolve, reject);
|
|
4758
|
+
}
|
|
4759
|
+
}
|
|
4760
|
+
function animateView(update, defaultOptions = {}) {
|
|
4761
|
+
return new ViewTransitionBuilder(update, defaultOptions);
|
|
4762
|
+
}
|
|
4763
|
+
|
|
4764
|
+
/**
|
|
4765
|
+
* @deprecated
|
|
4766
|
+
*
|
|
4767
|
+
* Import as `frame` instead.
|
|
4768
|
+
*/
|
|
4769
|
+
const sync = frame;
|
|
4770
|
+
/**
|
|
4771
|
+
* @deprecated
|
|
4772
|
+
*
|
|
4773
|
+
* Use cancelFrame(callback) instead.
|
|
4774
|
+
*/
|
|
4775
|
+
const cancelSync = stepsOrder.reduce((acc, key) => {
|
|
4776
|
+
acc[key] = (process) => cancelFrame(process);
|
|
4777
|
+
return acc;
|
|
4778
|
+
}, {});
|
|
4779
|
+
|
|
4780
|
+
/**
|
|
4781
|
+
* @public
|
|
4782
|
+
*/
|
|
4783
|
+
const MotionConfigContext = React$1.createContext({
|
|
4784
|
+
transformPagePoint: (p) => p,
|
|
4785
|
+
isStatic: false,
|
|
4786
|
+
reducedMotion: "never",
|
|
4787
|
+
});
|
|
4788
|
+
|
|
4789
|
+
/**
|
|
4790
|
+
* Measurement functionality has to be within a separate component
|
|
4791
|
+
* to leverage snapshot lifecycle.
|
|
4792
|
+
*/
|
|
4793
|
+
class PopChildMeasure extends React__namespace.Component {
|
|
4794
|
+
getSnapshotBeforeUpdate(prevProps) {
|
|
4795
|
+
const element = this.props.childRef.current;
|
|
4796
|
+
if (element && prevProps.isPresent && !this.props.isPresent) {
|
|
4797
|
+
const parent = element.offsetParent;
|
|
4798
|
+
const parentWidth = isHTMLElement(parent)
|
|
4799
|
+
? parent.offsetWidth || 0
|
|
4800
|
+
: 0;
|
|
4801
|
+
const size = this.props.sizeRef.current;
|
|
4802
|
+
size.height = element.offsetHeight || 0;
|
|
4803
|
+
size.width = element.offsetWidth || 0;
|
|
4804
|
+
size.top = element.offsetTop;
|
|
4805
|
+
size.left = element.offsetLeft;
|
|
4806
|
+
size.right = parentWidth - size.width - size.left;
|
|
4807
|
+
}
|
|
4808
|
+
return null;
|
|
4809
|
+
}
|
|
4810
|
+
/**
|
|
4811
|
+
* Required with getSnapshotBeforeUpdate to stop React complaining.
|
|
4812
|
+
*/
|
|
4813
|
+
componentDidUpdate() { }
|
|
4814
|
+
render() {
|
|
4815
|
+
return this.props.children;
|
|
4816
|
+
}
|
|
4817
|
+
}
|
|
4818
|
+
function PopChild({ children, isPresent, anchorX }) {
|
|
4819
|
+
const id = React$1.useId();
|
|
4820
|
+
const ref = React$1.useRef(null);
|
|
4821
|
+
const size = React$1.useRef({
|
|
4822
|
+
width: 0,
|
|
4823
|
+
height: 0,
|
|
4824
|
+
top: 0,
|
|
4825
|
+
left: 0,
|
|
4826
|
+
right: 0,
|
|
4827
|
+
});
|
|
4828
|
+
const { nonce } = React$1.useContext(MotionConfigContext);
|
|
4829
|
+
/**
|
|
4830
|
+
* We create and inject a style block so we can apply this explicit
|
|
4831
|
+
* sizing in a non-destructive manner by just deleting the style block.
|
|
4832
|
+
*
|
|
4833
|
+
* We can't apply size via render as the measurement happens
|
|
4834
|
+
* in getSnapshotBeforeUpdate (post-render), likewise if we apply the
|
|
4835
|
+
* styles directly on the DOM node, we might be overwriting
|
|
4836
|
+
* styles set via the style prop.
|
|
4837
|
+
*/
|
|
4838
|
+
React$1.useInsertionEffect(() => {
|
|
4839
|
+
const { width, height, top, left, right } = size.current;
|
|
4840
|
+
if (isPresent || !ref.current || !width || !height)
|
|
4841
|
+
return;
|
|
4842
|
+
const x = anchorX === "left" ? `left: ${left}` : `right: ${right}`;
|
|
4843
|
+
ref.current.dataset.motionPopId = id;
|
|
4844
|
+
const style = document.createElement("style");
|
|
4845
|
+
if (nonce)
|
|
4846
|
+
style.nonce = nonce;
|
|
4847
|
+
document.head.appendChild(style);
|
|
4848
|
+
if (style.sheet) {
|
|
4849
|
+
style.sheet.insertRule(`
|
|
4850
|
+
[data-motion-pop-id="${id}"] {
|
|
4851
|
+
position: absolute !important;
|
|
4852
|
+
width: ${width}px !important;
|
|
4853
|
+
height: ${height}px !important;
|
|
4854
|
+
${x}px !important;
|
|
4855
|
+
top: ${top}px !important;
|
|
4856
|
+
}
|
|
4857
|
+
`);
|
|
4858
|
+
}
|
|
4859
|
+
return () => {
|
|
4860
|
+
if (document.head.contains(style)) {
|
|
4861
|
+
document.head.removeChild(style);
|
|
4862
|
+
}
|
|
4863
|
+
};
|
|
4864
|
+
}, [isPresent]);
|
|
4865
|
+
return (jsx(PopChildMeasure, { isPresent: isPresent, childRef: ref, sizeRef: size, children: React__namespace.cloneElement(children, { ref }) }));
|
|
4866
|
+
}
|
|
4867
|
+
|
|
4868
|
+
const PresenceChild = ({ children, initial, isPresent, onExitComplete, custom, presenceAffectsLayout, mode, anchorX, }) => {
|
|
4869
|
+
const presenceChildren = useConstant(newChildrenMap);
|
|
4870
|
+
const id = React$1.useId();
|
|
4871
|
+
let isReusedContext = true;
|
|
4872
|
+
let context = React$1.useMemo(() => {
|
|
4873
|
+
isReusedContext = false;
|
|
4874
|
+
return {
|
|
4875
|
+
id,
|
|
4876
|
+
initial,
|
|
4877
|
+
isPresent,
|
|
4878
|
+
custom,
|
|
4879
|
+
onExitComplete: (childId) => {
|
|
4880
|
+
presenceChildren.set(childId, true);
|
|
4881
|
+
for (const isComplete of presenceChildren.values()) {
|
|
4882
|
+
if (!isComplete)
|
|
4883
|
+
return; // can stop searching when any is incomplete
|
|
4884
|
+
}
|
|
4885
|
+
onExitComplete && onExitComplete();
|
|
4886
|
+
},
|
|
4887
|
+
register: (childId) => {
|
|
4888
|
+
presenceChildren.set(childId, false);
|
|
4889
|
+
return () => presenceChildren.delete(childId);
|
|
4890
|
+
},
|
|
4891
|
+
};
|
|
4892
|
+
}, [isPresent, presenceChildren, onExitComplete]);
|
|
4893
|
+
/**
|
|
4894
|
+
* If the presence of a child affects the layout of the components around it,
|
|
4895
|
+
* we want to make a new context value to ensure they get re-rendered
|
|
4896
|
+
* so they can detect that layout change.
|
|
4897
|
+
*/
|
|
4898
|
+
if (presenceAffectsLayout && isReusedContext) {
|
|
4899
|
+
context = { ...context };
|
|
4900
|
+
}
|
|
4901
|
+
React$1.useMemo(() => {
|
|
4902
|
+
presenceChildren.forEach((_, key) => presenceChildren.set(key, false));
|
|
4903
|
+
}, [isPresent]);
|
|
4904
|
+
/**
|
|
4905
|
+
* If there's no `motion` components to fire exit animations, we want to remove this
|
|
4906
|
+
* component immediately.
|
|
4907
|
+
*/
|
|
4908
|
+
React__namespace.useEffect(() => {
|
|
4909
|
+
!isPresent &&
|
|
4910
|
+
!presenceChildren.size &&
|
|
4911
|
+
onExitComplete &&
|
|
4912
|
+
onExitComplete();
|
|
4913
|
+
}, [isPresent]);
|
|
4914
|
+
if (mode === "popLayout") {
|
|
4915
|
+
children = (jsx(PopChild, { isPresent: isPresent, anchorX: anchorX, children: children }));
|
|
4916
|
+
}
|
|
4917
|
+
return (jsx(PresenceContext.Provider, { value: context, children: children }));
|
|
4918
|
+
};
|
|
4919
|
+
function newChildrenMap() {
|
|
4920
|
+
return new Map();
|
|
4921
|
+
}
|
|
4922
|
+
|
|
4923
|
+
/**
|
|
4924
|
+
* When a component is the child of `AnimatePresence`, it can use `usePresence`
|
|
4925
|
+
* to access information about whether it's still present in the React tree.
|
|
4926
|
+
*
|
|
4927
|
+
* ```jsx
|
|
4928
|
+
* import { usePresence } from "framer-motion"
|
|
4929
|
+
*
|
|
4930
|
+
* export const Component = () => {
|
|
4931
|
+
* const [isPresent, safeToRemove] = usePresence()
|
|
4932
|
+
*
|
|
4933
|
+
* useEffect(() => {
|
|
4934
|
+
* !isPresent && setTimeout(safeToRemove, 1000)
|
|
4935
|
+
* }, [isPresent])
|
|
4936
|
+
*
|
|
4937
|
+
* return <div />
|
|
4938
|
+
* }
|
|
4939
|
+
* ```
|
|
4940
|
+
*
|
|
4941
|
+
* If `isPresent` is `false`, it means that a component has been removed the tree, but
|
|
4942
|
+
* `AnimatePresence` won't really remove it until `safeToRemove` has been called.
|
|
4943
|
+
*
|
|
4944
|
+
* @public
|
|
4945
|
+
*/
|
|
4946
|
+
function usePresence(subscribe = true) {
|
|
4947
|
+
const context = React$1.useContext(PresenceContext);
|
|
4948
|
+
if (context === null)
|
|
4949
|
+
return [true, null];
|
|
4950
|
+
const { isPresent, onExitComplete, register } = context;
|
|
4951
|
+
// It's safe to call the following hooks conditionally (after an early return) because the context will always
|
|
4952
|
+
// either be null or non-null for the lifespan of the component.
|
|
4953
|
+
const id = React$1.useId();
|
|
4954
|
+
React$1.useEffect(() => {
|
|
4955
|
+
if (subscribe) {
|
|
4956
|
+
return register(id);
|
|
4957
|
+
}
|
|
4958
|
+
}, [subscribe]);
|
|
4959
|
+
const safeToRemove = React$1.useCallback(() => subscribe && onExitComplete && onExitComplete(id), [id, onExitComplete, subscribe]);
|
|
4960
|
+
return !isPresent && onExitComplete ? [false, safeToRemove] : [true];
|
|
4961
|
+
}
|
|
4962
|
+
/**
|
|
4963
|
+
* Similar to `usePresence`, except `useIsPresent` simply returns whether or not the component is present.
|
|
4964
|
+
* There is no `safeToRemove` function.
|
|
4965
|
+
*
|
|
4966
|
+
* ```jsx
|
|
4967
|
+
* import { useIsPresent } from "framer-motion"
|
|
4968
|
+
*
|
|
4969
|
+
* export const Component = () => {
|
|
4970
|
+
* const isPresent = useIsPresent()
|
|
4971
|
+
*
|
|
4972
|
+
* useEffect(() => {
|
|
4973
|
+
* !isPresent && console.log("I've been removed!")
|
|
4974
|
+
* }, [isPresent])
|
|
4975
|
+
*
|
|
4976
|
+
* return <div />
|
|
4977
|
+
* }
|
|
4978
|
+
* ```
|
|
4979
|
+
*
|
|
4980
|
+
* @public
|
|
4981
|
+
*/
|
|
4982
|
+
function useIsPresent() {
|
|
4983
|
+
return isPresent(React$1.useContext(PresenceContext));
|
|
4984
|
+
}
|
|
4985
|
+
function isPresent(context) {
|
|
4986
|
+
return context === null ? true : context.isPresent;
|
|
4987
|
+
}
|
|
4988
|
+
|
|
4989
|
+
const getChildKey = (child) => child.key || "";
|
|
4990
|
+
function onlyElements(children) {
|
|
4991
|
+
const filtered = [];
|
|
4992
|
+
// We use forEach here instead of map as map mutates the component key by preprending `.$`
|
|
4993
|
+
React$1.Children.forEach(children, (child) => {
|
|
4994
|
+
if (React$1.isValidElement(child))
|
|
4995
|
+
filtered.push(child);
|
|
4996
|
+
});
|
|
4997
|
+
return filtered;
|
|
4998
|
+
}
|
|
4999
|
+
|
|
5000
|
+
/**
|
|
5001
|
+
* `AnimatePresence` enables the animation of components that have been removed from the tree.
|
|
5002
|
+
*
|
|
5003
|
+
* When adding/removing more than a single child, every child **must** be given a unique `key` prop.
|
|
5004
|
+
*
|
|
5005
|
+
* Any `motion` components that have an `exit` property defined will animate out when removed from
|
|
5006
|
+
* the tree.
|
|
5007
|
+
*
|
|
5008
|
+
* ```jsx
|
|
5009
|
+
* import { motion, AnimatePresence } from 'framer-motion'
|
|
5010
|
+
*
|
|
5011
|
+
* export const Items = ({ items }) => (
|
|
5012
|
+
* <AnimatePresence>
|
|
5013
|
+
* {items.map(item => (
|
|
5014
|
+
* <motion.div
|
|
5015
|
+
* key={item.id}
|
|
5016
|
+
* initial={{ opacity: 0 }}
|
|
5017
|
+
* animate={{ opacity: 1 }}
|
|
5018
|
+
* exit={{ opacity: 0 }}
|
|
5019
|
+
* />
|
|
5020
|
+
* ))}
|
|
5021
|
+
* </AnimatePresence>
|
|
5022
|
+
* )
|
|
5023
|
+
* ```
|
|
5024
|
+
*
|
|
5025
|
+
* You can sequence exit animations throughout a tree using variants.
|
|
5026
|
+
*
|
|
5027
|
+
* If a child contains multiple `motion` components with `exit` props, it will only unmount the child
|
|
5028
|
+
* once all `motion` components have finished animating out. Likewise, any components using
|
|
5029
|
+
* `usePresence` all need to call `safeToRemove`.
|
|
5030
|
+
*
|
|
5031
|
+
* @public
|
|
5032
|
+
*/
|
|
5033
|
+
const AnimatePresence = ({ children, custom, initial = true, onExitComplete, presenceAffectsLayout = true, mode = "sync", propagate = false, anchorX = "left", }) => {
|
|
5034
|
+
const [isParentPresent, safeToRemove] = usePresence(propagate);
|
|
5035
|
+
/**
|
|
5036
|
+
* Filter any children that aren't ReactElements. We can only track components
|
|
5037
|
+
* between renders with a props.key.
|
|
5038
|
+
*/
|
|
5039
|
+
const presentChildren = React$1.useMemo(() => onlyElements(children), [children]);
|
|
5040
|
+
/**
|
|
5041
|
+
* Track the keys of the currently rendered children. This is used to
|
|
5042
|
+
* determine which children are exiting.
|
|
5043
|
+
*/
|
|
5044
|
+
const presentKeys = propagate && !isParentPresent ? [] : presentChildren.map(getChildKey);
|
|
5045
|
+
/**
|
|
5046
|
+
* If `initial={false}` we only want to pass this to components in the first render.
|
|
5047
|
+
*/
|
|
5048
|
+
const isInitialRender = React$1.useRef(true);
|
|
5049
|
+
/**
|
|
5050
|
+
* A ref containing the currently present children. When all exit animations
|
|
5051
|
+
* are complete, we use this to re-render the component with the latest children
|
|
5052
|
+
* *committed* rather than the latest children *rendered*.
|
|
5053
|
+
*/
|
|
5054
|
+
const pendingPresentChildren = React$1.useRef(presentChildren);
|
|
5055
|
+
/**
|
|
5056
|
+
* Track which exiting children have finished animating out.
|
|
5057
|
+
*/
|
|
5058
|
+
const exitComplete = useConstant(() => new Map());
|
|
5059
|
+
/**
|
|
5060
|
+
* Save children to render as React state. To ensure this component is concurrent-safe,
|
|
5061
|
+
* we check for exiting children via an effect.
|
|
5062
|
+
*/
|
|
5063
|
+
const [diffedChildren, setDiffedChildren] = React$1.useState(presentChildren);
|
|
5064
|
+
const [renderedChildren, setRenderedChildren] = React$1.useState(presentChildren);
|
|
5065
|
+
useIsomorphicLayoutEffect(() => {
|
|
5066
|
+
isInitialRender.current = false;
|
|
5067
|
+
pendingPresentChildren.current = presentChildren;
|
|
5068
|
+
/**
|
|
5069
|
+
* Update complete status of exiting children.
|
|
5070
|
+
*/
|
|
5071
|
+
for (let i = 0; i < renderedChildren.length; i++) {
|
|
5072
|
+
const key = getChildKey(renderedChildren[i]);
|
|
5073
|
+
if (!presentKeys.includes(key)) {
|
|
5074
|
+
if (exitComplete.get(key) !== true) {
|
|
5075
|
+
exitComplete.set(key, false);
|
|
5076
|
+
}
|
|
5077
|
+
}
|
|
5078
|
+
else {
|
|
5079
|
+
exitComplete.delete(key);
|
|
5080
|
+
}
|
|
5081
|
+
}
|
|
5082
|
+
}, [renderedChildren, presentKeys.length, presentKeys.join("-")]);
|
|
5083
|
+
const exitingChildren = [];
|
|
5084
|
+
if (presentChildren !== diffedChildren) {
|
|
5085
|
+
let nextChildren = [...presentChildren];
|
|
5086
|
+
/**
|
|
5087
|
+
* Loop through all the currently rendered components and decide which
|
|
5088
|
+
* are exiting.
|
|
5089
|
+
*/
|
|
5090
|
+
for (let i = 0; i < renderedChildren.length; i++) {
|
|
5091
|
+
const child = renderedChildren[i];
|
|
5092
|
+
const key = getChildKey(child);
|
|
5093
|
+
if (!presentKeys.includes(key)) {
|
|
5094
|
+
nextChildren.splice(i, 0, child);
|
|
5095
|
+
exitingChildren.push(child);
|
|
5096
|
+
}
|
|
5097
|
+
}
|
|
5098
|
+
/**
|
|
5099
|
+
* If we're in "wait" mode, and we have exiting children, we want to
|
|
5100
|
+
* only render these until they've all exited.
|
|
5101
|
+
*/
|
|
5102
|
+
if (mode === "wait" && exitingChildren.length) {
|
|
5103
|
+
nextChildren = exitingChildren;
|
|
5104
|
+
}
|
|
5105
|
+
setRenderedChildren(onlyElements(nextChildren));
|
|
5106
|
+
setDiffedChildren(presentChildren);
|
|
5107
|
+
/**
|
|
5108
|
+
* Early return to ensure once we've set state with the latest diffed
|
|
5109
|
+
* children, we can immediately re-render.
|
|
5110
|
+
*/
|
|
5111
|
+
return null;
|
|
5041
5112
|
}
|
|
5042
|
-
|
|
5043
|
-
|
|
5113
|
+
if (mode === "wait" &&
|
|
5114
|
+
renderedChildren.length > 1) {
|
|
5115
|
+
console.warn(`You're attempting to animate multiple children within AnimatePresence, but its mode is set to "wait". This will lead to odd visual behaviour.`);
|
|
5044
5116
|
}
|
|
5045
|
-
|
|
5046
|
-
|
|
5047
|
-
|
|
5048
|
-
|
|
5117
|
+
/**
|
|
5118
|
+
* If we've been provided a forceRender function by the LayoutGroupContext,
|
|
5119
|
+
* we can use it to force a re-render amongst all surrounding components once
|
|
5120
|
+
* all components have finished animating out.
|
|
5121
|
+
*/
|
|
5122
|
+
const { forceRender } = React$1.useContext(LayoutGroupContext);
|
|
5123
|
+
return (jsx(Fragment, { children: renderedChildren.map((child) => {
|
|
5124
|
+
const key = getChildKey(child);
|
|
5125
|
+
const isPresent = propagate && !isParentPresent
|
|
5126
|
+
? false
|
|
5127
|
+
: presentChildren === renderedChildren ||
|
|
5128
|
+
presentKeys.includes(key);
|
|
5129
|
+
const onExit = () => {
|
|
5130
|
+
if (exitComplete.has(key)) {
|
|
5131
|
+
exitComplete.set(key, true);
|
|
5132
|
+
}
|
|
5133
|
+
else {
|
|
5134
|
+
return;
|
|
5135
|
+
}
|
|
5136
|
+
let isEveryExitComplete = true;
|
|
5137
|
+
exitComplete.forEach((isExitComplete) => {
|
|
5138
|
+
if (!isExitComplete)
|
|
5139
|
+
isEveryExitComplete = false;
|
|
5140
|
+
});
|
|
5141
|
+
if (isEveryExitComplete) {
|
|
5142
|
+
forceRender?.();
|
|
5143
|
+
setRenderedChildren(pendingPresentChildren.current);
|
|
5144
|
+
propagate && safeToRemove?.();
|
|
5145
|
+
onExitComplete && onExitComplete();
|
|
5146
|
+
}
|
|
5147
|
+
};
|
|
5148
|
+
return (jsx(PresenceChild, { isPresent: isPresent, initial: !isInitialRender.current || initial
|
|
5149
|
+
? undefined
|
|
5150
|
+
: false, custom: custom, presenceAffectsLayout: presenceAffectsLayout, mode: mode, onExitComplete: isPresent ? undefined : onExit, anchorX: anchorX, children: child }, key));
|
|
5151
|
+
}) }));
|
|
5152
|
+
};
|
|
5049
5153
|
|
|
5050
5154
|
/**
|
|
5051
|
-
*
|
|
5155
|
+
* Note: Still used by components generated by old versions of Framer
|
|
5052
5156
|
*
|
|
5053
|
-
* Import as `frame` instead.
|
|
5054
|
-
*/
|
|
5055
|
-
const sync = frame;
|
|
5056
|
-
/**
|
|
5057
5157
|
* @deprecated
|
|
5058
|
-
*
|
|
5059
|
-
* Use cancelFrame(callback) instead.
|
|
5060
5158
|
*/
|
|
5061
|
-
const
|
|
5062
|
-
acc[key] = (process) => cancelFrame(process);
|
|
5063
|
-
return acc;
|
|
5064
|
-
}, {});
|
|
5159
|
+
const DeprecatedLayoutGroupContext = React$1.createContext(null);
|
|
5065
5160
|
|
|
5066
5161
|
const SCALE_PRECISION = 0.0001;
|
|
5067
5162
|
const SCALE_MIN = 1 - SCALE_PRECISION;
|
|
@@ -5135,8 +5230,6 @@
|
|
|
5135
5230
|
};
|
|
5136
5231
|
}
|
|
5137
5232
|
|
|
5138
|
-
const isMotionValue = (value) => Boolean(value && value.getVelocity);
|
|
5139
|
-
|
|
5140
5233
|
const isNotNull = (value) => value !== null;
|
|
5141
5234
|
function getFinalKeyframe(keyframes, { repeat, repeatType = "loop" }, finalKeyframe) {
|
|
5142
5235
|
const resolvedKeyframes = keyframes.filter(isNotNull);
|
|
@@ -5303,10 +5396,6 @@
|
|
|
5303
5396
|
return visualElement.props[optimizedAppearDataAttribute];
|
|
5304
5397
|
}
|
|
5305
5398
|
|
|
5306
|
-
function isSVGElement(element) {
|
|
5307
|
-
return element instanceof SVGElement && element.tagName !== "svg";
|
|
5308
|
-
}
|
|
5309
|
-
|
|
5310
5399
|
const compareByDepth = (a, b) => a.depth - b.depth;
|
|
5311
5400
|
|
|
5312
5401
|
class FlatTree {
|
|
@@ -5356,7 +5445,7 @@
|
|
|
5356
5445
|
|
|
5357
5446
|
const borders = ["TopLeft", "TopRight", "BottomLeft", "BottomRight"];
|
|
5358
5447
|
const numBorders = borders.length;
|
|
5359
|
-
const asNumber
|
|
5448
|
+
const asNumber = (value) => typeof value === "string" ? parseFloat(value) : value;
|
|
5360
5449
|
const isPx = (value) => typeof value === "number" || px.test(value);
|
|
5361
5450
|
function mixValues(target, follow, lead, progress, shouldCrossfadeOpacity, isOnlyMember) {
|
|
5362
5451
|
if (shouldCrossfadeOpacity) {
|
|
@@ -5381,7 +5470,7 @@
|
|
|
5381
5470
|
leadRadius === 0 ||
|
|
5382
5471
|
isPx(followRadius) === isPx(leadRadius);
|
|
5383
5472
|
if (canMix) {
|
|
5384
|
-
target[borderLabel] = Math.max(mixNumber$1(asNumber
|
|
5473
|
+
target[borderLabel] = Math.max(mixNumber$1(asNumber(followRadius), asNumber(leadRadius), progress), 0);
|
|
5385
5474
|
if (percent.test(leadRadius) || percent.test(followRadius)) {
|
|
5386
5475
|
target[borderLabel] += "%";
|
|
5387
5476
|
}
|
|
@@ -6104,7 +6193,7 @@
|
|
|
6104
6193
|
mount(instance) {
|
|
6105
6194
|
if (this.instance)
|
|
6106
6195
|
return;
|
|
6107
|
-
this.isSVG = isSVGElement(instance);
|
|
6196
|
+
this.isSVG = isSVGElement(instance) && !isSVGSVGElement(instance);
|
|
6108
6197
|
this.instance = instance;
|
|
6109
6198
|
const { layoutId, layout, visualElement } = this.options;
|
|
6110
6199
|
if (visualElement && !visualElement.current) {
|
|
@@ -10927,65 +11016,6 @@
|
|
|
10927
11016
|
return htmlProps;
|
|
10928
11017
|
}
|
|
10929
11018
|
|
|
10930
|
-
/**
|
|
10931
|
-
* We keep these listed separately as we use the lowercase tag names as part
|
|
10932
|
-
* of the runtime bundle to detect SVG components
|
|
10933
|
-
*/
|
|
10934
|
-
const lowercaseSVGElements = [
|
|
10935
|
-
"animate",
|
|
10936
|
-
"circle",
|
|
10937
|
-
"defs",
|
|
10938
|
-
"desc",
|
|
10939
|
-
"ellipse",
|
|
10940
|
-
"g",
|
|
10941
|
-
"image",
|
|
10942
|
-
"line",
|
|
10943
|
-
"filter",
|
|
10944
|
-
"marker",
|
|
10945
|
-
"mask",
|
|
10946
|
-
"metadata",
|
|
10947
|
-
"path",
|
|
10948
|
-
"pattern",
|
|
10949
|
-
"polygon",
|
|
10950
|
-
"polyline",
|
|
10951
|
-
"rect",
|
|
10952
|
-
"stop",
|
|
10953
|
-
"switch",
|
|
10954
|
-
"symbol",
|
|
10955
|
-
"svg",
|
|
10956
|
-
"text",
|
|
10957
|
-
"tspan",
|
|
10958
|
-
"use",
|
|
10959
|
-
"view",
|
|
10960
|
-
];
|
|
10961
|
-
|
|
10962
|
-
function isSVGComponent(Component) {
|
|
10963
|
-
if (
|
|
10964
|
-
/**
|
|
10965
|
-
* If it's not a string, it's a custom React component. Currently we only support
|
|
10966
|
-
* HTML custom React components.
|
|
10967
|
-
*/
|
|
10968
|
-
typeof Component !== "string" ||
|
|
10969
|
-
/**
|
|
10970
|
-
* If it contains a dash, the element is a custom HTML webcomponent.
|
|
10971
|
-
*/
|
|
10972
|
-
Component.includes("-")) {
|
|
10973
|
-
return false;
|
|
10974
|
-
}
|
|
10975
|
-
else if (
|
|
10976
|
-
/**
|
|
10977
|
-
* If it's in our list of lowercase SVG tags, it's an SVG component
|
|
10978
|
-
*/
|
|
10979
|
-
lowercaseSVGElements.indexOf(Component) > -1 ||
|
|
10980
|
-
/**
|
|
10981
|
-
* If it contains a capital letter, it's an SVG component
|
|
10982
|
-
*/
|
|
10983
|
-
/[A-Z]/u.test(Component)) {
|
|
10984
|
-
return true;
|
|
10985
|
-
}
|
|
10986
|
-
return false;
|
|
10987
|
-
}
|
|
10988
|
-
|
|
10989
11019
|
const dashKeys = {
|
|
10990
11020
|
offset: "stroke-dashoffset",
|
|
10991
11021
|
array: "stroke-dasharray",
|
|
@@ -11092,6 +11122,65 @@
|
|
|
11092
11122
|
return visualProps;
|
|
11093
11123
|
}
|
|
11094
11124
|
|
|
11125
|
+
/**
|
|
11126
|
+
* We keep these listed separately as we use the lowercase tag names as part
|
|
11127
|
+
* of the runtime bundle to detect SVG components
|
|
11128
|
+
*/
|
|
11129
|
+
const lowercaseSVGElements = [
|
|
11130
|
+
"animate",
|
|
11131
|
+
"circle",
|
|
11132
|
+
"defs",
|
|
11133
|
+
"desc",
|
|
11134
|
+
"ellipse",
|
|
11135
|
+
"g",
|
|
11136
|
+
"image",
|
|
11137
|
+
"line",
|
|
11138
|
+
"filter",
|
|
11139
|
+
"marker",
|
|
11140
|
+
"mask",
|
|
11141
|
+
"metadata",
|
|
11142
|
+
"path",
|
|
11143
|
+
"pattern",
|
|
11144
|
+
"polygon",
|
|
11145
|
+
"polyline",
|
|
11146
|
+
"rect",
|
|
11147
|
+
"stop",
|
|
11148
|
+
"switch",
|
|
11149
|
+
"symbol",
|
|
11150
|
+
"svg",
|
|
11151
|
+
"text",
|
|
11152
|
+
"tspan",
|
|
11153
|
+
"use",
|
|
11154
|
+
"view",
|
|
11155
|
+
];
|
|
11156
|
+
|
|
11157
|
+
function isSVGComponent(Component) {
|
|
11158
|
+
if (
|
|
11159
|
+
/**
|
|
11160
|
+
* If it's not a string, it's a custom React component. Currently we only support
|
|
11161
|
+
* HTML custom React components.
|
|
11162
|
+
*/
|
|
11163
|
+
typeof Component !== "string" ||
|
|
11164
|
+
/**
|
|
11165
|
+
* If it contains a dash, the element is a custom HTML webcomponent.
|
|
11166
|
+
*/
|
|
11167
|
+
Component.includes("-")) {
|
|
11168
|
+
return false;
|
|
11169
|
+
}
|
|
11170
|
+
else if (
|
|
11171
|
+
/**
|
|
11172
|
+
* If it's in our list of lowercase SVG tags, it's an SVG component
|
|
11173
|
+
*/
|
|
11174
|
+
lowercaseSVGElements.indexOf(Component) > -1 ||
|
|
11175
|
+
/**
|
|
11176
|
+
* If it contains a capital letter, it's an SVG component
|
|
11177
|
+
*/
|
|
11178
|
+
/[A-Z]/u.test(Component)) {
|
|
11179
|
+
return true;
|
|
11180
|
+
}
|
|
11181
|
+
return false;
|
|
11182
|
+
}
|
|
11183
|
+
|
|
11095
11184
|
function createUseRender(forwardMotionProps = false) {
|
|
11096
11185
|
const useRender = (Component, props, ref, { latestValues }, isStatic) => {
|
|
11097
11186
|
const useVisualProps = isSVGComponent(Component)
|
|
@@ -11893,7 +11982,7 @@
|
|
|
11893
11982
|
latestValues: {},
|
|
11894
11983
|
},
|
|
11895
11984
|
};
|
|
11896
|
-
const node = isSVGElement(element)
|
|
11985
|
+
const node = isSVGElement(element) && !isSVGSVGElement(element)
|
|
11897
11986
|
? new SVGVisualElement(options)
|
|
11898
11987
|
: new HTMLVisualElement(options);
|
|
11899
11988
|
node.mount(element);
|
|
@@ -12111,7 +12200,7 @@
|
|
|
12111
12200
|
const { inlineSize, blockSize } = borderBoxSize[0];
|
|
12112
12201
|
return { width: inlineSize, height: blockSize };
|
|
12113
12202
|
}
|
|
12114
|
-
else if (target
|
|
12203
|
+
else if (isSVGElement(target) && "getBBox" in target) {
|
|
12115
12204
|
return target.getBBox();
|
|
12116
12205
|
}
|
|
12117
12206
|
else {
|
|
@@ -12253,7 +12342,7 @@
|
|
|
12253
12342
|
const inset = { x: 0, y: 0 };
|
|
12254
12343
|
let current = element;
|
|
12255
12344
|
while (current && current !== container) {
|
|
12256
|
-
if (current
|
|
12345
|
+
if (isHTMLElement(current)) {
|
|
12257
12346
|
inset.x += current.offsetLeft;
|
|
12258
12347
|
inset.y += current.offsetTop;
|
|
12259
12348
|
current = current.offsetParent;
|
|
@@ -12829,56 +12918,19 @@
|
|
|
12829
12918
|
return useCombineMotionValues(values.filter(isMotionValue), buildValue);
|
|
12830
12919
|
}
|
|
12831
12920
|
|
|
12832
|
-
function useSpring(source,
|
|
12921
|
+
function useSpring(source, options = {}) {
|
|
12833
12922
|
const { isStatic } = React$1.useContext(MotionConfigContext);
|
|
12834
|
-
const
|
|
12835
|
-
|
|
12836
|
-
|
|
12837
|
-
|
|
12838
|
-
|
|
12839
|
-
const value = useMotionValue(
|
|
12840
|
-
const latestValue = React$1.useRef(initialValue);
|
|
12841
|
-
const latestSetter = React$1.useRef(noop);
|
|
12842
|
-
const startAnimation = () => {
|
|
12843
|
-
stopAnimation();
|
|
12844
|
-
activeSpringAnimation.current = new JSAnimation({
|
|
12845
|
-
keyframes: [asNumber(value.get()), asNumber(latestValue.current)],
|
|
12846
|
-
velocity: value.getVelocity(),
|
|
12847
|
-
type: "spring",
|
|
12848
|
-
restDelta: 0.001,
|
|
12849
|
-
restSpeed: 0.01,
|
|
12850
|
-
...config,
|
|
12851
|
-
onUpdate: latestSetter.current,
|
|
12852
|
-
});
|
|
12853
|
-
};
|
|
12854
|
-
const stopAnimation = () => {
|
|
12855
|
-
if (activeSpringAnimation.current) {
|
|
12856
|
-
activeSpringAnimation.current.stop();
|
|
12857
|
-
}
|
|
12858
|
-
};
|
|
12923
|
+
const getFromSource = () => (isMotionValue(source) ? source.get() : source);
|
|
12924
|
+
// isStatic will never change, allowing early hooks return
|
|
12925
|
+
if (isStatic) {
|
|
12926
|
+
return useTransform(getFromSource);
|
|
12927
|
+
}
|
|
12928
|
+
const value = useMotionValue(getFromSource());
|
|
12859
12929
|
React$1.useInsertionEffect(() => {
|
|
12860
|
-
return value
|
|
12861
|
-
|
|
12862
|
-
return set(v);
|
|
12863
|
-
latestValue.current = v;
|
|
12864
|
-
latestSetter.current = (latest) => set(parseValue(latest, unit));
|
|
12865
|
-
frame.postRender(startAnimation);
|
|
12866
|
-
return value.get();
|
|
12867
|
-
}, stopAnimation);
|
|
12868
|
-
}, [JSON.stringify(config)]);
|
|
12869
|
-
useIsomorphicLayoutEffect(() => {
|
|
12870
|
-
if (isMotionValue(source)) {
|
|
12871
|
-
return source.on("change", (v) => value.set(parseValue(v, unit)));
|
|
12872
|
-
}
|
|
12873
|
-
}, [value, unit]);
|
|
12930
|
+
return attachSpring(value, source, options);
|
|
12931
|
+
}, [value, JSON.stringify(options)]);
|
|
12874
12932
|
return value;
|
|
12875
12933
|
}
|
|
12876
|
-
function parseValue(v, unit) {
|
|
12877
|
-
return unit ? v + unit : v;
|
|
12878
|
-
}
|
|
12879
|
-
function asNumber(v) {
|
|
12880
|
-
return typeof v === "number" ? v : parseFloat(v);
|
|
12881
|
-
}
|
|
12882
12934
|
|
|
12883
12935
|
function useAnimationFrame(callback) {
|
|
12884
12936
|
const initialTimestamp = React$1.useRef(0);
|
|
@@ -13761,6 +13813,7 @@
|
|
|
13761
13813
|
exports.animations = animations;
|
|
13762
13814
|
exports.anticipate = anticipate;
|
|
13763
13815
|
exports.applyPxDefaults = applyPxDefaults;
|
|
13816
|
+
exports.attachSpring = attachSpring;
|
|
13764
13817
|
exports.backIn = backIn;
|
|
13765
13818
|
exports.backInOut = backInOut;
|
|
13766
13819
|
exports.backOut = backOut;
|
|
@@ -13838,11 +13891,15 @@
|
|
|
13838
13891
|
exports.isDragging = isDragging;
|
|
13839
13892
|
exports.isEasingArray = isEasingArray;
|
|
13840
13893
|
exports.isGenerator = isGenerator;
|
|
13894
|
+
exports.isHTMLElement = isHTMLElement;
|
|
13841
13895
|
exports.isMotionComponent = isMotionComponent;
|
|
13842
13896
|
exports.isMotionValue = isMotionValue;
|
|
13843
13897
|
exports.isNodeOrChild = isNodeOrChild;
|
|
13844
13898
|
exports.isNumericalString = isNumericalString;
|
|
13899
|
+
exports.isObject = isObject;
|
|
13845
13900
|
exports.isPrimaryPointer = isPrimaryPointer;
|
|
13901
|
+
exports.isSVGElement = isSVGElement;
|
|
13902
|
+
exports.isSVGSVGElement = isSVGSVGElement;
|
|
13846
13903
|
exports.isValidMotionProp = isValidMotionProp;
|
|
13847
13904
|
exports.isWaapiSupportedEasing = isWaapiSupportedEasing;
|
|
13848
13905
|
exports.isZeroValueString = isZeroValueString;
|
|
@@ -13897,6 +13954,7 @@
|
|
|
13897
13954
|
exports.setDragLock = setDragLock;
|
|
13898
13955
|
exports.setStyle = setStyle;
|
|
13899
13956
|
exports.spring = spring;
|
|
13957
|
+
exports.springValue = springValue;
|
|
13900
13958
|
exports.stagger = stagger;
|
|
13901
13959
|
exports.startOptimizedAppearAnimation = startOptimizedAppearAnimation;
|
|
13902
13960
|
exports.startWaapiAnimation = startWaapiAnimation;
|