Given this working code:
<!DOCTYPE html>
<html lang="en">
<head>
<title>canvas test</title>
<meta http-equiv="Content-Type" content="text/html"; charset="utf-8" />
</head>
<body>
<canvas id="canvas"></canvas>
<script type="text/javascript">
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'green';
ctx.fillRect(20, 10, 150, 100);
</script>
</body>
</html>
We can write
/* file: Demo.re */
type document;
type canvas;
type context = {. [@bs.set] "fillStyle": string};
/* https://bucklescript.github.io/docs/en/object-2 */
[@bs.val] external document: document = "";
[@bs.send] [@bs.return null_to_opt]
external getElementById: (document, string) => option(canvas) = "";
[@bs.send] [@bs.return null_to_opt]
external getContext: (canvas, string) => option(context) = "";
[@bs.send] external fillRect: (context, int, int, int, int) => unit = "";
let setupContext = context => {
context##fillStyle #= "green";
fillRect(context, 20, 10, 150, 100);
};
let setupCanvas = canvas =>
switch (getContext(canvas, "2d")) {
| Some(context) => setupContext(context)
| None => Js.log("null context")
};
switch (getElementById(document, "canvas")) {
| Some(canvas) => setupCanvas(canvas)
| None => Js.log("null canvas")
};
/* file: Demo.rei */
/*
Empty interface file to avoid "exports" being generated
in Demo.bs.js
(at which point we need to get a bundler involved)
*/
So that this works
<!DOCTYPE html>
<html lang="en">
<head>
<title>canvas test</title>
<meta http-equiv="Content-Type" content="text/html"; charset="utf-8" />
</head>
<body>
<canvas id="canvas"></canvas>
<script type="text/javascript" src="Demo.bs.js"></script>
</body>
</html>
Alternately this works as well:
type document;
type canvas;
type context;
[@bs.val] external document: document = "";
[@bs.send] [@bs.return null_to_opt]
external getElementById: (document, string) => option(canvas) = "";
[@bs.send] [@bs.return null_to_opt]
external getContext: (canvas, string) => option(context) = "";
/* https://bucklescript.github.io/bucklescript/Manual.html#_binding_to_getter_setter_code_bs_get_code_code_bs_set_code */
[@bs.set] external fillStyleSet: (context, string) => unit = "fillStyle";
[@bs.send] external fillRect: (context, int, int, int, int) => unit = "";
let setupContext = context => {
fillStyleSet(context, "green");
fillRect(context, 20, 10, 150, 100);
};
let setupCanvas = canvas =>
switch (getContext(canvas, "2d")) {
| Some(context) => setupContext(context)
| None => Js.log("null context")
};
switch (getElementById(document, "canvas")) {
| Some(canvas) => setupCanvas(canvas)
| None => Js.log("null canvas")
};
And yet another option
type document;
type canvas;
[@bs.deriving abstract]
type context = {mutable fillStyle: string};
/* https://bucklescript.github.io/docs/en/object#write */
[@bs.val] external document: document = "";
[@bs.send] [@bs.return null_to_opt]
external getElementById: (document, string) => option(canvas) = "";
[@bs.send] [@bs.return null_to_opt]
external getContext: (canvas, string) => option(context) = "";
[@bs.send] external fillRect: (context, int, int, int, int) => unit = "";
let setupContext = context => {
fillStyleSet(context, "green");
fillRect(context, 20, 10, 150, 100);
};
let setupCanvas = canvas =>
switch (getContext(canvas, "2d")) {
| Some(context) => setupContext(context)
| None => Js.log("null context")
};
switch (getElementById(document, "canvas")) {
| Some(canvas) => setupCanvas(canvas)
| None => Js.log("null canvas")
};