├── src
├── QuestionnairAnswer
│ ├── index.less
│ └── index.js
├── .DS_Store
├── index.js
├── main.js
├── Questionnair
│ ├── index.less
│ └── index.js
├── QuestionnairContent
│ ├── index.less
│ └── index.js
├── QuestionnairSiderbar
│ ├── index.less
│ └── index.js
└── QuestionnairEditor
│ ├── index.less
│ └── index.js
├── .gitignore
├── .DS_Store
├── assets
├── .DS_Store
├── iconfonts
│ ├── .DS_Store
│ ├── iconfont.eot
│ ├── iconfont.ttf
│ ├── iconfont.woff
│ ├── iconfont.css
│ └── iconfont.svg
└── scale_default.png
├── libs
├── .DS_Store
├── Dropdown
│ ├── index.less
│ └── index.js
├── ContentEditable
│ ├── index.less
│ └── index.js
├── Shake
│ ├── index.less
│ └── index.js
├── DragSort
│ ├── index.less
│ ├── index.js
│ └── example.js
├── Button
│ ├── index.less
│ └── index.js
├── Input
│ ├── index.less
│ └── index.js
├── Checkbox
│ ├── index.less
│ └── index.js
├── Radio
│ ├── index.less
│ └── index.js
└── Dialog
│ ├── index.less
│ └── index.js
├── .babelrc
├── react-questionnair.png
├── dist
├── 29933c03dca9629dd8bfef50bec5005f.png
├── 3f8467b01369f58b0a67ac2ed08c8f3a.eot
├── ab85a97f51f177206f0635614657e685.ttf
└── index.html
├── utils
└── utils.js
├── index.html
├── bin
└── dev-server.js
├── package.json
├── webpack
└── webpack.config.js
└── README.md
/src/QuestionnairAnswer/index.less:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | npm-debug.log*
--------------------------------------------------------------------------------
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pandly/react-questionnair/HEAD/.DS_Store
--------------------------------------------------------------------------------
/src/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pandly/react-questionnair/HEAD/src/.DS_Store
--------------------------------------------------------------------------------
/assets/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pandly/react-questionnair/HEAD/assets/.DS_Store
--------------------------------------------------------------------------------
/libs/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pandly/react-questionnair/HEAD/libs/.DS_Store
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "es2015",
4 | "react",
5 | "stage-1"
6 | ],
7 | }
--------------------------------------------------------------------------------
/libs/Dropdown/index.less:
--------------------------------------------------------------------------------
1 | :global{
2 | .wowjoy-select {
3 | display: inline-block;
4 | }
5 | };
--------------------------------------------------------------------------------
/react-questionnair.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pandly/react-questionnair/HEAD/react-questionnair.png
--------------------------------------------------------------------------------
/assets/iconfonts/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pandly/react-questionnair/HEAD/assets/iconfonts/.DS_Store
--------------------------------------------------------------------------------
/assets/scale_default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pandly/react-questionnair/HEAD/assets/scale_default.png
--------------------------------------------------------------------------------
/assets/iconfonts/iconfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pandly/react-questionnair/HEAD/assets/iconfonts/iconfont.eot
--------------------------------------------------------------------------------
/assets/iconfonts/iconfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pandly/react-questionnair/HEAD/assets/iconfonts/iconfont.ttf
--------------------------------------------------------------------------------
/assets/iconfonts/iconfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pandly/react-questionnair/HEAD/assets/iconfonts/iconfont.woff
--------------------------------------------------------------------------------
/libs/ContentEditable/index.less:
--------------------------------------------------------------------------------
1 | :global {
2 | .contentEditable {
3 | outline: none;
4 | line-height: 36px;
5 | }
6 | }
--------------------------------------------------------------------------------
/dist/29933c03dca9629dd8bfef50bec5005f.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pandly/react-questionnair/HEAD/dist/29933c03dca9629dd8bfef50bec5005f.png
--------------------------------------------------------------------------------
/dist/3f8467b01369f58b0a67ac2ed08c8f3a.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pandly/react-questionnair/HEAD/dist/3f8467b01369f58b0a67ac2ed08c8f3a.eot
--------------------------------------------------------------------------------
/dist/ab85a97f51f177206f0635614657e685.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pandly/react-questionnair/HEAD/dist/ab85a97f51f177206f0635614657e685.ttf
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import Questionnair from './Questionnair';
2 | import Editor from './QuestionnairEditor';
3 | import Answer from './QuestionnairAnswer';
4 | import 'assets/iconfonts/iconfont.css';
5 |
6 | Questionnair.Editor = Editor;
7 | Questionnair.Answer = Answer;
8 |
9 | export default Questionnair;
--------------------------------------------------------------------------------
/utils/utils.js:
--------------------------------------------------------------------------------
1 | export default function uuid() {
2 | const s = [];
3 | const hexDigits = '0123456789abcdef';
4 | for (let i = 0; i < 36; i += 1) {
5 | s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
6 | }
7 | s[14] = '4';
8 | s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);
9 | const id = s.join('');
10 | return id;
11 | }
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | react-questionnair
6 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/libs/Shake/index.less:
--------------------------------------------------------------------------------
1 | //animate
2 | @keyframes shake {
3 | from, to {
4 | transform: translate3d(0, 0, 0);
5 | }
6 |
7 | 10%, 30%, 50%, 70%, 90% {
8 | transform: translate3d(-8px, 0, 0);
9 | }
10 |
11 | 20%, 40%, 60%, 80% {
12 | transform: translate3d(8px, 0, 0);
13 | }
14 | }
15 | .shake-transition {
16 | height: 100%;
17 | width: 100%;
18 | }
19 | .shaked {
20 | animation-name: shake;
21 | animation-duration: 1s;
22 | animation-fill-mode: both;
23 | }
24 |
--------------------------------------------------------------------------------
/dist/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | react-questionnair
6 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {
3 | render,
4 | } from 'react-dom';
5 | import Questionnair from './index.js';
6 |
7 | const index = require('./index');
8 |
9 | const renderDom = (Component) => {
10 | render(
11 | ,
12 | document.getElementById('app')
13 | );
14 | };
15 | renderDom(Questionnair);
16 | if (module.hot) {
17 | module.hot.accept('./index', () => {
18 | const QuestionnairEl = index.default;
19 | renderDom(QuestionnairEl);
20 | });
21 | }
--------------------------------------------------------------------------------
/src/Questionnair/index.less:
--------------------------------------------------------------------------------
1 | * {
2 | box-sizing: border-box;
3 | user-select: none;
4 | font-family: "PingFang SC", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;
5 | }
6 | .questionnair {
7 | display: flex;
8 | width: 100%;
9 | height: 100%;
10 | background: #f0f0f0;
11 | }
12 | :global {
13 | .title-inner {
14 | width: 700px;
15 | height: 45px;
16 | margin: 0 auto;
17 | background: #fff;
18 | display: flex;
19 | justify-content: center;
20 | align-items: center;
21 | border: 1px solid transparent;
22 | }
23 | }
--------------------------------------------------------------------------------
/libs/DragSort/index.less:
--------------------------------------------------------------------------------
1 | :global {
2 | .item{
3 | height: 35px;
4 | margin:10px;
5 | // background-color: #eee;
6 | // &:hover {
7 | // background-color: red;
8 | // }
9 | }
10 | .item-notdrag {
11 | height: 35px;
12 | margin:10px;
13 | background-color: #eee;
14 |
15 | }
16 | .inner {
17 | height: 100%;
18 | }
19 | .item.active{
20 | //height: 35px;
21 | //margin:10px;
22 | opacity: 0;
23 | //background-color: #eee !important;
24 | }
25 | };
--------------------------------------------------------------------------------
/libs/Button/index.less:
--------------------------------------------------------------------------------
1 | :global{
2 | .wowjoy-button {
3 | padding: 6px 20px;
4 | border: 1px solid #06aea6;
5 | margin: 0 10px;
6 | outline: none;
7 | cursor: pointer;
8 | font-size: 14px
9 | }
10 | .wowjoy-button__primary {
11 | background: #06aea6;
12 | color: #fff;
13 | }
14 | .wowjoy-button__normal {
15 | background: #fff;
16 | color: #06aea6;
17 | }
18 | .wowjoy-button__mini {
19 | padding: 4px;
20 | font-size: 12px;
21 | }
22 | .wowjoy-button__small {
23 | padding: 7px 9px;
24 | font-size: 12px;
25 | }
26 | .wowjoy-button__large {
27 | padding: 11px 19px;
28 | font-size: 16px;
29 | }
30 | };
--------------------------------------------------------------------------------
/libs/Input/index.less:
--------------------------------------------------------------------------------
1 | :global {
2 | .wowjoy-input {
3 | overflow: hidden;
4 | width: 100%;
5 | height: 100%;
6 | flex: 1;
7 | z-index: 5;
8 | display: inline-block;
9 | }
10 | .wowjoy-input__inner {
11 | width: 100%;
12 | height: 36px;
13 | border: 1px solid #ddd;
14 | outline: none;
15 | transition: all .3s;
16 | padding-left: 11px;
17 | font-size: 14px;
18 | color: rgb(102, 102, 102);
19 | &:focus {
20 | border-color: #06AEA6;
21 | }
22 | }
23 | .wowjoy-textarea__inner {
24 | width: 100%;
25 | border: 1px solid #ddd;
26 | outline: none;
27 | transition: all .3s;
28 | padding: 0 11px;
29 | font-size: 14px;
30 | color: rgb(102, 102, 102);
31 | &:focus {
32 | border-color: #06AEA6;
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/bin/dev-server.js:
--------------------------------------------------------------------------------
1 | /*
2 | * webpack-dev-server是一个小型的静态文件服务器,为webpack打包的资源文件提供Web服务
3 | */
4 | const WebpackDevServer = require('webpack-dev-server');
5 | const config = require('../webpack/webpack.config');
6 | const webpack = require('webpack');
7 | const path = require('path');
8 | const compiler = webpack(config);
9 | const port = 9090;
10 |
11 | const server = new WebpackDevServer(compiler, {
12 | contentBase: path.resolve(__dirname, '../dist'), //默认会以根文件夹提供本地服务器,这里指定文件夹
13 | historyApiFallback: true, //在开发单页应用时非常有用,它依赖于HTML5 history API,如果设置为true,所有的跳转将指向index.html
14 | port: port, //如果省略,默认8080
15 | publicPath: "/",
16 | inline: true, // 自动刷新
17 | hot: true, // 开启热模块替换
18 | });
19 |
20 | console.log('> Starting dev server...')
21 | server.listen(port, 'localhost', function(err) {
22 | if (err) throw err
23 | })
--------------------------------------------------------------------------------
/libs/Checkbox/index.less:
--------------------------------------------------------------------------------
1 | :global {
2 | .wowjoy-checkbox {
3 | cursor: pointer;
4 | display: inline-block;
5 | }
6 | input[type='checkbox']:checked {
7 | &+.wowjoy-checkbox__inner {
8 | border-color: #06aea6;
9 | &:before {
10 | content: '\2713';
11 | color: #06aea6;
12 | position: absolute;
13 | top: 50%;
14 | left: 50%;
15 | transform: translate(-50%, -50%);
16 | }
17 | }
18 | }
19 | .wowjoy-checkbox__inner {
20 | position: relative;
21 | display: inline-block;
22 | width: 16px;
23 | height: 16px;
24 | background: #fff;
25 | border: 1px solid #DBDBDB;
26 | vertical-align: sub;
27 | margin-right: 5px;
28 | }
29 | .wowjoy-checkbox__text {
30 | display: inline-block;
31 | max-width: 80%;
32 | vertical-align: top;
33 | word-break: break-all;
34 | }
35 | }
--------------------------------------------------------------------------------
/src/QuestionnairAnswer/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const QuestionnairAnswer = ({
4 | answer
5 | }) => {
6 | return (
7 |
8 |
{`${index + 1}.${answer.type === 'input' ? answer.completionForwards : answer.title + ':'}`}
9 |
{typeof answer.answer[answer.type] !== 'string' ? (
10 | typeof answer.answer[answer.type].optionValue !== 'string' ? (
11 | answer.answer[answer.type].optionValue.map((item, index) => {
12 | return (
13 | item && {item}
14 | )
15 | })
16 | ) : answer.answer[answer.type].optionValue
17 | ) : answer.answer[answer.type]}
18 |
19 | );
20 | }
21 |
22 | export default QuestionnairAnswer;
--------------------------------------------------------------------------------
/libs/Radio/index.less:
--------------------------------------------------------------------------------
1 | :global {
2 | .wowjoy-radio {
3 | cursor: pointer;
4 | display: inline-block;
5 | }
6 | input[type='radio']:checked {
7 | &+.wowjoy-radio__inner {
8 | border-color: #06aea6;
9 | &:before {
10 | content: '';
11 | background: #06aea6;
12 | width: 8px;
13 | height: 8px;
14 | border-radius: 50%;
15 | position: absolute;
16 | top: 50%;
17 | left: 50%;
18 | transform: translate(-50%, -50%);
19 | }
20 | }
21 | }
22 | .wowjoy-radio__inner {
23 | position: relative;
24 | display: inline-block;
25 | width: 16px;
26 | height: 16px;
27 | border-radius: 50%;
28 | background: #fff;
29 | border: 1px solid #DBDBDB;
30 | vertical-align: sub;
31 | margin-right: 5px;
32 | }
33 | .wowjoy-radio__text {
34 | display: inline-block;
35 | max-width: 80%;
36 | vertical-align: top;
37 | word-break: break-all;
38 | }
39 | }
--------------------------------------------------------------------------------
/libs/Dropdown/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import './index.less';
3 |
4 | class Select extends React.PureComponent {
5 |
6 | handleChange = (e) => {
7 | const {
8 | onChange,
9 | } = this.props;
10 | if (onChange) {
11 | onChange(e);
12 | };
13 | }
14 |
15 | render() {
16 | const {
17 | name,
18 | value,
19 | options,
20 | } = this.props;
21 | return (
22 |
23 |
33 |
34 | );
35 | }
36 | }
37 |
38 | export default Select;
--------------------------------------------------------------------------------
/libs/Radio/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import './index.less';
3 |
4 | class Radio extends React.PureComponent {
5 |
6 | handleChange = (e) => {
7 | const {
8 | onChange,
9 | } = this.props;
10 | if (onChange) {
11 | onChange(e);
12 | };
13 | }
14 |
15 | render() {
16 | const {
17 | defaultChecked,
18 | value,
19 | name,
20 | label,
21 | style,
22 | } = this.props;
23 | return (
24 |
35 | );
36 | }
37 | }
38 |
39 | export default Radio;
--------------------------------------------------------------------------------
/libs/Button/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import './index.less';
3 |
4 | class Button extends React.PureComponent {
5 | static defaultProps = {
6 | disabled: false,
7 | type: '',
8 | size: '',
9 | }
10 |
11 | handleClick = (e) => {
12 | const {
13 | onClick,
14 | } = this.props;
15 | if (onClick) {
16 | onClick();
17 | };
18 | }
19 |
20 | render() {
21 | const {
22 | type,
23 | size,
24 | disabled,
25 | children,
26 | onClick,
27 | ...otherProps,
28 | } = this.props;
29 | const buttonType = type ? `wowjoy-button__${type}` : '';
30 | const buttonSize = size ? `wowjoy-button__${size}` : '';
31 | return (
32 |
38 | );
39 | }
40 | }
41 |
42 | export default Button;
--------------------------------------------------------------------------------
/libs/Shake/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import './index.less';
3 |
4 | class ShakeTransition extends React.PureComponent {
5 | state = {
6 | shake: false,
7 | }
8 |
9 | componentWillReceiveProps(nextProps) {
10 | if (nextProps.shake !== this.props.shake) {
11 | this.setState({
12 | shake: true,
13 | });
14 | this.timerID = setTimeout(() => this.triggerShake(), 1000);
15 | };
16 | }
17 |
18 | triggerShake = () => {
19 | this.setState({
20 | shake: false,
21 | });
22 | }
23 |
24 | componentWillUnmount() {
25 | clearTimeout(this.timerID);
26 | }
27 |
28 | render() {
29 | const {
30 | children,
31 | } = this.props;
32 | const {
33 | shake,
34 | } = this.state;
35 | return (
36 |
37 | {this.props.children}
38 |
39 | );
40 | }
41 | }
42 |
43 | export default ShakeTransition;
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-questionnair",
3 | "version": "v1.0.1",
4 | "description": "",
5 | "main": "src/index.js",
6 | "scripts": {
7 | "dev": "node bin/dev-server",
8 | "build": "webpack --config webpack/webpack.config.js"
9 | },
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "babel-core": "^6.26.3",
14 | "babel-loader": "^7.1.4",
15 | "babel-preset-es2015": "^6.24.1",
16 | "babel-preset-react": "^6.24.1",
17 | "babel-preset-stage-1": "^6.24.1",
18 | "react": "^16.4.1",
19 | "react-dom": "^16.4.1"
20 | },
21 | "devDependencies": {
22 | "babel-eslint": "^8.2.6",
23 | "css-loader": "^0.28.11",
24 | "file-loader": "^1.1.11",
25 | "html-webpack-plugin": "^3.2.0",
26 | "less": "^3.0.4",
27 | "less-loader": "^4.1.0",
28 | "style-loader": "^0.21.0",
29 | "url-loader": "^1.0.1",
30 | "webpack": "^4.15.0",
31 | "webpack-cli": "^3.0.8",
32 | "webpack-dev-server": "^3.1.4"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/libs/Checkbox/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import './index.less';
3 |
4 | class Checkbox extends React.PureComponent {
5 | static defaultProps = {
6 | value: '',
7 | name: '',
8 | }
9 |
10 | handleChange = (e) => {
11 | const {
12 | onChange,
13 | index,
14 | } = this.props;
15 | if (onChange) {
16 | onChange(e, index);
17 | };
18 | }
19 |
20 | render() {
21 | const {
22 | defaultChecked,
23 | value,
24 | name,
25 | index,
26 | label,
27 | style,
28 | } = this.props;
29 | return (
30 |
42 | );
43 | }
44 | }
45 |
46 | export default Checkbox;
--------------------------------------------------------------------------------
/libs/Dialog/index.less:
--------------------------------------------------------------------------------
1 | :global {
2 | .wowjoy-dialog {
3 | position: absolute;
4 | top: 0;
5 | left: 0;
6 | right: 0;
7 | bottom: 0;
8 | background: rgba(0,0,0,0.30);
9 | //visibility: hidden;
10 | display: none;
11 | //transition: all .3s;
12 | z-index: 10;
13 | }
14 | .wowjoy-dialog__fadeIn {
15 | display: block;
16 | }
17 | .wowjoy-dialog__inner {
18 | background: #FFFFFF;
19 | box-shadow: 0 0 4px 0 rgba(0,0,0,0.20);
20 | border-radius: 3px;
21 | padding: 10px 20px;
22 | width: 40%;
23 | max-width: 500px;
24 | min-width: 300px;
25 | position: absolute;
26 | top: 50%;
27 | left: 50%;
28 | transform: translate(-50%, -50%);
29 | //opacity: 0;
30 | //transition: all .3s;
31 | }
32 | .wowjoy-dialog__slideDown {
33 | opacity: 1;
34 | transform: translateY(-50%);
35 | }
36 | .wowjoy-dialog__header {
37 | margin-bottom: 15px;
38 | font-family: PingFangSC-Medium;
39 | font-size: 16px;
40 | color: #333333;
41 | }
42 | .wowjoy-dialog__footer {
43 | height: 40px;
44 | width: 100%;
45 | display: flex;
46 | align-items: center;
47 | justify-content: center;
48 | }
49 | };
--------------------------------------------------------------------------------
/src/QuestionnairContent/index.less:
--------------------------------------------------------------------------------
1 | .questionnair-page {
2 | flex: 1;
3 | background: #fff;
4 | box-shadow: 0 3px 4px 0 rgba(202,202,202,0.50);
5 | margin-left: 20px;
6 | overflow: auto;
7 | position: absolute;
8 | left: 170px;
9 | right: 20px;
10 | top: 20px;
11 | bottom: 20px;
12 | width: 1000px;
13 | margin: auto;
14 | }
15 | .questionnair-page-banner {
16 | height: 46px;
17 | width: 700px;
18 | margin: 0 auto;
19 | border-bottom: 1px solid #DBDBDB;
20 | display: flex;
21 | align-items: center;
22 | justify-content: flex-end;
23 | }
24 | .banner-text {
25 | cursor: pointer;
26 | display: inline-block;
27 | color: #999;
28 | }
29 | .questionnair-page-title {
30 | margin: 10px 0;
31 | width: 100%;
32 | padding: 10px 0;
33 | border-top: 1px solid transparent;
34 | border-bottom: 1px solid transparent;
35 | &:hover {
36 | border-color: #DBDBDB;
37 | background: #FAFAFA;
38 | :global {
39 | .title-inner {
40 | border-color: #DBDBDB;
41 | }
42 | };
43 | }
44 | }
45 | .questionnair-page-content {
46 | width: 100%;
47 | }
48 | .questionnair-page-default {
49 | display: flex;
50 | align-items: center;
51 | justify-content: center;
52 | flex-direction: column;
53 | position: absolute;
54 | top: 45%;
55 | left: 50%;
56 | transform: translate(-50%, -50%);
57 | }
58 | .page-default-text {
59 | font-size: 16px;
60 | color: #999;
61 | margin-top: 20px;
62 | }
--------------------------------------------------------------------------------
/libs/Dialog/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Button from 'libs/Button';
3 | import './index.less'
4 |
5 | class Dialog extends React.PureComponent {
6 | state = {
7 | visible: this.props.visible,
8 | }
9 |
10 | componentWillReceiveProps(nextProps) {
11 | if (nextProps.visible !== this.props.visible) {
12 | this.setState({
13 | visible: nextProps.visible,
14 | });
15 | };
16 | }
17 |
18 | confirm = () => {
19 | const {
20 | onConfirm,
21 | } = this.props;
22 | if (onConfirm) {
23 | onConfirm();
24 | };
25 | }
26 |
27 | cancel = () => {
28 | const {
29 | onCancel,
30 | } = this.props;
31 | if (onCancel) {
32 | onCancel();
33 | };
34 | }
35 |
36 | render() {
37 | const {
38 | title,
39 | children,
40 | onCancel,
41 | onConfirm,
42 | } = this.props;
43 | const {
44 | visible,
45 | } = this.state;
46 | const fade = visible ? 'wowjoy-dialog__fadeIn' : '';
47 | return (
48 |
49 |
50 |
51 | {title}
52 |
53 |
54 | {children}
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 | );
63 | }
64 | }
65 |
66 | export default Dialog;
--------------------------------------------------------------------------------
/src/QuestionnairSiderbar/index.less:
--------------------------------------------------------------------------------
1 | .questionnair-siderbar {
2 | position: absolute;
3 | bottom: 20px;
4 | top: 20px;
5 | left: 20px;
6 | width: 210px;
7 | display: flex;
8 | flex-direction: column;
9 | }
10 | .siderbar-tab {
11 | width: 100%;
12 | height: 30px;
13 | display: flex;
14 | position: relative;
15 | z-index: 1;
16 | }
17 | .tab-item {
18 | flex: 1;
19 | text-align: center;
20 | height: 30px;
21 | line-height: 30px;
22 | color: #666;
23 | background: #F7F7F7;
24 | border: 1px solid #e8e8e8;
25 | cursor: pointer;
26 | }
27 | .tab-item-active {
28 | box-shadow: 0 0 4px 0 rgba(202,202,202,0.50);
29 | border: 1px solid transparent;
30 | background: #fff;
31 | position: relative;
32 | &:before {
33 | content: '';
34 | position: absolute;
35 | top: -1px;
36 | left: -1px;
37 | right: -1px;
38 | height: 2px;
39 | background-color: #06AEA6;
40 | z-index: 1;
41 | }
42 | }
43 | .siderbar-menu {
44 | flex: 1;
45 | box-shadow: 0 3px 4px 0 rgba(202,202,202,0.50);
46 | background: #fff;
47 | z-index: 2;
48 | }
49 | .siderbar-menu-content {
50 | width: 100%;
51 | }
52 | .siderbar-menu-icon {
53 | margin-right: 10px;
54 | }
55 | .siderbar-menu-editors {
56 | width: 168px;
57 | height: 36px;
58 | border: 1px solid #06AEA6;
59 | color: #06AEA6;
60 | padding-left: 8px;
61 | margin: 15px auto;
62 | cursor: pointer;
63 | display: flex;
64 | align-items: center;
65 | position: relative;
66 | }
67 | .siderbar-menu-summary {
68 | width: 100%;
69 | height: 36px;
70 | color: #06AEA6;
71 | padding-left: 30px;
72 | padding-right: 10px;
73 | margin: 0 auto;
74 | cursor: pointer;
75 | display: flex;
76 | align-items: center;
77 | position: relative;
78 | }
79 | .summary-text {
80 | overflow: hidden;
81 | text-overflow: ellipsis;
82 | white-space: nowrap;
83 | }
84 | .summary-drag-mask {
85 | position: absolute;
86 | top: 0;
87 | left: 0;
88 | right: 0;
89 | bottom: 0;
90 | }
91 |
--------------------------------------------------------------------------------
/libs/DragSort/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | let curDragIndex = null;
4 |
5 | export default function DragSort(props) {
6 | let container = props.children;
7 | let draggable = props.draggable;
8 |
9 | function onChange(from, to) {
10 | let curValue = props.data;
11 | let newValue = arrMove(curValue, from, to);
12 | if (typeof props.onDragMove === 'function') {
13 | return props.onDragMove(newValue, from, to);
14 | }
15 | }
16 | return (
17 |
18 | {container.map((item, index)=>{
19 | if(React.isValidElement(item)){
20 | return React.cloneElement(item, {
21 | draggable,
22 | //开始拖动元素时触发此事件
23 | onDragStart(){
24 | curDragIndex = index;
25 | },
26 | /*
27 | * 当被拖动的对象进入其容器范围内时触发此事件
28 | * 在自身拖动时也会触发该事件
29 | */
30 | onDragEnter() {
31 | onChange(curDragIndex, index);
32 | curDragIndex = index;
33 | },
34 | /*
35 | * 当被拖动的对象在另一对象容器范围内拖动时触发此事件
36 | * 在拖动元素时,每隔350毫秒会触发onDragOver事件
37 | */
38 | onDragOver(e) {
39 | /*
40 | * 默认情况下,数据/元素不能放置到其他元素中。如果要实现该功能,我们需要
41 | * 防止元素的默认处理方法,我们可以通过调用event.preventDefault()方法来实现onDragOver事件
42 | */
43 | e.preventDefault();
44 | },
45 | //完成元素拖动后触发
46 | onDragEnd(){
47 | curDragIndex = null;
48 | if(typeof props.onDragEnd === 'function'){
49 | props.onDragEnd(index);
50 | };
51 | },
52 | })
53 | }
54 | return item;
55 | })}
56 |
57 | );
58 | }
59 |
60 | function arrMove(arr, fromIndex, toIndex) {
61 | if (fromIndex !== toIndex) {
62 | arr = arr.concat();
63 | let item = arr.splice(fromIndex, 1)[0];
64 | arr.splice(toIndex, 0, item);
65 | };
66 | return arr;
67 | }
--------------------------------------------------------------------------------
/libs/DragSort/example.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import DragSort from './index.js';
3 |
4 | export default class DragSortExample extends React.Component {
5 | constructor(props) {
6 | super(props);
7 | this.state = {
8 | list: [{
9 | name: 'title'
10 | }, {
11 | name: 'name'
12 | }, {
13 | name: 'code'
14 | }, {
15 | name: 'email'
16 | }],
17 | curMoveItem: null,
18 | index: '',
19 | dragged: false,
20 | }
21 | }
22 |
23 | handleDragMove = (data, from, to) => {
24 | this.setState({
25 | curMoveItem: to,
26 | list: data,
27 | index: null,
28 | });
29 | }
30 |
31 | handleDragEnd = (index) => {
32 | this.setState({
33 | curMoveItem: null,
34 | dragged: false,
35 | index,
36 | });
37 | }
38 |
39 | enter = (index) => {
40 | if (this.state.index !== null) {
41 | this.setState({
42 | index,
43 | });
44 | };
45 | }
46 |
47 | leave = () => {
48 | if (this.state.index !== null) {
49 | this.setState({
50 | index: '',
51 | });
52 | };
53 | }
54 |
55 | render() {
56 | const {
57 | dragged,
58 | } = this.state;
59 | const el = this.state.list.map((item, index) => {
60 | return (
61 |
71 | );
72 | });
73 | return (
74 |
85 | );
86 | }
87 | }
--------------------------------------------------------------------------------
/libs/Input/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import './index.less'
3 |
4 | class Input extends React.PureComponent {
5 | static defaultProps = {
6 | disabled: false,
7 | type: 'text',
8 | }
9 |
10 | handleChange = (e) => {
11 | const {
12 | onChange,
13 | index,
14 | } = this.props;
15 | if (onChange) {
16 | onChange(e, index);
17 | };
18 | }
19 |
20 | handleBlur = (e) => {
21 | const {
22 | onBlur,
23 | index,
24 | } = this.props;
25 | if (onBlur) {
26 | onBlur(e, index);
27 | };
28 | }
29 |
30 | fixControlledValue = (value) => {
31 | if (typeof value === 'undefined' || value === null) {
32 | return '';
33 | };
34 | return value;
35 | }
36 |
37 | render() {
38 | const {
39 | type,
40 | name,
41 | width,
42 | margin,
43 | style,
44 | maxLength,
45 | rows,
46 | disabled,
47 | ...otherProps
48 | } = this.props;
49 | /*
50 | * defaultValue只会在第一次渲染有效
51 | * defaultValue和value尽量不共存,如果共存的话value将会覆盖defaultValue
52 | * 在共存的情况下,如果value值为undefined或者null,会被defaultValue覆盖
53 | */
54 | if ('value' in otherProps) {
55 | otherProps.value = this.fixControlledValue(otherProps.value);
56 | delete otherProps.defaultValue;
57 | };
58 | return (
59 |
62 | {type === 'textarea' ? (
63 |
71 | ) : (
72 |
82 | )}
83 |
84 | );
85 | }
86 | }
87 |
88 | export default Input;
--------------------------------------------------------------------------------
/webpack/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const webpack = require('webpack');
3 | const HtmlWebpackPlugin = require('html-webpack-plugin');
4 |
5 | module.exports = {
6 | entry: [
7 | 'webpack-dev-server/client?http://localhost:9090',
8 | 'webpack/hot/only-dev-server',
9 | path.resolve(__dirname, '../src/main.js'),
10 | ],
11 | //指定入口文件,程序从这里开始编译,__dirname当前所在目录
12 | output: {
13 | path: path.resolve(__dirname, '../dist'),
14 | filename: 'bundle.js'
15 | },
16 | resolve: {
17 | extensions: ['.js', '.jsx'],
18 | alias: {
19 | 'libs': path.resolve(__dirname, '../libs'),
20 | 'assets': path.resolve(__dirname, '../assets'),
21 | 'utils': path.resolve(__dirname, '../utils'),
22 | }
23 | },
24 | module: {
25 | rules: [{
26 | test: /\.(js|jsx)$/,
27 | loader: ['babel-loader'],
28 | exclude: /node_modules/
29 | }, {
30 | test: /\.less$/,
31 | use: [
32 | 'style-loader', {
33 | loader: 'css-loader?modules',
34 | options: {
35 | importLoaders: 1
36 | }
37 | },
38 | 'less-loader'
39 | ]
40 | }, {
41 | test: /\.css$/,
42 | use: [
43 | 'style-loader', //模块运行时,使用