Improve accordion first animation

Also upgraded react-spring and removed patch
This commit is contained in:
Bruno Lemos
2019-02-07 21:18:22 -02:00
parent 4c77c27a52
commit fcc1eef827
6 changed files with 57 additions and 300 deletions

View File

@@ -36,7 +36,7 @@
"react-native-splash-screen": "^3.1.1",
"react-native-vector-icons": "^6.1.0",
"react-redux": "6.0.0",
"react-spring": "^8.0.2",
"react-spring": "^8.0.4",
"react-test-renderer": "16.8.1",
"redux": "^4.0.1",
"redux-devtools-extension": "^2.13.7",

View File

@@ -87,7 +87,11 @@ export const ColumnOptionsRenderer = React.memo(
zIndex: 200,
}}
>
<AccordionView ref={accordionRef} property="height">
<AccordionView
ref={accordionRef}
accordionKey="accordion-view-column-options-rendered"
property="height"
>
{!!visible && (
<ColumnOptions
availableHeight={

View File

@@ -208,7 +208,11 @@ export function ColumnOptionsRow(props: ColumnOptionsRowProps) {
</View>
</ConditionalWrap>
<AccordionView property="height">
<AccordionView
accordionKey={`accordion-view-column-options-row-${title}}`}
property="height"
skipFirst={opened}
>
{!!opened && (
<View
style={[

View File

@@ -1,4 +1,4 @@
import React, { useImperativeHandle, useRef, useState } from 'react'
import React, { useEffect, useImperativeHandle, useRef, useState } from 'react'
import { ScrollView, View } from 'react-native'
import { config, ReactSpringHook, useTransition } from 'react-spring/native'
@@ -8,9 +8,11 @@ import { SpringAnimatedView } from '../animated/spring/SpringAnimatedView'
export type Transition = ReactSpringHook
export interface AccordionViewProps {
accordionKey: string
children: React.ReactNode
fixedSize?: number
property: 'width' | 'height'
skipFirst?: boolean
}
export interface AccordionView {
@@ -20,18 +22,26 @@ export interface AccordionView {
unlock: () => void
}
export const AccordionView = React.forwardRef(
(props: AccordionViewProps, ref) => {
const { children, fixedSize, property } = props
export const AccordionView = React.memo(
React.forwardRef((props: AccordionViewProps, ref) => {
const { accordionKey, children, fixedSize, property, skipFirst } = props
const openCountRef = useRef(0)
const onFinishRef = useRef<null | (() => void)>(null)
const contentSize = useRef({ width: 0, height: 0 })
const [size, setSize] = useState<number | 'auto'>(fixedSize || 0)
useEffect(
() => {
openCountRef.current = openCountRef.current + 1
},
[!!children],
)
const transitions = useTransition(
children ? [children] : [],
() => 'accordion-view',
() => accordionKey,
{
from: { [property]: 0 },
enter: { [property]: children ? size : 0 },
@@ -40,13 +50,9 @@ export const AccordionView = React.forwardRef(
},
leave: { [property]: 0 },
config: { ...config.default, precision: 1 },
immediate: openCountRef.current === 1 && skipFirst,
force: false,
unique: true,
// TODO: API was changed on v8.
// Reimplement this or make this hack unnecessary,
// fix the nested accordion animation use case in a different way
// @see https://github.com/react-spring/react-spring/issues/512
/*
onRest: (
_e: any,
state: string,
@@ -60,25 +66,28 @@ export const AccordionView = React.forwardRef(
onFinishRef.current()
}
},
*/
},
)
useImperativeHandle(ref, () => ({
setOnFinishListener: (callback: null | (() => void)) => {
onFinishRef.current = callback
},
isLocked: () => {
return size === 'auto'
},
lock: () => {
if (size !== 'auto') setSize('auto')
},
unlock: () => {
if (size !== contentSize.current[property])
setSize(contentSize.current[property])
},
}))
useImperativeHandle(
ref,
() => ({
setOnFinishListener: (callback: null | (() => void)) => {
onFinishRef.current = callback
},
isLocked: () => {
return size === 'auto'
},
lock: () => {
if (size !== 'auto') setSize('auto')
},
unlock: () => {
if (size !== contentSize.current[property])
setSize(contentSize.current[property])
},
}),
[size],
)
const handleContentSizeChange = (width: number, height: number) => {
contentSize.current = { width, height }
@@ -94,10 +103,12 @@ export const AccordionView = React.forwardRef(
{transitions.map(({ key, item, props: animatedStyle }) => (
<SpringAnimatedView
key={key}
style={{
...(animatedStyle as any),
overflow: 'hidden',
}}
style={[
animatedStyle as any,
{
overflow: 'hidden',
},
]}
>
{Platform.OS === 'web' ? (
<View
@@ -123,5 +134,5 @@ export const AccordionView = React.forwardRef(
))}
</>
)
},
}),
)

View File

@@ -1,262 +0,0 @@
patch-package
deleted file mode 100644
--- a/node_modules/react-spring/native-hooks.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './hooks'
--- a/node_modules/react-spring/native.d.ts
+++ b/node_modules/react-spring/native.d.ts
@@ -1 +1 @@
-export * from './renderprops-universal'
+export * from './index'
--- a/node_modules/react-spring/native.js
+++ b/node_modules/react-spring/native.js
@@ -2228,7 +2228,7 @@ injectCreateAnimatedStyle(function (styles) {
injectAnimatedApi(function (node, mounted, forceUpdate) {
return {
setNativeProps: function setNativeProps(props) {
- var didUpdate = ApplyAnimatedValues(node.current, props);
+ var didUpdate = Globals.applyAnimatedValues.fn(node.current, props);
if (!didUpdate) mounted.current && forceUpdate();
},
getNode: function getNode() {
--- a/node_modules/react-spring/renderprops-universal.d.ts
+++ b/node_modules/react-spring/renderprops-universal.d.ts
@@ -3,14 +3,14 @@
import {
Component,
- PureComponent,
- ReactNode,
ComponentClass,
+ ComponentPropsWithRef,
ComponentType,
+ ForwardRefExoticComponent,
+ PureComponent,
+ ReactNode,
ReactType,
Ref,
- ForwardRefExoticComponent,
- ComponentPropsWithRef,
} from 'react'
export type SpringEasingFunc = (t: number) => number
@@ -121,11 +121,11 @@ export class Spring<DS extends object> extends PureComponent<SpringProps<DS>> {}
export function interpolate(
parent: number[],
- config: (...args: number[]) => any
+ config: (...args: number[]) => any,
): any
export function animated<T extends ReactType>(
- comp: T
+ comp: T,
): ForwardRefExoticComponent<ComponentPropsWithRef<T>>
export type TransitionKeyProps = string | number
@@ -180,7 +180,7 @@ export interface TransitionProps<
*/
keys?:
| ((item: TItem) => TransitionKeyProps)
- | Array<TransitionKeyProps>
+ | TransitionKeyProps[]
| TransitionKeyProps
/**
* An array of items to be displayed, this is used by Transition as the primary means of detecting changes.
@@ -193,7 +193,7 @@ export interface TransitionProps<
children?: (
item: TItem,
state: State,
- index: number
+ index: number,
) =>
| boolean
| null
@@ -248,7 +248,7 @@ interface TrailProps<TItem, DS extends object = {}> extends SpringProps {
* Item keys (the same keys you'd hand over to react in a list). If you specify items, keys can be an accessor function (item => item.key)
* @default item => item
*/
- keys?: ((item: TItem) => TrailKeyProps) | Array<TrailKeyProps> | TrailKeyProps
+ keys?: ((item: TItem) => TrailKeyProps) | TrailKeyProps[] | TrailKeyProps
/**
* A single function-child that receives the individual item and return a functional component (item, index) => props => view)
*/
@@ -268,28 +268,28 @@ export class Keyframes<
DS extends object
> extends PureComponent<KeyframesProps<DS> & S> {
static create<S extends object, DS extends object>(
- primitive: ComponentType
+ primitive: ComponentType,
): (states: object) => (props: object) => Keyframes<S, DS>
static Spring<S extends object, DS extends object>(
- states: object
+ states: object,
): (
- props: object
+ props: object,
) => Keyframes<
S | Pick<SpringProps<DS>, Exclude<keyof SpringProps<DS>, 'to'>>,
DS
>
static Trail<S extends object, DS extends object>(
- states: object
+ states: object,
): (
- props: object
+ props: object,
) => Keyframes<
S | Pick<TrailProps<DS>, Exclude<keyof TrailProps<DS>, 'to'>>,
DS
>
static Transition<S extends object, DS extends object>(
- states: object
+ states: object,
): (
- props: object
+ props: object,
) => Keyframes<
S | Pick<TransitionProps<S, DS>, Exclude<keyof TransitionProps<DS>, 'to'>>,
DS
--- a/node_modules/react-spring/web.d.ts
+++ b/node_modules/react-spring/web.d.ts
@@ -1,9 +1,9 @@
import { CSSProperties, RefObject } from 'react'
import {
- SpringConfig,
SpringBaseProps,
- TransitionKeyProps,
+ SpringConfig,
State,
+ TransitionKeyProps,
} from './renderprops-universal'
export { SpringConfig, SpringBaseProps, TransitionKeyProps, State }
@@ -37,7 +37,7 @@ type ExcludedProps =
// The config options for an interoplation. It maps out from in "in" type
// to an "out" type.
-export type InterpolationConfig<T, U = T> = {
+export interface InterpolationConfig<T, U = T> {
range: T[]
output: U[]
}
@@ -76,7 +76,7 @@ type InferFrom<T extends object> = T extends { to: infer TTo }
type Merge<A, B> = { [K in keyof A]: K extends keyof B ? B[K] : A[K] } & B
export type SetUpdateFn<DS extends object> = (
- ds: Pick<DS, Exclude<keyof DS, ExcludedProps>>
+ ds: Pick<DS, Exclude<keyof DS, ExcludedProps>>,
) => void
// The hooks do emulate React's 'ref' by accepting { ref?: React.RefObject<Controller> } and
@@ -93,11 +93,17 @@ export function useChain(refs: ReadonlyArray<RefObject<ReactSpringHook>>): void
export function useChain(
refs: ReadonlyArray<RefObject<ReactSpringHook>>,
timeSteps: number[],
- timeFrame?: number
+ timeFrame?: number,
): void
export interface HooksBaseProps
extends Pick<SpringBaseProps, Exclude<keyof SpringBaseProps, 'config'>> {
+ /**
+ * Will skip rendering the component if true and write to the dom directly.
+ * @default true
+ * @deprecated
+ */
+ native?: never
// there is an undocumented onKeyframesHalt which passes the controller instance,
// so it also cannot be typed unless Controller types are written
ref?: React.RefObject<ReactSpringHook>
@@ -120,51 +126,43 @@ export type UseSpringProps<DS extends object> = Merge<
// there's a third value in the tuple but it's not public API (?)
export function useSpring<DS extends CSSProperties>(
- values: UseSpringProps<DS & CSSProperties>
+ values: UseSpringProps<DS & CSSProperties>,
): ForwardedProps<DS>
export function useSpring<DS extends CSSProperties>(
- getProps: () => UseSpringProps<DS & CSSProperties>
+ getProps: () => UseSpringProps<DS & CSSProperties>,
): [ForwardedProps<DS>, SetUpdateFn<DS>]
export function useSpring<DS extends object>(
- getProps: () => UseSpringProps<DS>
+ getProps: () => UseSpringProps<DS>,
): [AnimatedValue<ForwardedProps<DS>>, SetUpdateFn<DS>]
export function useSpring<DS extends object>(
- values: UseSpringProps<DS>
+ values: UseSpringProps<DS>,
): AnimatedValue<ForwardedProps<DS>>
// there's a third value in the tuple but it's not public API (?)
export function useTrail<DS extends CSSProperties>(
count: number,
- getProps: () => UseSpringProps<DS & CSSProperties>
-): [ForwardedProps<DS>[], SetUpdateFn<DS>]
+ getProps: () => UseSpringProps<DS & CSSProperties>,
+): [Array<ForwardedProps<DS>>, SetUpdateFn<DS>]
export function useTrail<DS extends CSSProperties>(
count: number,
- values: UseSpringProps<DS & CSSProperties>
-): ForwardedProps<DS>[] // safe to modify (result of .map)
+ values: UseSpringProps<DS & CSSProperties>,
+): Array<ForwardedProps<DS>> // safe to modify (result of .map)
export function useTrail<DS extends object>(
count: number,
- getProps: () => UseSpringProps<DS>
-): [AnimatedValue<ForwardedProps<DS>>[], SetUpdateFn<DS>]
+ getProps: () => UseSpringProps<DS>,
+): [Array<AnimatedValue<ForwardedProps<DS>>>, SetUpdateFn<DS>]
export function useTrail<DS extends object>(
count: number,
- values: UseSpringProps<DS>
-): AnimatedValue<ForwardedProps<DS>>[] // safe to modify (result of .map)
+ values: UseSpringProps<DS>,
+): Array<AnimatedValue<ForwardedProps<DS>>> // safe to modify (result of .map)
export interface UseTransitionProps<TItem, DS extends object>
extends HooksBaseProps {
- items: ReadonlyArray<TItem> | null | undefined
/**
* Spring config, or for individual items: fn(item => config)
* @default config.default
*/
config?: SpringConfig | ((item: TItem) => SpringConfig)
- /**
- * The same keys you would normally hand over to React in a list. Keys can be specified as a key-accessor function, an array of keys, or a single value
- */
- keys?:
- | ((item: TItem) => TransitionKeyProps)
- | ReadonlyArray<TransitionKeyProps>
- | TransitionKeyProps
/**
* When true enforces that an item can only occur once instead of allowing two or more items with the same key to co-exist in a stack
@@ -201,8 +199,21 @@ export interface UseTransitionResult<TItem, DS extends object> {
}
export function useTransition<TItem, DS extends CSSProperties>(
- values: Merge<DS & CSSProperties, UseTransitionProps<TItem, DS>>
-): UseTransitionResult<TItem, ForwardedProps<DS>>[] // result array is safe to modify
+ items: ReadonlyArray<TItem> | null | undefined,
+ keys:
+ | ((item: TItem) => TransitionKeyProps)
+ | ReadonlyArray<TransitionKeyProps>
+ | TransitionKeyProps,
+ values: Merge<DS & CSSProperties, UseTransitionProps<TItem, DS>>,
+): Array<UseTransitionResult<TItem, ForwardedProps<DS>>> // result array is safe to modify
export function useTransition<TItem, DS extends object>(
- values: Merge<DS, UseTransitionProps<TItem, DS>>
-): UseTransitionResult<TItem, AnimatedValue<ForwardedProps<DS>>>[] // result array is safe to modify
\ No newline at end of file
+ items: ReadonlyArray<TItem> | null | undefined,
+ /**
+ * The same keys you would normally hand over to React in a list. Keys can be specified as a key-accessor function, an array of keys, or a single value
+ */
+ keys:
+ | ((item: TItem) => TransitionKeyProps)
+ | ReadonlyArray<TransitionKeyProps>
+ | TransitionKeyProps,
+ values: Merge<DS, UseTransitionProps<TItem, DS>>,
+): Array<UseTransitionResult<TItem, AnimatedValue<ForwardedProps<DS>>>> // result array is safe to modify

View File

@@ -10650,10 +10650,10 @@ react-scripts@2.1.1:
optionalDependencies:
fsevents "1.2.4"
react-spring@^8.0.2:
version "8.0.2"
resolved "https://registry.npmjs.org/react-spring/-/react-spring-8.0.2.tgz#a17715908c0c0b122c9dd44aba984aa1798d66e1"
integrity sha512-E5dVqxwYmsCwvVfp1vdaNRB1p162hSEQZZhqSZuH+9LHDREHixApHX/kQRC1zTmS8jBoqgBILKIxbzsqykqa7g==
react-spring@^8.0.4:
version "8.0.4"
resolved "https://registry.npmjs.org/react-spring/-/react-spring-8.0.4.tgz#410da78ddb1f30a4567492288f9be963aa9c3d30"
integrity sha512-cNAs+ChoA4ZcUnVzd0KjJpkZCWOQSO82FtvYS6JlCgt4aRvpg7qbeq5ySTzFnAHo02mj0vhqQWf5MVpBZexuYA==
dependencies:
"@babel/runtime" "^7.0.0"