Skip to content
This repository was archived by the owner on Jan 5, 2023. It is now read-only.

Commit 5270d93

Browse files
Created withSmartKnob.
1 parent 57d6a39 commit 5270d93

File tree

3 files changed

+91
-2
lines changed

3 files changed

+91
-2
lines changed

.eslintrc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
extends: [ "taller/react" ],
3+
globals: {
4+
__DEBUG__: true,
5+
location: true
6+
}
7+
}

package.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@
22
"name": "storybook-addon-smart-knobs",
33
"version": "0.1.0",
44
"description": "Automatically created knobs for storybook.",
5-
"main": "index.js",
5+
"main": "src/index.js",
66
"scripts": {
77
"test": "jest"
88
},
99
"author": "",
10-
"license": "MIT"
10+
"license": "MIT",
11+
"peerDependencies": {
12+
"@kadira/storybook-addon-knobs": "^1.3.0",
13+
"react": "^0.14.7 || ^15.0.0"
14+
}
1115
}

src/index.js

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import { cloneElement } from 'react'
2+
import { action } from '@kadira/storybook'
3+
import { text, boolean, number, object, select } from '@kadira/storybook-addon-knobs'
4+
5+
const knobResolvers = {}
6+
export const addKnobResolver = ({ name, resolver, weight = 0 }) => (knobResolvers[name] = { name, resolver, weight })
7+
8+
/*
9+
* Register default knob resolvers.
10+
* --------------------------------
11+
*/
12+
13+
export const propTypeKnobResolver = (test, knob, ...args) =>
14+
(name, validate, value, propTypes, defaultProps) => !validate({ 'prop': test }, 'prop')
15+
? knob(name, value, ...args) : undefined
16+
17+
/* eslint-disable no-multi-spaces */
18+
// Default simple PropType based knob map.
19+
const propTypeKnobsMap = [
20+
{ name: 'string', test: '', knob: text },
21+
{ name: 'number', test: 0, knob: number },
22+
{ name: 'bool', test: true, knob: boolean },
23+
{ name: 'func', test: () => {}, knob: (name, value) => value || action(name) },
24+
{ name: 'object', test: {}, knob: object }
25+
]
26+
27+
propTypeKnobsMap.forEach(({ name, test, knob, args = [] }) => addKnobResolver({
28+
name,
29+
resolver: propTypeKnobResolver(test, knob, ...args)
30+
}))
31+
32+
// Defalt oneOf PropType knob resolver.
33+
addKnobResolver({
34+
name: 'oneOf',
35+
resolver: (name, validate, value, propTypes, defaultProps) => {
36+
const error = validate({ 'prop': '' }, 'prop')
37+
const match = error ? /expected one of (\[.*\])/.exec(error.message) : null
38+
39+
if (match && match[1]) {
40+
const parsedOptions = JSON.parse(match[1])
41+
const options = parsedOptions.reduce((res, value) => ({ ...res, [value]: value }), {})
42+
43+
return select(name, {
44+
'': '--',
45+
...options
46+
}, defaultProps[name])
47+
}
48+
}
49+
})
50+
51+
export const withSmartKnobs = (story, context) => {
52+
const component = story()
53+
const propTypes = component.type.propTypes
54+
const defaultProps = {
55+
...component.type.defaultProps,
56+
...component.props
57+
}
58+
59+
return cloneElement(component, resolvePropValues(propTypes, defaultProps))
60+
}
61+
62+
const resolvePropValues = (propTypes, defaultProps) => {
63+
const propKeys = Object.keys(propTypes)
64+
const resolvers = Object.keys(knobResolvers)
65+
.sort((a, b) => knobResolvers[a].weight < knobResolvers[b].weight)
66+
.map(name => knobResolvers[name].resolver)
67+
68+
return propKeys
69+
.map(prop => resolvers.reduce(
70+
(value, resolver) => value !== undefined ? value
71+
: resolver(prop, propTypes[prop], defaultProps[prop], propTypes, defaultProps),
72+
undefined
73+
))
74+
.reduce((props, value, i) => ({
75+
...props,
76+
[propKeys[i]]: value
77+
}), defaultProps)
78+
}

0 commit comments

Comments
 (0)