Skip to content

Commit

Permalink
docs: add kitchen sink example
Browse files Browse the repository at this point in the history
  • Loading branch information
Luke-zhang-04 committed Apr 8, 2024
1 parent 2e9a8ae commit 88708c0
Show file tree
Hide file tree
Showing 10 changed files with 763 additions and 74 deletions.
237 changes: 174 additions & 63 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,99 +63,210 @@ With a CDN

## Kitchen Sink Example

Sorta. There's way more you can do with DeStagnate. See [https://luke-zhang-04.github.io/DeStagnate](https://luke-zhang-04.github.io/DeStagnate) for example code and documentation.
See [luke-zhang-04.github.io/DeStagnate/kitchen-sink.html](https://luke-zhang-04.github.io/DeStagnate/kitchen-sink.html) for working demo.

```tsx
const divRef = DeStagnate.createRef<HTMLDivElement>()
import * as DeStagnate from "../../.."

document.getElementById("my-container")?.appendChild(
// `createElement` can be abbreviated to `ce`
DeStagnate.createElement(
DeStagnate.Fragment,
null,
DeStagnate.createElement(
"div",
const width = 250

// Class which contains reference to some SVG rectangle and a value that is stateful
class RectState extends DeStagnate.StateContainer<number, SVGRectElement | null> {
constructor() {
super(0)
}

// Define what an update should do
updateDOM(rectRef: DeStagnate.Ref<SVGRectElement>) {
// Use the bindProps helper function to update the x value of the rectangle and change its colour
DeStagnate.bindProps(
rectRef.current,
{
class: "my-class",
ref: divRef,
onMyCustomEvent: (event: Event) => console.log(event),
x: this.value.toString(),
fill: this.value % 2 === 0 ? "#0D6EFD" : "#28A745",
},
DeStagnate.createElement(
"p",
null,
"My paragraph",
DeStagnate.createElement("i", null, " italic"),
),
),
true,
)
}
}

createElement: {
const rectState = new RectState()
const divRef = DeStagnate.createRef<HTMLDivElement>()

const ReactiveRect: DeStagnate.FC<{state: RectState}> = () =>
DeStagnate.createElement(
"button",
"svg:svg",
{
onClick: (event) =>
divRef.current?.dispatchEvent(
new CustomEvent("mycustomevent", {detail: event}),
),
width: width * 2,
height: width,
viewBox: `0 0 ${width * 2} ${width}`,
fill: "none",
},
"Click me!",
DeStagnate.createElement("svg:rect", {
width,
height: width,
fill: rectState.value % 2 === 0 ? "#0D6EFD" : "#28A745",
x: rectState.value,
ref: rectState.ref,
}),
)

document.getElementById("my-container-1")?.appendChild(
// `createElement` can be abbreviated to `ce`
DeStagnate.createElement(
DeStagnate.Fragment,
null,
DeStagnate.createElement(
"div",
{
class: "my-class",
ref: divRef,
onMyCustomEvent: (event: Event) => {
console.log(event)
rectState.update(rectState.value + 25)
},
},
DeStagnate.createElement(
"p",
null,
"My paragraph",
DeStagnate.createElement("i", null, " italic"),
),
),
DeStagnate.createElement(
"button",
{
onClick: (event) =>
divRef.current?.dispatchEvent(
new CustomEvent("mycustomevent", {detail: event}),
),
class: "btn btn-secondary mr-3",
},
"Click me!",
),
DeStagnate.createElement(ReactiveRect, {state: rectState}),
),
),
)
)
}

// Alternatively, you can use JSX. You will need a tranpiler, though.
document.getElementById("my-container")?.appendChild(
<>
<div class="my-class" ref={divRef} onMyCustomEvent={(event: Event) => console.log(event)}>
<p>
My paragraph
<i> italic</i>
</p>
</div>
<button
onClick={(event) =>
divRef.current?.dispatchEvent(new CustomEvent("mycustomevent", {detail: event}))
}
jsx: {
const rectState = new RectState()
const divRef = DeStagnate.createRef<HTMLDivElement>()

const ReactiveRect: DeStagnate.FC<{state: RectState}> = () => (
<svg:svg
width={width * 2}
height={width}
viewBox={`0 0 ${width * 2} ${width}`}
fill="none"
>
Click me!
</button>
</>,
)
<svg:rect
width={width}
height={width}
fill={rectState.value % 2 === 0 ? "#0D6EFD" : "#28A745"}
x={rectState.value}
ref={rectState.ref}
/>
</svg:svg>
)

document.getElementById("my-container-2")?.appendChild(
<>
<div
class="my-class"
ref={divRef}
onMyCustomEvent={(event: Event) => {
console.log(event)
rectState.update(rectState.value + 25)
}}
>
<p>
My paragraph
<i> italic</i>
</p>
</div>
<button
onClick={(event) =>
divRef.current?.dispatchEvent(
new CustomEvent("mycustomevent", {detail: event}),
)
}
class="btn btn-secondary mr-3"
>
Click me!
</button>
<ReactiveRect state={rectState} />
</>,
)
}

// Using vanilla DOM methods:
const container = document.getElementById("my-container")
const div = document.createElement("div")
vanillaDOM: {
const svgURI = "http://www.w3.org/2000/svg"
let rectStateValue = 0

const container = document.getElementById("my-container-4")
const svg = document.createElementNS(svgURI, "svg")

svg.setAttributeNS(null, "width", (width * 2).toString())
svg.setAttributeNS(null, "height", width.toString())
svg.setAttributeNS(null, "viewBox", `0 0 ${width * 2} ${width}`)
svg.setAttributeNS(null, "fill", "none")

div.classList.add("my-class")
div.addEventListener("mycustomevent", (event) => console.log(event))
const rect = document.createElementNS(svgURI, "rect")

const paragraph = document.createElement("p")
rect.setAttributeNS(null, "width", width.toString())
rect.setAttributeNS(null, "height", width.toString())
rect.setAttributeNS(null, "fill", rectStateValue % 2 === 0 ? "#0D6EFD" : "#28A745")
rect.setAttributeNS(null, "x", rectStateValue.toString())
svg.appendChild(rect)

paragraph.innerText = "My paragraph"
const div = document.createElement("div")

const italic = document.createElement("i")
div.classList.add("my-class")
div.addEventListener("mycustomevent", (event) => {
console.log(event)
rectStateValue += 25
rect.setAttributeNS(null, "fill", rectStateValue % 2 === 0 ? "#0D6EFD" : "#28A745")
rect.setAttributeNS(null, "x", rectStateValue.toString())
})

italic.innerText = " italic"
const paragraph = document.createElement("p")

paragraph.appendChild(italic)
div.appendChild(paragraph)
container?.appendChild(div)
paragraph.innerText = "My paragraph"

const button = document.createElement("button")
const italic = document.createElement("i")

button.addEventListener("click", (event) =>
div.dispatchEvent(new CustomEvent("mycustomevent", {detail: event})),
)
button.innerText = "Click me!"
italic.innerText = " italic"

container?.appendChild(button)
paragraph.appendChild(italic)
div.appendChild(paragraph)
container?.appendChild(div)

const button = document.createElement("button")

button.addEventListener("click", (event) =>
div.dispatchEvent(new CustomEvent("mycustomevent", {detail: event})),
)
button.innerText = "Click me!"
button.className = "btn btn-secondary mr-3"

container?.appendChild(button)
container?.appendChild(svg)
}
```

## Alternatives

- Why not just `innerHTML`?
- You're missing dev tool support, it's a big security risk, and you'll have to deal with character escaping. Not fun. Mike Bostock goes over why `innerHTML` is bad in the [HTL README](https://github.com/observablehq/htl?tab=readme-ov-file#why-not-concatenate).
- What about [HTL](https://www.npmjs.com/package/htl)?
- HTL is cool, but it involves an HTML parser at runtime, which makes it quite slow. You also lose devtool support whren working with strings. One upside though, you don't need to transpile to create DOM using XML-like syntax.
- HTL is cool, but it involves an HTML parser at runtime, which makes it quite slow. You also lose devtool support when working with strings.
- Upside: you don't need to transpile to create DOM using XML-like syntax. However you can use HTM (see [#using-htm](#using-htm)) with DeStagnate and it will be faster.
- What about [VHTML](https://github.com/developit/vhtml)?
- VHTML generates strings which you can safely add to the DOM with `innerHTML`. Unfortunately this has the drawback of not supporting refs or event listeners, which is extremely limiting.
- Why not just `innerHTML`?
- You're missing dev tool support, it's a big security risk, and you'll have to deal with character escaping. Not fun. Mike Bostock goes over why `innerHTML` is bad in the [HTL README](https://github.com/observablehq/htl?tab=readme-ov-file#why-not-concatenate).

## Using HTM

Expand Down
2 changes: 1 addition & 1 deletion docs/public/calculator.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

<div class="container">
<div class="row" id="calculator-h">
<h1 class="mt-3">Calculator example</h1>
<h1 class="mt-3">Calculator Example</h1>
<p>
This example was written with TypeScript and JSX, which needs to be compiled with the
Typscript Compiler or Babel. See <a href="using-jsx.html">using JSX</a>.
Expand Down
8 changes: 4 additions & 4 deletions docs/public/eventListener.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

<div class="container">
<div id="elistener-h">
<h1 class="mt-3">Event listener example</h1>
<h1 class="mt-3">Event Listener Example</h1>
<a
href="https://github.com/Luke-zhang-04/DeStagnate/blob/master/docs/src/examples/eventListener.js"
target="_blank"
Expand All @@ -29,7 +29,7 @@ <h1 class="mt-3">Event listener example</h1>
</div>
<div id="elistener-source">
<pre class="d-block">
<code class="language-js">
<code class="language-js">
import {createElement, createRef} from &quot;destagnate&quot;

const colors = [&quot;primary&quot;, &quot;secondary&quot;, &quot;success&quot;, &quot;info&quot;, &quot;warning&quot;, &quot;danger&quot;, &quot;light&quot;, &quot;dark&quot;]
Expand Down Expand Up @@ -58,8 +58,8 @@ <h1 class="mt-3">Event listener example</h1>
&quot;Click me!&quot;,
),
)
</code>
</pre>
</code>
</pre>
</div>
</div>
</div>
Expand Down
8 changes: 4 additions & 4 deletions docs/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

<div class="container">
<div id="nested-h">
<h1 class="mt-3">TicTacToe example</h1>
<h1 class="mt-3">TicTacToe Example</h1>
<p>
This example was written with TypeScript and JSX, which needs to be compiled with the
Typscript Compiler or Babel. See <a href="using-jsx.html">using JSX</a>.
Expand All @@ -36,7 +36,7 @@ <h1 class="mt-3">TicTacToe example</h1>
</div>
<div id="nested-source">
<pre class="d-block">
<code class="language-ts">
<code class="language-ts">
import * as DeStagnate from &quot;../../..&quot;
import {type Ref, StateContainer} from &quot;../../..&quot;

Expand Down Expand Up @@ -126,8 +126,8 @@ <h1 class="mt-3">TicTacToe example</h1>
}
}
})
</code>
</pre>
</code>
</pre>
</div>
</div>
</div>
Expand Down
Loading

0 comments on commit 88708c0

Please sign in to comment.