0

This component from react-sticky is one of two in the library.

  • container, which initializes and passes down a context to its child...
  • sticky, which uses the context and scroll position to achieve a sticky header effect.

I just spent about two hours or more porting this laboriously into ReactJS in scalajs and I've pasted below what I have done thus far. It doesn't compile; there are still loose wires.

I'm starting to think that I should give up because maybe my path is not a good one. What I tried to do is to eliminate the use of context which is unavailable in the sjs library with a ParentProps and pass its state to the child and back.

However given the number of moving parts involved I am losing faith that this may even work. I need to know whether there is a better approach or not to porting.

package shindig.frontend.component.layout

import fr.iscpif.scaladget.mapping.ace.PlaceHolder
import japgolly.scalajs.react._
import japgolly.scalajs.react.vdom._
import japgolly.scalajs.react.vdom.prefix_<^._
import org.scalajs.dom.html.Div
import org.scalajs.dom.window
import org.scalajs.dom.raw.ClientRect

import scalacss.Defaults._

object StickyComponent {


  case class Props(
                    isActive: Boolean                   = true,
                    className: String                   = "",
                    style: Seq[StyleA]                  = Seq(),
                    stickyClassName: String             = "",
                    stickyStyle: Seq[StyleA]            = Seq(),
                    offsetTop:   Double                    = 0,
                    offsetBottom: Double                   = 0,
                    stickyStateChange: () ⇒ Callback    = () ⇒ (),
                    contextProps: StickyContainer.Props = StickyContainer.Props()
                  )

  case class State(isSticky: Boolean = false, origin: PlaceHolder)

  class Backend($:           BackendScope[Props, State]) {

    def componentDidMount(): Unit = {

    }

    def getNode: TopNode = ReactDOM.findDOMNode($)
    def getRect          = getNode.getBoundingClientRect()
    def getY             = window.pageYOffset

    def getOrigin(y: Double): Double = getPlaceholderRef.top + y
    def getPlaceholderRef = $.refs.apply[Div]("placeholder").get.getDOMNode().getBoundingClientRect()
    def getProps: Props  = $.props.runNow()

    def isBelow(y: Double, contextProps: StickyContainer.Props): Boolean =
      y + contextProps.offset >= getOrigin(y)

    def isAbove(y: Double, contextProps: StickyContainer.Props, offset: Double): Boolean =
      contextProps.offset <= contextProps.bottomOfRectOrNil - offset

    def isStickyAt(y: Double, origin: Double): Boolean = {
      val props = getProps
      val y = getY
      props.isActive && isBelow(y, props.contextProps) && isAbove(y, props.contextProps, props.offsetBottom)
    }

    def update() = $.setState(State(

    ))

  }

}

object StickyContainer {

  case class Props(
                    node: Option[TopNode] = None,
                    offset: Double = 0,
                    rect: Option[ClientRect] = None
                  ) {
    def bottomOfRectOrNil: Double = rect match {
      case Some(r) ⇒ r.bottom
      case None ⇒ 0
    }
  }

  case class State(
                    node: Option[TopNode] = None,
                    offset: Double = 0,
                    rect: Option[_] = None
                  ) {
    def withNode(node: TopNode) =
      State(Some(node), offset, rect)
  }

  class Backend($: BackendScope[Unit, State]) {

    def componentDidMount(): Unit = {
      $.modState(_.withNode(ReactDOM.findDOMNode($)))
    }

    def render() = {
      <.div(
        $.propsChildren()
      )
    }

  }

  val component =

    ReactComponentB[Unit]("StickyContainer")
      .initialState(State())
      .backend[Backend]($ ⇒ new Backend($))
      .renderBackend
      .build

}
tacos_tacos_tacos
  • 10,277
  • 11
  • 73
  • 126

1 Answers1

0

So there are two answers really: the first answer is, I still don't know how you might use context within scalajs wrt reactjs, but the second answer is, it didn't matter, and since this time I've ported like ten other small react libs without issue. I was focusing on porting methods I did not need to port.

All you need to do is follow the guide at https://github.com/chandu0101/scalajs-react-components/blob/master/doc/InteropWithThirdParty.md . If you have been searching for a while you probably already saw this and maybe didn't believe it would work (I didn't quite grasp that it would work at first), since all you're doing is copying Props and creating a faux constructor. Well, that's all you need to do - in all likelihood - so try porting only what is required on that page before tackling this task.

tacos_tacos_tacos
  • 10,277
  • 11
  • 73
  • 126