npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

hyperapp-module-views

v0.0.5

Published

Allow hyperapp modules to provide components bound to their state and actions

Downloads

3

Readme

hyperapp-module-views

A decorator (a k a "higher order app") for Hyperapp, which allows your modules to provide components bound to its state and actions

Installation and Basic Usage

Via npm

In your project folder:

npm install hyperapp-module-views

Then import/require moduleViews in your project, and use it to decorate your app:

const {h, app} = require('hyperapp')
const moduleViews = require('hyperapp-module-views')

moduleViews(app)({
  ...
})

Via CDN

Add the following script tag to the <head>...</head> section of your html page:

<script src="https://unpkg.com/hyperapp-module-views"></script>

... that will export moduleViews in your global scope, which you use to decorate your app:

moduleViews(app)({
  ...
})

How to use it

You may now define views in your modules:


const sharedModule = {
  views: {
    ok: _ => <p>Ok</p>
  }
}

const answerModule = {
  views: {
    affirmative: _ => <p>Yes!</p>,
    negative: _ => <p>No!</p>
  }
  modules: {
    shared: sharedModule
  }
}

const questionModule = {
  views: {
    what: _ => <p>What?</p>
  },
  modules: {
    shared: sharedModule
  }
}

Now those views are available to the main view, in the third argument.


app(moduleViews)({
  modules: {
    q: questionModule,
    a: answerModule
  },
  view: (state, actions, views) => <div>
    <views.q.what />
    <views.a.affirmative />
    <views.a.shared.ok />
  </div>
})

/*
App as above renders:
<div>
  <p>What?</p>
  <p>Yes!</p>
  <p>Ok</p>
</div>
*/

Module views are called with state & action as first and second parameters just like the main app view. So you don't have to pass those as props to the components.

State and actions passed to a module view, are scoped according to the module.


const counterModule =  {
  state: {value: 0},
  actions: {
    increment: state => ({value: state.value + 1}),
    decrement: state => ({value: state.value - 1}),
    views: {
      counter: (state, actions) => <p>
        <button onclick={actions.decrement}> - </button>
        {state.value}
        <button onclick={actions.increment}> + </button>
      </p>
    }
  }
}

app(moduleViews)({
  modules: {
    c1: counterModule,
    c2: counterModule,
  },
  view: (state, actions, views) => <div>
    <h1>Here is one counter</h1>
    <views.c1.counter />
    <h1>And here is a separate counter </h1>
    <views.c2.counter />
  </div>
})

So there is a tree of views which corresponds to the tree of state and actions. In modules with modules, take care not to use views with names that collide with one of the modules. (if you do, view will take precedence in the views-tree)

The third argument to module views is the view tree (scoped to the modules level, just as state and actions) This is useful for reusing ui elements in separate modules.


const toggler = {
  state: {value: false},
  actions: {
    toggle: state => ({value: !state.value})
  },
  views: {
    value: state => state.value ? 'On' : 'Off',
    switch: (state, actions) => <button onclick={actions.toggle}>Flip</button>
  }
}

const auxiliary = {
  modules: {
    power: toggler
  },
  views: {
    panel: (state, actions, views) => <p>
      Auxiliary power is <views.power.value /> <br />
      Power switch: <views.power.switch />
    </p>
  }
}

const main = {
  modules: {
    power: toggler
  },
  views: {
    panel: (state, actions, views) => <p>
      Main power is <views.power.value /> <br  />
      Power switch: <views.power.switch />
    </p>
  }
}

app({
  modules: { main, auxiliary},  
  view: (state, actions, views) => <div>
    <h1>Power system status</h1>
    <h2>Main:</h2>
    <views.main.panel />
    <h2>Auxiliary:</h2>
    <views.auxiliary.panel />
  </div>
})

Although state and actions are already provided to module views, you can still pass additional props, as well as children to them -- just like any other component. These will be provided in the fourth and fifth arguments respectively


const alertBox = {
  state: {blinking: false},
  actions: {
    toggleBlink: state => ({blinking: !state.blinking}),
  },
  views: {
    box: (state, actions, views, props, children) => {
      if (props.blinking != state.blinking) actions.toggleBlink()
      return <div class={'blinkbox' + (state.blinking ? ' blinking' : '')}>
        {children}
      </div>
    }
  }
}

app(moduleViews)({
  modules: { alertBox },
  view: (state, actions, views) => <main>
    <views.alertbox.box blink={true}>
      This content should be blinking annoyingly,
      provided you defined the CSS for `.blinkbox.blinking`
      to do so.
    </views.alertbox.box>
  </main>
})

Note: In the examples above, I have defined the components directly in the module view function, only so as not to over-complicate these simple examples. In general, it is better to write generic, reusable components, which you compose in your module views.