Giter Club home page Giter Club logo

snabbdom.scala's Introduction

Snabbdom.scala – Virtual DOM for Scala.js

This is a Scala.js interface to Snabbdom.js, a popular virtual DOM library with a focus on simplicity, modularity, powerful features and performance.

"com.raquo" %%% "snabbdom" % "0.1.1"

The main goal of Snabbdom is to provide an easily extensible foundation for building frontend libraries that need to manipulate DOM. Other than "you need a virtual DOM", Snabbdom doesn't have an opinion on how to structure your frontend code, it is rather low-level. It is well suited to be used in all kinds of UI libraries including those that work on Streams and Observables.

Many Javascript libraries use Snabbdom.js under the hood, for example Vue.js, Cycle.js, Kaiju.

In Scala.js world, Outwatch uses Snabbdom.js (although not Snabbdom.scala).

Basic Usage

With minor syntactic differences, using Snabbdom.scala is just like using Snabbdom.js:

import com.raquo.snabbdom
import com.raquo.snabbdom.Snabbdom
import com.raquo.snabbdom.simple.attrs.size
import com.raquo.snabbdom.simple.events.onChange
import com.raquo.snabbdom.simple.styles.opacity
import com.raquo.snabbdom.simple.tags.{div, input}
import com.raquo.snabbdom.simple.implicits._
import org.scalajs.dom
 
val foo: dom.Event => Unit = ???
 
// Initialize snabbdom
val container = dom.document.getElementById("my-app-container")
val patch = Snabbdom.init(snabbdom.builtInModules)
 
// Create a virtual node
val node = div(
  opacity := 0.5,
  "Please enter a value: ",
  input(
    size := 3,
    onChange := foo 
  )
)
 
// Mount the virtual node
patch(container, node)
 
// Update the virtual node with a different opacity
val newNode = node.copy()
newNode(opacity := 0.7)
 
// Apply the change to the DOM
patch(node, newNode)

Who's Using It?

Snabbdom.js is an established, well respected JS library with a long history. Many, many projects use it.

Snabbdom.scala is a Scala.js interface to it. Although I've just released it, I have been working on it for quite some time now, and it is pretty much feature-complete.

Laminar used to rely on Snabbdom.scala until I realized that Laminar's API does not map well to virtual DOM, and switched out Snabbdom.scala for Scala DOM Builder.

If you're using Snabbdom.scala, please submit a PR to add your project link here! (open source or not)

Features

Type-safe builders for virtual nodes

Node building API is similar to ScalaTags. However, Snabbdom.scala does not depend on ScalaTags, but rather uses Scala DOM Types.

Extensible API

Snabbdom.scala provides a type-safe way to extend core Snabbdom functionality.

  • Write Snabbdom modules in Scala. A Snabbdom.scala module is simply an instance of ModuleHooks with pretty much the same API as native Snabbdom modules.

  • Extend Node and NodeData classes to provide any kind of logic you need. Snabbdom.scala itself gives you the canonical VNode and VNodeData which have no special logic in them. If you were building a UI library on top of Snabbdom or creating a Snabbdom module, you would instead create MyNode extends Node and MyNodeData extends NodeData. This old version of Laminar provides an example of this. Note that it was compiled against an old, untagged version of Snabbdom.scala.

  • Use existing Snabbdom.js modules written in Javascript. Those should work as-is if they do not create or modify the virtual nodes themselves.

Out of the box Snabbdom.scala supports the following Snabbdom.js modules: attrs, props, events, styles.

Test Utils

Snabbdom.scala uses Scala DOM Test Utils for its own tests. I guess I could extract SnabbdomSpec into a reusable package, but for now you can just copy it into your own project to test your Snabbdom nodes. Example test code:

val expectedTitle1 = randomString("title1_")
val expectedTitle2 = randomString("title2_")
val expectedText1 = randomString("text1_")
val expectedText2 = randomString("text2_")
val expectedColSpan = Random.nextInt(15)
val expectedRowSpan = 15 + Random.nextInt(7)
 
mount(
  td(
    colSpan := expectedColSpan,
    rowSpan := expectedRowSpan,
    span(
      title := expectedTitle1,
      expectedText1,
      span(
        expectedText2,
        title := expectedTitle2
      )
    ),
    span()
  )
)
 
expectNode(
  td like(
    colSpan is expectedColSpan,
    rowSpan is expectedRowSpan,
    title isEmpty,
    span like(
      title is expectedTitle1,
      colSpan isEmpty,
      rowSpan isEmpty,
      expectedText1,
      span like(
        title is expectedTitle2,
        colSpan isEmpty,
        rowSpan isEmpty,
        expectedText2
      )
    ),
    span
  )
)

In this example, expectNode verifies that the real DOM element produced by snabbdom (not the virtual node) matches the description provided to it.

Snabbdom's own tests run with ScalaTest, but the latter is not required to use the testing utils.

Differences from Snabbdom.js

  • Snabbdom.scala does not provide an h function to build virtual nodes, and thus any logic that lives there is absent from Snabbdom.scala. You should use the type-safe node builders we provide instead.
  • Snabbdom.scala does not store class names and IDs in .sel property of the node. However, there are performance advantages to using .sel for more than just tag name because Snabbdom's sameVnode method uses it to decide whether to patch or re-create DOM nodes. It is not yet clear to me which way is the best way. I'm not sure if shoving all classes into .sel is a good idea because in web application code it is common to toggle CSS classes just for styling (e.g. visibility).
  • Snabbdom.scala does not use the .text property on nodes that have a .sel. Instead, we create an empty text node when given a string as a child. This makes things easier when using the builder pattern, and when you're updating the node with new children.

My Related Projects

  • Scala DOM Types – Type definitions that we use for all the HTML tags, attributes, properties, and styles
  • Scala DOM Builder – Low-level Scala & Scala.js library for building and manipulating DOM trees
  • Scala DOM TestUtils – Test that your Javascript DOM nodes match your expectations
  • Laminar – Reactive UI library based on Scala DOM Builder
  • XStream.scala – Scala.js interface to a simple JS reactive streams library
  • Cycle.scala – Scala.js interface to a popular JS functional reactive library

Author

Nikita Gazarov – raquo.com

License

Snabbdom.scala is provided under the MIT license.

snabbdom.scala's People

Contributors

raquo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

Forkers

inigo

snabbdom.scala's Issues

svg support

Hi,

I'm currently migrating a snabbdom project to snabbdom.scala. I found an issue with svgs. Maybe you can supply a solution to that problem:

snabbdom does some magic in it's h-function, that sets the namespace for svg elements. See: https://github.com/snabbdom/snabbdom/blob/v0.7.3/src/h.ts#L42
As far as I know, snabbdom.scala doesn't use that function so the namespace won't be set. Without the namespace, I can't set some attributes (like viewBox) as the xml relies on case sensitivity and normal html elements are case insensitive.

unable to run examples

The short example is not working,the symbol := and lots of other things are undefined,do i have to add some other dependencies or the api is changed?

Type unsoundness in ModuleHooks

Our hooks have correct types except for one edge case, when the hooks for the initial app container are processed. Snabbdom creates a virtual empty node for the first argument of patch method when it's a real DOM element, and that empty virtual node is not an instance of our own Node class but a plain JS object which although has a similar shape will be missing any additional fields and methods defined in Scala. This is especially a problem for libraries based on Snabbdom.scala that subclass Node and NodeData.

There are a couple ways to fix that. One is to make the types reflect this reality. Another is to keep current types but avoid calling Scala-provided hook on the snabbdom-created node in that edge case.

I kinda favour the latter option because we will probably not lose anything of significance, but it would be a departure from Snabbdom.js API, so needs to be considered more carefully. Which is why this is not yet resolved.

Run tests in Selenium

Selenium is slower than JSDom but provides a real browser with a real DOM, an environment much closer to where your code will actually run.

There are some commented rambles in build.sbt, but I was so far unable to get this to work. I think we need this scalajs-bundler ticket addressed to get this to work. scalacenter/scalajs-bundler#89

Current Status of Snabbdom.scala

For anyone wondering what's happening with this project:

Since I originally wrote Snabbdom.scala I have been busy working on other Scala.js DOM-related projects. To minimize redundancy in all those projects, I have extracted parts of Snabbdom.scala into more generic packages – Scala DOM Types and Scala DOM TestUtils.

I am currently working on migrating Snabbdom.scala to use these libraries. Once that is done I will publish version 0.1 of Snabbdom.scala to Maven Central. If you want to get notified when that happens you can watch this project on github, or subscribe to this specific issue.

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.