A UI component library built on top of re-frame and Domino. The library provides a multimethod for declaring UI components along with re-frame events and subscriptions for managing the state of these components.
This section will show how to declare and use domino-ui components.
Components are declared using the domino.ui.component/component
multimethod. As an example, let's
take a look at declaring a text input component. First, we'll need to require the following namespaces:
(ns myapp.components
(:require
[domino.ui.core :as core]
[domino.ui.component :refer [component] :as cp]
[re-frame.core :as rf]))
The component accepts a Hiccup style vector that contains a namespaced keyword specifying the type of the component, followed by an options map, and an optional body of the component. A declaration for a text input might look as follows:
[:domino.ui.component/text-input {:id :first-name}]
The :id
key specified in the options map references the ID for the path in the Domino model. Given the above declaration
we will write the following multimethod to instantiate the component:
(defmethod component :domino.ui.component/text-input [[_ {:keys [context id]}]]
(fn []
(let [{:keys [disabled?]} @(rf/subscribe [::core/component-state context id])]
[:input
{:type :text
:disabled disabled?
:value @(rf/subscribe [::core/subscribe context id])
:on-change #(rf/dispatch [::core/transact context id (-> % .-target .-value)])}])))
Note that domino-ui supports multiple Domino contexts, and the context for the specific component will be injected in the component options map when components are parsed.
The multimethod will receive the vector declaration for the component and create a Reagent component function using it.
The component can observe its state using the :domino.ui.core/component-state
subscription. This subscription should
contain a map with the state of the component. In the example, the map can have a :disabled?
key that toggles whether
the component is disabled.
The state of the component can be modified using the :domino.ui.core/merge-component-state
and :domino.ui.core/update-component-state
events. The merge event accepts Domino context, component id, and a map containing the new state that will be merged on top of the current state.
The update event accepts the Domino context, component id, and a function that should accept the current state of the component and return an updated one.
The value of the component is read using the :domino.ui.core/subscribe
subscription and passing it the Domino context and the component id matching one
of the components specified in the options map. In this case, the id is :first-name
.
Finally, the component updates the current value in the model associated with the component using the :domino.ui.core/transact
event. This event accepts the Domino context followed by the value.
Once the component is declared we can create a Domino schema and add a :views
key to it. This key will contain a map of view
declarations, e.g:
(def default-schema
{:views {:default [:dv
[:h3 "User"]
[:div
[:label "First name"]
[:domino.ui.component/text-input {:id :first-name}]]
[:div
[:label "Last name"]
[:domino.ui.component/text-input {:id :last-name}]]]}
:model [[:demographics
[:first-name {:id :first-name}]
[:last-name {:id :last-name}]
[:full-name {:id :full-name}]]]
:effects [{:inputs [:first-name]
:handler (fn [_ {:keys [first-name]}]
(rf/dispatch [::core/update-component-state
:default-ctx
:last-name
{:disabled? (empty? first-name)}]))}]
:events [(domino/event [ctx {:keys [first-name last-name]} {:keys [full-name]}]
{:full-name (or (when (and first-name last-name)
(str last-name ", " first-name))
first-name
last-name)})]})
The view declaration uses plain Hiccup to declare the scaffolding and uses components for interactive elements.
The schema can now be initialized calling the :domino.ui.core/init-ctx
re-frame event:
(rf/dispatch-sync [:domino.ui.core/init-ctx :default-ctx default-schema {}])
Once the view is initialized, it can be used via the :domino.ui.core/view
subscription:
(defn default-ctx-page []
[:div
[:h3 "default context"]
@(rf/subscribe [::core/view :default-ctx :default])])
See here for a complete example of this in action.
Copyright © 2018 FIXME
Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.
Can you improve this documentation? These fine people already did:
dmitri.sotnikov@gmail.com & Dmitri SotnikovEdit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close