Skip to content

Commit f3c4c0b

Browse files
dbismutjoshuaellis
andauthored
fix: make SpringRef instances callable to avoid breaking change #1359 (#1387)
* chore: inline alloc/fluids and upgrade rafz * chore: inline alloc/types * chore: normalize demo styles * chore: add flipCard sandbox * chore: add Slide sandbox * chore: add sandboxes * chore: add TS to dev dependencies to sandboxes demo * chore: add alloc/types missing types * chore: inline react-layout-effect and remove it from deps * fix: make SpringRef instances callable to avoid breaking change #1359 * chore: optimize sandbox * chore: refactor based on react-use-gesture sandbox * fix: make SpringRef instances callable to avoid breaking change #1359 * fix: `alias ref()` to `ref.start()` instead of `ref.set()` * chore: add comment about deprecating calling ref as a fn * fix: replace ref with api and set with start * fix: make SpringRef instances callable to avoid breaking change #1359 * chore: update comment to reflect * feat: add directCall of set deprecation log * fix: infer SpringValue types only from the `from` prop when it exists * fix: remove global styles * fix: remove logs * fix: remove duplicates * fix: use proper api for useTrail Co-authored-by: Josh Ellis <[email protected]>
1 parent c6f2872 commit f3c4c0b

File tree

5 files changed

+60
-36
lines changed

5 files changed

+60
-36
lines changed

demo/src/sandboxes/goo-blobs/src/App.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ const trans = (x: number, y: number) =>
99
`translate3d(${x}px,${y}px,0) translate3d(-50%,-50%,0)`
1010

1111
export default function App() {
12-
const [trail, api] = useTrail(3, () => ({
12+
const [trail, api] = useTrail(3, i => ({
1313
xy: [0, 0],
14-
config: i => (i === 0 ? fast : slow), // TODO fix lint error
14+
config: i === 0 ? fast : slow,
1515
}))
1616
return (
1717
<>

demo/src/sandboxes/notification-hub/src/App.tsx

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,26 +40,14 @@ function MessageHub({
4040
await next({ opacity: 1, height: refMap.get(item).offsetHeight })
4141
await next({ life: '0%' })
4242
},
43-
leave: [
44-
{
45-
opacity: 0,
46-
onResolve: (v, c, i) => console.log('onResolve', v, c, i),
47-
onRest: (v, c, i) => console.log('onRest', v, c, i),
48-
},
49-
{ height: 0 },
50-
],
51-
onStart: (result, ctrl, item) => console.log(result, ctrl, item),
52-
// onChange: {
53-
// opacity: (result, ctrl, item) => console.log(result, ctrl, item),
54-
// },
43+
leave: [{ opacity: 0 }, { height: 0 }],
5544
onRest: (result, ctrl, item) => {
5645
setItems(state =>
5746
state.filter(i => {
5847
return i.key !== item.key
5948
})
6049
)
6150
},
62-
// onResolve: (result, ctrl, item) => console.log('resolve', result, ctrl, item),
6351
config: (item, index, phase) => key => (phase === 'enter' && key === 'life' ? { duration: timeout } : config),
6452
})
6553

packages/core/src/SpringRef.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { each, is } from '@react-spring/shared'
1+
import { each, is, deprecateDirectCall } from '@react-spring/shared'
22
import { Lookup, Falsy, OneOrMore } from '@react-spring/types'
33
import { AsyncResult, ControllerUpdate } from './types'
44
import { Controller } from './Controller'
@@ -7,9 +7,29 @@ interface ControllerUpdateFn<State extends Lookup = Lookup> {
77
(i: number, ctrl: Controller<State>): ControllerUpdate<State> | Falsy
88
}
99

10-
export class SpringRef<State extends Lookup = Lookup> {
10+
/**
11+
* Extending from function allows SpringRef instances to be callable.
12+
* https://hackernoon.com/creating-callable-objects-in-javascript-d21l3te1
13+
*
14+
* ```js
15+
* const [springs, api] = useSpring(() => ({x: 0}))
16+
* api.start({x: 3}) // this works
17+
* api({x: 3}) // this also works (non breaking from 9rc3)
18+
* ```
19+
*/
20+
export class SpringRef<State extends Lookup = Lookup> extends Function {
1121
readonly current: Controller<State>[] = []
1222

23+
constructor() {
24+
super('return arguments.callee._call.apply(arguments.callee, arguments)')
25+
}
26+
27+
/** @deprecated use the property 'start' instead */
28+
_call(props?: ControllerUpdate<State> | ControllerUpdateFn<State>) {
29+
deprecateDirectCall()
30+
this.start(props)
31+
}
32+
1333
/** Update the state of each controller without animating. */
1434
set(values: Partial<State>) {
1535
each(this.current, ctrl => ctrl.set(values))
@@ -79,6 +99,9 @@ export class SpringRef<State extends Lookup = Lookup> {
7999
}
80100

81101
export interface SpringRef<State extends Lookup> {
102+
(props?: ControllerUpdate<State> | ControllerUpdateFn<State>): AsyncResult<
103+
Controller<State>
104+
>[]
82105
/** Stop all animations. */
83106
stop(): this
84107
/** Stop animations for the given keys. */

packages/core/src/types/props.ts

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -352,10 +352,11 @@ export type PickAnimated<Props extends object, Fwd = true> = unknown &
352352
: [object] extends [Props]
353353
? Lookup
354354
: ObjectFromUnion<
355-
| FromValues<Props>
356-
| (TransitionKey & keyof Props extends never
357-
? ToValues<Props, Fwd>
358-
: TransitionValues<Props>)
355+
Props extends { from: infer From } // extract prop from the `from` prop if it exists
356+
? ObjectType<From>
357+
: TransitionKey & keyof Props extends never
358+
? ToValues<Props, Fwd>
359+
: TransitionValues<Props>
359360
>)
360361

361362
/**
@@ -368,10 +369,3 @@ type ToValues<Props extends object, AndForward = true> = unknown &
368369
? ForwardProps<[To] extends [object] ? To : Partial<Extract<To, object>>>
369370
: never
370371
: unknown)
371-
372-
/**
373-
* Pick the values of the `from` prop.
374-
*/
375-
type FromValues<Props extends object> = ForwardProps<
376-
Props extends { from?: infer From } ? ObjectType<From> : object
377-
>

packages/shared/src/deprecations.ts

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,32 @@ declare const console: any
22

33
const prefix = 'react-spring: '
44

5-
let flagInterpolate = false
6-
export function deprecateInterpolate() {
7-
if (!flagInterpolate) {
8-
flagInterpolate = true
9-
console.warn(
10-
prefix +
11-
'The "interpolate" function is deprecated in v9 (use "to" instead)'
12-
)
5+
const once = <TFunc extends (...args: any) => any>(fn: TFunc) => {
6+
const func = fn
7+
let called = false
8+
9+
if (typeof func != 'function') {
10+
throw new TypeError(`${prefix}once requires a function parameter`)
1311
}
12+
13+
return (...args: any) => {
14+
if (!called) {
15+
func(...args)
16+
called = true
17+
}
18+
}
19+
}
20+
21+
const warnInterpolate = once(console.warn)
22+
export function deprecateInterpolate() {
23+
warnInterpolate(
24+
`${prefix}The "interpolate" function is deprecated in v9 (use "to" instead)`
25+
)
26+
}
27+
28+
const warnDirectCall = once(console.warn)
29+
export function deprecateDirectCall() {
30+
warnDirectCall(
31+
`${prefix}Directly calling start instead of using the api object is deprecated in v9 (use ".start" instead)`
32+
)
1433
}

0 commit comments

Comments
 (0)