Skip to content

Commit 23d7a9d

Browse files
committed
Merge branch 'master' of github.com:ThoughtWorksInc/bindable.scala into template
2 parents b78f28d + 8b4d12f commit 23d7a9d

File tree

23 files changed

+625
-28
lines changed

23 files changed

+625
-28
lines changed

.git-blame-ignore-revs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
# Scala Steward: Reformat with scalafmt 3.1.2
22
fb6cfb8aea15a1b339e3ed69e1e96acd7df4cae6
3+
4+
# Scala Steward: Reformat with scalafmt 3.7.0
5+
60bbc545deefa9146a980bab48284d4d674c4bc2

.github/workflows/scala-steward.yml

Lines changed: 0 additions & 19 deletions
This file was deleted.

.github/workflows/scala.yml

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,11 @@ jobs:
1414
strategy:
1515
fail-fast: false
1616
matrix:
17-
scala:
18-
- 2.12.15
17+
include:
18+
- scala: 3.2.1
19+
- scala: 2.13.4
20+
sbt-args: --addPluginSbtFile=project/plugins.sbt.scalajs06
21+
- scala: 2.13.4
1922

2023
steps:
2124
- uses: actions/checkout@v3
@@ -35,12 +38,13 @@ jobs:
3538
~/.sbt/
3639
~/.coursier/
3740
key: |
38-
${{ runner.os }}-${{matrix.scala}}-${{ hashFiles('**/*.sbt') }}
39-
${{ runner.os }}-${{matrix.scala}}-
41+
${{runner.os}}-${{matrix.scala}}-${{hashFiles('**/*.sbt')}}-${{matrix.sbt-args}}
42+
${{runner.os}}-${{matrix.scala}}-${{hashFiles('**/*.sbt')}}-
43+
${{runner.os}}-${{matrix.scala}}-
4044
- name: Run tests
41-
run: sbt ++${{ matrix.scala }} test
45+
run: sbt ${{matrix.sbt-args}} ++${{matrix.scala}} test
4246
- name: Publish to Maven Central Repository
4347
env:
4448
GITHUB_PERSONAL_ACCESS_TOKEN: ${{secrets.PERSONAL_ACCESS_TOKEN}}
4549
if: ${{ env.GITHUB_PERSONAL_ACCESS_TOKEN != '' && github.event_name != 'pull_request' }}
46-
run: sbt ++${{ matrix.scala }} "set every Seq(sonatypeSessionName := \"${{github.workflow}} ${{github.run_id}}-${{github.run_number}}-${{github.run_attempt}}-$$ ${{ matrix.scala }}\", publishTo := sonatypePublishToBundle.value)" publishSigned sonatypeBundleRelease
50+
run: sbt ${{matrix.sbt-args}} ++${{matrix.scala}} "set every Seq(sonatypeSessionName := \"${{github.workflow}} ${{github.run_id}} ${{github.run_number}} ${{github.run_attempt}} ${{matrix.scala}}\", publishTo := sonatypePublishToBundle.value)" publishSigned sonatypeBundleRelease

.scalafmt.conf

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
runner.dialect = scala212source3
2-
version = "3.6.1"
1+
runner.dialect = scala3
2+
version = "3.7.1"
33
maxColumn = 80

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2018 ThoughtWorks Inc.
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# bindable.scala
2+
[![Latest version](https://index.scala-lang.org/thoughtworksinc/bindable.scala/bindable/latest.svg)](https://index.scala-lang.org/thoughtworksinc/bindable.scala/bindable)
3+
[![Scaladoc](https://javadoc.io/badge/com.thoughtworks.binding/bindable_sjs0.6_2.13.svg?label=scaladoc)](https://javadoc.io/page/com.thoughtworks.binding/bindable_sjs0.6_2.13/latest/com/thoughtworks/binding/bindable/index.html)
4+
[![Scala CI](https://github.com/ThoughtWorksInc/bindable.scala/actions/workflows/scala.yml/badge.svg)](https://github.com/ThoughtWorksInc/bindable.scala/actions/workflows/scala.yml)
5+
6+
**bindable.scala** is a library of type classes for creating user-friendly [Binding.scala](https://github.com/ThoughtWorksInc/Binding.scala) components.
7+
8+
## Motivation
9+
10+
When creating a component that accepts parameters or “holes”, it is difficult to determine the types of those parameters.
11+
12+
For example, the following component accepts two `Binding` as parameters:
13+
14+
```scala
15+
@dom def myComponent1(title: Binding[String], children: Binding[BindingSeq[Node]]) = {
16+
<div title={title.bind}>
17+
{children.bind}
18+
</div>
19+
}
20+
```
21+
22+
By typing parameters as `Binding`s, `myComponent1` allows partial rendering whenever the value of `title` or `children` is changed. Unfortunately, it is too verbose to use `myComponent1` for simple use cases when the parameters are constants.
23+
24+
```scala
25+
// Does not compile
26+
@dom def myUseCases1 = myComponent1("My Title", <img/>).bind
27+
28+
// Compiles, but too verbose
29+
@dom def myUseCases2 = myComponent1(Constant("My Title"), Constant(Constants(<img/>))).bind
30+
```
31+
32+
In this library, we introduced two type classes, `Bindable` and `BindableSeq`, to allow heterogeneous types of parameters for a component.
33+
34+
## Usage
35+
36+
### Step 1: adding the following settings into your `build.sbt`
37+
38+
```sbt
39+
addCompilerPlugin("org.spire-math" %% "kind-projector" % "latest.release")
40+
41+
libraryDependencies += "com.thoughtworks.binding" %%% "bindable" % "latest.release"
42+
```
43+
44+
### Step 2: creating a component that accepts bindable parameters
45+
46+
```scala
47+
import com.thoughtworks.binding.bindable._
48+
import org.scalajs.dom.raw._
49+
@dom def myComponent2[Title: Bindable.Lt[?, String], Children: BindableSeq.Lt[?, Node]](title: Title, children: Children) = {
50+
<div title={title.bind}>
51+
{children.bindSeq}
52+
</div>
53+
}
54+
```
55+
56+
### Step 3: using the component with any parameters that can be converted to `Binding` or `BindingSeq`
57+
58+
59+
```scala
60+
import com.thoughtworks.binding._, Binding._
61+
@dom def myUseCases3 = myComponent2("My Title", <img/>).bind
62+
@dom def myUseCases4 = myComponent2(Constant("My Title"), Constant(Constants(<img/>))).bind
63+
@dom def myUseCases5 = myComponent2("My Title", <img/><img/>).bind
64+
@dom def myUseCases6 = myComponent2("My Title", Binding(<img/><img/>)).bind
65+
```
66+
67+
Unlike use cases of `myComponent1`, all the above use cases of `myComponent2` compile now, with the help of the `Bindable` and `BindableSeq` type classes.
68+
69+
## Links
70+
71+
* [Documentation](https://javadoc.io/page/com.thoughtworks.binding/bindable_sjs0.6_2.13/latest/com/thoughtworks/binding/bindable/index.html)
72+
* [Binding.scala](https://github.com/ThoughtWorksInc/Binding.scala)
73+
* [Limitations of the component model](https://github.com/ThoughtWorksInc/Binding.scala/issues/128)

build.sbt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import sbtcrossproject.CrossPlugin.autoImport.{crossProject, CrossType}
2+
3+
Global / parallelExecution := false
4+
5+
publish / skip := true
6+
7+
organization in ThisBuild := "com.thoughtworks.binding"
8+
9+
lazy val bindable = crossProject(JVMPlatform, JSPlatform) in file(".")

js/build.sbt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../shared/build.sbt

js/js.sbt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
enablePlugins(ScalaJSBundlerPlugin)
2+
3+
enablePlugins(Example)
4+
5+
libraryDependencies += "com.thoughtworks.binding" %%% "jspromisebinding" % "12.1.1"
6+
7+
libraryDependencies ++= PartialFunction.condOpt(scalaBinaryVersion.value) {
8+
case "2.13" =>
9+
"com.yang-bo" %%% "html" % "2.0.0" % Optional
10+
}
11+
12+
libraryDependencies ++= PartialFunction.condOpt(scalaBinaryVersion.value) {
13+
case "2.13" =>
14+
compilerPlugin("org.typelevel" %% "kind-projector" % "0.10.3")
15+
}
16+
17+
requireJsDomEnv in Test := true
18+
19+
Test / scalacOptions ++= PartialFunction.condOpt(scalaBinaryVersion.value) {
20+
case "2.13" =>
21+
"-Ymacro-annotations"
22+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package com.thoughtworks.binding.bindable
2+
3+
/** @example
4+
* This type class is internally used in the [[org.lrng.binding.html]]
5+
* annotation, automatically converting any compatible values into
6+
* [[com.thoughtworks.binding.Binding.BindingSeq]], injecting into a HTML
7+
* template.
8+
* {{{
9+
* import org.lrng.binding.html
10+
* import org.scalajs.dom._
11+
* @html
12+
* def myBinding = <span>Single Element</span>
13+
*
14+
* @html
15+
* def myBindingSeq = <span>Element 1</span><span>Element 2</span>
16+
*
17+
* @html
18+
* def myBindingOrBindingSeq(singleElement: Boolean) = {
19+
* if (singleElement) {
20+
* <span>Single Element</span>
21+
* } else {
22+
* <span>Element 1</span><span>Element 2</span>
23+
* }
24+
* }
25+
*
26+
* @html
27+
* def mySection = <section>
28+
* {myBinding.bind}
29+
* {myBinding}
30+
* {myBindingSeq}
31+
* {Binding{myBindingSeq.all.bind.toSeq}}
32+
* {myBindingSeq.all.bind.toSeq}
33+
* {myBindingOrBindingSeq(true)}
34+
* {myBindingOrBindingSeq(false)}
35+
* </section>
36+
*
37+
* val root = document.createElement("span")
38+
* html.render(root, mySection)
39+
*
40+
* root.innerHTML should be(
41+
* """<section>
42+
* <span>Single Element</span>
43+
* <span>Single Element</span>
44+
* <span>Element 1</span><span>Element 2</span>
45+
* <span>Element 1</span><span>Element 2</span>
46+
* <span>Element 1</span><span>Element 2</span>
47+
* <span>Single Element</span>
48+
* <span>Element 1</span><span>Element 2</span>
49+
* </section>"""
50+
* )
51+
* }}}
52+
*/
53+
private[bindable] trait BindableSeqScaladoc

0 commit comments

Comments
 (0)