Skip to content

Commit

Permalink
docs: Add api documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
Nefsen402 committed Mar 23, 2024
1 parent 873df10 commit 0602363
Show file tree
Hide file tree
Showing 2 changed files with 281 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

This is a dom manipulation library built on destam. This library does not use a virtual dom and its purpose is to provide a binding from mutation events that happen through the destam state manager to then manipulate the dom. This library is designed to be as simple as possible. It does not provide any filtering of events to account for browser differences or any magic regarding node attributes. This is designed to be a base for other libraries to build on top of to provide those creature comforts.

See the [documentation](doc.md)

## Basic counter
```js
const count = Observer.mutable(0);
Expand Down
279 changes: 279 additions & 0 deletions doc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
destam-dom is designed to be as simple as possible and only provides two functions:
- mount
- html

## mount
`mount()` is the entry point for destam-dom to then mount anything it needs onto the real dom. Typically, a mount point of `document.body` will be enough for applications fully written with destam-dom. Let's see a basic example where we mount some text onto the body of the page:

```js
mount(document.body, "Hello, world!");
```

`mount()` also supports mounting to null. This can be useful if you want destam to manage the dom elements, but otherwise you want to mount it yourself.

```js
const div = document.createElement('div');

mount(null, html`
<${div}>Hello, world!</>
`);

document.body.appendChild(div);
```

Mount supports:
- Strings
- Html nodes
- Arrays (common references will be reconciliated)
- Any iterable
- Numbers
- booleans (will be rendered as the string true/false)
- `null`
- Functions (these functions are not the same as what you would see for custom elements, but internally used functions that `html()` generates)

## html
`html()` is meant to be used with tagged template literals and provides an easy and build-free way to start creating complex dom structures in javascript. Note that for cases like the `br` element, you will have to close those manually.

```js
html`
<div>
<p>
This is my website!
</p>
<p>
Welcome visitor!
</p>
</div>
`
```

However, we add one addition to destam-dom's flavour of html. In javascript, it's useful to have access to the raw element node because a lot of browser interfaces exist as properties on it. Suppose we are using an `input`. `input` does not understand `value` as an attribute, instead `value` has to be accessed on the element reference directly like so:

```js
const input = document.createElement('input');
input.value = 'my value';
```

destam-dom provides a way set these values without breaking out the elements yourself. This is done by prefixing the attribute with `$`. `$` was chosen because it is compatible with existing jsx parsers.

```js
html`
<input $value="my value" />
`
```

## Event listeners

Event listeners are managed the same way. In javascript, there are two ways of creating event listeners. One is to use `addEventListener` and another is to set your listener function on the element itself like so:


```js
const button = document.createElement('button');
button.onclick = () => console.log("button was clicked!");
```

This is the way that destam-dom manages event listeners:

```js
html`
<button $onclick=${() => console.log("button was clicked!")}>Click me!</button>
`
```

Tying this all together, an html definition like this:

```js
html`
<input autofocus $value="input field" $oninput=${e => console.log(e.target.value)} />
`
```
would provide an element that is equivilent of this vanilla js:
```js
const input = document.createElement('input');
input.setAttribute('autofocus', true);
input.value = 'input field';
input.oninput = e => console.log(e.target.value);
```

Styles are also managed this way. With javascript, a style could be changed:
```js
const button = document.createElement('button');
button.style.background = 'red';
```
This is achieved in destam-dom:
```js
html`
<button $style=${{
background: 'red'
}} />
`
```

## Reactivity
Any part of the template literal can be replaced with an expression for reactivity.

```js
const name = Observer.mutable('visitor');

getUserAuthentication().then(name_ => {
name.set(name_);
});

html`
<div>
<p>
This is my website!
</p>
<p>
Welcome ${name}!
</p>
</div>
`
```

Element names can even be expressions! This acts as the way for destam-dom to create refs like in React. In React, because it uses a virtual dom, refs need to have special handling. Because we don't use a virtual dom, we can pass raw html elements directly around.

```js
const div = document.createElement(div);

html`
<${div} />
`
```

## Custom elements

Element names don't just have to be a reference to an html node, they can also be functions to create custom elements.

```js
const Header = () => {
return "This is my header!";
};

html`
<${Header} />
`
```

Note that custom elements can return whatever value is supported by `mount()`.

Custom elements in destam-dom are inspired by functional elements in [React](https://react.dev/). Properties are passed the same way as we would in react:

```js
const Header = ({text}) => {
return text;
};

html`
<${Header} text="This is my header!" />
`
```

Like React, a special cased `children` property is used for the children of an element.

Note that destam-dom special cases the property names:
- children
- each

Every other property name can be used for arbitrary purposes.

```js
const Header = ({children}) => {
return children;
};

html`
<${Header}>
This is my header!
</>
`
```

## Lists

Custom elements are also the basis of how destam-dom manages rendering a list of items with an arbitrary format. Suppose we have this data that we want to render:

```js
const names = [
'Bob',
'Bill',
'Jane',
];
```

The `each` element property can be used to iterate a list and transform the list into html elements at the same time with a custom element. In the custom component, the `each` property will no longer be the list, but instead an element of the list.

```js
const Name = ({each: name}) => {
return name;
};

html`
<${Name} each=${names} />
`
```

Note that destam-dom will compare by reference every value in each to try to reduce rendering nodes. For instance, if `names` was an observer itself, that observer could be updated with a different list and if there are common elements between the old list and the new one, existing element mounts will be reused.

```js
const names = Observer.mutable([
'Bob',
'Bill',
'Jane',
]);

const Name = ({each: name}) => {
return name;
};

html`
<${Name} each=${names} />
`

names.set([...names.get(), 'Ford']);
```

In this example, the `Name` custom component will be involked only 4 times. Note that the above example can be further optimized by using an `OArray` provided by destam.

```js
const names = OArray([
'Bob',
'Bill',
'Jane',
]);

const Name = ({each: name}) => {
return name;
};

html`
<${Name} each=${names} />
`

names.push('Ford');
```

The optimization here will let destam-dom not need to compare references, but instead just directly the new name in constant time. Prefer these kinds of arrays.

## JSX
JSX support is provided from the `transform/htmlLiteral` file. This can be hooked up to any build system with a vite example being provided in this repository.

The JSX will be similar the html template literals except when it comes to templating node values. Custom elements and html nodes must be capitalized for the build system to understand that a browser html node is not desired, but instead should be a reference.
```jsx
const Website = () => {
return <p>
Welcome to my website!
</p
};

mount(document.body, <Website />);
```

or for refs:
```jsx
const Div = document.createElement('div');

mount(document.body, <Div />);
```

0 comments on commit 0602363

Please sign in to comment.