! Attention: This whole repo is automatically generated !
Building, linting and unit tests can be found in original repo:
https://github.com/eirikb/domdom
This repo exists only for pure Deno support.
It makes domdom available without use of pika.dev or jspm!
Usage with Deno
index.tsx
import domdom from 'https://deno.land/x/domdom';
const { React, data, append } = domdom();
append(document.body, ({ on }) => <div>Hello {on('test')}</div>);
data.set('test', 'World!');
tsconfig.json
{
"compilerOptions": {
"lib": ["dom", "esnext"],
"noImplicitAny": false
}
}
Original readme below here
The proactive web framework for the unprofessional
domdom is an alternative to React + Redux or Vue + Vuex, with support for routing.
Thereâs no virtual dom.
Install
npm i @eirikb/domdom
Getting started
index.html
<body><script src="app.jsx"></script></body>
app.jsx
import domdom from '@eirikb/domdom'
const dd = domdom()
const view = ({ on }) => <div>Hello, {on('name')}</div>
dd.append(document.body, view)
dd.set('name', 'world!')
Run
npx parcel index.html
Recipes
How to handle common tasks with domdom
Routing
const view = ({ when }) => <div>
{when('route', [
'login', () => <Login/>,
'welcome', () => <Welcome/>,
]).or('Loading app...')}
</div>
function gotoRoute(route) {
window.location.hash = route
}
window.addEventListener('hashchange', () =>
dd.set('route', window.location.hash.slice(1))
)
Login form
function login(event) {
event.preventDefault()
fetch('/login', {
method: 'post',
body: new URLSearchParams(new FormData(event.target))
})
}
const view = () => <form onSubmit={login}>
<input name="username"/>
<input name="password" type="password"/>
<button type="submit">Login</button>
</form>
Split view and data
data.js
export default ({ on, set }) => {
on('= search', event => {
event.preventDefault()
const searchText = event.target.search.value
set('result', `Data for ${searchText} here...`)
})
}
index.jsx
import data from './data'
import domdom from '@eirikb/domdom'
const dd = domdom()
data(dd)
const view = ({ on, trigger }) => <form onSubmit={e => trigger('search', e)}>
<input type="search" name="search"/>
<button type="submit">Search</button>
{on('result', _ => _)}
</form>
dd.append(document.body, view)
Animation (garbage collection)
At writing moment domdom doesnât have any unmount callback.
Iâm not a big fan of destructors, unmounted, dispose or similar.
This might seem silly, and it might not be obvious how to use say setInterval
,
without this preventing the element from ever being cleaned up by garbage collector.
The idea is to use dd
for such things, as these listeners are automatically cleaned up.
const view = ({ on, get, set }) => {
const img = <img src="https://i.imgur.com/rsD0RUq.jpg"/>
on('tick', time => img.style.transform = `rotate(${time % 180}deg)`)
return <div>
<button onClick={() => set('run', !get('run'))}>Start/Stop</button>
{img}
</div>
}
(function loop(time) {
if (dd.get('run')) {
dd.set('tick', time)
}
requestAnimationFrame(loop)
})(0)
API
The domdom object (from domdom()
, called dd
above) extends from @eirikb/data.
All data functions are available,
on
off
get
set
unset
trigger
, so itâs possible to do things like:
dd.on('!+* a', a => console.log(a))
dd.set('a', 'yes')
The only function in addition is append
, which is for appending a view to a parent element.
const viewFunction = () => <div></div>
const parentElement = document.querySelector('#app')
dd.append(parentElement, viewFunction)
Elements
All elements created with jsx, in the context of domdom, are elements which can be instantly referenced.
const element = <div>Behold!</div>
element.style.color = 'red'
âComponentsâ
By creating a function you create a component.
function MyComponent({ on })âŻ{
return <ul>
{on('players.$id.name', name => <li>Player {name}</li>)}
</ul>
}
Children / Composition
Content of a component will be passed as children
.
function Button({ children }) {
return <button>{children}</button>
}
const view = () => <div>
<Button>
<b>Hello</b>
</Button>
</div>
Events
All attributes starting with âonâ are added to addEventListener
on the element.
function MyButton({trigger}) {
return <button onClick={() => trigger('Clicked!')}>Click me!</button>
}
on(path, callback)
Similar to data.on
, except without flags.
Note that on
triggers on change in accordance with data.on
, and itâs not âtrueyâ/âfalseyâ, in order
for elements to be removed one must use dd.unset
.
callback
is optional, if omitted the result will be returned as-is,
either as string or JSON of object.
const view = ({ on }) => <ul>
{on('players.$id.name', name => <li>Player {name}</li>)}
{on('info')}
</ul>
when(path, oddEvenArrayOfCheckAndResult)
Heard of pattern matching? This isnât it
const view = ({ when }) => <div>
{when('route', [
'home', () => <div>Home!</div>,
'away', () => <div>Away!</div>,
route => (route || '').startsWith('eh'), () => <div>Eh?</div>,
false, () => <div>Route is literally boolean false</div>
])}
</div>
or
Neither on
or when
will trigger unless there is a value on the path, in order to show something at all
until some value is set or
must be used.
const view = ({ when }) => <div>
{when('routing', [
'home', () => <div>Home!</div>
]).or(<div>Loading app in the fastest possible way...</div>)}
</div>
dd-model
This is a convenience hack for putting data into and out of a data path from an input.
Similar to v-model and ng-model.
Suggest not using this if possible, using forms directly like in recipes is much better.
dd.on('= search', event => {
event.preventDefault()
dd.set('result', `Data for ${dd.get('text')} here...`)
})
const view = ({ when, on, trigger }) => <form onSubmit={e => trigger('search', e)}>
<input type="search" dd-model="text"/>
<input type="checkbox" dd-model="more"/>
{when('more', [
true, () => 'This is more'
])}
Current text: {on('text')}
<button type="submit">Search</button>
{on('result', _ => _)}
</form>
Attributes
Itâs possible to use on
directly on attributes.
It might feel and look a bit quirky, but there it is.
const view = ({ on, set, get }) => <div>
<button onClick={() => set('toggle', !get('toggle'))}>Toggle</button>
<button disabled={on('toggle').or(true)}>A</button>
<button disabled={on('toggle', res => !res)}>B</button>
</div>;