Skip to content

Commit

Permalink
add react-markdown example (#9)
Browse files Browse the repository at this point in the history
  • Loading branch information
mvillafuertem authored Mar 29, 2021
1 parent 46c3663 commit ba3960e
Show file tree
Hide file tree
Showing 11 changed files with 5,164 additions and 6 deletions.
20 changes: 18 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,22 @@ lazy val `react-window` = project
"react-virtualized-auto-sizer" -> "1.0.2", // as recommended by react-window
"@types/react-virtualized-auto-sizer" -> "1.0.0",
)
)
)

lazy val `react-markdown` = project
.enablePlugins(ScalablyTypedConverterPlugin)
.configure(baseSettings, withCssLoading, browserProject, reactNpmDeps, bundlerSettings)
.settings(
webpack / version := "4.44.1",
useYarn := true,
webpackDevServerPort := 8017,
stFlavour := Flavour.Japgolly,
Compile / npmDependencies ++= Seq(
"react-markdown"-> "^5.0.3",
"react-syntax-highlighter"-> "^15.4.3",
"@types/react-syntax-highlighter"-> "^13.5.0"
)
)

/** Note: This can't use scalajs-bundler (at least I don't know how),
* so we run yarn ourselves with an external package.json.
Expand Down Expand Up @@ -342,7 +357,8 @@ lazy val withCssLoading: Project => Project =
"css-loader" -> "3.4.2",
"style-loader" -> "1.1.3",
"file-loader" -> "5.1.0",
"url-loader" -> "3.0.0"
"url-loader" -> "4.1.0",
"copy-webpack-plugin" -> "6.0.3"
)
)

Expand Down
19 changes: 15 additions & 4 deletions custom.webpack.config.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
var merge = require('webpack-merge');
var generated = require('./scalajs.webpack.config');
const merge = require('webpack-merge');
const generated = require('./scalajs.webpack.config');
const path = require("path");
const CopyWebpackPlugin = require('copy-webpack-plugin');

var local = {
const local = {
module: {
rules: [
{
Expand All @@ -17,7 +19,16 @@ var local = {
use: 'url-loader'
}
]
}
},
plugins: [
new CopyWebpackPlugin({
patterns: [
{
from: path.resolve(__dirname, "../../../../src/main/js")
}
]
})
]
};

module.exports = merge(generated, local);
66 changes: 66 additions & 0 deletions docs/react-markdown/docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Working with objects

Javascript is remarkably flexible. When we integrate with arbitrary Javascript code in Scala.js, we need a very flexible
encoding to tag along. The encoding chosen for ScalablyTyped is the result of years of experimentation, and has
a much more dynamic feeling than what you may be used to.

Let's start with an example of a type definition we want to use:

```scala
@js.native
trait Point extends StObject {

var x: Double = js.native

var y: Double = js.native
}
object Point {

@scala.inline
def apply(x: Double, y: Double): Point = {
val __obj = js.Dynamic.literal(x = x.asInstanceOf[js.Any], y = y.asInstanceOf[js.Any])
__obj.asInstanceOf[Point]
}

@scala.inline
implicit class PointMutableBuilder[Self <: Point] (val x: Self) extends AnyVal {

@scala.inline
def setX(value: Double): Self = StObject.set(x, "x", value.asInstanceOf[js.Any])

@scala.inline
def setY(value: Double): Self = StObject.set(x, "y", value.asInstanceOf[js.Any])
}
}
```

We notice several things:
- it's a `@js.native` trait, so we cannot `new` it ourselves. This can be [`changed`](conversion-options.md#stenablescalajsdefined), but it's not recommended.
- it has two required members (`x` and `y`). Optional members would typically be wrapped in `js.UndefOr`
- it has an `object` with syntax to help us work with it
- the entire syntax is built on mutability. It's Javascript, after all. more on that further down

### Basic usage

```scala
// At construction time we need to supply all required parameters
val p = Point(x = 1,y = 2)

// we can mutate what we have
// this is equivalent to typescript `p.x = 3
val p2 = p.setX(3)

// or we can duplicate and then mutate.
// this is equivalent to typescript `const p2 = {...p, x: 3}
val p3 = p.duplicate.setX(3)

// we can combine with other javascript objects.
// this is equivalent to javascript `const p3 = {...p, {}}`
val p4: Point with TickOptions = p.combineWith(TickOptions())

// fallback, if the type definitions are wrong or for any other reason you can break the contract
val p5: p.duplicate.set("x", "foo")

// you can also set any other property
val p6: p.duplicate.set("x2", "foo")
```
12 changes: 12 additions & 0 deletions docs/react-markdown/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>React-markdown demo</title>
</head>
<body>
<div id="container"></div>

<script type="text/javascript" src="react-markdown-opt-bundle.js"></script>
</body>
</html>
60 changes: 60 additions & 0 deletions docs/react-markdown/react-markdown-opt-bundle.js

Large diffs are not rendered by default.

66 changes: 66 additions & 0 deletions react-markdown/src/main/js/docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Working with objects

Javascript is remarkably flexible. When we integrate with arbitrary Javascript code in Scala.js, we need a very flexible
encoding to tag along. The encoding chosen for ScalablyTyped is the result of years of experimentation, and has
a much more dynamic feeling than what you may be used to.

Let's start with an example of a type definition we want to use:

```scala
@js.native
trait Point extends StObject {

var x: Double = js.native

var y: Double = js.native
}
object Point {

@scala.inline
def apply(x: Double, y: Double): Point = {
val __obj = js.Dynamic.literal(x = x.asInstanceOf[js.Any], y = y.asInstanceOf[js.Any])
__obj.asInstanceOf[Point]
}

@scala.inline
implicit class PointMutableBuilder[Self <: Point] (val x: Self) extends AnyVal {

@scala.inline
def setX(value: Double): Self = StObject.set(x, "x", value.asInstanceOf[js.Any])

@scala.inline
def setY(value: Double): Self = StObject.set(x, "y", value.asInstanceOf[js.Any])
}
}
```

We notice several things:
- it's a `@js.native` trait, so we cannot `new` it ourselves. This can be [`changed`](conversion-options.md#stenablescalajsdefined), but it's not recommended.
- it has two required members (`x` and `y`). Optional members would typically be wrapped in `js.UndefOr`
- it has an `object` with syntax to help us work with it
- the entire syntax is built on mutability. It's Javascript, after all. more on that further down

### Basic usage

```scala
// At construction time we need to supply all required parameters
val p = Point(x = 1,y = 2)

// we can mutate what we have
// this is equivalent to typescript `p.x = 3
val p2 = p.setX(3)

// or we can duplicate and then mutate.
// this is equivalent to typescript `const p2 = {...p, x: 3}
val p3 = p.duplicate.setX(3)

// we can combine with other javascript objects.
// this is equivalent to javascript `const p3 = {...p, {}}`
val p4: Point with TickOptions = p.combineWith(TickOptions())

// fallback, if the type definitions are wrong or for any other reason you can break the contract
val p5: p.duplicate.set("x", "foo")

// you can also set any other property
val p6: p.duplicate.set("x2", "foo")
```
12 changes: 12 additions & 0 deletions react-markdown/src/main/js/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>React-markdown demo</title>
</head>
<body>
<div id="container"></div>

<script type="text/javascript" src="react-markdown-fastopt-bundle.js"></script>
</body>
</html>
49 changes: 49 additions & 0 deletions react-markdown/src/main/scala/demo/DocPage.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package demo

import japgolly.scalajs.react.component.ScalaFn.Component
import japgolly.scalajs.react.raw.React.{ElementType, Node}
import japgolly.scalajs.react.vdom.html_<^._
import japgolly.scalajs.react.{CtorType, ScalaFnComponent}
import org.scalablytyped.runtime.StringDictionary
import org.scalajs.dom.raw.XMLHttpRequest
import typings.react.mod.{EffectCallback, useEffect, useState}
import typings.reactMarkdown.components.ReactMarkdown
import typings.reactMarkdown.mod.{ReactMarkdownProps, ReactMarkdownPropsBase}
import typings.reactSyntaxHighlighter.components.{Light => SyntaxHighligther}
import typings.reactSyntaxHighlighter.mod.Light
import typings.reactSyntaxHighlighter.{scalaMod, stylesHljsMod}

import scala.scalajs.js


object DocPage {

val docFile = "./docs/README.md"

Light.registerLanguage("scala", scalaMod.default)

class LanguageValue(val language: String, val value: String) extends js.Object

val codeRender: js.Function1[LanguageValue, Node] =
rp => SyntaxHighligther.style(stylesHljsMod.darcula).language(rp.language)(rp.value).build.rawElement

val component: Component[Unit, CtorType.Nullary] = ScalaFnComponent[Unit] { _ =>
val js.Tuple2(document, setDocument) = useState[Option[String]](None)

useEffect((() => {
val xhr = new XMLHttpRequest
xhr.onload = _ => {
setDocument(Some(xhr.responseText))
}
xhr.open("GET", docFile)
xhr.send()
}): EffectCallback, js.Array(docFile))

val props = ReactMarkdownPropsBase()
.setRenderers(StringDictionary("code" -> codeRender).asInstanceOf[StringDictionary[ElementType]])
.asInstanceOf[ReactMarkdownProps]

ReactMarkdown(props)(document)

}
}
11 changes: 11 additions & 0 deletions react-markdown/src/main/scala/demo/Main.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package demo

import org.scalajs.dom

// https://stackblitz.com/edit/react-syntax-highlighter-issue-js
// https://github.com/remarkjs/react-markdown#use-custom-renderers-syntax-highlight
object Main {

def main(args: Array[String]): Unit =
DocPage.component().renderIntoDOM(dom.document.getElementById("container"))
}
Loading

0 comments on commit ba3960e

Please sign in to comment.