Comparing version 0.1.0 to 0.2.0
{ | ||
"name": "compo", | ||
"version": "0.1.0", | ||
"description": "Compose a queue of functions", | ||
"main": "Composer.js", | ||
"directories": { | ||
"test": "test" | ||
}, | ||
"version": "0.2.0", | ||
"description": "Compo·sing Web Compo·nents", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "mocha" | ||
"2048": "parcel --no-hmr --no-cache examples/2048/index.html", | ||
"2048-compat": "parcel --no-hmr --no-cache examples/2048-compat/index.html", | ||
"lint": "eslint src examples", | ||
"test": "ava", | ||
"counter": "parcel --no-hmr --no-cache examples/counter/index.html" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git://github.com/curvedmark/compo.git" | ||
"url": "git+https://github.com/Swiip/compo.git" | ||
}, | ||
"keywords": [ | ||
"compose", | ||
"composer", | ||
"queue", | ||
"async" | ||
"javascript", | ||
"frontend", | ||
"ui", | ||
"library", | ||
"web-components" | ||
], | ||
"author": "Glen Huang <curvedmark@gmail.com>", | ||
"author": "Matthieu Lux", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/curvedmark/compo/issues" | ||
"url": "https://github.com/Swiip/compo/issues" | ||
}, | ||
"homepage": "https://github.com/Swiip/compo#readme", | ||
"devDependencies": { | ||
"mocha": "1.x" | ||
"@babel/register": "^7.0.0-beta.51", | ||
"@webcomponents/webcomponentsjs": "^2.0.2", | ||
"ava": "1.0.0-beta.6", | ||
"eslint": "^4.19.1", | ||
"eslint-config-airbnb-base": "^12.1.0", | ||
"eslint-plugin-import": "^2.12.0", | ||
"parcel-bundler": "^1.9.1", | ||
"sinon": "^6.0.0" | ||
}, | ||
"ava": { | ||
"require": [ | ||
"@babel/register" | ||
] | ||
} | ||
} | ||
} |
246
README.md
# Compo | ||
Compose a queue of functions. The returns values of the previous function are passed as arguments to the next one. | ||
![Travis Status](https://travis-ci.org/Swiip/compo.svg?branch=master) | ||
Compo is a JavaScript Web UI tiny library powering Web Components with a functional API and a Virtual DOM rendering. | ||
You have to **compo**·se your **compo**·nents by enriching them with each feature through a central composing function. Markup and Style are considered as a feature you can add to your components. | ||
## Installation | ||
npm install compo | ||
``` | ||
npm install compo | ||
yarn add compo | ||
``` | ||
## Example | ||
```javascript | ||
var Composer = require('compo'); | ||
var composer = new Composer(); | ||
import { | ||
html, | ||
css, | ||
createStore, | ||
component, | ||
withProp, | ||
withStore, | ||
withStyle, | ||
withMarkup, | ||
} from 'compo'; | ||
composer.add(addOne); | ||
composer.add(addOne); | ||
composer.add(function (num) { | ||
console.log(num); // 3 | ||
}); | ||
createStore((state, action) => { | ||
switch (action.type) { | ||
case 'ADD': return state + 1; | ||
case 'SUB': return state - 1; | ||
default: return state; | ||
} | ||
}, 0); | ||
composer.run(1); | ||
component( | ||
'my-counter-label', | ||
withProp('value'), | ||
withStyle(({ value }) => css` | ||
:host { | ||
color: ${value < 1 ? 'red' : 'black'}; | ||
} | ||
`,), | ||
); | ||
function addOne(num, next) { | ||
next(num + 1); | ||
} | ||
component( | ||
'my-counter', | ||
withStore(({ getState, dispatch }) => ({ | ||
counter: getState(), | ||
add: () => dispatch({ type: 'ADD' }), | ||
sub: () => dispatch({ type: 'SUB' }), | ||
})), | ||
withMarkup(({ counter, add, sub }) => html` | ||
<div> | ||
<my-counter-label value=${counter}>${counter}</my-counter-label> | ||
<button onclick=${add}>+</button> | ||
<button onclick=${sub}>-</button> | ||
</div> | ||
`), | ||
); | ||
``` | ||
@@ -30,16 +68,186 @@ | ||
### component( name:String, ...enhancers:Array<(Component => Component)> ):void | ||
Define a [Custom Element](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements) with named `name` and enhanced by each enhancers. | ||
- `name` is directly passed to `customElement.define()` so you have to follow Web Components constraints such as a `-` in the name and only used once in the application. | ||
- `enhancers` are function taking in parameter a component class definition and returning a new one, most often my extending it. You can create your own but you can use all the `with` prefixed enhancers provided in the framework. | ||
```javascript | ||
composer.add(fn); | ||
component( | ||
'my-component', | ||
withProp('my-prop') | ||
); | ||
``` | ||
Add a function to the composer queue, if the composer has already run, the function will be automatically dequeued and executed, unless the previous function hasn't finished yet. | ||
### withMarkup( (props => Markup) ):(Component => Component) | ||
`fn` has a signature of `fn(..args, next)`, where `...args` is the returned values of previous function, and `next` is a callback function that should be called when `fn` is finished. | ||
Define an enhancer which will render the `Markup` returned in the component and will re-render on every change detection. | ||
You can pass arguments to `next()`, which will be the returned values of the function. `return` values directly won't work. | ||
You'll obtain an `Markup` object by using the `html` tagged template described bellow. | ||
```javascript | ||
composer.run(..args); | ||
component( | ||
'my-component', | ||
withMarkup(() => html`<div>Hello World</div>`) | ||
); | ||
``` | ||
Run the composer, with `...args` being passed to the first function in the queue as arguments. | ||
### withStyle( (props => Style) ):(Component => Component) | ||
Define an enhancer which will add a `style` block with the `Style` returned and will update the style on every change detection. | ||
The `Style` object can be either a standard `string` or an object using the `css` tagged template described bellow. | ||
```javascript | ||
component( | ||
'my-component', | ||
withStyle(() => css`:host { color: red; }`) | ||
); | ||
``` | ||
### withProp( name ):(Component => Component) | ||
Define an enhancer which will instrument and trigger an update on modification on the component property `name`. | ||
```javascript | ||
component( | ||
'my-component', | ||
withProp('my-prop') | ||
); | ||
``` | ||
### withHandler( name, (props => handler) ):(Component => Component) | ||
Define an enhancer which will add a `name` property to the component with `handler` returned to be used in the markup. | ||
```javascript | ||
component( | ||
'my-component', | ||
withHandler(() => event => console.log('my handler', event)) | ||
) | ||
``` | ||
### withConnected( (props => void) ):(Component => Component) | ||
Define an enhancer which will run the function in parameter when the component is connected corresponding to the Custom Element standard `connectedCallback` function. | ||
```javascript | ||
component( | ||
'my-component', | ||
withConnected(() => console.log('component connected')) | ||
) | ||
``` | ||
### withStore( ((store, props) => object) ):(Component => Component) | ||
Define an enhancer which will run the function in parameter at every store updates and assign all return object properties to the component object. | ||
The store must be created beforehand by using `createStore` described bellow. | ||
```javascript | ||
component( | ||
"my-component", | ||
withStore(({ getState, dispatch }) => { | ||
myData: getState().my.data, | ||
myAction: () => dispatch({ type: "MY_ACTION" }) | ||
}) | ||
) | ||
``` | ||
### html | ||
ES2015 tagged template allowing to create DOM templates with rich interpolations. | ||
```javascript | ||
html` | ||
<my-component my-prop=${prop}> | ||
${content} | ||
</my-component> | ||
` | ||
``` | ||
Known limitation: you currently can't use serveral interpolations in a single DOM node or property. | ||
### css | ||
ES2015 tagged template allowing to create CSS content. | ||
To be perfectly honest it does absolutely nothing right now! Still reserving the API can be good and it triggers syntax highlighting in many editors. | ||
```javascript | ||
css` | ||
my-component { | ||
color: red; | ||
} | ||
` | ||
``` | ||
### createStore( ((state, action) => state), initialState ): Store | ||
Initialize the internal store with the reducer in argument. | ||
In contrary to Redux, you don't always need to get the `Store` returned. It's automatically passed to the `withStore` enhancer. | ||
```javascript | ||
createStore((state, action) => { | ||
switch (action.type) { | ||
case 'ADD': return state + 1; | ||
case 'SUB': return state - 1; | ||
default: return state; | ||
} | ||
}, 0); | ||
``` | ||
## Examples | ||
### Counter | ||
Most basic example exactly the same as above in this readme. | ||
Try it in CodeSanbox: https://codesandbox.io/s/yv5y14o6pj | ||
## 2048 | ||
Advanced example implementing the popular 2048 game. | ||
Try it in CodeSanbox: https://codesandbox.io/s/k55w33zvkv | ||
## 2048 compat | ||
Same as 2048 but with polyfill loaded to be tested on other browsers than Chrome | ||
*Strangely doesn't work yet on CodeSanbox* | ||
## Inspiration | ||
### Other frameworks | ||
- [React](https://reactjs.org/) for the v-dom, applying changed by a diff mechanism. | ||
- [recompose](https://github.com/acdlite/recompose) for the composition API | ||
- [styled-components](https://www.styled-components.com/) for the CSS as ad integrant part as a component definition | ||
- [Redux](https://redux.js.org/) for the state management | ||
- [hyperapp](https://github.com/hyperapp/hyperapp) for proving that you can build a complete framework with only a few bytes | ||
### Blogs | ||
- https://medium.com/@deathmood/how-to-write-your-own-virtual-dom-ee74acc13060 | ||
- http://2ality.com/2014/07/jsx-template-strings.html | ||
- https://gist.github.com/lygaret/a68220defa69174bdec5 | ||
## Motivations | ||
It started with the exploration of the Web Components and Shadow DOM APIs and followed by the willing to use v-dom concepts in this contexts. | ||
Based upon that foundations, the objective was to have a functional API like _recompose_ to power Web Components. | ||
Minimalism and staying close and bounded to the standards. | ||
## Compatibility | ||
Compo is not transpiled to old JavaScript and _really_ based upon Web Components so it only works out of the box on recent Chrome. It works almost on Firefox but still needs a flag to be set. | ||
It's planned to have a compatibility build using polyfills. | ||
## Licence | ||
Compo is MIT licensed. See [LICENSE](./LICENSE.md). |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Native code
Supply chain riskContains native code (e.g., compiled binaries or shared libraries). Including native code can obscure malicious behavior.
Found 4 instances in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
161022
59
1738
1
253
8
6