Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/den1k/root
A recursive UI resolver
https://github.com/den1k/root
Last synced: 2 months ago
JSON representation
A recursive UI resolver
- Host: GitHub
- URL: https://github.com/den1k/root
- Owner: den1k
- Created: 2019-03-12T17:08:54.000Z (almost 6 years ago)
- Default Branch: master
- Last Pushed: 2023-01-26T17:43:05.000Z (almost 2 years ago)
- Last Synced: 2023-03-11T18:33:00.713Z (almost 2 years ago)
- Language: Clojure
- Homepage: https://den1k.github.io/root
- Size: 4.31 MB
- Stars: 10
- Watchers: 3
- Forks: 0
- Open Issues: 5
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# root
**What is root?**
root is a recursive UI resolver.
- Approaches to UI development like react.js + graphQL require UI components to __request__ data in a shape that satisfies the UI tree. This means the shape of the data is determined by the UI tree. Root takes an inverse approach where the UI tree is determined by the shape of the data.
- A major benefit of this approach is that the UI layout is thus entirely determined by data, data that can be traversed, transformed and stored in arbitrary ways and by arbitrary means.
- This is powerful for unstructured, user-determined, block-based UI's like rich documents (think Roam Research, Notion etc.) enabling queries and functions that, based on users' demands, __derive__ the optimal presentation of a document.**Does root manage state?**
No, root is agnostic to your state and state management. It cares only for a `lookup` function.
**What is developing a root like?**
root is data first. It recurses through your data resolving UI components along the way.
With data in place, it lets you develop incrementally, even for data you haven't defined components for yet.## live examples
- [minimal](https://den1k.github.io/root/minimal.html)
- [DataScript notebook](https://den1k.github.io/root/datascript.html)
- [hackernews reader](https://den1k.github.io/root/fetch.html)
- [using spec](https://den1k.github.io/root/spec-dispatch.html)
- [a struggling Notion clone in 200 LoC (reactive)](https://den1k.github.io/root/rich-document.html)## code example
Root is data-first. Without data it doesn't render.
So let's define `data` to be:```clojure
(def data
{1 {:type :user
:first-name "Eva"
:last-name "Luator"}})
```And a minimal root with a `:lookup` into data and a `:dispatch-fn` on the `:type`
key of each data-node:```clojure
(ns my-ns
(:require [root.impl.core :as rc]))(def root
(rc/ui-root
{:lookup (fn [k] (get data k))
:dispatch-fn :type
:content-keys [:content]
:content-spec integer?}))
```Rendering `[root :resolve {:root-id 1}]` results in
Note that even though we haven't defined any UI componenets, root renders a UI.
This is the `default-view` in root. It always tries to render all
keys and values on a given data node.root acts like `multimethod`. Add new components like this:
```clojure
(root :view :profile-pic
(fn [{:keys [src]}]
[:img.br-100 {:src src}]))
````:profile-pic` is the `dispatch-value`, the function is the UI component definition in hiccup.
If we now define `data` to be
```clojure
(def data
{1 {:type :user
:first-name "Eva"
:last-name "Luator"
:content {:profile-pic 3
:address 2}}
2 {:type :address
:street "1 Long Infinite Loop"}
3 {:type :profile-pic
:src "https://picsum.photos/id/1005/200"}})
```root will use `content-keys` to examine each node for child-content and when such content exists pass it to `lookup` in turn. `lookup` is expected to return a node that might again have children under `content-keys` and from there the root grows (recurses).
When lookup returns a non-nil value, root invokes it with `dispatch-fn` looking for a matching UI component. In the case of `:profile-pic` it found the component we defined above. However, for `:user` and `:address` it fell back on `default-view`.
Now the rendered result is:
[Here's](https://github.com/den1k/root/blob/master/dev/examples/minimal/views.cljc)
the full code and [live example](https://den1k.github.io/root/minimal.html). I recommend playing with it yourself.problems with current UI development conventions
- anti-ui-reuse: data-fetching inside components or through wrapper components
- **solution:** data-first. components are defined as dispatches on data but oblivious to data-origin.
- defocused UI: component tree as the result of numerous control flow decisions spread out over many components
- child-components rendered as a reaction: state change → parent-component subscription → control flow expression → child-component
- **solution:** component tree is derived from data traversal by dispatching nodes along the way. Derived component tree has broadly the same shape as the data.
- lacking oversight: dense component tree (DOM elements and css classes and elements) makes semantics unclear
- **solution:** print the (denormalized) data. Done.
- application data is invisible in the UI until components are defined and instantiated
- **solution:** Data first, incremental UI development! Render views for your data even when components for it are not yet defined.problems with root
- loose UIX dependency
- for a reactive/dynamic root: single DB in xframe doesn't currently allow for multiple roots to render within each other
- xframe (re-frame like event handling+subscription sub-lib) is overkill. Reagent ratom + cursor like abstraction would do.## Status
This software is so **alpha** you don't even...
## License
Copyright © 2020 Dennis Heihoff
Distributed under the Eclipse Public License either version 1.0 or (at
your option) any later version.