Skip to content

m-bock/purescript-interactive-data

Repository files navigation

purescript-interactive-data

interactive-data

Define UIs in terms of data types.

ci   release

Table of Contents

Live Demo

Features

  • Data centric
    UIs are defined in terms of data types. You don't have to know much about frontends.
  • Type safety
    Impossible to create wrong configutations for given types.
  • Framework agnostic
    Can be embedded in any ReactBasic or Halogen app
  • Configurable
    UIs for each data type can be customized
  • Extensible
    UIs for any data type can be written in a simple MVC architecture
  • Data validation
    Data is validated on the fly and errors are displayed

Use cases

Any part of a web app that need to handle user input of nested structured data. E.g: It works best for scenarios where highest priority is correctness of data and not so much the look and feel.

  • Settings/Config panels
  • Controls to showcase UI components
  • Back office tools

Supported types

The following types are supported out of the box:

  • Primitives like String, Int, Number, Boolean
  • Record
  • Variant
  • Array
  • Common ADTs like Maybe, Either, Tuple
  • Newtypes
  • Refinement of existing types (smart constructor pattern)
  • Custom ADTs
  • Generic Json inputs for not yet supported types

Documentation

API

API docs are published on Pursuit.

Library Manual

Learn about the core concepts of interactive-data in the Library Manual.

Getting started

Installation

  1. Install the library

    spago install interactive-data
    
  2. Install a virtual dom implementation, e.g. one of the following:

    spago install chameleon-halogen
    spago install chameleon-react-basic
    
  3. Install a bundler, e.g.:

    npm install --dev --save parcel
    

Minimal complete example

The following example renders with Halogen. Have a look at the demo folder for more examples in different frameworks.

src/Main.purs:

module Main (main) where

import Prelude

import Data.Maybe (Maybe(..))
import Effect (Effect)
import Effect.Class.Console (log)
import InteractiveData as ID
import Chameleon.Impl.Halogen as HI

main :: Effect Unit
main = do
  let
    -- 1. Compose a "Data UI" for a specific type
    sampleDataUi = ID.record_
      { user: ID.record_
          { firstName: ID.string_
          , lastName: ID.string_
          , size: ID.number { min: 0.0, max: 100.0 }
          }
      , meta: ID.record_
          { description: ID.string_
          , headline: ID.string_
          }
      }

    -- 2. Turn "Data UI" into an App interface
    sampleApp =
      ID.toApp
        { name: "Sample"
        , initData: Nothing
        , fullscreen: true
        , showLogo: false
        }
        sampleDataUi

    -- 3. Create Halogen component
    halogenComponent =
      HI.uiToHalogenComponent
        { onStateChange: \newState -> do

            -- Use the `extract` function to get data out of the state
            log (show $ sampleApp.extract newState)
        }
        sampleApp.ui

  -- 4. Finally mount the component to the DOM
  HI.uiMountAtId "root" halogenComponent

We also need to create a simple html file and a index.js file to run the web app.

static/index.html:

<html>
  <head>
    <title>Interactive Data Sample</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
  </head>
  <body>
    <script src="index.js" type="module"></script>
    <div id="root"></div>
  </body>
</html>

static/index.js:

import { main } from "../output/Main/index.js";

main();

Run

spago build
parcel static/index.html

Go to http://localhost:1234

Limitations

  • Currently no support for recursive types.
  • Data UIs cannot have side effects other than user input. A Data UI that fetches data from a server is currently not possible.

Contributing

If you have ideas for improvements or want to contribute, please open an issue or PR.

The repo structure is described in docs/repo-structure.md.