Giter Club home page Giter Club logo

react-flip-toolkit's Introduction

react-flip-toolkit animated logo

Minified & Gzipped size MIT license npm version

Comparison with other React FLIP libraries

Feature react-flip-move react-overdrive react-flip-toolkit
Animate position
Animate scale
Animate opacity
Animate parent's size without warping children
Use real FLIP instead of cloning & crossfading
Use springs for animations
Support spring-based stagger effects
Usable with frameworks other than React

Quick start

npm install react-flip-toolkit or yarn add react-flip-toolkit

  1. Wrap all animated children with a single Flipper component that has a flipKey prop that changes every time animations should happen.

  2. Wrap elements that should be animated with Flipped components that have a flipId prop matching them across renders.

Table of Contents

Forkable Examples

Simple Example: An Expanding Div

animated square

Fork this example on Code Sandbox

import React, { useState } from 'react'
import { Flipper, Flipped } from 'react-flip-toolkit'

const AnimatedSquare = () => {
  const [fullScreen, setFullScreen] = useState(false)
  const toggleFullScreen = () => setFullScreen(prevState => !prevState)

  return (
    <Flipper flipKey={fullScreen}>
      <Flipped flipId="square">
        <div
          className={fullScreen ? 'full-screen-square' : 'square'}
          onClick={toggleFullScreen}
        />
      </Flipped>
    </Flipper>
  )
}

Simple Example: Two Divs

2 animated squares

Fork this example on Code Sandbox

import React, { useState } from 'react'
import { Flipper, Flipped } from 'react-flip-toolkit'

const Square = ({ toggleFullScreen }) => (
  <Flipped flipId="square">
    <div className="square" onClick={toggleFullScreen} />
  </Flipped>
)

const FullScreenSquare = ({ toggleFullScreen }) => (
  <Flipped flipId="square">
    <div className="full-screen-square" onClick={toggleFullScreen} />
  </Flipped>
)

const AnimatedSquare = () => {
  const [fullScreen, setFullScreen] = useState(false)
  const toggleFullScreen = () => setFullScreen(prevState => !prevState)

  return (
    <Flipper flipKey={fullScreen}>
      {fullScreen ? (
        <FullScreenSquare toggleFullScreen={toggleFullScreen} />
      ) : (
        <Square toggleFullScreen={toggleFullScreen} />
      )}
    </Flipper>
  )
}

Simple Example: List Shuffle

shuffling a list

Fork this example on Code Sandbox

import React, { useState } from 'react'
import { Flipper, Flipped } from 'react-flip-toolkit'
import shuffle from 'lodash.shuffle'

const ListShuffler = () => {
  const [data, setData] = useState([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
  const shuffleList = () => setData(shuffle(data))

  return (
    <Flipper flipKey={data.join('')}>
      <button onClick={shuffleList}> shuffle</button>
      <ul className="list">
        {data.map(d => (
          <Flipped key={d} flipId={d}>
            <li>{d}</li>
          </Flipped>
        ))}
      </ul>
    </Flipper>
  )
}

List Transitions

Add some interest to a dynamic list of cards by animating changes to cards' sizes and positions.

animated list

Fork this example on Code Sandbox

Stagger Effects

The react-flip-toolkit library offers spring-driven stagger configurations so that you can achieve complex sequenced effects.

For the most basic stagger effect, you can simply add a stagger boolean prop to your Flipped element:

<Flipped flipId={`element-${i}`} stagger>
  <AnimatedListItem/>
</Flipped>
animation for the selected state of a list item

Fork this example on Code Sandbox

Spring Customizations

react-flip-toolkit uses springs for animations. To customize the spring, you can pass in a preset name:

// spring preset can be one of: "stiff", "noWobble", "gentle", "veryGentle", or "wobbly"
<Flipper flipKey='foo' spring='wobbly'>
  {/* Flipped components go here...*/}
</Flipper>

or a custom spring config:

<Flipper flipKey='foo' spring={{ stiffness: 280, damping: 22 }} >
  {/* Flipped components go here...*/}
</Flipper>

View all spring options in the interactive explorer

Nested Scale Transforms

stripe menu

Interesting animations often involve scale transforms in addition to simple translate transforms. The problem with scale animations has to do with children — if you scale a div up 2x, you will warp any children it has by scaling them up too, creating a weird-looking animation. That's why this library allows you to wrap the child with a Flipped component that has an inverseFlipId to counteract the transforms of the parent:

<Flipped flipId={id}>
  <div>
    <Flipped inverseFlipId={id} scale>
      <div>some text that will not be warped</div>
    </Flipped>
  </div>
</Flipped>

By default, both the scale and the translation transforms of the parent will be counteracted (this allows children components to make their own FLIP animations without being affected by the parent). But for many use cases, you'll want to additionally specify the scale prop to limit the adjustment to the scale and allow the positioning to move with the parent.

Note: the DOM element with the inverse transform should lie flush against its parent container for the most seamless animation.

That means any layout styles — padding, flexbox, etc—should be applied to the inverted container (the element wrapped with a Flipped component with an inverseFlipId) rather than the parent Flipped container.

Route-based Animations With React Router

React-flip-toolkit with React-Router

Fork Github repo

react-flip-toolkit works great with client-side routers to provide route-driven transitions:

<Route
  render={({ location, search }) => {
    return (
      <Flipper
        flipKey={`${location.pathname}-${location.search}`}
      >
      {/* Child routes that contain Flipped components go here...*/}
      </Flipper>
    )
  }}
/>

More examples

The Components

Flipper

The parent wrapper component that contains all the elements to be animated. You'll often need only one of these per page, but sometimes it will be more convenient to have multiple Flipper regions of your page concerned with different transitions.

<Flipper flipKey={someKeyThatChanges}>{/* children */}</Flipper>

Basic Props

prop default type details
flipKey (required) - string, number, bool Changing this tells react-flip-toolkit to transition child elements wrapped in Flipped components.
children (required) - node One or more element children
spring noWobble string or object Provide a string referencing one of the spring presets — noWobble (default), veryGentle, gentle, wobbly, or stiff, OR provide an object with stiffness and damping parameters. Explore the spring setting options here. The prop provided here will be the spring default that can be overrided on a per-element basis on the Flipped component.
applyTransformOrigin true bool Whether or not react-flip-toolkit should apply a transform-origin of "0 0" to animating children (this is generally, but not always, desirable for FLIP animations)
element div string If you'd like the wrapper element created by the Flipped container to be something other than a div, you can specify that here.
className - string A class applied to the wrapper element, helpful for styling.
staggerConfig - object Provide configuration for staggered Flipped children. The config object might look something like the code snippet below:
staggerConfig={{
  // the "default" config will apply to staggered elements without explicit keys
      default: {
        // default direction is forwards
        reverse: true,
        // default is .1, 0 < n < 1
        speed: .5
      },
  // this will apply to Flipped elements with the prop stagger='namedStagger'
    namedStagger : { speed: .2 }
  }}

Advanced Props

prop default type details
decisionData - any Sometimes, you'll want the animated children of Flipper to behave differently depending on the state transition — maybe only certain Flipped elements should animate in response to a particular change. By providing the decisionData prop to the Flipper component, you'll make that data available to the shouldFlip and shouldInvert methods of each child Flipped component, so they can decided for themselves whether to animate or not.
debug false boolean This experimental prop will pause your animation right at the initial application of FLIP-ped styles. That will allow you to inspect the state of the animation at the very beginning, when it should look similar or identical to the UI before the animation began.
portalKey - string In general, the Flipper component will only apply transitions to its descendents. This allows multiple Flipper elements to coexist on the same page, but it will prevent animations from working if you use portals. You can provide a unique portalKey prop to Flipper to tell it to scope element selections to the entire document, not just to its children, so that elements in portals can be transitioned.
onStart - function This callback prop will be called before any of the individual FLIP animations have started. It receives as arguments the HTMLElement of the Flipper and the decisionData object described elsewhere.
onComplete - function This callback prop will be called when all individual FLIP animations have completed. Its single argument is a list of flipIds for the Flipped components that were activated during the animation. If an animation is interrupted, onComplete will be still called right before the in-progress animation is terminated.
handleEnterUpdateDelete - function By default, react-flip-toolkit finishes animating out exiting elements before animating in new elements, with updating elements transforming immediately. You might want to have more control over the sequence of transitions — say, if you wanted to hide elements, pause, update elements, pause again, and finally animate in new elements. Or you might want transitions to happen simultaneously. If so, provide the function handleEnterUpdateDelete as a prop. The best way to understand how this works is to check out this interactive example. handleEnterUpdateDelete receives the following arguments every time a transition occurs:
handleEnterUpdateDelete({
  // this func applies an opacity of 0 to entering elements so
  // they can be faded in - it should be called immediately
  hideEnteringElements,
  // calls `onAppear` for all entering elements
  animateEnteringElements,
  //calls `onExit` for all exiting elements
  // returns a promise that resolves when all elements have exited
  animateExitingElements,
  // the main event: `FLIP` animations for updating elements
  // this also returns a promise that resolves when
  // animations have completed
  animateFlippedElements
})

Flipped

Wraps an element that should be animated.

E.g. in one component you can have

<Flipped flipId="coolDiv">
  <div className="small" />
</Flipped>

and in another component somewhere else you can have

<Flipped flipId="coolDiv">
  <div className="big" />
</Flipped>

and they will be tweened by react-flip-toolkit.

The Flipped component produces no markup, it simply passes some props down to its wrapped child.

Wrapping a React Component

If you want to wrap a React component rather than a JSX element like a div, you can provide a render prop and then apply the flippedProps directly to the wrapped element in your component:

<Flipped>
  {flippedProps => <MyCoolComponent flippedProps={flippedProps} />}
</Flipped>

const MyCoolComponent = ({ flippedProps }) => <div {...flippedProps} />

You can also simply provide a regular React component as long as that component spreads unrecognized props directly onto the wrapped element (this technique works well for wrapping styled components):

<Flipped>
  <MyCoolComponent />
</Flipped>

const MyCoolComponent = ({ knownProp, ...rest }) => <div {...rest} />

Basic props

prop default type details
children (required) - node or function Wrap a single element, React component, or render prop child with the Flipped component
flipId (required unless inverseFlipId is provided) - string Use this to tell react-flip-toolkit how elements should be matched across renders so they can be animated.
inverseFlipId - string Refer to the id of the parent Flipped container whose transform you want to cancel out. If this prop is provided, the Flipped component will become a limited version of itself that is only responsible for cancelling out its parent transform. It will read from any provided transform props and will ignore all other props (besides inverseFlipId.) Read more about canceling out parent transforms here.
transformOrigin "0 0" string This is a convenience method to apply the proper CSS transform-origin to the element being FLIP-ped. This will override react-flip-toolkit's default application of transform-origin: 0 0; if it is provided as a prop.
spring noWobble string or object Provide a string referencing one of the spring presets — noWobble (default), veryGentle, gentle, wobbly, or stiff, OR provide an object with stiffness and damping parameters. Explore the spring setting options here.
stagger false boolean or string Provide a natural, spring-based staggering effect in which the spring easing of each item is pinned to the previous one's movement. Provide true to stagger the element with all other staggered elements. If you want to get more granular, you can provide a string key and the element will be staggered with other elements with the same key.
delayUntil false string (flipId) Delay an animation by providing a reference to another Flipped component that it should wait for before animating (the other Flipped component should have a stagger delay as that is the only use case in which this prop is necessary.)

Callback props

animation of a sentence transforming into another sentence

The above animation uses onAppear and onExit callbacks for fade-in and fade-out animations.

prop arguments details
onAppear element, index, {previous: decisionData, current: decisionData } Called when the element first appears in the DOM. It is provided a reference to the DOM element being transitioned as the first argument, and the index of the element relative to all appearing elements as the second. Note: If you provide an onAppear prop, the default opacity of the element will be set to 0 to allow you to animate it in without any initial flicker. If you don't want any opacity animation, just set the element's opacity to 1 immediately in your onAppear function.
onStart element, {previous: decisionData, current: decisionData } Called when the FLIP animation for the element starts. It is provided a reference to the DOM element being transitioned as the first argument.
onStartImmediate element, {previous: decisionData, current: decisionData } Similar to onStart, but guaranteed to run for all FLIP-ped elements on the initial tick of the FLIP animation, before the next frame has rendered, even if the element in question has a stagger delay. It is provided a reference to the DOM element being transitioned as the first argument.
onSpringUpdate springValue Called with the current spring value (normally between 0 - 1 but might briefly go over or under that range depending on the level of "bounciness" of the spring). Useful if you'd like to tween other, non-FLIP animations in concert with a FLIP transition.
onComplete element,{previous: decisionData, current: decisionData } Called when the FLIP animation completes. It is provided a reference to the DOM element being transitioned as the first argument. (If transitions are interruped by new ones, onComplete will still be called.)
onExit element, index, removeElement, {previous: decisionData, current: decisionData } Called when the element is removed from the DOM. It must call the removeElement function when the exit transition has completed.

Transform props

By default the FLIP-ped elements' translate, scale, and opacity properties are all transformed. However, certain effects require more control so if you specify any of these props, only the specified attribute(s) will be tweened:

prop type details
translate bool Tween translateX and translateY
scale bool Tween scaleX and scaleY
opacity bool

Advanced props

Functions to control when FLIP happens

prop arguments details
shouldFlip previousDecisionData, currentDecisionData A function provided with the current and previous decisionData props passed down by the Flipper component. Returns a boolean to indicate whether a Flipped component should animate at that particular moment or not.
shouldInvert previousDecisionData, currentDecisionData A function provided with the current and previous decisionData props passed down by the Flipper component. Returns a boolean indicating whether to apply inverted transforms to all Flipped children that request it via an inverseFlipId.

Spring

As a convenience, react-flip-toolkit exports a tiny function to access the same spring system used to create FLIP transitions.

Fork example on CodeSandbox

import { spring } from 'react-flip-toolkit'

spring({
  config: "wobbly",
  values: {
    translateY: [-15, 0],
    opacity: [0, 1]
  },
  onUpdate: ({ translateY, opacity }) => {
    el.style.opacity = opacity;
    el.style.transform = `translateY(${translateY}px)`;
  },
  delay: i * 25,
  onComplete: () => console.log('done')
});
spring example

Global configuration functions

You can programmatically call the following functions if you need to disable (or re-enable) FLIP animations everywhere.

disableFlip()

Global switch to disable all animations in all Flipper containers.

enableFlip()

Global switch to (re-)enable all animations in all Flipper containers. Animations are enabled by default. Calling this function is needed only if animations were previously disabled with disableFlip().

isFlipEnabled()

Returns a boolean indicating whether animations are globally enabled or disabled.

Library details

browserstack
  • Tested in latest Chrome, Firefox, Safari, and Edge with Browserstack.
  • Requires React 16+
  • Uses Rematrix for matrix calculations and a simplified fork of Rebound for spring animations

Troubleshooting

Problem #1: Nothing is happening

  • Make sure you're updating the flipKey attribute in the Flipper component whenever an animation should happen.
  • If one of your Flipped components is wrapping another React component rather than a DOM element, use a render prop to get the Flipped props and pass down to the necessary DOM element.
  • Is the element that's receiving props from Flipped visible in the DOM? react-flip-toolkit attempts to optimize performance by not animating elements that are off-screen or elements that have no width or height.
  • display:inline elements cannot be animated. If you want an inline element to animate, set display:inline-block.
  • Do you have the prefers-reduced-motion setting turned on? As of v7.1.0 that setting will disable all animations.

Problem #2: Things look weird / animations aren't behaving

  • Check to make sure all flipIds are unique. At any point, there can only be one element with a specified flipId on the page. If there are multiple Flipped elements on the page with the same id, the animation will break.
  • Make sure you are animating the element you want to animate and not, for instance, a wrapper div. If you are animating an inline element like some text, but have wrapped it in a div, you're actually animating the div, which might have a much wider width that you'd expect at certain points, which will throw off the animation. Check to see if you need to add an inline-block style to the animated element.
  • Make sure you don't have any competing CSS transitions on the element in question.
  • If you are animating an image, try giving the image hard-coded dimensions and seeing if that fixes the problem. (If you are relying on the innate dimensions of the image, it might not have been fully rendered by the browser in time for the new image dimensions to be measured.)

Problem #3: It's still not working

  • Try out the debug prop. If you still can't figure out what's going wrong, you can add the the debug prop directly on your Flipper component to pause transitions at the beginning.
  • If you think something might actually be broken, or are completely stuck, feel free to make an issue.

Performance

React-flip-toolkit does a lot of work under the hood to try to maximize the performance of your animations — for instance, off-screen elements won't be animated, and style updates are batched to prevent layout thrashing. However, if you are building particularly complex animations—ones that involve dozens of elements or large images— there are some additional strategies you can use to ensure performant animations.

Memoization

When you trigger a complex FLIP animation with react-flip-toolkit, React could be spending vital milliseconds doing unnecessary reconciliation work before allowing the animation to start. If you notice a slight delay between when the animation is triggered, and when it begins, this is probably the culprit. To short-circuit this possibly unnecessary work, try memoizing your component by using React.memo or PureComponent for your animated elements, and seeing if you can refactor your code to minimize prop updates to animated children when an animation is about to occur.

will-change:transform

.box {
  will-change: transform;
}

This CSS property tells the browser to anticipate changes to an element. It should be used with caution, because it can increase browser resource usage. If you notice rendering issues in your animation, try seeing if it increases the performance of the animation.

react-flip-toolkit's People

Contributors

aholachek avatar ai avatar dependabot[bot] avatar jackjocross avatar lytc avatar regulyarniy avatar rodrigopr avatar rschristian avatar singintime avatar slig avatar tkriplean avatar ughitsaaron avatar vsaarinen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

react-flip-toolkit's Issues

Fade out animation callback is ignoring element's transforms

Please see the following example:

https://codesandbox.io/s/qzp4zrr206

Click "Move" and note that the box fade in and moves correctly, but when the times comes to fade out, it jumps back as if the transform did not occur.

I thought it was an issue with animeJS, however, if I comment out the anime in fade-out, you can see still that react-flip-toolkit puts it there:

https://codesandbox.io/s/w25q9z8o75

After lots of trial and error, I managed to make it work for me, for animeJs example, by setting manually a static transform value in the animation:

translateY: [0, 0]

As can be seen here: https://codesandbox.io/s/l2oyv18zrl

Object(...) is not a function

Getting an error that says: TypeError: Object(...) is not a function. from line 14 of Flipper.js

the error is pointing to the line:
export var FlipContext = createContext("flip");

not sure what this means, I've set up flipper exactly as described. nothing I do seems to alleviate this error.

The page scrolls to the top during the flip animation.

Hey there!

I found a problem with animating a large list that doesn't fit on the page.
During the animation the page scrolls to the top and flipped elements appear from the top, not from the bottom. It looks very wierd. This problem comes only if you run animation via the button that lies below the list. So, if the button is placed on the top of the list, everything works great.
You can see example in the sandbox: https://codesandbox.io/s/88n1nmy7wj

What I've already tried:

  • run animation via setInterval to ensure that the problem is not because of button behaviour
  • pull the button and the span tags out of the Flipped component and push them back
  • change inner tag from li to div
    No use.

Will wait for any comments.
TIA

Tips for building a carousel

Hey there,

I'm hoping you could offer some guidance with building a carousel like component using react-flip-toolkit. For reference, here is a POC to try to show what i'm trying to build: https://codesandbox.io/s/qlqwkp9524. If you feel this isn't the right forum for this question, please let me know!

I've been trying to control the animation of elements as they enter/exit the list. You can think of it similar to a typical image carousel component. I have got things sort of working by using a combination of react-flip-toolkit and anime, however this combination feels a little unnatural, as it seems like it's something i should be able to accomplish using this library.

The issue i'm having is animating elements into position. It's quite tricky since the animations are triggered based on the flipKey value, which i'm changing every time the visible elements in the list change. I can't quite come up with a solution that is able to specify a "starting" position for the entering element, or the "exit" position for an element that is leaving, without involving anime.

My desired behavior is somewhat as follows:

  • When changing from 1 => 1,2, panel 1 should shrink from 100% to 50% width, and panel 2 should slide in from right

  • When changing from 1,2 => 2,3, panel 1 should exit left, panel 3 should slide in right

  • When changing from 2,3 => 1,2, panel 3 should exit right, panel 1 should enter left

My example with the shrinking from 100% to 50% width is fairly specific, however my thought is that if we come up with an elegant solution for the generic carousel case, then perhaps others could benefit by us building a carousel example to show controlling the entering/exit of elements as they move through the carousel.

Thanks 😄

Issue animating inner content in Safari after animation starts

Hi! Really impressed with this library, it puts my extremely hacky attempts at similar behavior in React to shame :)

I ran into an issue in Safari, unfortunately, and I'm not sure what the best way around it is. Basically, I tried to copy your strategy of using the onStart() callback to hide incoming content, which allows me to fade content in (in my case I'm just applying a CSS transition after a tick, but using something like anime.js has the same issue, I believe). Unfortunately, I'm getting a flash of visible content when I apply this in onStart() in Safari. I don't know why it's only an issue in Safari and not Chrome or Firefox, other than Safari's general IE6-ness.

I created a small test case for it (ofc, it only shows the issue in Safari). This issue seems to be really inconsistent, so you might have to play with it a bit (I get the most consistent reproductions in the iOS Simulator).

It's worth noting this isn't an issue if the inner content has 0 opacity to begin with, before the animation even triggers, but in this example, this could only be easily achieved for the open card content, and not the closed content (or otherwise it would be invisible when the page is opened!).

I can only think of a couple possible fixes:

  • Do you think there's any good consistent way to run onStart() after the DOM has been updated (so that I can apply style to the child elements, whether through querySelector() lookups or something like React refs), but before the first actual browser rendering pass? My guess is "no," but I'm secretly hopeful there's like a setTimeout(fn, 0) somewhere in the codebase that has inconsistent behavior between browsers and sometimes causes a rendering flush, or something like that.
  • Is there a secret better way to structure this that I'm not seeing? I know <Flipped /> itself can animate opacity, but I need to animate the content's opacity, not the element itself - in this demo, I'd want the boxes to be full opacity, but the text fades in.
  • Are there any better ways to initialize the animating-in state?

2 lock files

I found that you have 2 lock files yarn.lock and package-lock.json. Is it by design? Or maybe it is just small mistake and we can remove one of lock files?

Element is tilted slightly after scale animation

After a scale transition is complete, the flipped element ends up with transform: matrix(1, 0.0001, -0.0001, 1, 0, 0);. Presumably, this should be transform: matrix(1, 0, 0, 1, 0, 0); (or no transform rule at all). Seems tiny, but it's actually noticeable in certain circumstances.

Unknown event handler property `onexit`. It will be ignored.

First of all thank you for such a great library, its beautiful and really easy to use.

Second sorry to ask here but I'm not sure where to.

Following the given example I tried to add the onExit callback for the Flipped element and somehow, it appears onExit gets lowercased into onexit and triggers a React warning that it will be ignored.

There is a good chance that the problem is from me but it appears I can not figure it out.

<ul className="list">
  {slicedData.map((product, i) => (
    <Flipped flipId={product.id} key={i + 'id'} onExit={onExit} onAppear={this.onElementAppear} >
	 <li  key={product.id}><ProductCardWithPopup product={product} /></li>
    </Flipped>
	))}
</ul>

This creates this error.

index.js:2178 Warning: Unknown event handler property onexit. It will be ignored.
in li (created by ProductList)
in Flipped
in FlippedWithContext (at Shop.js:129)
in ul (at Shop.js:127)
in main (at Shop.js:114)
in div (created by Flipper)
in Flipper (at Shop.js:109)
in ProductList (at Shop.js:39)
in div (created by GridColumn)
in GridColumn (at Shop.js:38)
in div (created by GridRow)
in GridRow (at Shop.js:34)
in div (created by Grid)
in Grid (at Shop.js:33)

Thank you so very much if you can help. If its not the place for help you can close this issue and i will not use onExit for now.

Version used is 3.0.4

Cannot debug

Put debug on the Flipper component in your codepen and you will see it breaks because flip is not a function...?

IE11 - loadComponents Syntax Error: Syntax Error

Running React 16 with Webpack and Babel. Rendered server side.

Latest version of react-flip-toolkit, window.Promise is polyfilled by babel-polyfill.

This works as expected in Chrome, Edge, Firefox and Safari but not IE11. On Component load the loadComponents Syntax Error occurs as follows:
screenshot 2019-01-16 at 14 21 54

I have tried swapping my Flipper and Flipped imports to react-flip-toolkit/es/core as well as react-flip-toolkit/lib/core but to no affect. I have also attempted to change my webpack config for @babel/preset-env to useBuiltIns: 'entry' as well as useBuiltIns: 'usage' - while specifying import 'babel-polyfill' at the top of my entry file, or webpack entry list.

Typing window.Promise into the IE11 console shows that Promises are indeed working as intended, as well as all other Promises in my application are working correctly. I have also tried importing Polyfill.io scripts for Promise, and while these imported correctly this didn't change the issue I have been having.

onAppear not called even though hideEnteringElements is called

First off, thanks for this great library! It's really powerful.

When trying to debug an issue I set breakpoints in flip/animateUnflippedElements/index.ts and noticed a scenario in which enteringElements was inconsistent between the call to hideEnteringElements and animateEnteringElements. The end result was that my appearing element was invisible, since it had it opacity set to 0 within hideEnteringElements, and onAppear was never called to reset the opacity back to 1.

I'm having trouble reproducing with a smaller scale example, and I'm wondering if you have any ideas. I'm confused as to how it would be possible for enteringElements to differ between the two callback functions returned by animateUnflippedElements

On a separate note, it might be worth calling out in the docs that the onAppear animation needs to reset opacity, since by default it is set to 0 in hideEnteringElements.

Missing staggerConfig in index.d.ts

staggerConfig is missing in index.d.ts file causing following error when I try to use it as prop on Flipper:

Property 'staggerConfig' does not exist on type 'IntrinsicAttributes & FlipperProps & { children?: ReactNode; }'.

I can create a PR to add this if needed

Minimal list example

A simple minimal list example would be nice - I thought it would be this, but it does not animate at all. Probably something basic I'm missing.

import React, { Component, PureComponent } from 'react';
import './App.css';
import { move, shuffle, reverse } from './array';
import { Flipper, Flipped } from 'react-flip-toolkit';

const generateItems = length => [...Array(length).keys()].map(k => `Item ${k}`)

const actions = {
  reverse: ({items}) => ({items: reverse(items)}),
  shuffle: ({items}) => ({items: shuffle(items)}),
  move: (oldIndex, newIndex) => ({items}) => ({items: move(items, oldIndex, newIndex)}),
}

export default class extends Component {

  state = { items: generateItems(20) }
  
  move = ({oldIndex, newIndex}) => this.setState(actions.move(oldIndex, newIndex));
  reverse = () => this.setState(actions.reverse);
  shuffle = () => this.setState(actions.shuffle);

  flip = false;
  render() {
    const { items } = this.state;
    this.flip = !this.flip;
    return (
      <div className="App" >
        <button onClick={this.reverse}>Reverse</button>
        <button onClick={this.shuffle}>Shuffle</button>
        <Flipper flipKey={this.flip} >
          {items.map(item => 
            <Flipped flipId={item} key={item}>
              <ListItem >{item}</ListItem>
            </Flipped>
          )}
        </Flipper>
      </div>
    );
  }
}

// FlipMove requires class compoonents as children
class ListItem extends PureComponent {
  render() {
    const { children } = this.props;
    return <div className="list-item" >{children}</div>
  }
}

"reverse" animation?

This is more a discussion than an issue, I'd like to understand if it'd be in scope of this project.

I think it would be valuable to have a way to keep the element that is being unmounted around, and have it do the opposite of what the element that is being mounted is doing.

Basically, if I have this panel:

kapture 2018-07-18 at 14 50 08

I'd like to be able to show the content of the panel while it's being collapsed. This would allow me to have some interpolation between the two components, for instance, I could have the panel content shrink and fade out to be replaced by the button.

I think it should be possible, the library should measure the size of the new state/component, and just apply the transformations to make it go from its original size to the one of the button.

Is this something this library could support?

shouldFlip not called on entering element

I have list of items connected to a redux store. That list of items is passed as decisionData. When a new item is added, the component re-renders but shouldFlip is not called for the new element. Instead shouldFlip is called on the subsequent render which is triggered by another prop change. I'm not sure if this is a race condition, but here is a slimmed down example.

class Component extends React.PureComponent<Props> {

  render() {
    const { items, otherProp } = this.props;

    <Flipper flipKey={items.join('') + otherProp} decisionData={items: items} />
       <ul>
       {items.map.(item => {
           return (
                <Flipped flipId={item //asume it's unique} shouldFlip={(prevData, currData) => {
                        // Goal is to not FLIP incoming items, but it does not get called when a new item 
                        // is added. Instead it gets called when otherProp changes, which breaks the logic
                        // since prevData.items and currData.items are now equal
                        return prevData.items === currData.items;
                     }}>
                    <li>{item}</li>}
                </Flipped>
           )
        }}  
      </ul>
    </Flipper>
  }
}

Props {
  items: string[];
  otherProp: string; // This changes almost immediately after items are added
}

Need Help - List Example

Hi Alex,

Great work on react-flip-toolkit. Pretty neat library!

I came across your library and thought of trying it out. I forked your expandable list example and created this https://codesandbox.io/s/w26p07w108

However, I am not able to make it work somehow.

  1. On left side content, first css is applied then animation takes place. I keep debug: true then I can see content is aligned to center first then it is being animated to new position.

initial

intermediate

final

  1. Whenever text moves around then there is a little squeeze or shrinking of the text (Refer second image left text). Is it because transform or something else?

Any tips on how to make it more seamless and smooth?
My apologies if these questions sound silly. New to all this animation stuff.

Thanks in advance though! :D

Blurry text after FLIP

After a FLIP is complete, the transformation styles are left on the animated element. This often causes blurry text due to the transform: translate() and transform: scale() being left on the element.

An approach to fix this would be to remove the styles after the animation is complete. I'm currently trying to manually accomplish using the onComplete call back and clearing out the inline styles, however I ran into a road block with #50.

[Question] Integration with "react-modal" (portals again)

Hello, thank you again for the beautiful library, I have used it on several projects so far.

On the current project we are using react-modal and it is using portals. I'm interested if toolkit can animate between element in the modal and element on the next page (after router transition).

I've tried using portalKey, setting it to "ReactModalPortal" (which is the class react-modal uses for it's portals), but with no luck.

This issue #5 had some helpful info, but it uses custom modal implementation, and I couldn't figure out if I can apply the same logic to react-modal.

Don't kill yourself over this :)
Cheers!

EDIT: Example of the transition I'm trying to make :) where modal is in portal which is not rendered on page2

______________________          ______________________
|     _________      |          |          |         |
|     | from  |      |          |          | to      |
|     | modal |      |  route   |          | sidebar |
|     |       |      |  change  |          |         |
|     |_______|      |  ---->   |          |         |
|                    |          |          |         |
| page1              |          | page2    |         |
|____________________|          |__________|_________|

Deformations when animating elements with border radius

Hi, first thanks for this great library and the excellent documentation and tutorials.

I'm having an issue trying to animate a box with border-radius. When the box change size, a scale transition is done, stretching the border radiuses horribly.
I know that your library allows only to interpolate GPU accelerated properties intentionally, but I keep wondering wether allowing to animate width & height directly might allow the kind of animations that I'm looking for.

You can see what I'm talking about there:
https://codesandbox.io/s/k0p9yo71v

When transitioning the element to the collapsed version, the borders are very pixellated and deformed.

Question: How to transition between two different elements

Hi, I found react-flip-toolkit a few months ago but never used it before.

I remember reading an example of creating transitions between two different elements, but I can't find it.

Can someone provide some guidance on how to create a transition between an item of a drag-and-drop
task list and the modal that opens on click with the item details?

What I'm trying to achieve visually is similar to the react-overdrive image gallery example:

Image of React Overdrive

In fact, I tried to use react-overdrive, but then the drag and drop stops working.

Thanks in advance

[Question] Unclear operator usage

Hi! And first of all, thank you for the amazing job you did!
I was reading the sources to find out how to control FLIP animation duration and came across the interesting syntax the purpose of which I can't understand. So that ! operator at the end of the line looks unclear for me.

Here is that line of code

const body = document.querySelector('body')!

Could you please send some link where I can find more about this?

Cards not flipping when mapping over an array that renders a card component

Hey guys,

This looks like a nice library. I'm coming from using React-Flip-Move, which isn't being maintained.

I've scoured the web (nothin on stackoverflow) and pored over the docs and examples here, but can't seem to make things flip with the code below.

In brief I'm mapping over an array that gets filtered when a user clicks on various controls on the page. So I'm using the length of that array, this.props.projects.length, as the flipKey.

The ProjectListItem is a component that renders a Card for each item in the array.

Everything works with React Flip Toolkit in place: filters work, cards are rendering correctly, etc.) yet nothing flips when the array length changes.

The debugger outputs the following to the console as filters are applied, but that's it:
The "debug" prop is set to true. All FLIP animations will return at the beginning of the transition.

It's entirely possible that I'm doing something stupid, but I don't know what.

<div className={classes.projectList}>
                <Flipper debug flipKey={this.props.projects.length}>
                  {this.props.projects.map(project => (
                    <Flipped flipId="projectCard" key={project.project_uid}>
                      <ProjectListItem
                        photoUrl={this.getInitiatorPhotoUrl(
                          project.initiator_uid
                        )}
                        project={project}
                      />
                    </Flipped>
                  ))}
                </Flipper>
              </div>

Animation from panel to button looks off?

infopanelanimation

As you can see, when the component switches from the "panel view" to the "button view", the button behaves weirdly.

Do you have any idea? May I be doing something wrong?

[Feature Request] Working with portal.

Hello! Thank you for this amazing library.
Everything is so wonderful, but I want to know if it is possible to compatible with react portal.
Right now, portal will work fine, but the animation will be lost.
Don't know what do you think. Thank you!

flipId and flipKey

Sorry if this is a stupid question, but I have spent many many hours trying to figure out what flipId and flipKey actually do. I've been playing around with the nested example but I'm not sure how the flipId and flipKeys affect the divs. What I'm trying to do is basically the photo-grid example but when the animation finishes (the image is expanded) the page changes using navigateTo() to the actual article url with the text fading in just like the photo-grid example. Going back into history (previous page) would close the article just like the photo-grid and the router-example one. I am using Gatsby Js if that helps. Sorry if this was confusing I can help clarify if needed.

Nothing is happening

Sorry, I came with the hardest issue “I added a library, but there is no any animation”.

It is definitely because I didn’t understand something or made some stupid mistake. But it could be a good opportunity to improve the docs or add a warning =^_^=.

I added FLIP toolkit to our popups.

render () {
    let last = this.props.popups.length - 1
    let currentPopup = this.props.popups[last] || { }
    return <Flipper flipKey={JSON.stringify(currentPopup)}>{
       this.props.popups.map(popup => {
         <Flipped flipId={JSON.stringify(popup)}>
           <span>
             <Popup data={ popup }></Popup>
           </span>
         </Flipped>
       })
    </Flipper>
}

Here is a link, which will open a popup:

  render () {
    return <Flipped flipId={JSON.stringify(popup)}>
      <span>
        <Tile></Tile>
      </span>
    </Flipped>
  }

Make sure you're updating the flipKey attribute in the Flipper component whenever an animation should happen.

Tested, flipKey is updating every time, when popup opens/closes (the popup link will add new popup description object to this.props.popups).

If one of your Flipped components is wrapping another React component rather than a DOM element, make sure that component passes down unknown props directly to its DOM element

I checked Chrome DevTools and link and popup has data attributes

<span data-flip-id="{&quot;type&quot;:&quot;links&quot;,&quot;projectId&quot;:1}" data-flip-config="{&quot;translate&quot;:true,&quot;scale&quot;:true,&quot;opacity&quot;:true}">

What else I can check?

Move react to devDependencies

Hey first of all -- great library! I'm coming over from react-flip-move and this looks really promising.

I was just taking a look at the dependencies of this library, and noticed that there is react listed as "react": "^16.7.0", as well as a peer dependency "react": "16.x".

react should be moved into the devDependencies to avoid duplicate versions of react being installed/bundled for those that may have their react version pinned to something older than 16.7.0, as this effectively declares a minimum 16.7.0 requirement to use this library. The peerDependencies can take care of communicating the min/max requirements of this lib.

Let me know if this makes sense. I don't mind doing a quick PR to fix this up.

Cheers!

Counter-scaling timing

Hi,
This isn't really an issue for this library, but rather me trying to understand how you solved the problem I'm having, I hope it's the right place for it, many thanks if you consider answering :)

I made a pen here to show it better.
Basically, counter-scaling child elements doesn't work well for me, because the expansion and counter-expansion don't happen at the same rate, the contents should stay the exact same size, but they're warped in the process.

I understand you used a fork of rebound here, which controls the values to animate directly with javascript rather than let the CSS do its thing, but I'm interested to know if you encountered the problem and what makes your library not have it..

Thanks for reading :)

Items not flipping in mapped array

I'm assuming I have a very similar problem as this thread. But I've been working on it long enough that it's just time to ask for help.

I'm mapping over an array of objects to display a series of cards, then filtering and sorting which cards to display. I believe I've followed the examples and more or less done what you suggested in the above issue. Yet they still don't flip when I filter or sort them.

At the actual flipper it looks like this:

<Flipper flipKey={this.state.flipKey} className="results">
      {this.state.resources.map(resource => {
         return (
           <Flipped flipId={resource.id} key={resource.id}>
             <div className="box">
                 <div className="box-img">
                   <img src={resource.imageUrl} alt={resource.title} />
                 </div>
                 <div className="box-details">
                    <h4>{resource.title}</h4>
                    <p>{resource.primaryCategory}</p>
                    <p>
                    {resource.categories
                       .filter(item => item !== resource.primaryCategory)
                       .slice(0, 2)
                       .reduce((acc, cur) => {
                           return `${acc} | ${cur}`;
                       })}
                    </p>
                </div>
              </div>
           </Flipped>
         );
       })}
</Flipper>

Any help you can offer would be greatly appreciated.

My project on CodeSandbox

index.d.ts gone missing in 6.3.2

Hi, love this library!

It appears that index.d.ts has gone missing during the last release:

https://unpkg.com/[email protected]/lib/
https://unpkg.com/[email protected]/lib/

This prevents the module from being loaded in some TypeScript environments:

Type error: Could not find a declaration file for module 'react-flip-toolkit'. '/node_modules/react-flip-toolkit/lib/index.js' implicitly has an 'any' type.
  Try `npm install @types/react-flip-toolkit` if it exists or add a new declaration (.d.ts) file containing `declare module 'react-flip-toolkit';`  TS7016

Could you please address this issue?

Warning: Unsafe legacy lifecycles in Flipper

Hello,
First, I want to thank you for the effort and the great library.

On one of the project I'm working on (React 16.2.0) I get the following error:

Warning: Unsafe legacy lifecycles will not be called for components using new component APIs.

Flipper uses getSnapshotBeforeUpdate() but also contains the following legacy lifecycles:
  componentWillReceiveProps
  componentWillUpdate

The above lifecycles should be removed. Learn more about this warning here:
https://fb.me/react-async-component-lifecycle-hooks

There are no real problems introduced by this issue, I'm more puzzled by it.

Funky thing is that I can't see componentWillReceiveProps nor componentWillUpdate anywhere in Flipper.js. Could it be related to one of the dependencies? As far as I can see you are not using any dependencies that are using react lifecycle. Only other thing I could think of that some other class is also called Flipper and that error message is misleading because of it.

screenshot 2018-09-28 14 41 57

Cheers and thank you once more!

Style the Flipper div?

Is there any way to give some custom CSS to the Flipper div? Specifically, I'd need to set its width to 100% to make it fit its context.

Flipped children styles not respeced

Hi Alex! Great work on the library. We are exploring implementing a similar menu to the one you've demo'd in your react-stripe-menu example, so many thanks for publicizing your hard work!

I come to you with a bug I've noticed during our own implementation that is present in yours as well. It appears a "flipped" element's children styles no longer apply. This is present when navigating to a non-first (second, third, etc) dropdown. You'll notice that hover styles are missing (no cursor pointer, no color change). See the gif below for details:

screen recording 2018-10-02 at 10 18 am

Any thoughts on what might be causing this? Any tips on debugging forwarded refs with chrome?

Would love to help you out with this!

Troubleshooting animations with codesplit routes

I am experiencing an issue with animations not executing when codesplit routes are loaded for the first time.

I've created an MWE here that illustrates the issue: https://codesandbox.io/s/7k5yorxlz6

Compare how the site loads initially compared to what happens when you flip between routes when both nested child routes have already been loaded.

Is it possible to get react-flip-toolkit working in this situation?

Does spring only work in certain scenarios?

I've gotten this working and it's pretty nifty. Right now I've made an accordion style component and I'm animating scaleY and opacity on the accordion container, using keyframes w/ styled-components. The one thing I can't seem to figure out is the spring prop. I've tried different values for it, and I'm not seeing any difference in effect, even when I slow my animation waaay down. Is there something I'm missing here?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.