Skip to content

Commit f0a0ee2

Browse files
author
anfa
committed
initial
1 parent bdf7f49 commit f0a0ee2

File tree

8 files changed

+8383
-11
lines changed

8 files changed

+8383
-11
lines changed

Diff for: demo/src/index.html

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
6+
<meta http-equiv="x-ua-compatible" content="ie=edge">
7+
<title><%= htmlWebpackPlugin.options.title %></title>
8+
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=AIzaSyDLXeDD9_L0ICnDRvNL6j2UZCVl0oGHnqk&libraries=places"></script>
9+
</head>
10+
<body>
11+
<div id="<%= htmlWebpackPlugin.options.mountId %>"></div>
12+
</body>
13+
</html>

Diff for: demo/src/index.js

+67-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,78 @@
11
import React, {Component} from 'react'
22
import {render} from 'react-dom'
3+
import PlacesAutocomplete, { geocodeByAddress, getLatLng } from 'react-places-autocomplete'
4+
import ReactPropsEditor, { PropObjects } from '../../src'
35

4-
import Example from '../../src'
6+
function sleep(ms) {
7+
return new Promise(resolve => setTimeout(resolve, ms));
8+
}
59

610
class Demo extends Component {
11+
state = {
12+
propValues:{}
13+
}
714
render() {
815
return <div>
916
<h1>react-props-editor Demo</h1>
10-
<Example/>
17+
<div>-----Prop Names-------</div>
18+
<ReactPropsEditor onChange={({propValues})=>{
19+
this.setState({propValues})
20+
}} propObjects={{
21+
name: PropObjects.string,
22+
location: PropObjects.string.render(({
23+
onChange,
24+
propValues
25+
})=>{
26+
return <PlacesAutocomplete
27+
value={this.state.address || ''}
28+
onChange={(address) => {
29+
this.setState({ address })
30+
}}
31+
onSelect={(address) => {
32+
geocodeByAddress(address)
33+
.then(results => getLatLng(results[0]))
34+
.then(latLng => {
35+
console.log('Success', latLng)
36+
onChange(`${latLng.lat}:${latLng.lng}`);
37+
})
38+
.catch(error => console.error('Error', error))
39+
}}
40+
>
41+
{({ getInputProps, suggestions, getSuggestionItemProps }) => (
42+
<div>
43+
<input
44+
{...getInputProps({
45+
placeholder: 'Search Places ...',
46+
className: 'location-search-input'
47+
})}
48+
/>
49+
<div className="autocomplete-dropdown-container">
50+
{suggestions.map(suggestion => {
51+
const className = suggestion.active ? 'suggestion-item--active' : 'suggestion-item';
52+
// inline style for demonstration purpose
53+
const style = suggestion.active
54+
? { backgroundColor: '#fafafa', cursor: 'pointer' }
55+
: { backgroundColor: '#ffffff', cursor: 'pointer' };
56+
return (
57+
<div {...getSuggestionItemProps(suggestion, { className, style })}>
58+
<span>{suggestion.description}</span>
59+
</div>
60+
)
61+
})}
62+
</div>
63+
</div>
64+
)}
65+
</PlacesAutocomplete>
66+
}),
67+
city: PropObjects.number
68+
}} />
69+
<div>
70+
<br/>
71+
<div>-----Prop Values-------</div>
72+
{Object.keys(this.state.propValues).map(propKey=>{
73+
return <div key={propKey} >{propKey},{this.state.propValues[propKey]}</div>
74+
})}
75+
</div>
1176
</div>
1277
}
1378
}

Diff for: nwb.config.js

+5
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,10 @@ module.exports = {
33
npm: {
44
esModules: true,
55
umd: false
6+
},
7+
webpack: {
8+
html: {
9+
template: 'demo/src/index.html'
10+
}
611
}
712
}

Diff for: package.json

+5-2
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,17 @@
1818
"test:coverage": "nwb test-react --coverage",
1919
"test:watch": "nwb test-react --server"
2020
},
21-
"dependencies": {},
21+
"dependencies": {
22+
"lodash": "^4.17.10"
23+
},
2224
"peerDependencies": {
2325
"react": "16.x"
2426
},
2527
"devDependencies": {
2628
"nwb": "0.21.x",
2729
"react": "^16.4.0",
28-
"react-dom": "^16.4.0"
30+
"react-dom": "^16.4.0",
31+
"react-places-autocomplete": "^7.1.2"
2932
},
3033
"author": "",
3134
"homepage": "",

Diff for: src/PropObjects.js

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import React from 'react'
2+
import PropTypes from 'prop-types';
3+
import _ from 'lodash';
4+
5+
export const TYPE_CONVERTER = {
6+
array(value, propTypes){
7+
//TODO: array not supported yet
8+
if(Array.isArray(value)){
9+
return value.map((v,i)=>TYPE_CONVERTER[i](value,propTypes[i]));
10+
}
11+
},
12+
bool(value){
13+
return JSON.parse(value);
14+
},
15+
func(value){
16+
return value;
17+
},
18+
number(value){
19+
return Number(value);
20+
},
21+
object(value){
22+
return value;
23+
},
24+
string(value){
25+
return value.toString();
26+
},
27+
symbol(value){
28+
return value
29+
}
30+
}
31+
32+
export function toPropTypes(propObjects){
33+
return _.mapValues(propObjects,(o=>o.propType));
34+
}
35+
36+
export function parseGraphData({name,types,values,...rest}){
37+
38+
const jsonTypes = JSON.parse(types)
39+
const jsonValues = JSON.parse(values);
40+
41+
//convert types
42+
for (const key in jsonValues) {
43+
const value = jsonValues[key]
44+
let propType = jsonTypes[key];
45+
jsonValues[key] = TYPE_CONVERTER[propType](value);
46+
}
47+
const parsedData = {
48+
name,
49+
types: jsonTypes,
50+
values: jsonValues,
51+
...rest
52+
}
53+
return parsedData;
54+
}
55+
56+
57+
const PROP_TYPE_NAMES = _.compact(
58+
Object.keys(PropTypes).map(k => {
59+
if ([
60+
// 'array',
61+
'bool',
62+
'number',
63+
// 'object',
64+
'string',
65+
// 'symbol'
66+
].indexOf(k)>-1) {
67+
return k;
68+
}
69+
return undefined;
70+
})
71+
);
72+
const tmpWPT = {}
73+
74+
PROP_TYPE_NAMES.forEach(k=>{
75+
tmpWPT[k] = {
76+
typeName: k,
77+
propType: PropTypes[k],
78+
render(renderComponent){
79+
return {
80+
typeName: k,
81+
propType: PropTypes[k],
82+
renderComponent
83+
}
84+
}
85+
};
86+
})
87+
88+
const nPropTypes = tmpWPT;
89+
export default nPropTypes;

Diff for: src/PropsEditor.js

+137
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
import React, { Component } from "react";
2+
import PropTypes from "prop-types";
3+
import { toPropTypes } from './PropObjects'
4+
import _ from "lodash";
5+
// import {
6+
// Form,
7+
// List
8+
// } from 'semantic-ui-react'
9+
10+
function getPropTypeName(propType) {
11+
return propType.typeName;
12+
}
13+
14+
function resolveValue(value){
15+
let pFnc = value;
16+
if (typeof value === 'function')
17+
pFnc = value();
18+
return Promise.resolve(pFnc)
19+
}
20+
21+
function toJsonOpts(options){
22+
return options.map(opt=>{
23+
return {
24+
key:(opt.key||opt),
25+
text:(opt.text||opt),
26+
}
27+
})
28+
}
29+
30+
function cleanState(state){
31+
const changedProps = Object.assign({},state);
32+
delete changedProps.propsTypes;
33+
delete changedProps.propsTypeOptions;
34+
delete changedProps.propsTypeRender;
35+
return changedProps;
36+
}
37+
38+
export default class PropsEditor extends Component {
39+
state = {}
40+
async triggerChange(){
41+
const { onChange, propObjects } = this.props;
42+
const changedProps = cleanState(this.state);
43+
const thePropTypes = toPropTypes(await resolveValue(propObjects));
44+
//TODO: add field validation
45+
PropTypes.checkPropTypes(thePropTypes, changedProps, 'prop', 'PropsEditor');
46+
onChange && onChange({
47+
propTypes:this.state.propsTypes,
48+
propValues:changedProps});
49+
}
50+
51+
async componentDidMount(){
52+
const { propObjects={} } = this.props;
53+
const thePropTypes = await resolveValue(propObjects)
54+
const propsTypeOptions = {};
55+
const propsTypeRender = {}
56+
const propsTypes = {}
57+
for (const propKey in thePropTypes) {
58+
propsTypes[propKey] = getPropTypeName(thePropTypes[propKey]);
59+
if(thePropTypes[propKey].options){
60+
propsTypeOptions[propKey] = toJsonOpts(await resolveValue(thePropTypes[propKey].options));
61+
}
62+
if(thePropTypes[propKey].renderComponent){
63+
propsTypeRender[propKey] = thePropTypes[propKey].renderComponent;
64+
}
65+
}
66+
this.setState({ propsTypes,
67+
propsTypeOptions,
68+
propsTypeRender
69+
})
70+
}
71+
72+
render() {
73+
const { propsTypes, propsTypeOptions, propsTypeRender } = this.state;
74+
if (!propsTypes) {
75+
return <div>loading...</div>
76+
}
77+
return (
78+
<div>
79+
{Object.keys(propsTypes).map(pKey => {
80+
// return <div key={pKey}>
81+
// <div>key:{pKey}</div>
82+
// <div>type:{propsTypes[pKey]}</div>
83+
// <div>options:{propsTypeOptions[pKey] && propsTypeOptions[pKey].map(opt=><div key={opt.key}>{opt.key},{opt.text}</div>)}</div>
84+
// <div>optionComponent: {propsTypeRender[pKey]?propsTypeRender[pKey]():''} </div>
85+
// <div>----</div>
86+
// </div>
87+
if(!propsTypeRender[pKey]) return <div key={pKey}>Error: no render component defined for prop "{pKey}"</div>;
88+
return <div key={pKey}>{propsTypeRender[pKey]({
89+
onChange:async (value)=>{
90+
await this.setState({[pKey]:value});
91+
return this.triggerChange()
92+
},
93+
propValues:cleanState(this.state)
94+
})}</div>
95+
})}
96+
</div>
97+
);
98+
}
99+
}
100+
101+
// <List horizontal>
102+
// {Object.keys(propsTypes).map(pKey => {
103+
// const propName = propsTypes[pKey];
104+
// const labelTxt = _.capitalize(_.kebabCase(pKey).replace('-',' '));
105+
// return (
106+
// <List.Item key={pKey}>
107+
// { propsTypeOptions[pKey] &&
108+
// <Form.Select label={`${labelTxt} `}
109+
// options={propsTypeOptions[pKey].map(opt=>({
110+
// text:opt,
111+
// value:opt
112+
// }))}
113+
// onChange={async (e,data) => {
114+
// await this.setState({ [pKey]: (data.value) } )
115+
// this.triggerChange();
116+
// }}/>
117+
// }
118+
// { !propsTypeOptions[pKey] &&
119+
// <React.Fragment>
120+
// {["string", "number"].indexOf(propName) > -1 && (
121+
// <Form.Input label={`${labelTxt} `} onChange={async (data) => {
122+
// await this.setState({ [pKey]: (data.target.value) } )
123+
// this.triggerChange();
124+
// }}/>
125+
// )}
126+
// {["bool"].indexOf(propName) > -1 && (
127+
// <Form.Checkbox label={labelTxt} onChange={async (_,data) => {
128+
// await this.setState({[pKey]: (data.checked) });
129+
// this.triggerChange();
130+
// }}/>
131+
// )}
132+
// </React.Fragment>
133+
// }
134+
// </List.Item>
135+
// );
136+
// })}
137+
// </List>

Diff for: src/index.js

+5-7
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
import React, {Component} from 'react'
1+
import PropsEditor from './PropsEditor'
2+
import PropObjects from './PropObjects'
23

3-
export default class extends Component {
4-
render() {
5-
return <div>
6-
<h2>Welcome to React components</h2>
7-
</div>
8-
}
4+
export {
5+
PropObjects
96
}
7+
export default PropsEditor;

0 commit comments

Comments
 (0)