Skip to content

Commit fc518f7

Browse files
committed
Initial commit
0 parents  commit fc518f7

10 files changed

+405
-0
lines changed

.editorconfig

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
root = true
2+
3+
[*]
4+
indent_style = tab
5+
end_of_line = lf
6+
charset = utf-8
7+
trim_trailing_whitespace = true
8+
insert_final_newline = true
9+
10+
[{package.json,.*rc,*.yml}]
11+
indent_style = space
12+
indent_size = 2
13+
14+
[*.md]
15+
trim_trailing_whitespace = false

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/dist
2+
/node_modules
3+
/npm-debug.log
4+
.DS_Store

LICENSE

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
Copyright (c) 2017, Synacor, Inc.
2+
All rights reserved.
3+
4+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
5+
6+
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7+
8+
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
9+
10+
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
11+
12+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

README.md

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
<p align="center">
2+
<img src="resources/preconf-logo.png" width="400" alt="preconf">
3+
<br>
4+
<a href="https://www.npmjs.org/package/preconf"><img src="https://img.shields.io/npm/v/preconf.svg?style=flat" alt="npm"></a> <a href="https://travis-ci.org/synacor/preconf"><img src="https://travis-ci.org/synacor/preconf.svg?branch=master" alt="travis"></a>
5+
</p>
6+
7+
A Higher Order Component that provides configuration (from context & defaults) as props.
8+
9+
Preconf is just 400 bytes and works well with [preact-context-provider](https://github.com/synacor/preact-context-provider).
10+
11+
* * *
12+
13+
## Usage
14+
15+
```js
16+
import preconf from 'preconf';
17+
import Provider from 'preact-context-provider';
18+
19+
// generally from an import
20+
const defaults = {
21+
greeting: 'hello'
22+
};
23+
24+
let configure = preconf(null, defaults);
25+
26+
/** Wire two configuration fields up to props: */
27+
@configure('greeting, name')
28+
class Foo extends Component {
29+
render({ greeting, name }) {
30+
return <span>{greeting}, {name}</span>
31+
}
32+
}
33+
34+
/** Render from defaults: */
35+
render(<Foo />);
36+
// <span>hello, </span>
37+
38+
/** Provide overrides as `context.config`: */
39+
render(
40+
<Provider config={{ name: 'Stan' }}>
41+
<Foo />
42+
</Provider>
43+
);
44+
// <span>hello, Stan</span>
45+
```
46+
47+
## API
48+
49+
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
50+
51+
### preconf
52+
53+
Creates a higher order component that provides values from configuration as props.
54+
55+
**Parameters**
56+
57+
- `namespace` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** If provided, exposes `defaults` under a `namespace`
58+
- `defaults` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)?** An object containing default configuration values
59+
60+
**Examples**
61+
62+
```javascript
63+
let configure = preconf();
64+
export default configure({ a: 'a' })(MyComponent);
65+
```
66+
67+
```javascript
68+
let configure = preconf(null, { url:'//foo.com' });
69+
export default configure({ url: 'url' })( props =>
70+
<a href={props.url} />
71+
);
72+
```
73+
74+
```javascript
75+
let configure = preconf('weather', { url:'//foo.com' });
76+
export default configure({
77+
url: 'weather.url'
78+
})( ({ url }) =>
79+
<a href={props.url} />
80+
);
81+
```
82+
83+
Returns **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)** [configure()](#configure)
84+
85+
#### configure
86+
87+
Creates a Higher Order Component that provides configuration as props.
88+
89+
**Parameters**
90+
91+
- `keys` **([Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) \| [Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)&lt;[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)>)** An object where the keys are prop names to pass down and values are dot-notated keypaths corresponding to values in configuration. If a string or array, prop names are inferred from configuration keys.
92+
93+
Returns **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)** configureComponent(Component) -> Component

package.json

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
{
2+
"name": "preconf",
3+
"amdName": "preconf",
4+
"version": "1.0.0",
5+
"description": "Configure your components, easily.",
6+
"main": "dist/preconf.js",
7+
"minified:main": "dist/preconf.min.js",
8+
"jsnext:main": "src/index.js",
9+
"scripts": {
10+
"build": "npm-run-all transpile optimize minify docs",
11+
"transpile": "rollup -c -m ${npm_package_main}.map -f umd -n $npm_package_amdName $npm_package_jsnext_main -o $npm_package_main",
12+
"optimize": "uglifyjs $npm_package_main -bc dead_code --pure-funcs _possibleConstructorReturn _classCallCheck -o $npm_package_main -p relative --in-source-map ${npm_package_main}.map --source-map ${npm_package_main}.map",
13+
"minify": "uglifyjs $npm_package_main -mc collapse_vars,evaluate,screw_ie8,unsafe,loops=false,keep_fargs=false,pure_getters,unused,dead_code --pure-funcs _possibleConstructorReturn _classCallCheck -o $npm_package_minified_main -p relative --in-source-map ${npm_package_main}.map --source-map ${npm_package_minified_main}.map",
14+
"test": "eslint src test && mocha --compilers js:babel-register test/**/*.js",
15+
"docs": "documentation readme src/index.js --section API -q",
16+
"prepublish": "npm run build",
17+
"release": "npm run build && git commit -am $npm_package_version && git tag $npm_package_version && git push --follow-tags && npm publish"
18+
},
19+
"eslintConfig": {
20+
"extends": "eslint-config-synacor",
21+
"rules": {
22+
"guard-for-in": 0
23+
}
24+
},
25+
"babel": {
26+
"presets": [
27+
"es2015",
28+
"stage-0"
29+
],
30+
"plugins": [
31+
"transform-class-properties",
32+
[
33+
"transform-react-jsx",
34+
{
35+
"pragma": "h"
36+
}
37+
]
38+
]
39+
},
40+
"keywords": [
41+
"config",
42+
"connect",
43+
"configure",
44+
"prop provider",
45+
"context"
46+
],
47+
"files": [
48+
"src",
49+
"dist"
50+
],
51+
"authors": [
52+
"Jason Miller <[email protected]>"
53+
],
54+
"license": "BSD 3-Clause",
55+
"repository": "synacor/preconf",
56+
"homepage": "https://github.com/synacor/preconf",
57+
"devDependencies": {
58+
"babel": "^6.5.2",
59+
"babel-eslint": "^7.1.0",
60+
"babel-plugin-transform-class-properties": "^6.18.0",
61+
"babel-plugin-transform-react-jsx": "^6.8.0",
62+
"babel-preset-es2015": "^6.18.0",
63+
"babel-preset-stage-0": "^6.16.0",
64+
"babel-register": "^6.18.0",
65+
"chai": "^4.0.2",
66+
"documentation": "^4.0.0-beta.18",
67+
"eslint": "^3.10.2",
68+
"eslint-config-synacor": "^1.0.0",
69+
"eslint-plugin-react": "^6.7.1",
70+
"mocha": "^3.1.2",
71+
"npm-run-all": "^4.0.2",
72+
"preact": "^7.2.0",
73+
"preact-context-provider": "^1.0.0",
74+
"rollup": "^0.42.0",
75+
"rollup-plugin-buble": "^0.15.0",
76+
"sinon": "^2.3.2",
77+
"sinon-chai": "^2.8.0",
78+
"uglify-js": "^2.7.4",
79+
"undom": "^0.3.1"
80+
},
81+
"peerDependencies": {
82+
"preact": "*"
83+
},
84+
"dependencies": {
85+
"dlv": "^1.1.0"
86+
}
87+
}

resources/preconf-icon.png

27.9 KB
Loading

resources/preconf-logo.png

43.5 KB
Loading

rollup.config.js

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import buble from 'rollup-plugin-buble';
2+
3+
export default {
4+
useStrict: false,
5+
external: [
6+
'preact',
7+
'dlv'
8+
],
9+
globals: {
10+
preact: 'preact',
11+
dlv: 'dlv'
12+
},
13+
plugins: [
14+
buble({
15+
objectAssign: 'assign',
16+
jsx: 'h'
17+
})
18+
]
19+
};

src/index.js

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { h } from 'preact';
2+
import delve from 'dlv';
3+
4+
/** Creates a higher order component that provides values from configuration as props.
5+
* @param {String} [namespace] If provided, exposes `defaults` under a `namespace`
6+
* @param {Object} [defaults] An object containing default configuration values
7+
* @returns {Function} [configure()](#configure)
8+
*
9+
* @example
10+
* let configure = preconf();
11+
* export default configure({ a: 'a' })(MyComponent);
12+
*
13+
* @example
14+
* let configure = preconf(null, { url:'//foo.com' });
15+
* export default configure({ url: 'url' })( props =>
16+
* <a href={props.url} />
17+
* );
18+
*
19+
* @example
20+
* let configure = preconf('weather', { url:'//foo.com' });
21+
* export default configure({
22+
* url: 'weather.url'
23+
* })( ({ url }) =>
24+
* <a href={props.url} />
25+
* );
26+
*/
27+
export default function preconf(namespace, defaults) {
28+
if (namespace) defaults = { [namespace]: defaults };
29+
30+
/** Creates a Higher Order Component that provides configuration as props.
31+
* @param {Object|Array<String>} keys An object where the keys are prop names to pass down and values are dot-notated keypaths corresponding to values in configuration. If a string or array, prop names are inferred from configuration keys.
32+
* @name configure
33+
* @memberof preconf
34+
* @returns {Function} configureComponent(Component) -> Component
35+
*/
36+
return keys => {
37+
if (typeof keys==='string') keys = keys.split(/\s*,\s*/);
38+
let isArray = Array.isArray(keys);
39+
40+
return Child => (originalProps, context) => {
41+
let props = {};
42+
for (let i in originalProps) props[i] = originalProps[i];
43+
for (let key in keys) {
44+
let path = keys[key];
45+
if (isArray) key = path.split('.').pop();
46+
if (typeof props[key]==='undefined' || props[key]===null) {
47+
props[key] = delve(context, 'config.'+path, delve(defaults, path));
48+
}
49+
}
50+
return h(Child, props);
51+
};
52+
};
53+
}

0 commit comments

Comments
 (0)