React Spring bindings

I’m trying to figure out how to write bindings for react-spring but it seems like a gargantuan task since it has so many config options.

I’m curious if anyone else has tackled this and could share their code.

For example

Seems like the binding for useTransition can have params that are objects with the entries from, enter, and leave which all accept all the CSS properties from React.

Looks intimidating although maybe it’s a matter of using 'a as parameter types?

Any guidance would be much appreciated

This is an old code I have to do spring animations in our app:

/**
 Spring are configurable and can be tuned.

 mass     - Spring mass
 tension  - Spring energetic load
 friction - Spring resistence
 duration - If > than 0 will switch to a duration-based animation instead of spring physics, value should be indicated in milliseconds
 */
module Config = {
  [@bs.deriving abstract]
  type t = {
    [@bs.optional]
    mass: int,
    [@bs.optional]
    tension: int,
    [@bs.optional]
    friction: int,
    [@bs.optional]
    duration: int,
  };
};

/**
 Spring props can be anything, not just styles
 */
module Props = {
  type t('a) = Js.t('a);

  external fromStyle: ReactDOMRe.Style.t => t('a) = "%identity";
};

/**
 The spring itself
 */
[@bs.deriving abstract]
type t('source, 'target) = {
  [@bs.optional]
  config: Config.t,
  [@bs.optional]
  from: Props.t('source),
  [@bs.optional] [@bs.as "to"]
  toValue: Props.t('target),
};

module Preset = {
  [@bs.module "react-spring/web.cjs"] [@bs.scope "config"] external default: Config.t = "default";
  [@bs.module "react-spring/web.cjs"] [@bs.scope "config"] external gentle: Config.t = "gentle";
  [@bs.module "react-spring/web.cjs"] [@bs.scope "config"] external wobbly: Config.t = "wobbly";
  [@bs.module "react-spring/web.cjs"] [@bs.scope "config"] external stiff: Config.t = "stiff";
  [@bs.module "react-spring/web.cjs"] [@bs.scope "config"] external slow: Config.t = "slow";
  [@bs.module "react-spring/web.cjs"] [@bs.scope "config"] external molasses: Config.t = "molasses";
  let fast = Config.t(~mass=1, ~tension=500, ~friction=30, ());
};

/**
 Turns values into animated-values.
 */
[@bs.module "react-spring/web.cjs"]
external useSpring: (unit => t('from, 'toValue)) => ('props, (. t('from, 'toValue)) => unit, 'stop) = "useSpring";

module Transition = {
  module ObjConfig = {
    [@bs.deriving abstract]
    type t('from, 'enter, 'leave) = {
      [@bs.optional]
      config: Config.t,
      [@bs.optional]
      from: Props.t('from),
      [@bs.optional]
      enter: Props.t('enter),
      [@bs.optional]
      leave: Props.t('leave),
    };
  };

  module FnConfig = {
    [@bs.deriving abstract]
    type t('item, 'from, 'enter, 'leave, 'a) = {
      [@bs.optional]
      config: Config.t,
      [@bs.optional]
      from: Props.t('from),
      [@bs.optional]
      enter: 'item => (. ((. Props.t('enter)) => 'a)) => Js.Promise.t('a),
      [@bs.optional]
      leave: Props.t('leave),
    };
  };

  module ItemConfig = {
    [@bs.deriving abstract]
    type t('item, 'from, 'enter, 'update, 'leave, 'a) = {
      [@bs.optional]
      config: Config.t,
      [@bs.optional]
      from: 'item => Props.t('from),
      [@bs.optional]
      enter: 'item => Props.t('enter),
      [@bs.optional]
      update: 'item => Props.t('update),
      [@bs.optional]
      leave: Props.t('leave),
    };
  };

  [@bs.deriving abstract]
  type t('item, 'a) = {
    item: 'item,
    key: string,
    props: 'a,
  };
};

[@bs.module "react-spring/web.cjs"]
external useTransitionObj:
  (array('item), option('item => string), Transition.ObjConfig.t('from, 'enter, 'leave)) =>
  array(Transition.t('item, 'a)) =
  "useTransition";

[@bs.module "react-spring/web.cjs"]
external useTransitionFn:
  (array('item), option('item => string), Transition.FnConfig.t('item, 'from, 'enter, 'leave, 'a)) =>
  array(Transition.t('item, 'a)) =
  "useTransition";

[@bs.module "react-spring/web.cjs"]
external useTransitionItem:
  (array('item), option('item => string), Transition.ItemConfig.t('item, 'from, 'enter, 'update, 'leave, 'a)) =>
  array(Transition.t('item, 'a)) =
  "useTransition";

module Animated = {
  /**
   Component extension to an animated one
   */
  [@bs.module "react-spring/web.cjs"] [@react.component] [@bs.scope "animated"]
  external make:
    (~ref: ReactDOMRe.Ref.t=?, ~style: Js.t('a)=?, ~className: string=?, ~children: React.element=?) => 'children =
    "div";
};

I copy paste it as is: the code is old and certainly not a state of the art, but it was enough for us.
It might help you to get started.

I use it with some code like this:

let config = Config.t(~duration=..., ());
let (props, setProps, stopProps) = useSpring(() => t(~config=config, ~from=..., ~toValue=..., ()))

<Spring.Animated style=props>
2 Likes

Thanks this is super helpful!
I struggled on how to use the Transition.t but finally I figured that it generates some getters

tx->Spring.Transition.itemGet :exploding_head:

#TodayILearned

The bs-react-spring lib is pretty nice, https://www.npmjs.com/package/bs-react-spring

1 Like