├── src
├── doc
│ ├── redemo.png
│ ├── index.scss
│ ├── index.js
│ └── template.html
├── iconfont
│ ├── iconfont.eot
│ ├── iconfont.ttf
│ ├── iconfont.woff
│ └── iconfont.svg
├── index.scss
└── index.js
├── .gitignore
├── .editorconfig
├── .babelrc
├── webpack.config.js
├── package.json
├── README.md
└── webpack-dist.config.js
/src/doc/redemo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imweb/redemo/HEAD/src/doc/redemo.png
--------------------------------------------------------------------------------
/src/iconfont/iconfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imweb/redemo/HEAD/src/iconfont/iconfont.eot
--------------------------------------------------------------------------------
/src/iconfont/iconfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imweb/redemo/HEAD/src/iconfont/iconfont.ttf
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | .idea/
3 | .npm/
4 | node_modules/
5 |
--------------------------------------------------------------------------------
/src/iconfont/iconfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imweb/redemo/HEAD/src/iconfont/iconfont.woff
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*]
2 | charset=utf-8
3 | end_of_line=lf
4 | insert_final_newline=false
5 | indent_style=space
6 | indent_size=2
7 |
--------------------------------------------------------------------------------
/src/doc/index.scss:
--------------------------------------------------------------------------------
1 | .my-demo {
2 | width: 600px;
3 | margin-top: 20px;
4 | left: 50%;
5 | transform: translate(-50%, 0);
6 | }
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "es2015",
4 | "stage-2",
5 | "react"
6 | ],
7 | "plugins": [
8 | [
9 | "transform-runtime",
10 | {
11 | "polyfill": false
12 | }
13 | ],
14 | [
15 | "import",
16 | {
17 | "libraryName": "antd",
18 | "style": "css"
19 | }
20 | ]
21 | ],
22 | "env": {
23 | "dist": {
24 | "plugins": [
25 | [
26 | "replace-require-suffix",
27 | {
28 | "from": "scss",
29 | "to": "css"
30 | }
31 | ]
32 | ]
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/doc/index.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { render } from 'react-dom';
3 |
4 | import Button from 'antd/lib/button';
5 | import 'antd/lib/button/style/index.css';
6 |
7 | import ReDemo from '../index';
8 | import './index.scss';
9 |
10 | const docgen = require('!!docgen-loader!../index');
11 |
12 | const doc = `
13 | ### react component used to demonstrate react component
14 | - in top section is demo instance to play
15 | - circle button in right are toggle for **component propTypes** and **demo source code**
16 | - propTypes table show all prop's info for this component
17 | - in bottom is source code for this demo
18 | - red prop name means it's required
19 | `
20 |
21 | const code = `
22 | import ReDemo from 'redemo';
23 |
24 |
30 | Hello World
31 |
32 | `
33 |
34 | const demo = (
35 |
45 | demo component instance
46 |
47 | )
48 |
49 | render(demo, window.document.getElementById('app'));
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const path = require('path');
3 | const { WebPlugin } = require('web-webpack-plugin');
4 |
5 | module.exports = {
6 | output: {
7 | publicPath: '',
8 | filename: '[name].js',
9 | },
10 | resolve: {
11 | // 加快搜索速度
12 | modules: [path.resolve(__dirname, 'node_modules')],
13 | // es tree-shaking
14 | mainFields: ['jsnext:main', 'browser', 'main'],
15 | },
16 | module: {
17 | rules: [
18 | {
19 | test: /\.js$/,
20 | // cacheDirectory 缓存babel编译结果加快重新编译速度
21 | loader: 'babel-loader?cacheDirectory',
22 | // 只命中src目录里的js文件,加快webpack搜索速度
23 | include: path.resolve(__dirname, 'src')
24 | },
25 | {
26 | test: /\.scss$/,
27 | loaders: ['style-loader', 'css-loader', 'sass-loader'],
28 | include: path.resolve(__dirname, 'src')
29 | },
30 | {
31 | test: /\.css$/,
32 | loaders: ['style-loader', 'css-loader'],
33 | },
34 | {
35 | test: /\.(gif|png|jpe?g|eot|woff|ttf|svg|pdf)$/,
36 | loader: 'file-loader',
37 | },
38 | ]
39 | },
40 | entry: {
41 | doc: './src/doc/index.js',
42 | },
43 | plugins: [
44 | new WebPlugin({
45 | template: './src/doc/template.html',
46 | filename: 'index.html'
47 | }),
48 | ],
49 | devtool: 'source-map',
50 | };
51 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "redemo",
3 | "version": "2.0.0",
4 | "description": "react demo component",
5 | "keywords": [
6 | "react",
7 | "demo",
8 | "component",
9 | "doc",
10 | "redemo"
11 | ],
12 | "repository": {
13 | "type": "git",
14 | "url": "git@github.com:imweb/redemo.git"
15 | },
16 | "main": "index.js",
17 | "scripts": {
18 | "dev": "webpack-dev-server --open",
19 | "doc:pub": "NODE_ENV=production webpack --config webpack-dist.config.js && rm -rf .doc",
20 | "npm:scss": "node-sass src/ -o .npm/",
21 | "npm:js": "BABEL_ENV=dist babel src/ --out-dir .npm/ --source-maps",
22 | "npm:pub": "npm run npm:scss && npm run npm:js && cp ./package.json .npm/ && cp -R ./src/iconfont ./.npm/iconfont && npm publish .npm/ && rm -rf .npm"
23 | },
24 | "author": "halwu",
25 | "license": "ISC",
26 | "dependencies": {
27 | "antd": "^2.10.2",
28 | "babel-runtime": "^6.23.0",
29 | "classnames": "^2.2.5",
30 | "prop-types": "^15.5.10",
31 | "react": "^16.0.0",
32 | "react-dom": "^16.0.0",
33 | "prop-types": "^15.6.0",
34 | "react-highlight": "^0.10.0",
35 | "remd": "^1.0.0"
36 | },
37 | "devDependencies": {
38 | "babel-cli": "^6.24.1",
39 | "babel-core": "^6.25.0",
40 | "babel-loader": "^7.1.0",
41 | "babel-plugin-import": "^1.2.1",
42 | "babel-plugin-replace-require-suffix": "^1.0.0",
43 | "babel-plugin-transform-runtime": "^6.23.0",
44 | "babel-preset-es2015": "^6.24.1",
45 | "babel-preset-react": "^6.24.1",
46 | "babel-preset-stage-2": "^6.24.1",
47 | "css-loader": "^0.28.4",
48 | "docgen-loader": "^1.3.4",
49 | "end-webpack-plugin": "^1.0.0",
50 | "file-loader": "^0.11.2",
51 | "gh-pages": "^1.0.0",
52 | "node-sass": "^4.5.3",
53 | "react-docgen": "^3.0.0-beta4",
54 | "sass-loader": "^6.0.6",
55 | "style-loader": "^0.18.2",
56 | "web-webpack-plugin": "^1.7.2",
57 | "webpack": "^3.0.0",
58 | "webpack-dev-server": "^2.5.0"
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/doc/template.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
8 |
9 |
11 | react demo component
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://www.npmjs.com/package/redemo)
2 | [](https://www.npmjs.com/package/redemo)
3 | [](https://npmjs.org/package/redemo)
4 |
5 | [中文文档](https://github.com/gwuhaolin/blog/issues/1)
6 |
7 | # redemo
8 | When you write a react component, you may need tell others how to use it by write some demos.
9 | Redemo is used to help write demo for react component in a easy way, is't pretty and simple to use.
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | ## feature
18 | - doc: write doc in markdown for this demo
19 | - code: show source code for this demo
20 | - propTypes: auto list react component `propTypes` document form comment in your component source instead of write by yourself
21 |
22 | ## install
23 | use it from npm in webpack
24 | ```bash
25 | npm i redemo
26 | ```
27 |
28 | then install webpack dependencies
29 | ```html
30 | npm i raw-loader react-docgen@next docgen-loader --save-dev
31 | ```
32 |
33 | ## example
34 | Let's write a demo for a `Button` component
35 |
36 | ```js
37 | import ReDemo from 'redemo';
38 | import Button from './button';
39 |
40 | // load propTypes by docgen-loader from button component source code
41 | const docgen = require('!!docgen-loader!../button');
42 |
43 | // load source code by raw-loader from button component source code
44 | const code = require('!!raw-loader!../button');
45 |
46 | // write doc for this demo in markdown
47 | const doc = `
48 | ### react component used to demonstrate react component
49 | #### structure
50 | - in top section is demo instance to play
51 | - circle button in right are toggle for **component propTypes** and **demo source code**
52 | - propTypes table show all prop's info for this component
53 | - in bottom is source code for this demo
54 | `
55 |
56 |
64 | demo component instance
65 |
66 | ```
67 |
68 | ## API
69 | see `ReDemo`'s all props [here](https://imweb.github.io/redemo/)
70 |
71 | ## In practice
72 | - [imuix](http://imweb.github.io/imuix/)
73 |
--------------------------------------------------------------------------------
/webpack-dist.config.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const path = require('path');
3 | const UglifyJsPlugin = require('webpack/lib/optimize/UglifyJsPlugin');
4 | const DefinePlugin = require('webpack/lib/DefinePlugin');
5 | const EndWebpackPlugin = require('end-webpack-plugin');
6 | const { WebPlugin } = require('web-webpack-plugin');
7 | const ghpages = require('gh-pages');
8 |
9 | const outputPath = path.resolve(__dirname, '.doc');
10 | module.exports = {
11 | output: {
12 | path: outputPath,
13 | publicPath: '',
14 | filename: '[name]_[chunkhash].js',
15 | },
16 | resolve: {
17 | // 加快搜索速度
18 | modules: [path.resolve(__dirname, 'node_modules')],
19 | // es tree-shaking
20 | mainFields: ['jsnext:main', 'browser', 'main'],
21 | },
22 | module: {
23 | rules: [
24 | {
25 | test: /\.js$/,
26 | // cacheDirectory 缓存babel编译结果加快重新编译速度
27 | loader: 'babel-loader?cacheDirectory',
28 | // 只命中src目录里的js文件,加快webpack搜索速度
29 | include: path.resolve(__dirname, 'src')
30 | },
31 | {
32 | test: /\.scss$/,
33 | loaders: ['style-loader', 'css-loader?minimize', 'sass-loader'],
34 | include: path.resolve(__dirname, 'src')
35 | },
36 | {
37 | test: /\.css$/,
38 | loaders: ['style-loader', 'css-loader?minimize'],
39 | },
40 | {
41 | test: /\.(gif|png|jpe?g|eot|woff|ttf|svg|pdf)$/,
42 | loader: 'file-loader',
43 | },
44 | ]
45 | },
46 | entry: {
47 | doc: './src/doc/index.js',
48 | },
49 | plugins: [
50 | new DefinePlugin({
51 | 'process.env': {
52 | 'NODE_ENV': JSON.stringify('production')
53 | }
54 | }),
55 | new UglifyJsPlugin({
56 | // 最紧凑的输出
57 | beautify: false,
58 | // 删除所有的注释
59 | comments: false,
60 | compress: {
61 | // 在UglifyJs删除没有用到的代码时不输出警告
62 | warnings: false,
63 | // 删除所有的 `console` 语句,可以兼容ie浏览器
64 | drop_console: true,
65 | // 内嵌定义了但是只用到一次的变量
66 | collapse_vars: true,
67 | // 提取出出现多次但是没有定义成变量去引用的静态值
68 | reduce_vars: true,
69 | }
70 | }),
71 | new WebPlugin({
72 | template: './src/doc/template.html',
73 | filename: 'index.html'
74 | }),
75 | new EndWebpackPlugin(() => {
76 | ghpages.publish(outputPath, { dotfiles: true }, (err) => {
77 | if (err) {
78 | console.error('push doc to gh-pages fail');
79 | } else {
80 | console.error('push doc to gh-pages succ');
81 | }
82 | })
83 | }),
84 | ]
85 | };
86 |
--------------------------------------------------------------------------------
/src/index.scss:
--------------------------------------------------------------------------------
1 | $colorBg: #fff;
2 | $colorBorder: #e9e9e9;
3 | $paddingRL: 15px;
4 | $paddingTB: 20px;
5 |
6 | @mixin ant-icon {
7 | @font-face {
8 | font-family: 'anticon';
9 | src: url('./iconfont/iconfont.eot') format('embedded-opentype'), /* chrome、firefox */
10 | url('./iconfont/iconfont.woff') format('woff'), /* chrome、firefox、opera、Safari, Android, iOS 4.2+*/
11 | url('./iconfont/iconfont.ttf') format('truetype'), /* iOS 4.1- */
12 | url('./iconfont/iconfont.svg') format('svg');
13 | }
14 |
15 | .anticon {
16 | display: inline-block;
17 | font-style: normal;
18 | vertical-align: baseline;
19 | text-align: center;
20 | text-transform: none;
21 | line-height: 1;
22 | text-rendering: optimizeLegibility;
23 | -webkit-font-smoothing: antialiased;
24 | -moz-osx-font-smoothing: grayscale;
25 | &:before {
26 | display: block;
27 | font-family: "anticon" !important;
28 | }
29 | }
30 |
31 | .anticon-copy:before {
32 | content: "\e648";
33 | }
34 |
35 | .anticon-exception:before {
36 | content: "\e665";
37 | }
38 |
39 | .anticon-bars:before {
40 | content: "\e639";
41 | }
42 |
43 | .anticon-code-o:before {
44 | content: "\e636";
45 | }
46 |
47 | .anticon-check-circle:before {
48 | content: "\e630";
49 | }
50 |
51 | .anticon-close-circle:before {
52 | content: "\e62e";
53 | }
54 | }
55 |
56 | @include ant-icon;
57 |
58 | @mixin reset {
59 | @font-face {
60 | font-family: "Helvetica Neue For Number";
61 | src: local("Helvetica Neue");
62 | unicode-range: U+30-39;
63 | }
64 | * {
65 | font-family: "Helvetica Neue For Number", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;
66 | font-size: 12px;
67 | line-height: 1.5;
68 | box-sizing: border-box;
69 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
70 | }
71 | a {
72 | text-decoration: none;
73 | color: #108ee9;
74 | }
75 | }
76 |
77 | .redemo {
78 | position: relative;
79 | border: 1px solid darken($colorBorder, 2%);
80 | border-radius: 4px;
81 | display: inline-block;
82 |
83 | &-toolbar {
84 | position: absolute;
85 | right: 10px;
86 | top: 10px;
87 |
88 | .ant-btn-circle {
89 | margin-left: 5px;
90 | }
91 | }
92 |
93 | &-run {
94 | padding: $paddingTB $paddingRL;
95 | }
96 |
97 | &-md {
98 | @include reset;
99 | color: rgba(0, 0, 0, 0.65);
100 | text-align: left;
101 | position: relative;
102 | padding: $paddingTB $paddingRL;
103 | border-top: 1px solid $colorBorder;
104 | }
105 |
106 | &-code {
107 | @include reset;
108 | text-align: left;
109 | position: relative;
110 | border-top: 1px dashed $colorBorder;
111 | padding: $paddingRL;
112 |
113 | .hljs {
114 | padding: 0;
115 | }
116 |
117 | &-copy {
118 | position: absolute;
119 | right: $paddingRL - 5px;
120 | top: $paddingRL;
121 | }
122 |
123 | pre {
124 | margin: 0;
125 | }
126 | }
127 |
128 | &-table {
129 | @include reset;
130 | color: rgba(0, 0, 0, 0.65);
131 | text-align: left;
132 | border-top: 1px dashed $colorBorder;
133 |
134 | th, td {
135 | word-break: normal !important;
136 | }
137 |
138 | &-required {
139 | color: #f46e65;
140 | }
141 |
142 | .ant-table-small {
143 | border: none;
144 | }
145 |
146 | .ant-table-title {
147 | margin-left: 8px;
148 | color: #000;
149 | font-weight: 500;
150 | }
151 | }
152 |
153 | &-tooltip {
154 | .ant-tooltip-inner {
155 | background-color: $colorBg;
156 | }
157 |
158 | .ant-tooltip-arrow {
159 | border-right-color: $colorBg;
160 | }
161 | }
162 |
163 | }
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 | import classnames from 'classnames';
4 | import Remd from 'remd';
5 |
6 | import Highlight from 'react-highlight';
7 | import 'highlight.js/styles/arduino-light.css';
8 |
9 | import message from 'antd/lib/message';
10 | import 'antd/lib/message/style/index.css';
11 |
12 | import Button from 'antd/lib/button';
13 | import 'antd/lib/button/style/index.css';
14 |
15 | import Table from 'antd/lib/table';
16 | import 'antd/lib/table/style/index.css';
17 |
18 | import Tag from 'antd/lib/tag';
19 | import 'antd/lib/tag/style/index.css';
20 |
21 | import Tooltip from 'antd/lib/tooltip';
22 | import 'antd/lib/tooltip/style/index.css';
23 |
24 | import './index.scss';
25 |
26 | /**
27 | * react component used to demonstrate react component
28 | */
29 | export default class Redemo extends Component {
30 |
31 | static propTypes = {
32 | /**
33 | * component instance
34 | */
35 | children: PropTypes.any.isRequired,
36 | /**
37 | * demo source code
38 | * - if it's void will not display
39 | */
40 | code: PropTypes.string,
41 | /**
42 | * explanation to this demo
43 | * - support markdown
44 | * - if it's void will not display
45 | */
46 | doc: PropTypes.string,
47 | /**
48 | * component's info load from [react-docgen](https://github.com/reactjs/react-docgen)
49 | * - support markdown
50 | * - if it's void will not display prop types table
51 | */
52 | docgen: PropTypes.arrayOf(PropTypes.shape({
53 | description: PropTypes.string,
54 | props: PropTypes.object,
55 | })),
56 | /**
57 | * whether show source code
58 | */
59 | codeVisible: PropTypes.bool,
60 | /**
61 | * whether show propTypes
62 | */
63 | propTypeVisible: PropTypes.bool,
64 | /**
65 | * whether show methods
66 | */
67 | methodsVisible: PropTypes.bool,
68 | /**
69 | * append className to Redemo
70 | */
71 | className: PropTypes.string,
72 | /**
73 | * className pass to markdown
74 | */
75 | mdClassName: PropTypes.string,
76 | /**
77 | * set style for Redemo
78 | */
79 | style: PropTypes.object,
80 | }
81 |
82 | static defaultProps = {
83 | codeVisible: false,
84 | propTypeVisible: true,
85 | methodsVisible: false,
86 | docgen: []
87 | }
88 |
89 | propTypesTableColumns = [
90 | {
91 | title: 'name',
92 | key: 'name',
93 | render: (_, record) => {
94 | const { propName, required } = record;
95 | return (
96 | {propName}
98 | )
99 | }
100 | }, {
101 | title: 'type',
102 | key: 'type',
103 | render: (_, record) => {
104 | const { type } = record;
105 | return (
106 |
107 | )
108 | }
109 | }, {
110 | title: 'description',
111 | dataIndex: 'description',
112 | key: 'description',
113 | render: (_, record) => {
114 | const { description } = record;
115 | if (typeof description === 'string' && description.length > 0) {
116 | const { mdClassName } = this.props;
117 | return {description} ;
118 | }
119 | return '-';
120 | }
121 | }, {
122 | title: 'defaultValue',
123 | dataIndex: 'defaultValue',
124 | key: 'defaultValue',
125 | render: (_, record) => {
126 | const { defaultValue = {}, type = {} } = record;
127 | let { value } = defaultValue;
128 | if (value === undefined) {
129 | return '-';
130 | }
131 | if (['object', 'shape'].indexOf(type.name) >= 0) {
132 | return (
133 |
135 | }>
136 | object
137 |
138 | )
139 | }
140 | return value;
141 | }
142 | }
143 | ];
144 |
145 | methodsTableColumns = [
146 | {
147 | title: 'name',
148 | key: 'name',
149 | render: (_, record) => {
150 | const { name } = record;
151 | if (name) {
152 | return name;
153 | }
154 | return '-';
155 | }
156 | }, {
157 | title: 'description',
158 | key: 'description',
159 | render: (_, record) => {
160 | const { description } = record;
161 | if (description) {
162 | return description;
163 | }
164 | return '-';
165 | }
166 | }, {
167 | title: 'params',
168 | key: 'params',
169 | render: (_, record) => {
170 | const { params } = record;
171 | if (Array.isArray(params)) {
172 | return params.map(({ description, name, type }) => (
173 |
174 |
175 | {name}
176 | {description}
177 |
178 | ));
179 | }
180 | return '-';
181 | }
182 | }, {
183 | title: 'returns',
184 | key: 'returns',
185 | render: (_, record) => {
186 | const { returns } = record;
187 | if (returns) {
188 | const { description, type } = returns;
189 | return (
190 |
191 |
192 | {description}
193 |
194 | )
195 | }else {
196 | return null;
197 | }
198 | }
199 | },
200 | ];
201 |
202 | state = {
203 | /**
204 | * whether show source code
205 | */
206 | codeVisible: this.props.codeVisible,
207 | /**
208 | * whether show propTypes
209 | */
210 | propTypeVisible: this.props.propTypeVisible,
211 | /**
212 | * whether show methods
213 | */
214 | methodsVisible: this.props.methodsVisible,
215 | }
216 |
217 | componentWillReceiveProps(nextProps) {
218 | const { codeVisible, propTypeVisible, methodsVisible } = this.props;
219 | if (nextProps.codeVisible !== codeVisible) {
220 | this._toggleCode();
221 | }
222 | if (nextProps.propTypeVisible !== propTypeVisible) {
223 | this._togglePropTypes();
224 | }
225 | if (nextProps.methodsVisible !== methodsVisible) {
226 | this._toggleMethods();
227 | }
228 | }
229 |
230 | _getPropTypes = () => {
231 | const { docgen } = this.props;
232 | return (docgen[0] || {}).props;
233 | }
234 |
235 | _getMethods = () => {
236 | const { docgen } = this.props;
237 | return (docgen[0] || {}).methods;
238 | }
239 |
240 | _toggleCode = () => {
241 | this.setState({
242 | codeVisible: !this.state.codeVisible
243 | })
244 | }
245 |
246 | _togglePropTypes = () => {
247 | this.setState({
248 | propTypeVisible: !this.state.propTypeVisible
249 | })
250 | }
251 |
252 | _toggleMethods = () => {
253 | this.setState({
254 | methodsVisible: !this.state.methodsVisible
255 | })
256 | }
257 |
258 | _copyCode = () => {
259 | const { code } = this.props;
260 | try {
261 | copyToClipboard(code);
262 | message.success('copy successful');
263 | } catch (err) {
264 | message.error(`copy failed, you browser don't support copy`);
265 | selectElementContents(this.refs['code']);
266 | }
267 | }
268 |
269 | _renderDoc = () => {
270 | const { code, doc, mdClassName } = this.props;
271 | const propTypes = this._getPropTypes();
272 | const methods = this._getMethods();
273 | return (
274 |
275 |
276 | {propTypes ? : null}
283 | {methods && methods.length > 0 ? : null}
290 | {code ? : null}
297 |
298 | {doc}
299 |
300 | )
301 | }
302 |
303 | _renderPropTypeTable = () => {
304 | const { propTypeVisible } = this.state;
305 | const propTypes = this._getPropTypes();
306 | if (propTypes && propTypeVisible) {
307 | const propTypesKeys = Object.keys(propTypes);
308 | // show PropTypeTable only if has more than one PropType
309 | if (propTypesKeys.length > 0) {
310 | const dataSource = propTypesKeys.map(propName => Object.assign({ propName }, propTypes[propName]));
311 | return (
312 | 'PropTypes'}
314 | rowKey="propName"
315 | className="redemo-table"
316 | columns={this.propTypesTableColumns}
317 | dataSource={dataSource}
318 | pagination={false}
319 | size="small"
320 | />
321 | )
322 | }
323 | }
324 | return null;
325 | }
326 |
327 | _renderMethodsTable = () => {
328 | const { methodsVisible } = this.state;
329 | const methods = this._getMethods();
330 | if (methods && methodsVisible) {
331 | // show MethodsTable only if has more than one method
332 | if (methods.length > 0) {
333 | return (
334 | 'Methods'}
336 | rowKey="name"
337 | className="redemo-table"
338 | columns={this.methodsTableColumns}
339 | dataSource={methods}
340 | pagination={false}
341 | size="small"
342 | />
343 | )
344 | }
345 | }
346 | return null;
347 | }
348 |
349 | _renderCode = () => {
350 | const { code } = this.props;
351 | const { codeVisible } = this.state;
352 | if (code && codeVisible) {
353 | return (
354 |
355 |
356 |
363 |
364 | {code}
365 |
366 | )
367 | }
368 | return null;
369 | }
370 |
371 | render() {
372 | const { className, style, children } = this.props;
373 | return (
374 |
375 |
{children}
376 | {this._renderDoc()}
377 | {this._renderPropTypeTable()}
378 | {this._renderMethodsTable()}
379 | {this._renderCode()}
380 |
381 | )
382 | }
383 | }
384 |
385 | /**
386 | * PropTypeValueTag show in propTypes Table for complex prop
387 | */
388 | class PropTypeValueTag extends Component {
389 |
390 | static propTypes = {
391 | type: PropTypes.object
392 | }
393 |
394 | static defaultProps = {
395 | type: {}
396 | }
397 |
398 | render() {
399 | const { type } = this.props;
400 | if (type) {
401 | const { name, value } = type;
402 | if (value !== undefined) {
403 | return (
404 |
406 | }>
407 | {name}
408 |
409 | )
410 | } else {
411 | return {name}
412 | }
413 | } else {
414 | return null;
415 | }
416 | }
417 | }
418 |
419 | /**
420 | * display a JSON in pop
421 | */
422 | class ObjectView extends Component {
423 | static propTypes = {
424 | object: PropTypes.any
425 | }
426 |
427 | static defaultProps = {
428 | object: {}
429 | }
430 |
431 | render() {
432 | const { object } = this.props;
433 | let code = object;
434 | if (typeof object === 'object') {
435 | code = JSON.stringify(code, null, 4);
436 | }
437 | return (
438 | {code}
439 | )
440 | }
441 | }
442 |
443 | /**
444 | * Copies a string to the clipboard. Must be called from within an
445 | * event handler such as click. May return false if it failed, but
446 | * this is not always possible. Browser support for Chrome 43+,
447 | * Firefox 42+, Safari 10+, Edge and IE 10+.
448 | * IE: The clipboard feature may be disabled by an administrator. By
449 | * default a prompt is shown the first time the clipboard is
450 | * used (per session).
451 | * @param text
452 | * @returns {boolean}
453 | */
454 | function copyToClipboard(text) {
455 | if (window.clipboardData && window.clipboardData.setData) {
456 | // IE specific code path to prevent textarea being shown while dialog is visible.
457 | return clipboardData.setData('Text', text);
458 |
459 | } else { //noinspection JSUnresolvedVariable,JSUnresolvedFunction
460 | if (document.queryCommandSupported && document.queryCommandSupported('copy')) {
461 | let textarea = document.createElement('textarea');
462 | textarea.textContent = text;
463 | textarea.style.position = 'fixed'; // Prevent scrolling to bottom of page in MS Edge.
464 | document.body.appendChild(textarea);
465 | textarea.select();
466 | try {
467 | return document.execCommand('copy'); // Security exception may be thrown by some browsers.
468 | } catch (err) {
469 | throw err;
470 | } finally {
471 | document.body.removeChild(textarea);
472 | }
473 | }
474 | }
475 | }
476 |
477 | /**
478 | * If you want to select all the content of an element (contenteditable or not) in Chrome, here's how.
479 | * This will also work in Firefox, Safari 3+, Opera 9+ (possibly earlier versions too) and IE 9.
480 | * You can also create selections down to the character level.
481 | * The APIs you need are DOM Range (current spec is DOM Level 2, see also MDN) and Selection,
482 | * which is being specified as part of a new Range spec (MDN docs).
483 | * @param el
484 | * http://stackoverflow.com/questions/6139107/programmatically-select-text-in-a-contenteditable-html-element
485 | */
486 | function selectElementContents(el) {
487 | let range = document.createRange();
488 | range.selectNodeContents(el);
489 | let sel = window.getSelection();
490 | sel.removeAllRanges();
491 | sel.addRange(range);
492 | }
--------------------------------------------------------------------------------
/src/iconfont/iconfont.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Created by FontForge 20120731 at Sun Nov 20 19:53:22 2016
6 | By admin
7 |
8 |
9 |
10 |
24 |
26 |
28 |
30 |
32 |
34 |
38 |
40 |
42 |
44 |
46 |
48 |
50 |
52 |
54 |
57 |
60 |
63 |
66 |
70 |
74 |
78 |
82 |
85 |
88 |
91 |
95 |
98 |
101 |
104 |
107 |
110 |
112 |
114 |
116 |
118 |
120 |
122 |
124 |
126 |
129 |
132 |
135 |
137 |
141 |
144 |
147 |
150 |
154 |
157 |
159 |
162 |
166 |
169 |
173 |
176 |
180 |
182 |
184 |
193 |
196 |
199 |
202 |
206 |
210 |
213 |
217 |
222 |
224 |
227 |
231 |
234 |
238 |
246 |
251 |
256 |
259 |
263 |
266 |
272 |
275 |
278 |
282 |
286 |
289 |
292 |
295 |
298 |
301 |
305 |
308 |
311 |
313 |
318 |
321 |
325 |
329 |
332 |
335 |
338 |
341 |
346 |
349 |
354 |
357 |
361 |
367 |
370 |
375 |
379 |
383 |
386 |
389 |
392 |
395 |
401 |
405 |
408 |
412 |
415 |
419 |
423 |
428 |
433 |
436 |
440 |
443 |
447 |
450 |
453 |
455 |
458 |
464 |
467 |
471 |
475 |
479 |
482 |
486 |
489 |
495 |
499 |
504 |
507 |
510 |
514 |
518 |
522 |
527 |
532 |
536 |
539 |
543 |
546 |
549 |
553 |
557 |
562 |
566 |
571 |
575 |
578 |
582 |
584 |
587 |
590 |
593 |
596 |
599 |
602 |
605 |
608 |
611 |
614 |
617 |
620 |
624 |
626 |
630 |
634 |
637 |
640 |
642 |
645 |
648 |
651 |
654 |
657 |
660 |
663 |
666 |
669 |
672 |
675 |
678 |
681 |
684 |
687 |
690 |
693 |
697 |
702 |
706 |
710 |
714 |
717 |
720 |
724 |
728 |
731 |
732 |
733 |
--------------------------------------------------------------------------------