This component from react-sticky
is one of two in the library.
container
, which initializes and passes down acontext
to itschild
...sticky
, which uses thecontext
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
}