2.0.13 • Published 5 years ago

funwork-js v2.0.13

Weekly downloads
1
License
MIT
Repository
github
Last release
5 years ago

funwork

Funwork is a framework for creating web applications usgin the SAM pattern

to install run either

yarn add funwork-js

or

npm install --save funwork-js

How it works

The SAM pattern consists of a few decoupled parts, in this implementation they are:

Model

Model just holds your data, it should look something like this

const model = {
  ...someModuleModel,
  someList: [],
  title: 'I am initial title',
  randomValue: 42
};

where someModuleModel is just another model object

Acceptor

It works like reducer, you create an acceptor function, which receives model as first and proposal from action as second argument

// reducer object, where every key is a action type name(I find it better and more composable, than using switch case )
const acceptorReducer = {
  ...someModuleReducer,
  addToSomeList,
  setTitle,
  setRandomValue,
  default: (model, payload) => {
    console.error('Action type ', payload.type, 'has no handler');
  }
};

// acceptor function, that is injected to the framework
const acceptor = (model, proposal) => {
  const acceptorType = acceptorReducer[proposal.type];
  if (acceptorType) {
    acceptorType(model, proposal.payload);
  } else {
    acceptorReducer.default(model, proposal);
  }
  return model;
};

Router

Router is just a reflection of a part of the model, that should appear in the URL and on the initial page load change the defualt properties of the model

const router = model => {
  const { history, location } = window;
  const query = {
    moduleValue: model.someModuleValue,
    someList: model.someList,
    title: model.title,
  };
	
  history.pushState(
    null,
    page,
    `/${page}?${qs.stringify(query)}`
  );

  const _query = qs.parse(location.search);
  
  return {
    ..._query,
  };
};

State

Model transformation for the view layer to be used, basically View-Model layer

const state = {
  ...someModuleState,
  someList: model => model.someList,
  title: model => model.title,
  randomValue: model => model.randomValue
}

NAP

It stands for Next-Action-Predicate and serves for additional necessary changes, of the model

// imagine someone sets title to say Fuck off
const nap = actions => computedState => {
  if (containsBadWord(computedState.title)) {
    actions.setTitle(censored(computedState.title)) // F**ck off
  }
};

Actions

More or less straightforward, just specifies what should be done with the model.

const acitons = present => ({
  ...someModuleActions(present),
  addToSomeList: value => present({ type: 'addToSomeList', payload: value }),
  setTitle: newTitle => present({ type: 'setTitle', payload: newTitle }),
  increaseRandomValue: byNumber => present({ type: 'increaseRandomValue', payload: byNumber || 1 }),
})

View

Funwork js is liberal in the usage of the view layer, only requirement is, that components are functions.

Main file

In your main/index file, it would look like this

// imports
import Funwork from 'funwork-js';
import { render } from 'react-dom';
import actions from './actions';
import { acceptor, model, router } from './model';
import { nap, state } from './state';

// function which handles rerendering has its argument in different order as React's render function
const patch = (rootNode, vNode) => {
  return render(vNode, rootNode).parentNode;
};

// init
const funwork = new Funwork(
  {
    model,
    acceptor,
    state,
    actions,
    nap,
    router
  },
  patch
);

export const { createComponent } = funwork

// mount method renders component to the real DOM, but needs to be called after funwork initialization
// due to the usage of the createComponent function in the component themselves
import('./App').then(App => {
  funwork.mount('#app', App.default);
});

// App.jsx
import { createComponent } from './index';
import React from 'react';

const App = createComponent(
  () => {
    return (
      <div>
        This is the title {App.title}
        <button onClick={App.setTitle('Hello World')} >
          Change title to 'Hello World'
        </button>
      </div>
    );
  },
  {
    actions: ['setTitle'],
    state: ['title']
  }
);

export default App;
2.0.13

5 years ago

2.0.12

5 years ago

2.0.11

5 years ago

2.0.10

5 years ago

2.0.9

5 years ago

2.0.8

5 years ago

2.0.7

5 years ago

2.0.6

5 years ago

2.0.5

5 years ago

2.0.4

5 years ago

2.0.3

5 years ago

2.0.2

5 years ago

2.0.1

5 years ago

2.0.0

5 years ago

1.0.0-beta.13

5 years ago

1.0.0-beta.12

5 years ago

1.0.0-beta.11

5 years ago

1.0.0-beta.10

5 years ago

1.0.0-beta.9

5 years ago

1.0.0-beta.8

5 years ago

1.0.0-beta.7

5 years ago

1.0.0-beta.6

5 years ago

1.0.0-beta.5

5 years ago

1.0.0-beta.4

5 years ago

1.0.0-beta.3

5 years ago

1.0.0-beta.2

5 years ago

1.0.0-beta.1

5 years ago

1.0.0-beta.0

5 years ago

0.0.34

5 years ago

0.0.33

5 years ago

0.0.32

5 years ago

0.0.31

5 years ago

0.0.30

5 years ago

0.0.29

5 years ago

0.0.28

5 years ago

0.0.27

5 years ago

0.0.26

5 years ago

0.0.25

5 years ago

0.0.24

5 years ago

0.0.23

5 years ago

0.0.22

5 years ago

0.0.21

5 years ago

0.0.20

5 years ago

0.0.19

5 years ago

0.0.18

5 years ago

0.0.17

5 years ago

0.0.16

5 years ago

0.0.15

5 years ago

0.0.14

5 years ago

0.0.13

5 years ago

0.0.12

5 years ago

0.0.11

5 years ago

0.0.10

5 years ago

0.0.9

5 years ago

0.0.8

5 years ago

0.0.7

5 years ago

0.0.6

5 years ago

0.0.5

5 years ago

0.0.4

5 years ago

0.0.3

5 years ago

0.0.2

5 years ago

0.0.1

5 years ago