
Security News
Deno 2.2 Improves Dependency Management and Expands Node.js Compatibility
Deno 2.2 enhances Node.js compatibility, improves dependency management, adds OpenTelemetry support, and expands linting and task automation for developers.
A 8kb
reactive user interface library.
Evolui magically understands Observable and Promises and takes care of refreshing your UI when they emit new values. You can only care about where the data should be displayed.
npm install evolui
import html, { render } from 'evolui'
const delay = ms => new Promise(resolve => setTimeout(resolve, ms))
render(
html`
<p>
Hello, ${delay(1000).then(() => 'World!')}
</p>
`,
document.body
)
import html, { render } from 'evolui'
import { Observable } from 'rxjs'
render(
html`
<p>
Hello, ${Observable.interval(1000)
.take(4)
.map(index => ['.', '..', '...', 'World!'][index])}
</p>
`,
document.body
)
The main goal of evolui is to make dealing with observables as easy as dealing with regular values.
Observables are a great way to represent values that change over time. The hard part though is combining them. This is where evolui comes in handy. It understands any combination of Array
s, Promise
s and Observable
s, so you never have to worry about the way you should combine them before putting them inside your template.
const getCharacterName = id =>
fetch(`https://swapi.co/api/people/${id}`)
.then(res => res.json())
.then(character => character.name)
html`
<div>
${'' /* this will return an array of observables. */}
${'' /* Don't panic! evolui understands that as well */}
${[1, 2, 3].map(
id => html`
<h1>${Observable.fromPromise(getCharacterName(id)).startWith(
'Loading...'
)}</h1>
`
)}
</div>
`
Evolui lets you organize your code in components.
Components are defined as a simple function of Observable Props -> Observable VirtualDOM
:
import html, { createState, render } from 'evolui'
const Button = props$ =>
props$.map(
({ text, onClick }) => html`
<button class="Button" onClick=${onClick}>
${text}
</button>
`
)
const App = () => {
const state = createState({ count: 0 })
return html`
<div>
<${Button}
text="-"
onClick=${() => state.count.set(c => c - 1)}
/>
count: ${state.count}
<${Button}
text="+"
onClick=${() => state.count.set(c => c + 1)}
/>
</div>
`
}
render(App(), document.body)
Evolui exports a spring animation helper called ease.
ease: (stiffness: number, damping: number) => number => Observable<number>
You just have to add .switchMap(ease(<stiffness>, <damping>))
to any of your observable to make it animated.
import html, { render, ease } from 'evolui'
import { Observable } from 'rxjs'
const position$ = new Observable(observer => {
observer.next({ x: 0, y: 0 })
window.addEventListener('click', e => {
observer.next({ x: e.clientX, y: e.clientY })
})
})
render(
html`
<div>
<div
class="circle"
style="transform: translate(
${position$.map(m => m.x).switchMap(ease(120, 18))}px,
${position$.map(m => m.y).switchMap(ease(120, 18))}px
);" />
</div>
`,
document.body
)
import { text } from 'evolui'
const style$ = text`
position: absolute;
transform: translate(${x$}px, ${y$}px);
`
import html from 'evolui'
const App = () => html`
<div style="${style$};" />
`
import { render } from 'evolui'
render(App(), document.body)
import { ease } from 'evolui'
import { Observable } from 'rxjs'
Observable.interval(1000)
.switchMap(ease(120, 20))
.forEach(x => console.log(x)) // every values will be interpolated
import html, { createState, render } from 'evolui'
const App = () => {
const state = createState({ count: 0 })
return html`
<button onClick=${() => state.count.set(c => c + 1)}>
you clicked ${state.count} times!
</button>
`
}
render(App(), document.body)
Each key on your initial state will be transformed into a stream, with a special set
method on it.
set
can take either a value or a mapper function.
const state = createState({ count: 0 })
const reset = () => state.count.set(0)
const add1 = () => state.count.set(c => c + 1)
import { all } from 'evolui'
const z$ = all([x$, y$]).map(([x, y]) => x + y)
html`
<div
mount="${el => console.log('mounted!', el)}"
update="${el => console.log('updated', el)}"
unmount="${el => console.log('will unmount!', el)}" />
`
To jump to the code, visite the example
folder.
If you find this interesting and you want to contribute, don't hesitate to open an issue or to reach me out on twitter @GabrielVergnaud!
FAQs
Observable powered templates for asynchronous UIs
The npm package evolui receives a total of 5 weekly downloads. As such, evolui popularity was classified as not popular.
We found that evolui demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Deno 2.2 enhances Node.js compatibility, improves dependency management, adds OpenTelemetry support, and expands linting and task automation for developers.
Security News
React's CRA deprecation announcement sparked community criticism over framework recommendations, leading to quick updates acknowledging build tools like Vite as valid alternatives.
Security News
Ransomware payment rates hit an all-time low in 2024 as law enforcement crackdowns, stronger defenses, and shifting policies make attacks riskier and less profitable.