💫 rilti.js 💫
a small flavorful and unapologetic library built for the modern web
currently in beta phase and potentially subject to breaking changes
Feel free to fork or raise issues. Constructive criticism is always welcome
- 🐫 Loadbearing Spirit - Expressive DOM generation and custom-element components sans polyfill
- 🐱 Lion - Simple and fearless element/component data-binding
- 👶 Child - Proxy enhanced DOM manipulation and Powerful all accepting async Rendering System
features
- elm-like ideas about architecture
- flexible declarative programming style
- node lifecycle hooks
- observe attributes
- generate all your dynamic/interactive/transient elements
- program without concern for page load state
- components aka. custom-elements. No polyfill needed!
- vue-like directives aka custom attributes
- great dom manipulation functions
- composition & currying
- powerful emitter system (pub/sub with proxy magic)
- no classes, no this, no extra fuzz, functional positive
- no old javascript, we use modern features like Proxy
- a gziped rilti.min.js weighs > 7kb
To use rilti just download /dist/rilti.min.js and pop it in a script tag. If you have any issues just tell me, I'm on it.
Install
yarn add rilti
npm i rilti
or
The Dao of Rilti
- Nominalism Good | Explicit Paradigms, Patterns & Universalism Bad
- More than one way of doing things, what is right/best is always contextual.
- No Explicit Object Orientation anything (no classes or this)
- simple functions and objects before imposing rigid structures
- Reserve identities only for things that would be otherwise obscure
- Don't hide things, let them be what they are
- Nothing for the sake of itself, no postmodern sollutions.
- Logic is just data (with potential) so pass it around too
- Factory-Functions always
- Mess With the DOM, it's alive
- Selectors & Templates? No, treat HTML as Mutable Object Holons
- Plain HTML is for simple websites, where state is not as complex
- DOM generation and components are for Apps and the modern interactive Web.
- MASA: Minimal API Surface Area.
- Polymorphic functions/functions-as-class-like-objects
- Infer Info with Good API Design before creating 12 parameter long functions.
- Use configurable Objects create dynamic APIs
- Some APIs can often be reduced to a fn e.g. Get: fn(key), Set: fn(key, val), Del: fn(key, nil)
- As Functional As Possible
- Perspectivism vs Pragmatism, people won't always use an API the same way.
- Leave some internals or lower level API features accessible for extendibility
Different strokes for different folks:
Also look at rilti.on
which can be used like this on['any-event'](node, func, =options)
,
as well as like this on('any-event', node)(func, =options)
and also on(node, { click: e => {} }, =options)
.
examples of rilti used to build things
- Rilti News - Progressive Web App
- Todo-list
- Javascript calculator
- Emil Cioran - Simple Tribute Page
- rilti-todomvc
- grimstack.io blog site
- grimstack.io/portfolio WIP Portfolio don't look
future plans
- offer collection of useful optional plugins
- stabalize features and release
- expand with a UI library
Example time!
Click Counting Button
const component componentReady dom: h1 = rilti
Two Button Counter
const databind dom: button div h1 = rilti div
Pointer tracker
riltidomdiv
the above produces this:
Pointer is at (0x, 0y)
Declaratively Generate a Site Navbar
Stop writing html (yes JSX too)! Just generate everything, it's so simple.
const a button h1 header nav section = riltidom section
The above produces this html
My Wicked Website Home Blog About Contact Github
API
method | description |
---|---|
.dom(tag, =options, ...children) |
where the magic happens, define behavior for elements and see them come to life |
.dom["any-tag"](=options, ...children) |
pre-bound tag version of .dom |
.query(string, Selector/Node) |
improved alternative to document.querySelector |
.queryAll(string, Selector/Node) |
improved alternative to document.querySelectorAll |
.queryAsync(string, func, Selector/Node) |
same as querySelector but async, good for pre-load logic |
.queryEach(string, Selector/Node, func) |
queries nodes returned by selector and iterates over them like .forEach would |
.dom.frag(=string) |
create a fragment or convert html text to nodes |
.on(target, type, listener, =options) |
generates event listener |
.once(target, type, listener, =options) |
generates event listener that triggers only once |
.curry(func, =argsLimit) |
curries a function |
.component(tag, {create, mount, unmount, attr, props, methods}) |
define custom elements, no polyfills needed |
.each(iterable, func) |
loop through objects, numbers, array(like)s, sets, maps... |
.extend(hostObj, obj, =safeMode) |
extends host object with all props of other object, won't overwrite if safe is true |
.flatten(arraylike) |
flattens multidimensional arraylike objects |
.render(AlmostAnything, Selector/Node, =connector = 'appendChild') |
renders things, independent of ready state |
.run(func) |
asynchronously executes a given function when the DOM is loaded |
.runAsync(func, ...args) |
run a function asynchronously |
.isMounted(node, =parentNode) |
determines whether or not the dom or other node contains a specific node |
rilti also exports a couple of useful Type-Testing functions
usage : rilti.isX( {any} ) // -> boolean
isArr, isNil, isDef, isObj, isFunc, isBool, isStr, isNum, isArrlike, isNodeList, isNode, isPrimitive, isPromise, isRenderable, isRegExp, isInput, isEmpty, isEl
DOM manipulation
rilti contains a domfn
that contains several useful dom manipulation functions.
these fucntions will all return the node passed as the first argument unless specified
otherwise such as with has/get(this/that) type functions
const attach css // (node, stylePropery, val) || (node, { styleProp:'4em' }) set element.style properties class // (node, class, =state) add/remove or toggle classes hasClass // (node, class) -> bool attr // (node, attrNameOrObj, =value): attr(el, 'href', '/') or attr(el, 'href') -> '/' removeAttribute // (node, ...attrNames) removes attributes hasAttr // hasAttr(node, attrName) -> bool attrToggle // (node, attrName, state = !hasAttr, =val = getAttr(name) || '') emit // (node, {type string/Event/CustomEvent}) dispatchEvents on node append prepend appendTo prependTo // (node, selectorOrNode) remove // (node, =afterMS) // remove node or remove after timeout} = riltidomfn
everything found in rilti.domfn will be available as:
rilti.$(Node).domfnMethod(...args)
const contentCard = async { const card = riltidomdiv // <- <div class="card"></div> card // add class .hidden if hidden === true cardclasshidden = hidden // <- this works too cardattr'aria-hidden' = hidden // set attribute card card try const res = await card cardon catch e card console }
Create Elements with Any Tag
dom['any-arbitrary-tag'](=options, ...children) -> Node/Element
dom'random-tag' // <- <random-tag class="with random chainable classes">withrandom'chainable'classes // render to dom using selectors or nodes render: '.main > header' // add attributes attr: contenteditable: true // set classes class: 'card active' // or class: 'card' 'active' // or conditionally class: card: true active: false // active won't be added // some styles? css: boxShadow: '0 2px 6px rgba(0,0,0,.12)' '--highlight-color': 'crimson' // ^- oh yeah, css variables work too // attach properties to the element props: oldtxt: '' // create property get/set traps accesors: contents: eltxt eltxt = val // or as one function { if val == null return eltxt eltxt = val } // plain getter/setters work too { return thisinnerText } { thisinnerText = val } methods: // el will be pre-bound upon execution // think of it like self in python classes // or rust struct methods { eloldtxt = eltxt elcontents = 'Sure you want to remove random-tag?' } { elcontents = eloldtxt } // listen for events on: { } { } // if there's just one listener then use: // once/onxevent: fn instead of once: { evt: fn } { el } // manage the element's lifecycle cycle: { /*...*/ } { /*...*/ } { /*...*/ } { /*...*/ } ...children // [], "", =>, Node, NodeList : should all render
Directives / Custom Attributes
// observe attributes with vue-like directivesrilti// revoke a directiveriltidirectives
Web Components / Custom Elements, no polyfills needed
rilti
weight
- unminified: 45.9kb
- minified: 18.9kb
- minified && compressed: 7.21kb