├── src
├── styles
│ ├── mixins.css
│ ├── variable.css
│ └── variable.scss
├── components
│ ├── tab
│ │ ├── index.js
│ │ ├── TabItem.js
│ │ └── Tab.js
│ ├── select
│ │ ├── index.js
│ │ ├── Option.js
│ │ ├── Picker.js
│ │ └── Select.js
│ ├── flexbox
│ │ ├── index.js
│ │ ├── FlexboxItem.js
│ │ └── Flexbox.js
│ ├── radio
│ │ ├── index.js
│ │ ├── RadioGroup.js
│ │ └── Radio.js
│ ├── swiper
│ │ ├── index.js
│ │ ├── SwiperItem.js
│ │ └── Swiper.js
│ ├── tabbar
│ │ ├── index.js
│ │ ├── TabbarItem.js
│ │ └── Tabbar.js
│ ├── checker
│ │ ├── index.js
│ │ ├── Checker.js
│ │ └── CheckerGroup.js
│ ├── marquee
│ │ ├── index.js
│ │ ├── MarqueeItem.js
│ │ └── Marquee.js
│ ├── sidebar
│ │ ├── index.js
│ │ ├── SidebarItem.js
│ │ └── Sidebar.js
│ ├── checkbox
│ │ ├── index.js
│ │ ├── CheckboxGroup.js
│ │ └── Checkbox.js
│ ├── accordion
│ │ ├── index.js
│ │ ├── Accordion.js
│ │ └── AccordionItem.js
│ ├── button-tab
│ │ ├── index.js
│ │ ├── ButtonTabItem.js
│ │ └── ButtonTab.js
│ ├── actionsheet
│ │ ├── index.js
│ │ ├── ActionsheetItem.js
│ │ └── Actionsheet.js
│ ├── alert
│ │ └── index.js
│ ├── icon
│ │ └── index.js
│ ├── divider
│ │ └── index.js
│ ├── body
│ │ └── index.js
│ ├── message
│ │ └── index.js
│ ├── group
│ │ └── index.js
│ ├── badge
│ │ └── index.js
│ ├── spinner
│ │ └── index.js
│ ├── overlay
│ │ └── index.js
│ ├── cell
│ │ └── index.js
│ ├── layout
│ │ └── index.js
│ ├── qrcode
│ │ └── index.js
│ ├── AsyncComponent.js
│ ├── rater
│ │ └── index.js
│ ├── switch
│ │ └── index.js
│ ├── button
│ │ └── index.js
│ ├── arrow
│ │ └── index.js
│ ├── nav
│ │ └── index.js
│ ├── ConnectComponent.js
│ ├── password
│ │ └── index.js
│ ├── prompt
│ │ └── index.js
│ ├── remtopx
│ │ └── index.js
│ ├── popover
│ │ └── index.js
│ ├── input
│ │ └── index.js
│ ├── textarea
│ │ └── index.js
│ ├── input-number
│ │ └── index.js
│ ├── ripple
│ │ └── index.js
│ ├── preview
│ │ └── index.js
│ ├── toast
│ │ └── index.js
│ ├── sticky
│ │ └── index.js
│ ├── popup-picker
│ │ └── index.js
│ └── img
│ │ └── index.js
├── store
│ ├── root
│ │ ├── action.js
│ │ └── reducer.js
│ ├── todo
│ │ ├── action.js
│ │ └── reducer.js
│ └── index.js
├── index.css
├── index.scss
├── App.scss
├── App.css
├── App.test.js
├── views
│ ├── Qrcode.js
│ ├── Group.js
│ ├── Nav.js
│ ├── Message.js
│ ├── Divider.js
│ ├── Password.js
│ ├── Spinner.js
│ ├── InputNumber.js
│ ├── Input.js
│ ├── Ripple.js
│ ├── Marquee.js
│ ├── Textarea.js
│ ├── IndexList.js
│ ├── Cell.js
│ ├── Badge.js
│ ├── Sidebar.js
│ ├── Alert.js
│ ├── Flexbox.js
│ ├── Tabbar.js
│ ├── ButtonTab.js
│ ├── Rater.js
│ ├── Switch.js
│ ├── Picker.js
│ ├── Swiper.js
│ ├── Range.js
│ ├── Tab.js
│ ├── Radio.js
│ ├── Popover.js
│ ├── Accordion.js
│ ├── Button.js
│ ├── Layout.js
│ ├── Preview.js
│ ├── Sticky.js
│ ├── Img.js
│ ├── Checker.js
│ ├── Swipeout.js
│ ├── Confirm.js
│ ├── Prompt.js
│ ├── Checkbox.js
│ ├── Actionsheet.js
│ ├── ListView.js
│ ├── Popup.js
│ ├── Toast.js
│ ├── Select.js
│ └── Home.js
├── devtools
│ └── index.js
├── App.js
├── index.js
├── logo.svg
└── registerServiceWorker.js
├── public
├── robots.txt
├── favicon.ico
├── images
│ ├── code.png
│ ├── logo.png
│ └── github.png
├── manifest.json
└── index.html
├── .gitignore
├── config
├── jest
│ ├── cssTransform.js
│ └── fileTransform.js
├── pnpTs.js
├── paths.js
├── env.js
└── modules.js
├── scripts
└── test.js
├── components.json
├── README.md
└── package.json
/src/styles/mixins.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/styles/variable.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunfeihuang/react-components/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/public/images/code.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunfeihuang/react-components/HEAD/public/images/code.png
--------------------------------------------------------------------------------
/public/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunfeihuang/react-components/HEAD/public/images/logo.png
--------------------------------------------------------------------------------
/public/images/github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yunfeihuang/react-components/HEAD/public/images/github.png
--------------------------------------------------------------------------------
/src/components/tab/index.js:
--------------------------------------------------------------------------------
1 | import Tab from './Tab';
2 | import TabItem from './TabItem';
3 |
4 | export {
5 | Tab,
6 | TabItem
7 | }
8 |
--------------------------------------------------------------------------------
/src/store/root/action.js:
--------------------------------------------------------------------------------
1 | export default {
2 | action (data) {
3 | return {
4 | type: 'ADD_TODO',
5 | data
6 | }
7 | }
8 | }
--------------------------------------------------------------------------------
/src/components/select/index.js:
--------------------------------------------------------------------------------
1 | import Select from './Select';
2 | import Option from './Option';
3 |
4 | export {
5 | Select,
6 | Option
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/flexbox/index.js:
--------------------------------------------------------------------------------
1 | import Flexbox from './Flexbox'
2 | import FlexboxItem from './FlexboxItem'
3 | export {
4 | Flexbox,
5 | FlexboxItem
6 | }
--------------------------------------------------------------------------------
/src/components/radio/index.js:
--------------------------------------------------------------------------------
1 | import Radio from './Radio';
2 | import RadioGroup from './RadioGroup';
3 |
4 | export {
5 | Radio,
6 | RadioGroup
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/swiper/index.js:
--------------------------------------------------------------------------------
1 | import Swiper from './Swiper';
2 | import SwiperItem from './SwiperItem';
3 |
4 | export {
5 | Swiper,
6 | SwiperItem
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/tabbar/index.js:
--------------------------------------------------------------------------------
1 | import Tabbar from './Tabbar';
2 | import TabbarItem from './TabbarItem';
3 |
4 | export {
5 | Tabbar,
6 | TabbarItem
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/checker/index.js:
--------------------------------------------------------------------------------
1 | import Checker from './Checker';
2 | import CheckerGroup from './CheckerGroup';
3 |
4 | export {
5 | Checker,
6 | CheckerGroup
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/marquee/index.js:
--------------------------------------------------------------------------------
1 | import Marquee from './Marquee';
2 | import MarqueeItem from './MarqueeItem';
3 |
4 | export {
5 | Marquee,
6 | MarqueeItem
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/sidebar/index.js:
--------------------------------------------------------------------------------
1 | import Sidebar from './Sidebar';
2 | import SidebarItem from './SidebarItem';
3 |
4 | export {
5 | Sidebar,
6 | SidebarItem
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/checkbox/index.js:
--------------------------------------------------------------------------------
1 | import Checkbox from './Checkbox';
2 | import CheckboxGroup from './CheckboxGroup';
3 |
4 | export {
5 | Checkbox,
6 | CheckboxGroup
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/accordion/index.js:
--------------------------------------------------------------------------------
1 | import Accordion from './Accordion';
2 | import AccordionItem from './AccordionItem';
3 |
4 | export {
5 | Accordion,
6 | AccordionItem
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/button-tab/index.js:
--------------------------------------------------------------------------------
1 | import ButtonTab from './ButtonTab';
2 | import ButtonTabItem from './ButtonTabItem';
3 |
4 | export {
5 | ButtonTab,
6 | ButtonTabItem
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/actionsheet/index.js:
--------------------------------------------------------------------------------
1 | import Actionsheet from './Actionsheet';
2 | import ActionsheetItem from './ActionsheetItem';
3 |
4 | export {
5 | Actionsheet,
6 | ActionsheetItem
7 | }
8 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | background: #f7f7f7; }
6 |
7 | a {
8 | color: inherit;
9 | text-decoration: none; }
10 |
--------------------------------------------------------------------------------
/src/index.scss:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | background:#f7f7f7;
6 | }
7 | a{
8 | color:inherit;
9 | text-decoration:none;
10 | }
11 |
--------------------------------------------------------------------------------
/src/store/root/reducer.js:
--------------------------------------------------------------------------------
1 | export let initialState = {
2 | global: {id: 'fdsafds'}
3 | }
4 |
5 | let reducer = {
6 | global (state = {}, action) {
7 | return state
8 | }
9 | }
10 |
11 | export default reducer
--------------------------------------------------------------------------------
/src/App.scss:
--------------------------------------------------------------------------------
1 | .flexbox-demo{
2 | padding:10px;
3 | overflow:hidden;
4 | background: #fff;
5 | .vx-flexbox--item{
6 | background:#eee;
7 | border-radius:6px;
8 | text-align:center;
9 | line-height:0.8rem;
10 | }
11 | }
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | .flexbox-demo {
2 | padding: 10px;
3 | overflow: hidden;
4 | background: #fff; }
5 | .flexbox-demo .vx-flexbox--item {
6 | background: #eee;
7 | border-radius: 6px;
8 | text-align: center;
9 | line-height: 0.8rem; }
10 |
--------------------------------------------------------------------------------
/src/components/alert/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Confirm from '../confirm';
3 |
4 | let Alert = props => {
5 | let {children, ...others} = props
6 | return (
7 | {children}
8 | )
9 | }
10 |
11 | export default Alert;
12 |
--------------------------------------------------------------------------------
/src/App.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | it('renders without crashing', () => {
6 | const div = document.createElement('div');
7 | ReactDOM.render(, div);
8 | ReactDOM.unmountComponentAtNode(div);
9 | });
10 |
--------------------------------------------------------------------------------
/src/components/icon/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import classnames from 'classnames'
3 |
4 | const Icon = props => {
5 | const { className, ...others } = props
6 | return (
7 |
9 |
10 | )
11 | }
12 |
13 | export default Icon
14 |
--------------------------------------------------------------------------------
/src/components/select/Option.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 |
3 | const Option = props => {
4 | return null
5 | }
6 | Option.propsTypes = {
7 | value: PropTypes.String,
8 | disabled: PropTypes.bool,
9 | label: PropTypes.String
10 | }
11 | Option.defaultProps = {
12 | disabled: false
13 | }
14 | export default Option;
15 |
--------------------------------------------------------------------------------
/src/store/todo/action.js:
--------------------------------------------------------------------------------
1 | export default {
2 | add (data) {
3 | return dispatch => {
4 | setTimeout(() => {
5 | dispatch({
6 | type: 'TODO_ADD',
7 | data
8 | })
9 | })
10 | }
11 | /*
12 | return {
13 | type: 'TODO_ADD',
14 | data
15 | }
16 | */
17 | }
18 | }
--------------------------------------------------------------------------------
/src/store/todo/reducer.js:
--------------------------------------------------------------------------------
1 | let initialState = {
2 | counter: 0
3 | }
4 |
5 | const todo = (state = initialState, action) => {
6 | switch (action.type) {
7 | case 'TODO_ADD':
8 | state.counter++
9 | return {
10 | ...state
11 | }
12 | default:
13 | return state
14 | }
15 | }
16 |
17 | export default todo;
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 |
12 | # misc
13 | .DS_Store
14 | .env.local
15 | .env.development.local
16 | .env.test.local
17 | .env.production.local
18 |
19 | npm-debug.log*
20 | yarn-debug.log*
21 | yarn-error.log*
22 |
--------------------------------------------------------------------------------
/src/components/divider/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import classnames from 'classnames'
3 |
4 | const Divider = props => {
5 | const { children, className, ...others } = props
6 | return (
7 |
10 | {children}
11 |
12 | )
13 | }
14 |
15 | export default Divider
16 |
--------------------------------------------------------------------------------
/config/jest/cssTransform.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // This is a custom Jest transformer turning style imports into empty objects.
4 | // http://facebook.github.io/jest/docs/en/webpack.html
5 |
6 | module.exports = {
7 | process() {
8 | return 'module.exports = {};';
9 | },
10 | getCacheKey() {
11 | // The output is always the same.
12 | return 'cssTransform';
13 | },
14 | };
15 |
--------------------------------------------------------------------------------
/src/components/swiper/SwiperItem.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import classnames from 'classnames';
3 |
4 | const SwiperItem = props => {
5 | let {children, className, ...others} = props
6 | return (
7 |
8 | {children}
9 |
10 | );
11 | }
12 |
13 | export default SwiperItem;
14 |
--------------------------------------------------------------------------------
/src/components/marquee/MarqueeItem.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import classnames from 'classnames';
3 |
4 | const MarqueeItem = props => {
5 | let {children, className, ...others} = props
6 | return (
7 |
8 | {children}
9 |
10 | );
11 | }
12 |
13 | export default MarqueeItem;
14 |
--------------------------------------------------------------------------------
/src/components/body/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import classnames from 'classnames'
3 | import { FlexboxItem } from '../flexbox'
4 |
5 | const Body = props => {
6 | const { children, className, ...others } = props
7 | return (
8 |
9 | {children}
10 |
11 | )
12 | }
13 |
14 | export default Body
15 |
--------------------------------------------------------------------------------
/src/components/message/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import classnames from 'classnames'
3 |
4 | const Message = props => {
5 | const { children, className, type, ...others } = props
6 | return (
7 |
10 | {children}
11 |
12 | )
13 | }
14 | Message.defaultProps = {
15 | type: 'warning'
16 | }
17 |
18 | export default Message
19 |
--------------------------------------------------------------------------------
/src/views/Qrcode.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Body, Nav, Qrcode } from '@/components'
3 |
4 | class Demo extends React.Component {
5 | render() {
6 | return (
7 |
8 |
9 |
10 |
11 |
12 |
13 | );
14 | }
15 | }
16 |
17 | export default Demo;
18 |
--------------------------------------------------------------------------------
/src/views/Group.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Body, Nav, Group, Cell } from '@/components'
3 |
4 | class Demo extends React.Component {
5 | render() {
6 | return (
7 |
8 |
9 |
10 |
11 | |
12 |
13 |
14 |
15 | );
16 | }
17 | }
18 |
19 | export default Demo;
20 |
--------------------------------------------------------------------------------
/src/devtools/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | //从redux-devtools中引入createDevTools
4 | import { createDevTools } from 'redux-devtools';
5 |
6 | //显示包是单独的,要额外指定
7 | import LogMonitor from 'redux-devtools-log-monitor';
8 | import DockMonitor from 'redux-devtools-dock-monitor';
9 |
10 | //创建DevTools组件
11 | const DevTools = createDevTools(
12 |
14 |
15 |
16 | );
17 |
18 | export default DevTools
19 |
--------------------------------------------------------------------------------
/src/components/actionsheet/ActionsheetItem.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import classnames from 'classnames';
4 |
5 | const ActionsheetItem = props => {
6 | let {children, className, ...others} = props
7 | return (
8 |
9 | {children}
10 |
11 | );
12 | }
13 | ActionsheetItem.propsTypes = {
14 | value: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
15 | }
16 |
17 | export default ActionsheetItem;
18 |
--------------------------------------------------------------------------------
/src/components/group/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import classnames from 'classnames'
3 |
4 | const Group = props => {
5 | const { className, title, component, children, ...others } = props
6 | let Component = component || 'div'
7 | return (
8 |
9 | {title && {title}
}
10 |
11 | {children}
12 |
13 |
14 | )
15 | }
16 |
17 | export default Group
18 |
--------------------------------------------------------------------------------
/src/views/Nav.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Nav } from '@/components'
3 |
4 | class Demo extends React.Component {
5 | render() {
6 | return (
7 |
8 |
9 |
13 |
14 | );
15 | }
16 | }
17 |
18 | export default Demo;
19 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { HashRouter as Router } from 'react-router-dom';
3 | import './App.css';
4 | import { renderRoutes } from 'react-router-config';
5 | import globalRouter from './views/router';
6 | // import DevTools from './devtools';
7 |
8 | const routes = [
9 | ...globalRouter
10 | ]
11 |
12 | class App extends React.Component {
13 | render() {
14 | return (
15 |
16 |
17 | {renderRoutes(routes)}
18 |
19 |
20 | )
21 | }
22 | }
23 |
24 | export default App;
25 |
--------------------------------------------------------------------------------
/src/components/sidebar/SidebarItem.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import classnames from 'classnames';
4 |
5 | const SidebarItem = props => {
6 | let {children, className, active, name, ripple, ...others} = props
7 | let cls = classnames(['vx-sidebar--item', {'is-active': active === name}])
8 | return (
9 |
10 | {children}
11 |
12 | );
13 | }
14 |
15 | SidebarItem.propsTypes = {
16 | name: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
17 | }
18 |
19 | export default SidebarItem;
20 |
--------------------------------------------------------------------------------
/src/views/Message.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Body, Nav, Message } from '@/components'
3 |
4 | class Demo extends React.Component {
5 | render() {
6 | return (
7 |
8 |
9 |
10 | 注意:此示例要在移动设备体验哦~
11 |
12 | 注意:此示例要在移动设备体验哦~
13 |
14 | 注意:此示例要在移动设备体验哦~
15 |
16 |
17 | );
18 | }
19 | }
20 |
21 | export default Demo;
22 |
--------------------------------------------------------------------------------
/src/views/Divider.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Body, Nav, Group, Divider } from '@/components'
3 |
4 | class Demo extends React.Component {
5 | render() {
6 | return (
7 |
8 |
9 |
10 |
11 |
12 | 标题
13 |
14 | 内容....
15 |
16 |
17 |
18 |
19 | );
20 | }
21 | }
22 |
23 | export default Demo;
24 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/src/components/button-tab/ButtonTabItem.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import classnames from 'classnames';
4 |
5 | const ButtonTabItem = props => {
6 | let {children, className, active, name, ...others} = props
7 | let cls = classnames(['vx-button-tab--item', 'vx-flexbox--item', {'is-active': active === name}], className)
8 | return (
9 |
10 | {children}
11 |
12 | );
13 | }
14 |
15 | ButtonTabItem.propsTypes = {
16 | name: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
17 | }
18 |
19 | export default ButtonTabItem;
20 |
--------------------------------------------------------------------------------
/src/views/Password.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Body, Nav, Password, Group } from '@/components'
3 |
4 | class Demo extends React.Component {
5 | state = {
6 | value: ''
7 | }
8 | render() {
9 | return (
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | );
19 | }
20 | handleChange (value) {
21 | this.setState({
22 | value
23 | })
24 | }
25 | }
26 |
27 | export default Demo;
28 |
--------------------------------------------------------------------------------
/src/components/badge/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import classnames from 'classnames'
4 |
5 | const Badge = props => {
6 | let {className, text, max, ...others} = props
7 | return (
8 |
9 | {typeof text === 'number' && max && text > max ? : text}
10 |
11 | )
12 | }
13 | Badge.propTypes = {
14 | text: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
15 | max: PropTypes.number
16 | }
17 | Badge.defaultProps = {
18 | text: '',
19 | max: 9
20 | }
21 |
22 | export default Badge;
23 |
--------------------------------------------------------------------------------
/src/components/spinner/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import classnames from 'classnames'
3 |
4 | let Spinner = props => {
5 | let {children, className, color, primaryColor, ...others} = props
6 | const style = {
7 | 'borderTopColor': `${primaryColor}`,
8 | 'borderRightColor': `${color}`,
9 | 'borderBottomColor': `${color}`,
10 | 'borderLeftColor': `${color}`
11 | }
12 | return (
13 |
14 |
15 | {children}
16 |
17 | )
18 | }
19 | Spinner.defaultProps = {
20 | color: '',
21 | primaryColor: ''
22 | }
23 | export default Spinner;
24 |
--------------------------------------------------------------------------------
/src/components/tab/TabItem.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import classnames from 'classnames';
4 | const TabItem = props => {
5 | let {children, className, underlineWidth, active, name, layout, ...others} = props
6 | return (
7 |
8 | {underlineWidth &&
9 | {children}
10 | }
11 | {!underlineWidth && children}
12 |
13 | );
14 | }
15 | TabItem.propsTypes = {
16 | name: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
17 | }
18 |
19 | export default TabItem;
20 |
--------------------------------------------------------------------------------
/src/views/Spinner.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Nav, Body, Spinner} from '@/components'
3 |
4 | class Demo extends React.Component {
5 | state = {
6 | open: false
7 | }
8 | render() {
9 | return (
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | LOGO
20 |
21 |
22 |
23 | );
24 | }
25 | }
26 |
27 | export default Demo;
28 |
--------------------------------------------------------------------------------
/src/views/InputNumber.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Body, Nav, Group, Cell, InputNumber } from '@/components'
3 |
4 | class Demo extends React.Component {
5 | state = {
6 | value: 0
7 | }
8 | render() {
9 | return (
10 |
11 |
12 |
13 |
14 |
15 |
16 | |
17 |
18 |
19 |
20 | );
21 | }
22 | handleChange (value) {
23 | this.setState({
24 | value
25 | })
26 | }
27 | }
28 |
29 | export default Demo;
30 |
--------------------------------------------------------------------------------
/config/pnpTs.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const { resolveModuleName } = require('ts-pnp');
4 |
5 | exports.resolveModuleName = (
6 | typescript,
7 | moduleName,
8 | containingFile,
9 | compilerOptions,
10 | resolutionHost
11 | ) => {
12 | return resolveModuleName(
13 | moduleName,
14 | containingFile,
15 | compilerOptions,
16 | resolutionHost,
17 | typescript.resolveModuleName
18 | );
19 | };
20 |
21 | exports.resolveTypeReferenceDirective = (
22 | typescript,
23 | moduleName,
24 | containingFile,
25 | compilerOptions,
26 | resolutionHost
27 | ) => {
28 | return resolveModuleName(
29 | moduleName,
30 | containingFile,
31 | compilerOptions,
32 | resolutionHost,
33 | typescript.resolveTypeReferenceDirective
34 | );
35 | };
36 |
--------------------------------------------------------------------------------
/src/views/Input.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Body, Nav, Input, Group } from '@/components'
3 |
4 | class Demo extends React.Component {
5 | state = {value: ''}
6 | render() {
7 | return (
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | );
20 | }
21 | handleChange (value) {
22 | this.setState({
23 | value
24 | })
25 | }
26 | }
27 |
28 | export default Demo;
29 |
--------------------------------------------------------------------------------
/src/components/flexbox/FlexboxItem.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import classnames from 'classnames'
4 |
5 | const FlexboxItem = props => {
6 | const { children, className, style, flex, order, gutter, ...others } = props
7 | let styles = {
8 | ...style,
9 | marginLeft: `${gutter}px`,
10 | marginRight: `${gutter}px`,
11 | flex,
12 | order
13 | }
14 | return (
15 |
18 | {children}
19 |
20 | )
21 | }
22 | FlexboxItem.propTypes = {
23 | flex: PropTypes.string,
24 | order: PropTypes.string,
25 | gutter: PropTypes.number
26 | }
27 | FlexboxItem.defaultProps = {
28 | flex: '1'
29 | }
30 |
31 | export default FlexboxItem
32 |
--------------------------------------------------------------------------------
/src/views/Ripple.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Nav, Body, Ripple, Group, Divider} from '@/components'
3 |
4 | class Demo extends React.Component {
5 | render() {
6 | return (
7 |
8 |
9 |
10 |
11 |
12 | 点击我会出现波纹
13 |
14 |
15 |
16 | 点击我会出现波纹
17 |
18 |
19 |
20 | 自定义颜色(prop color:rgba(255,0,0,0.1))
21 |
22 |
23 |
24 |
25 | );
26 | }
27 | }
28 |
29 | export default Demo;
30 |
--------------------------------------------------------------------------------
/src/components/overlay/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import classnames from 'classnames'
3 | import PropTypes from 'prop-types'
4 | import Transition from 'react-transition-group/Transition'
5 |
6 | const Overlay = props => {
7 | const { className, open, ...others } = props
8 | const transitionState = {
9 | entering: 'popup-fade-enter',
10 | entered: 'popup-fade-enter-active',
11 | exiting: 'popup-fade-leave-active',
12 | exited: 'popup-fade-leave'
13 | }
14 | return (
15 |
16 | {state => {
17 | return
18 | }}
19 |
20 | )
21 | }
22 |
23 | Overlay.propTypes = {
24 | open: PropTypes.bool
25 | }
26 |
27 | export default Overlay
28 |
--------------------------------------------------------------------------------
/src/components/tabbar/TabbarItem.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import classnames from 'classnames';
4 | import Ripple from '../ripple'
5 |
6 | const TabbarItem = props => {
7 | let {children, className, active, name, ripple, ...others} = props
8 | let cls = classnames(['vx-tabbar--item', 'vx-flexbox--item', {'is-active': active === name}, className])
9 | if (ripple) {
10 | return (
11 |
12 | {children}
13 |
14 | )
15 | } else {
16 | return (
17 |
18 | {children}
19 |
20 | );
21 | }
22 | }
23 | TabbarItem.propsTypes = {
24 | name: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
25 | }
26 |
27 | export default TabbarItem;
28 |
--------------------------------------------------------------------------------
/src/views/Marquee.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Body, Nav, Marquee, MarqueeItem } from '@/components'
3 |
4 | class Demo extends React.Component {
5 | render() {
6 | return (
7 |
8 |
9 |
10 |
18 |
26 |
27 |
28 | );
29 | }
30 | }
31 |
32 | export default Demo;
33 |
--------------------------------------------------------------------------------
/src/views/Textarea.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Body, Nav, Textarea, Group } from '@/components'
3 |
4 | class Demo extends React.Component {
5 | state = {value: ''}
6 | render() {
7 | return (
8 |
9 |
10 |
11 |
12 |
14 |
15 | 注:输入换行符或者更多内容我会自动”撑高“
16 |
17 | {this.state.value}
18 |
19 |
20 | );
21 | }
22 | handleChange (value) {
23 | this.setState({
24 | value
25 | })
26 | }
27 | }
28 |
29 | export default Demo;
30 |
--------------------------------------------------------------------------------
/src/views/IndexList.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Nav, IndexList } from '@/components'
3 |
4 | let list = []
5 | let array = ['★', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L']
6 | array.forEach(item1 => {
7 | let items = array.map(item2 => {
8 | return {
9 | value: item1 + item2,
10 | label: `label-${item1 + item2}`
11 | }
12 | })
13 | list.push({
14 | label: item1,
15 | items
16 | })
17 | })
18 | class Demo extends React.Component {
19 | state = {
20 | list: list
21 | }
22 | render() {
23 | return (
24 |
25 |
26 |
27 |
28 | );
29 | }
30 | handleClick (value) {
31 | console.log(value)
32 | }
33 | }
34 |
35 | export default Demo;
36 |
--------------------------------------------------------------------------------
/src/components/cell/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import classnames from 'classnames'
3 | import { Link } from 'react-router-dom';
4 | import { Flexbox, FlexboxItem } from '../flexbox'
5 |
6 | const Cell = props => {
7 | const { className, title, value, icon, arrow, to, children, ...others } = props
8 | let Component = to ? Link : 'div'
9 | return (
10 |
17 |
18 | {icon}
19 |
20 |
21 | {title}
22 |
23 |
24 | {value || children}
25 |
26 |
27 | )
28 | }
29 |
30 | export default Cell
31 |
--------------------------------------------------------------------------------
/src/styles/variable.scss:
--------------------------------------------------------------------------------
1 | // Prefix
2 | $css-prefix : vx-;
3 | $css-prefix-iconfont : vx-icon;
4 |
5 | // color
6 | $color-black : #333;
7 | $color-primary : #3399ff;
8 | $color-error : #f56c6c;
9 | $color-sub : #999;
10 | $color-divider : #f5f5f5;
11 | $color-warning : #ff9900;
12 | $color-danger : $color-error;
13 | $color-star : #f5a623;
14 | $color-placeholder : rgba(0,0,0,0.4);
15 | $color-background : #f7f7f7;
16 |
17 | $font-size-default : 0.28rem;
18 | $font-size-small : 0.24rem;
19 | $font-size-large : 0.32rem;
20 |
21 | $item-padding : 0.3rem 0;
22 |
23 | // Border color
24 | $border-color-base : rgb(229, 229, 229); // outside
25 | $border-radius-base : 6px;
26 |
27 | // Animation
28 | $animation-time : .3s;
29 | $transition-time : .2s;
30 | $ease-in-out : ease-in-out;
31 |
--------------------------------------------------------------------------------
/src/views/Cell.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Body, Nav, Group, Cell, Switch } from '@/components'
3 |
4 | class Demo extends React.Component {
5 | state = {open: false}
6 | render() {
7 | let icon =
8 | return (
9 |
10 |
11 |
12 |
13 | |
14 |
15 |
16 |
17 |
18 | |
19 |
20 |
21 |
22 | );
23 | }
24 | handleChange (value) {
25 | this.setState({
26 | open: value
27 | })
28 | }
29 | }
30 |
31 | export default Demo;
32 |
--------------------------------------------------------------------------------
/src/components/radio/RadioGroup.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import classnames from 'classnames';
4 |
5 | const RadioGroup = props => {
6 | let {children, className, divider, onChange, ...others} = props
7 | let handleChange = value => {
8 | value !== props.value && onChange && onChange(value)
9 | }
10 | let cloneChildren = React.Children.map(children, item => {
11 | if (item) {
12 | return React.cloneElement(item, {
13 | $parent: {
14 | ...others,
15 | onChange: handleChange
16 | }
17 | })
18 | }
19 | return item
20 | })
21 | return (
22 |
23 | {cloneChildren}
24 |
25 | );
26 | }
27 | RadioGroup.propsTypes = {
28 | divider: PropTypes.bool,
29 | onChange: PropTypes.func
30 | }
31 | RadioGroup.defaultProps = {
32 | divider: true
33 | }
34 |
35 | export default RadioGroup;
36 |
--------------------------------------------------------------------------------
/src/components/layout/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import classnames from 'classnames'
3 | import { Flexbox } from '../flexbox'
4 |
5 | const Layout = props => {
6 | const { children, className, bodyComponent, ...others } = props
7 | let slots = {
8 | others: []
9 | }
10 | React.Children.map(children, item => {
11 | if (item.props.slot) {
12 | if (!slots[item.props.slot]) {
13 | slots[item.props.slot] = []
14 | }
15 | slots[item.props.slot].push(item)
16 | } else {
17 | slots.others.push(item)
18 | }
19 | })
20 | return (
21 |
22 |
23 | {slots['header']}
24 | {slots['body']}
25 | {slots['footer']}
26 |
27 | {slots['others']}
28 |
29 | )
30 | }
31 | Layout.defaultProps = {
32 | type: 'default'
33 | }
34 | export default Layout
35 |
--------------------------------------------------------------------------------
/src/components/sidebar/Sidebar.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import classnames from 'classnames';
3 | import PropTypes from 'prop-types';
4 |
5 | const Sidebar = props => {
6 | let {children, className, active, ripple, onChange, ...others} = props
7 | let handleClick = value => {
8 | value !== active && onChange && onChange(value)
9 | }
10 | let cloneChildren = React.Children.map(children, item => {
11 | if (item) {
12 | return React.cloneElement(item, {
13 | active,
14 | ripple,
15 | onClick: handleClick.bind(this, item.props.name)
16 | })
17 | }
18 | return item
19 | })
20 | return (
21 |
22 | {cloneChildren}
23 |
24 | );
25 | }
26 | Sidebar.propTypes = {
27 | active: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
28 | ripple: PropTypes.bool,
29 | onChange: PropTypes.func
30 | }
31 | Sidebar.defaultProps = {
32 | ripple: false
33 | }
34 |
35 | export default Sidebar;
36 |
--------------------------------------------------------------------------------
/src/components/tabbar/Tabbar.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import classnames from 'classnames';
3 | import PropTypes from 'prop-types';
4 |
5 | const Tabbar = props => {
6 | let {children, className, active, ripple, onChange, ...others} = props
7 | let handleClick = value => {
8 | value !== active && onChange && onChange(value)
9 | }
10 | let cloneChildren = React.Children.map(children, item => {
11 | if (item) {
12 | return React.cloneElement(item, {
13 | active,
14 | ripple,
15 | onClick: handleClick.bind(this, item.props.name)
16 | })
17 | }
18 | return item
19 | })
20 | return (
21 |
22 | {cloneChildren}
23 |
24 | );
25 | }
26 | Tabbar.propTypes = {
27 | active: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
28 | ripple: PropTypes.bool,
29 | onChange: PropTypes.func
30 | }
31 | Tabbar.defaultProps = {
32 | ripple: false
33 | }
34 |
35 | export default Tabbar;
36 |
--------------------------------------------------------------------------------
/src/components/radio/Radio.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import classnames from 'classnames';
3 | import PropTypes from 'prop-types'
4 |
5 | const Radio = props => {
6 | let {children, className, style, $parent, onChange, ...others} = props
7 | let checked = others.checked
8 | if ($parent) {
9 | checked = $parent.value === others.value
10 | }
11 | let handleChange = e => {
12 | let value = e.target.value
13 | if ($parent) {
14 | $parent.onChange && $parent.onChange(value)
15 | } else {
16 | onChange && onChange(value)
17 | }
18 | }
19 | return (
20 |
29 | );
30 | }
31 | Radio.propTypes = {
32 | onChange: PropTypes.func
33 | }
34 |
35 | export default Radio;
36 |
--------------------------------------------------------------------------------
/src/components/button-tab/ButtonTab.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import classnames from 'classnames';
3 | import PropTypes from 'prop-types';
4 |
5 | const ButtonTab = props => {
6 | let {children, className, active, size, onChange, ...others} = props
7 | let handleClick = value => {
8 | value !== active && onChange && onChange(value)
9 | }
10 | let cloneChildren = React.Children.map(children, item => {
11 | if (item) {
12 | return React.cloneElement(item, {
13 | active,
14 | onClick: handleClick.bind(this, item.props.name)
15 | })
16 | }
17 | return item
18 | })
19 | return (
20 |
21 | {cloneChildren}
22 |
23 | );
24 | }
25 | ButtonTab.propTypes = {
26 | active: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
27 | size: PropTypes.string,
28 | onChange: PropTypes.func
29 | }
30 | ButtonTab.defaultProps = {
31 | size: 'default'
32 | }
33 |
34 | export default ButtonTab;
35 |
--------------------------------------------------------------------------------
/src/views/Badge.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Nav, Body, Badge, Cell, Group} from '@/components'
3 |
4 | class Demo extends React.Component {
5 | state = {
6 | count: 8
7 | }
8 | render() {
9 | return (
10 |
11 |
12 |
13 |
14 |
15 | 新消息
16 | |
17 |
18 | 新消息
19 | |
20 |
21 | 新消息
22 | |
23 |
24 | 新消息
25 | |
26 |
27 |
28 |
29 | );
30 | }
31 | handleClick () {
32 | this.setState({
33 | count: this.state.count + 1
34 | })
35 | }
36 | }
37 |
38 | export default Demo;
39 |
--------------------------------------------------------------------------------
/src/components/qrcode/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import classnames from 'classnames'
3 | import PropTypes from 'prop-types'
4 |
5 | export default class Qrcode extends React.Component {
6 | static propTypes = {
7 | text: PropTypes.string,
8 | height: PropTypes.number,
9 | width: PropTypes.number
10 | }
11 | static defaultProps = {
12 | height: 200,
13 | width: 200,
14 | text: ''
15 | }
16 | render () {
17 | let {children, className,...others} = this.props
18 | return (
19 |
20 | )
21 | }
22 | componentDidMount () {
23 | this.$el = this.refs.$el
24 | import('qrcodejs2').then(res => {
25 | let QRCode = res.default
26 | this.$$qrcode = new QRCode(this.$el, {
27 | ...this.props
28 | })
29 | })
30 | }
31 | componentDidUpdate (prevProps) {
32 | if (prevProps.text !== this.props.text && this.$$qrcode) {
33 | this.$$qrcode.clear()
34 | this.$$qrcode.makeCode(this.props.text)
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/views/Sidebar.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Body, Nav, Sidebar, SidebarItem} from '@/components'
3 |
4 | let data = []
5 | for (let i = 0; i < 20; i++) {
6 | data.push({
7 | name: i,
8 | label: `选项${i}`
9 | })
10 | }
11 | class Demo extends React.Component {
12 | state = {
13 | active: 0,
14 | data
15 | }
16 | style = {
17 | width:'80px',
18 | background:'#f7f7f7',
19 | position:'absolute',
20 | height:'100%'
21 | }
22 | render() {
23 | return (
24 |
25 |
26 |
27 |
28 | {this.state.data.map((item, i) => {
29 | return {item.label}
30 | })}
31 |
32 |
33 |
34 | );
35 | }
36 | handleChange (value) {
37 | this.setState({
38 | active: value
39 | })
40 | }
41 | }
42 |
43 | export default Demo;
44 |
--------------------------------------------------------------------------------
/src/views/Alert.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Nav, Body, Alert, Switch, Cell, Group} from '@/components'
3 |
4 | class Demo extends React.Component {
5 | state = {
6 | open: false
7 | }
8 | render() {
9 | return (
10 |
11 |
12 |
13 |
14 |
15 |
16 | |
17 |
18 | 点击我打开
19 | |
20 |
21 |
22 |
23 | 确认删除我么
24 |
25 |
26 | );
27 | }
28 | handleChange (value) {
29 | this.setState({
30 | open: value
31 | })
32 | }
33 | handleConfirm () {
34 | this.handleChange(false)
35 | }
36 | handleClick () {
37 | Alert.open({
38 | message: 'alert'
39 | })
40 | }
41 | }
42 |
43 | export default Demo;
44 |
--------------------------------------------------------------------------------
/src/views/Flexbox.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Body, Nav, Flexbox, FlexboxItem } from '@/components'
3 |
4 | class Demo extends React.Component {
5 | render() {
6 | return (
7 |
8 |
9 |
10 | ### 平均跨度
11 |
12 | 1
13 | 2
14 | 3
15 |
16 |
17 | ### 跨度
18 |
19 | 1
20 | 2
21 | 3
22 |
23 |
24 | ### 列布局
25 |
26 | 1
27 | 2
28 | 3
29 |
30 |
31 |
32 | );
33 | }
34 | }
35 |
36 | export default Demo;
37 |
--------------------------------------------------------------------------------
/src/views/Tabbar.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Body, Nav, Tabbar, TabbarItem} from '@/components'
3 |
4 | class Demo extends React.Component {
5 | state = {
6 | active: 'home'
7 | }
8 | render() {
9 | return (
10 |
11 |
12 |
13 |
14 |
15 | ★
16 | 主页
17 |
18 |
19 | ♡
20 | 消息
21 |
22 |
23 | ★
24 | 我的
25 |
26 |
27 |
28 | );
29 | }
30 | handleChange (value) {
31 | this.setState({
32 | active: value
33 | })
34 | }
35 | }
36 |
37 | export default Demo;
38 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.css';
4 | import App from './App';
5 | import registerServiceWorker from './registerServiceWorker';
6 | import { Provider } from 'react-redux';
7 | import store from './store';
8 | import 'vx-ui/lib/style/theme/index.css'
9 | import '@/components';
10 |
11 | ReactDOM.render(
12 |
13 |
14 | ,
15 | document.getElementById('root')
16 | );
17 | registerServiceWorker();
18 |
19 | let initRootFontSize = function () {
20 | let deviceWidth = window.innerWidth
21 | let devicePixelRatio = window.devicePixelRatio || window.webkitDevicePixelRatio || window.mozDevicePixelRatio
22 | let calc = 7.5
23 | if (deviceWidth > 768) deviceWidth = 768
24 | if (deviceWidth < 320) deviceWidth = 320
25 | if (deviceWidth < 320 && devicePixelRatio >= 2) calc = calc - (devicePixelRatio - 1)
26 | let fontSize = Math.ceil(deviceWidth / calc)
27 | if (fontSize % 2 === 1) {
28 | fontSize--
29 | }
30 | document.documentElement.style.fontSize = fontSize + 'px'// 计算设计稿和实际像素的缩放比。向上取整1px = 0.01rem
31 | }
32 | window.addEventListener('resize', initRootFontSize)
33 | initRootFontSize()
34 |
--------------------------------------------------------------------------------
/src/components/AsyncComponent.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import Toast from '@/components/toast'
4 |
5 | export default function asyncComponent(importComponent) {
6 | class AsyncComponent extends React.Component {
7 | constructor(props) {
8 | super(props)
9 | this.state = {
10 | component: null
11 | }
12 | this.node = document.createElement('div')
13 | document.body.appendChild(this.node)
14 | ReactDOM.render(
15 | 页面努力加载...,
16 | this.node
17 | )
18 | }
19 |
20 | async componentDidMount() {
21 | const { default: component } = await importComponent()
22 | this.setState({
23 | component: component
24 | }, () => {
25 | setTimeout(() => {
26 | ReactDOM.unmountComponentAtNode(this.node)
27 | this.node && this.node.parentNode && this.node.parentNode.removeChild(this.node)
28 | this.node = null
29 | }, 200)
30 | })
31 | }
32 |
33 | render() {
34 | const C = this.state.component
35 | return C ? : null
36 | }
37 | }
38 | return AsyncComponent
39 | }
--------------------------------------------------------------------------------
/src/components/rater/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import classnames from 'classnames'
4 |
5 | const Rater = props => {
6 | let {className, disabled, value, max, color, gutter, star, onChange, ...others} = props
7 | let handleChange = _value => {
8 | _value !== value && onChange && onChange(_value)
9 | }
10 | let items = []
11 | for (let i = 1; i <= max; i++) {
12 | items.push(
13 |
18 | {star}
19 |
20 | )
21 | }
22 |
23 | return (
24 |
25 | {items}
26 |
27 | )
28 | }
29 | Rater.propTypes = {
30 | value: PropTypes.number,
31 | max: PropTypes.number,
32 | disabled: PropTypes.bool,
33 | star: PropTypes.string,
34 | color: PropTypes.string,
35 | gutter: PropTypes.string,
36 | onChange: PropTypes.func
37 | }
38 | Rater.defaultProps = {
39 | gutter: '',
40 | max: 5,
41 | star: '★',
42 | disabled: false,
43 | }
44 |
45 | export default Rater;
46 |
--------------------------------------------------------------------------------
/src/components/switch/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import classnames from 'classnames'
4 |
5 | const Switch = props => {
6 | const { className, style, onValue, offValue, value, onChange, size, ...others } = props
7 | let handleChange = (e) => {
8 | onChange && onChange(e.target.checked ? onValue : offValue)
9 | }
10 | return (
11 |
12 |
19 |
20 |
21 | )
22 | }
23 |
24 | Switch.propTypes = {
25 | disabled: PropTypes.bool,
26 | value: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.bool]),
27 | onValue: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.bool]),
28 | offValue: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.bool]),
29 | size: PropTypes.string,
30 | onChange: PropTypes.func
31 | }
32 |
33 | Switch.defaultProps = {
34 | value: false,
35 | onValue: true,
36 | offValue: false,
37 | size: 'default'
38 | }
39 |
40 | export default Switch
41 |
--------------------------------------------------------------------------------
/src/components/button/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import classnames from 'classnames'
4 | import Spinner from '../spinner'
5 | import Ripple from '../ripple'
6 |
7 | const Button = props => {
8 | const { type, size, plain, className, disabled, nativeType, loading, ripple, children, ...others } = props
9 | const cls = classnames(['vx-btn', 'vx-btn--' + type, 'vx-btn--size-' + size, {
10 | 'is-plain': plain || type === 'default',
11 | 'is-disabled': disabled || loading,
12 | 'is-ripple': ripple
13 | }, className])
14 |
15 | return (
16 |
24 | )
25 | }
26 |
27 | Button.propTypes = {
28 | disabled: PropTypes.bool,
29 | loading: PropTypes.bool,
30 | ripple: PropTypes.bool,
31 | type: PropTypes.string,
32 | size: PropTypes.string,
33 | plain: PropTypes.bool,
34 | nativeType: PropTypes.string
35 | }
36 | Button.defaultProps = {
37 | disabled: false,
38 | loading: false,
39 | ripple: false,
40 | type: 'default',
41 | size: 'normal',
42 | nativeType: 'button'
43 | }
44 |
45 | export default Button
46 |
--------------------------------------------------------------------------------
/src/views/ButtonTab.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Body, Nav, ButtonTab, ButtonTabItem } from '@/components'
3 |
4 | class Demo extends React.Component {
5 | state = {
6 | active: 'recommed',
7 | items: [
8 | {name: 'recommed', label: '推荐'},
9 | {name: 'it', label: '科技'},
10 | {name: 'active', label: '活动'},
11 | {name: 'find', label: '发现'}
12 | ]
13 | }
14 | render() {
15 | let items = this.state.items.map((item, index) => {
16 | return {item.label}
17 | })
18 | return (
19 |
20 |
21 |
22 |
23 |
24 | {items}
25 |
26 |
27 |
28 | {items}
29 |
30 |
31 |
32 |
33 | );
34 | }
35 | handleChange (value) {
36 | this.setState({
37 | active: value
38 | })
39 | }
40 | }
41 |
42 | export default Demo;
43 |
--------------------------------------------------------------------------------
/src/components/arrow/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import classnames from 'classnames'
4 |
5 | const Arrow = props => {
6 | const { direction, size, color, component, style, className, ...others } = props
7 | const Component = component
8 | const styles = {
9 | display: 'inline-block',
10 | borderWidth: '1px',
11 | borderStyle: 'solid',
12 | verticalAlign: 'middle',
13 | boxSizing: 'border-box',
14 | transform: 'rotate(45deg)',
15 | height: size,
16 | width: size,
17 | borderColor: {
18 | up: `${color} transparent transparent ${color}`,
19 | right: `${color} ${color} transparent transparent`,
20 | down: `transparent ${color} ${color} transparent`,
21 | left: `transparent transparent ${color} ${color}`
22 | }[direction],
23 | ...style
24 | }
25 | return (
26 |
30 |
31 | )
32 | }
33 |
34 | Arrow.propTypes = {
35 | direction: PropTypes.string,
36 | size: PropTypes.string,
37 | color: PropTypes.string,
38 | component: PropTypes.string
39 | }
40 |
41 | Arrow.defaultProps = {
42 | direction: 'right',
43 | size: '0.2rem',
44 | color: '#999',
45 | component: 'i'
46 | }
47 |
48 | export default Arrow
49 |
--------------------------------------------------------------------------------
/src/views/Rater.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Nav, Body, Rater, Cell, Group} from '@/components'
3 |
4 | class Demo extends React.Component {
5 | state = {
6 | value: 0
7 | }
8 | render() {
9 | return (
10 |
11 |
12 |
13 |
14 |
15 |
16 | |
17 |
18 |
19 | |
20 |
21 |
22 | |
23 |
24 |
25 | |
26 |
27 |
28 |
29 | );
30 | }
31 | handleChange (value) {
32 | this.setState({
33 | value
34 | })
35 | }
36 | }
37 |
38 | export default Demo;
39 |
--------------------------------------------------------------------------------
/src/components/checker/Checker.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import classnames from 'classnames';
3 | import PropTypes from 'prop-types';
4 |
5 | const Checker = props => {
6 | let {children, style, className, $parent, onChange, ...others} = props
7 | let type = $parent && $parent.max === 1 ? 'radio' : 'checkbox'
8 | let checked = others.checked
9 | let disabled = others.disabled
10 | if ($parent) {
11 | if ($parent.value instanceof Array) {
12 | checked = $parent.value.indexOf(others.value) > -1
13 | } else {
14 | checked = $parent.value === others.value
15 | }
16 | if ($parent.value.length >= $parent.max && $parent.max > 1) {
17 | disabled = $parent.value.indexOf(others.value) === -1
18 | }
19 | }
20 | let handleChange = (e) => {
21 | if ($parent) {
22 | $parent.onChange && $parent.onChange(e)
23 | } else {
24 | onChange && onChange(e)
25 | }
26 | }
27 | return (
28 |
36 | );
37 | }
38 | Checker.propTypes = {
39 | onChange: PropTypes.func
40 | }
41 |
42 | export default Checker;
43 |
--------------------------------------------------------------------------------
/src/views/Switch.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Body, Nav, Group, Cell, Switch } from '@/components'
3 |
4 | class Demo extends React.Component {
5 | state = {
6 | open: false,
7 | value: '0'
8 | }
9 | render() {
10 | return (
11 |
12 |
13 |
14 |
15 |
16 |
17 | |
18 |
19 |
20 |
21 |
22 | |
23 |
24 |
25 |
26 |
27 | |
28 |
29 |
30 |
31 | );
32 | }
33 | handleChange (value) {
34 | console.log(value)
35 | this.setState({
36 | open: value
37 | })
38 | }
39 | handleChange2 (value) {
40 | this.setState({
41 | value
42 | })
43 | }
44 | }
45 |
46 | export default Demo;
47 |
--------------------------------------------------------------------------------
/src/components/nav/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import classnames from 'classnames'
4 | import Arrow from '../arrow'
5 | import { Flexbox, FlexboxItem } from '../flexbox'
6 |
7 | const Nav = props => {
8 | const { className, title, isBack, backText, onBack, pull, children, type, ...others } = props
9 | return (
10 |
13 |
14 | {isBack && }
18 |
19 | {title}
20 |
21 | {pull}
22 |
23 | {children}
24 |
25 | )
26 | }
27 | Nav.propTypes = {
28 | type: PropTypes.string,
29 | back: PropTypes.bool,
30 | title: PropTypes.string,
31 | backText: PropTypes.string,
32 | onBack: PropTypes.func
33 | }
34 | Nav.defaultProps = {
35 | type: 'default',
36 | isBack: true,
37 | onBack: () => {
38 | window.history.back()
39 | }
40 | }
41 | export default Nav
42 |
--------------------------------------------------------------------------------
/config/jest/fileTransform.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 | const camelcase = require('camelcase');
5 |
6 | // This is a custom Jest transformer turning file imports into filenames.
7 | // http://facebook.github.io/jest/docs/en/webpack.html
8 |
9 | module.exports = {
10 | process(src, filename) {
11 | const assetFilename = JSON.stringify(path.basename(filename));
12 |
13 | if (filename.match(/\.svg$/)) {
14 | // Based on how SVGR generates a component name:
15 | // https://github.com/smooth-code/svgr/blob/01b194cf967347d43d4cbe6b434404731b87cf27/packages/core/src/state.js#L6
16 | const pascalCaseFilename = camelcase(path.parse(filename).name, {
17 | pascalCase: true,
18 | });
19 | const componentName = `Svg${pascalCaseFilename}`;
20 | return `const React = require('react');
21 | module.exports = {
22 | __esModule: true,
23 | default: ${assetFilename},
24 | ReactComponent: React.forwardRef(function ${componentName}(props, ref) {
25 | return {
26 | $$typeof: Symbol.for('react.element'),
27 | type: 'svg',
28 | ref: ref,
29 | key: null,
30 | props: Object.assign({}, props, {
31 | children: ${assetFilename}
32 | })
33 | };
34 | }),
35 | };`;
36 | }
37 |
38 | return `module.exports = ${assetFilename};`;
39 | },
40 | };
41 |
--------------------------------------------------------------------------------
/src/components/ConnectComponent.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import rootAction from '@/store/root/action';
3 |
4 | export default function connectComponent(component, mapStateToProps, mapDispatchToProps) {
5 | const _mapStateToProps = mapStateToProps ? mapStateToProps : (state, ownProps) => {
6 | return {
7 | state,
8 | ownProps
9 | }
10 | }
11 |
12 | const _mapDispatchToProps = mapDispatchToProps ? mapDispatchToProps : (dispatch) => {
13 | return {
14 | dispatch (action, data) {
15 | let lastIndex = action.lastIndexOf('/')
16 | let name = lastIndex ? action.substring(lastIndex + 1) : action
17 | let path = lastIndex ? action.substring(0, lastIndex) : ''
18 | if (path) {
19 | import(`../store/${path}/action`).then(res => {
20 | if (res.default && res.default[name]) {
21 | let result = res.default[name](data)
22 | result.$$module = path
23 | dispatch(result)
24 | }
25 | }).catch(() => {
26 | console.log(`not find store module "${name}"`)
27 | })
28 | } else {
29 | if (rootAction[action]) {
30 | dispatch(rootAction[action](data))
31 | } else {
32 | console.log(`not find store module "${action}"`)
33 | }
34 | }
35 | }
36 | }
37 | }
38 | return connect(_mapStateToProps, _mapDispatchToProps)(component)
39 | }
--------------------------------------------------------------------------------
/src/views/Picker.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Nav, Body, Message, Picker, Group} from '@/components'
3 |
4 | class Demo extends React.Component {
5 | state = {
6 | value: '010101',
7 | options: [{
8 | value: '010101',
9 | label: '南山区'
10 | },
11 | {
12 | value: '010102',
13 | label: '福田区'
14 | },
15 | {
16 | value: '010103',
17 | label: '罗湖区'
18 | },
19 | {
20 | value: '010104',
21 | label: '宝安区'
22 | },
23 | {
24 | value: '010105',
25 | label: '龙华区'
26 | },
27 | {
28 | value: '010106',
29 | label: '龙岗区'
30 | },
31 | {
32 | value: '010107',
33 | label: '盐田区'
34 | },
35 | {
36 | value: '010108',
37 | label: '坪山区'
38 | },
39 | {
40 | value: '010109',
41 | label: '光明区'
42 | }]
43 | }
44 | render() {
45 | return (
46 |
47 |
48 |
49 | 注意:此示例要在移动设备体验哦~
50 |
51 |
52 |
53 |
54 |
55 | );
56 | }
57 | handleChange (value) {
58 | this.setState({
59 | value
60 | })
61 | }
62 | }
63 |
64 | export default Demo;
65 |
--------------------------------------------------------------------------------
/src/components/password/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import classnames from 'classnames'
3 | import Input from '../input'
4 |
5 | export default class Password extends React.Component {
6 | static defaultProps= {
7 | autoComplete: 'new-password',
8 | icons: [
9 | '',
10 | 'abc'
11 | ]
12 | }
13 | constructor (props) {
14 | super(props)
15 | this.handleSwitch = this.handleSwitch.bind(this)
16 | this.state = {
17 | type: this.props.type || 'password'
18 | }
19 | }
20 | render () {
21 | let {children, className, style, icons, ...others} = this.props
22 | return (
23 |
24 |
29 |
30 |
31 |
32 | }/>
33 |
34 | )
35 | }
36 | handleSwitch () {
37 | this.setState({
38 | type: this.state.type === 'password' ? 'text' : 'password'
39 | })
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/views/Swiper.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Body, Nav, Swiper, SwiperItem } from '@/components'
3 |
4 | class Demo extends React.Component {
5 | state = {
6 | images: [
7 | 'http://assets.bittyos.com/images/swiper/01.jpg',
8 | 'http://assets.bittyos.com/images/swiper/02.jpg',
9 | 'http://assets.bittyos.com/images/swiper/03.jpg',
10 | 'http://assets.bittyos.com/images/swiper/04.jpg',
11 | 'http://assets.bittyos.com/images/swiper/05.jpg'
12 | ],
13 | active: 0,
14 | options: {
15 | speed: 500
16 | }
17 | }
18 | render() {
19 | let items = this.state.images.map((item,index) =>{
20 | return (
21 |
22 |
23 |
24 | )
25 | })
26 | return (
27 |
28 |
29 |
30 |
31 | {items}
32 |
33 |
34 | {items}
35 |
36 |
37 |
38 | );
39 | }
40 | handleChange (active) {
41 | console.log(active)
42 | this.setState({
43 | active
44 | })
45 | }
46 | }
47 |
48 | export default Demo;
49 |
--------------------------------------------------------------------------------
/src/components/checker/CheckerGroup.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import classnames from 'classnames';
4 |
5 | const CheckerGroup = props => {
6 | let {children, className, onChange, disabled, ...others} = props
7 | let handleChange = e => {
8 | let value = null
9 | if (props.max === 1) {
10 | value = [e.target.value]
11 | } else {
12 | if (e.target.checked && props.max !== 0 && props.max === props.value.length) {
13 | console.log('max:', props.max)
14 | } else {
15 | value = [...props.value]
16 | if (e.target.checked) {
17 | value.indexOf(e.target.value) === -1 && value.push(e.target.value)
18 | } else {
19 | value.splice(value.indexOf(e.target.value), 1)
20 | }
21 | }
22 | }
23 | value && onChange && onChange(value)
24 | }
25 | let cloneChildren = React.Children.map(children, item => {
26 | if (item) {
27 | return React.cloneElement(item, {
28 | $parent: {
29 | ...others,
30 | onChange: handleChange
31 | }
32 | })
33 | }
34 | return item
35 | })
36 | return (
37 |
38 | {cloneChildren}
39 |
40 | );
41 | }
42 | CheckerGroup.propsTypes = {
43 | value: PropTypes.array,
44 | max: PropTypes.number,
45 | onChange: PropTypes.func
46 | }
47 | CheckerGroup.defaultProps = {
48 | value: [],
49 | max: 0,
50 | }
51 |
52 | export default CheckerGroup;
53 |
--------------------------------------------------------------------------------
/scripts/test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // Do this as the first thing so that any code reading it knows the right env.
4 | process.env.BABEL_ENV = 'test';
5 | process.env.NODE_ENV = 'test';
6 | process.env.PUBLIC_URL = '';
7 |
8 | // Makes the script crash on unhandled rejections instead of silently
9 | // ignoring them. In the future, promise rejections that are not handled will
10 | // terminate the Node.js process with a non-zero exit code.
11 | process.on('unhandledRejection', err => {
12 | throw err;
13 | });
14 |
15 | // Ensure environment variables are read.
16 | require('../config/env');
17 |
18 |
19 | const jest = require('jest');
20 | const execSync = require('child_process').execSync;
21 | let argv = process.argv.slice(2);
22 |
23 | function isInGitRepository() {
24 | try {
25 | execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore' });
26 | return true;
27 | } catch (e) {
28 | return false;
29 | }
30 | }
31 |
32 | function isInMercurialRepository() {
33 | try {
34 | execSync('hg --cwd . root', { stdio: 'ignore' });
35 | return true;
36 | } catch (e) {
37 | return false;
38 | }
39 | }
40 |
41 | // Watch unless on CI or explicitly running all tests
42 | if (
43 | !process.env.CI &&
44 | argv.indexOf('--watchAll') === -1 &&
45 | argv.indexOf('--watchAll=false') === -1
46 | ) {
47 | // https://github.com/facebook/create-react-app/issues/5210
48 | const hasSourceControl = isInGitRepository() || isInMercurialRepository();
49 | argv.push(hasSourceControl ? '--watch' : '--watchAll');
50 | }
51 |
52 |
53 | jest.run(argv);
54 |
--------------------------------------------------------------------------------
/src/views/Range.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Nav, Body, Range, Group} from '@/components'
3 |
4 | class Demo extends React.Component {
5 | state = {
6 | value1: 0,
7 | value2: 0
8 | }
9 | render() {
10 | return (
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | );
37 | }
38 | handleChange (key, value) {
39 | let state = {...this.state}
40 | state[key] = value
41 | this.setState(state)
42 | }
43 | }
44 |
45 | export default Demo;
46 |
--------------------------------------------------------------------------------
/src/components/prompt/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import classnames from 'classnames'
3 | import Input from '../input'
4 | import Password from '../password'
5 | import Confirm from '../confirm'
6 |
7 | class Prompt extends React.Component {
8 | static defaultProps = {
9 | inputProps: {}
10 | }
11 | constructor(props) {
12 | super(props)
13 | this.state = {
14 | value: this.props.inputProps.value || ''
15 | }
16 | this.handleInput = this.handleInput.bind(this)
17 | this.handleConfirm = this.handleConfirm.bind(this)
18 | }
19 | render () {
20 | let {children, inputProps, className, style, disabled, ...others} = this.props
21 | let _children = children
22 | if (!_children) {
23 | if (inputProps && inputProps.type === 'password') {
24 | _children =
25 | } else {
26 | _children =
27 | }
28 | }
29 | return (
30 | {_children}
31 | )
32 | }
33 | handleInput (value) {
34 | this.setState({value})
35 | }
36 | handleConfirm () {
37 | this.props.onConfirm && this.props.onConfirm(this.state.value)
38 | }
39 | }
40 |
41 | export default Prompt;
42 |
--------------------------------------------------------------------------------
/src/components/marquee/Marquee.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import classnames from 'classnames';
3 | import PropTypes from 'prop-types';
4 |
5 | class Marquee extends React.Component {
6 | static propTypes = {
7 | active: PropTypes.number,
8 | options: PropTypes.object,
9 | direction: PropTypes.string,
10 | autoplay: PropTypes.number,
11 | effect: PropTypes.string,
12 | loop: PropTypes.bool,
13 | onChange: PropTypes.func
14 | }
15 | static defaultProps = {
16 | active: 0,
17 | autoplay: 2000,
18 | direction: 'vertical',
19 | effect: 'slide',
20 | loop: true
21 | }
22 | render () {
23 | let {children, className, ...others} = this.props
24 | return (
25 |
26 |
27 | {children}
28 |
29 |
30 | );
31 | }
32 | componentDidMount () {
33 | let {active, direction, autoplay, loop, onChange} = this.props
34 | import('swiper/dist/js/swiper.min.js').then(res => {
35 | let Swiper = res.default
36 | import('swiper/dist/css/swiper.min.css')
37 | let options = Object.assign({
38 | initialSlide: active,
39 | direction: direction,
40 | autoplay: autoplay,
41 | loop: loop,
42 | onSlideChangeStart: (swiper) => {
43 | onChange && onChange(swiper.activeIndex)
44 | }
45 | }, this.props.options)
46 | this.$$swiper = new Swiper(this.refs.$el, options)
47 | })
48 | }
49 | }
50 |
51 | export default Marquee;
52 |
--------------------------------------------------------------------------------
/src/components/flexbox/Flexbox.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import classnames from 'classnames'
4 | const mapFlexLayout = {
5 | direction: {
6 | column: `flexbox--column`
7 | },
8 | wrap: {
9 | wrap: `flexbox--wrap`
10 | },
11 | justify: {
12 | center: `flexbox--content-center`
13 | },
14 | align: {
15 | center: `flexbox--align-center`
16 | }
17 | }
18 | const Flexbox = props => {
19 | const { className, direction, wrap, justify, align, children, component, ...others } = props
20 | let array = ['vx-flexbox']
21 | for (let name in mapFlexLayout) {
22 | if (props[name] && mapFlexLayout[name][props[name]]) {
23 | array.push('vx-' + mapFlexLayout[name][props[name]])
24 | }
25 | }
26 |
27 | array.push(className)
28 | const cls = classnames(array)
29 | let cloneChildren = React.Children.map(children, (item) => {
30 | if (item) {
31 | return React.cloneElement(item, {
32 | gutter: props.gutter
33 | })
34 | }
35 | return item;
36 | })
37 |
38 | let Component = component || 'div'
39 | return (
40 |
43 | {cloneChildren}
44 |
45 | )
46 | }
47 | Flexbox.propTypes = {
48 | direction: PropTypes.string,
49 | wrap: PropTypes.string,
50 | justify: PropTypes.string,
51 | align: PropTypes.string,
52 | gutter: PropTypes.number
53 | }
54 | Flexbox.defaultProps = {
55 | direction: 'normal',
56 | wrap: 'normal',
57 | align: 'normal',
58 | justify: 'normal',
59 | gutter: 0
60 | }
61 |
62 | export default Flexbox
63 |
--------------------------------------------------------------------------------
/src/components/accordion/Accordion.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import classnames from 'classnames';
4 |
5 | class Accordion extends React.Component{
6 | static propTypes = {
7 | mutex: PropTypes.bool
8 | }
9 | static defaultProps = {
10 | mutex: true
11 | }
12 | constructor (props) {
13 | super(props)
14 | this.state = {value: []}
15 | this.open = this.open.bind(this)
16 | this.close = this.close.bind(this)
17 | }
18 | render () {
19 | let {children, className, mutex, ...others} = this.props
20 | let cloneChildren = React.Children.map(children, (item) => {
21 | if (item) {
22 | return React.cloneElement(item, {
23 | toOpen: this.open,
24 | toClose: this.close,
25 | value: this.state.value
26 | })
27 | }
28 | return item;
29 | })
30 | return (
31 |
32 | {cloneChildren}
33 |
34 | );
35 | }
36 | open (name) {
37 | if (!this.props.mutex) {
38 | if (this.state.value.indexOf(name) === -1) {
39 | this.setState({
40 | value: [...this.state.value, name]
41 | })
42 | } else {
43 | this.close(name)
44 | }
45 | } else {
46 | this.setState({
47 | value: this.state.value[0] === name ? [] : [name]
48 | })
49 | }
50 | }
51 | close (name) {
52 | let value = this.state.value.filter(item => {
53 | return item !== name
54 | })
55 | this.setState({value})
56 | }
57 | }
58 |
59 | export default Accordion;
60 |
--------------------------------------------------------------------------------
/src/store/index.js:
--------------------------------------------------------------------------------
1 | import { createStore, applyMiddleware, compose, combineReducers } from 'redux';
2 | import thunk from 'redux-thunk';
3 | import { createLogger } from 'redux-logger';
4 | import reducer, { initialState } from './root/reducer';
5 | import DevTools from '../devtools'
6 |
7 | let rootReducer = reducer
8 |
9 | const AsyncReducer = store => next => action => {
10 | let module = action.$$module
11 | if (module) {
12 | import(`@/store/${module}/reducer`).then(res => {
13 | injectReducer({key: module, reducer: res.default})
14 | next(action)
15 | }).catch(() => {
16 | return next(action)
17 | })
18 | } else {
19 | return next(action)
20 | }
21 | }
22 |
23 | let enhancer = applyMiddleware(AsyncReducer, thunk)
24 | if (process.env.NODE_ENV === 'development') {
25 | enhancer = compose(
26 | applyMiddleware(AsyncReducer, thunk, createLogger()),
27 | DevTools.instrument()
28 | )
29 | }
30 |
31 | export const makeRootReducer = (asyncReducers) => {
32 | return combineReducers({
33 | ...rootReducer,
34 | ...asyncReducers
35 | })
36 | }
37 |
38 | let store = createStore(makeRootReducer(), initialState, enhancer);
39 |
40 | store.asyncReducers = {}
41 |
42 | export const injectReducer = ({ key, reducer }) => {
43 | store.asyncReducers[key] = reducer
44 | store.replaceReducer(makeRootReducer(store.asyncReducers))
45 | }
46 |
47 | if (process.env.NODE_ENV === 'development') {
48 | if (module.hot) {
49 | module.hot.accept('./root/reducer', () => {
50 | rootReducer = require('./root/reducer').default;
51 | store.replaceReducer(makeRootReducer(store.asyncReducers))
52 | })
53 | }
54 | }
55 |
56 |
57 | export default store
--------------------------------------------------------------------------------
/src/views/Tab.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Body, Nav, Tab, TabItem } from '@/components'
3 |
4 | class Demo extends React.Component {
5 | state = {
6 | active: 'recommed',
7 | items: [
8 | {name: 'recommed', label: '推荐'},
9 | {name: 'it', label: '科技'},
10 | {name: 'active', label: '活动'},
11 | {name: 'find', label: '发现'},
12 | {name: 'sort', label: '排行'},
13 | {name: 'msg', label: '消息'},
14 | {name: 'sns', label: '社区'}
15 | ]
16 | }
17 | render() {
18 | let items = this.state.items.slice(0,4).map((item, index) => {
19 | return {item.label}
20 | })
21 | return (
22 |
23 |
24 |
25 |
26 | {items}
27 |
28 |
29 | {items}
30 |
31 |
32 | {items}
33 |
34 |
35 | {this.state.items.map((item, index) => {
36 | return {item.label}
37 | })}
38 |
39 |
40 |
41 |
42 | );
43 | }
44 | handleChange (value) {
45 | this.setState({
46 | active: value
47 | })
48 | }
49 | }
50 |
51 | export default Demo;
52 |
--------------------------------------------------------------------------------
/src/views/Radio.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Body, Nav, Group, Radio, RadioGroup, Divider } from '@/components'
3 |
4 | class Demo extends React.Component {
5 | state = {
6 | checked: false,
7 | value: '1',
8 | options: [
9 | {
10 | value: '1',
11 | label: '篮球'
12 | },
13 | {
14 | value: '2',
15 | label: '羽毛球'
16 | },
17 | {
18 | value: '3',
19 | label: '乒乓球',
20 | disabled: true
21 | },
22 | {
23 | value: '4',
24 | label: '高尔夫'
25 | }
26 | ]
27 | }
28 | render() {
29 | return (
30 |
31 |
32 |
33 |
34 | 篮球
35 |
36 | 羽毛球
37 |
38 |
39 |
40 | {(() => {
41 | return this.state.options.map((item, index) => {
42 | return {item.label}
43 | })
44 | })()}
45 |
46 |
47 |
48 |
49 | );
50 | }
51 | handleChange (e) {
52 | this.setState({
53 | checked: e.target.checked
54 | })
55 | }
56 | handleGroupChange (value) {
57 | this.setState({
58 | value: value
59 | })
60 | }
61 | }
62 |
63 | export default Demo;
64 |
--------------------------------------------------------------------------------
/src/views/Popover.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Nav, Body, Popover, Button, Divider, Flexbox, FlexboxItem} from '@/components'
3 |
4 | class Demo extends React.Component {
5 | render() {
6 | let menu = (
7 |
8 |
扫一扫
9 |
10 |
找朋友
11 |
12 |
收付款
13 |
14 | )
15 | return (
16 |
17 |
18 |
19 |
20 |
21 | left top}>
22 | {menu}
23 |
24 |
25 |
26 | right top}>
27 | {menu}
28 |
29 |
30 |
31 |
32 |
33 | left bottom}>
34 | {menu}
35 |
36 |
37 |
38 | right bottom}>
39 | {menu}
40 |
41 |
42 |
43 |
44 |
45 | );
46 | }
47 | handleClick (e) {
48 | console.log(e.target.innerHTML)
49 | }
50 | }
51 |
52 | export default Demo;
53 |
--------------------------------------------------------------------------------
/src/components/checkbox/CheckboxGroup.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import classnames from 'classnames';
4 |
5 | const CheckboxGroup = props => {
6 | let {children, className, divider, inline, iconStyle, onChange, ...others} = props
7 | let handleChange = e => {
8 | let value = null
9 | if (props.max === 1) {
10 | value = [e.target.value]
11 | } else {
12 | if (e.target.checked && props.max !== 0 && props.max === props.value.length) {
13 | console.log('max:', props.max)
14 | } else {
15 | value = [...props.value]
16 | if (e.target.checked) {
17 | value.indexOf(e.target.value) === -1 && value.push(e.target.value)
18 | } else {
19 | value.splice(value.indexOf(e.target.value), 1)
20 | }
21 | }
22 | }
23 | value && onChange && onChange(value)
24 | }
25 | let cloneChildren = React.Children.map(children, item => {
26 | if (item) {
27 | return React.cloneElement(item, {
28 | $parent: {
29 | ...others,
30 | inline,
31 | iconStyle,
32 | onChange: handleChange
33 | }
34 | })
35 | }
36 | return item
37 | })
38 | return (
39 |
40 | {cloneChildren}
41 |
42 | );
43 | }
44 | CheckboxGroup.propsTypes = {
45 | value: PropTypes.array,
46 | divider: PropTypes.bool,
47 | inline: PropTypes.bool,
48 | max: PropTypes.number,
49 | direction: PropTypes.string,
50 | iconStyle: PropTypes.string,
51 | onChange: PropTypes.func
52 | }
53 | CheckboxGroup.defaultProps = {
54 | value: [],
55 | divider: true,
56 | max: 0,
57 | inline: false,
58 | direction: 'normal'
59 | }
60 |
61 | export default CheckboxGroup;
62 |
--------------------------------------------------------------------------------
/src/views/Accordion.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Body, Nav, Accordion, AccordionItem, Group} from '@/components'
3 |
4 | class Demo extends React.Component {
5 | render() {
6 | return (
7 |
8 |
9 |
10 |
11 |
12 |
13 | 如果有一天我能够拥有一个大果园,
14 | 我愿放下所有追求做个农夫去种田,
15 | 每一个早晨我耕耘在绿野田园,
16 | 每一个黄昏我守望在乡间的麦田。
17 | 我会把忧虑都融化在夕阳里,
18 | 让孤独的心等待秋收的欢喜。
19 |
20 |
21 | 如果有一天我能够拥有一个大果园,
22 | 我愿放下所有追求做个农夫去种田,
23 | 每一个早晨我耕耘在绿野田园,
24 | 每一个黄昏我守望在乡间的麦田。
25 | 我会把忧虑都融化在夕阳里,
26 | 让孤独的心等待秋收的欢喜。
27 |
28 |
29 |
30 |
31 |
32 |
33 | 如果有一天我能够拥有一个大果园,
34 | 我愿放下所有追求做个农夫去种田,
35 | 每一个早晨我耕耘在绿野田园,
36 | 每一个黄昏我守望在乡间的麦田。
37 | 我会把忧虑都融化在夕阳里,
38 | 让孤独的心等待秋收的欢喜。
39 |
40 |
41 | 如果有一天我能够拥有一个大果园,
42 | 我愿放下所有追求做个农夫去种田,
43 | 每一个早晨我耕耘在绿野田园,
44 | 每一个黄昏我守望在乡间的麦田。
45 | 我会把忧虑都融化在夕阳里,
46 | 让孤独的心等待秋收的欢喜。
47 |
48 |
49 |
50 |
51 |
52 | );
53 | }
54 | }
55 |
56 | export default Demo;
57 |
--------------------------------------------------------------------------------
/src/views/Button.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Body, Nav, Button } from '@/components'
3 |
4 | class Demo extends React.Component {
5 | render() {
6 | return (
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | );
45 | }
46 | }
47 |
48 | export default Demo;
49 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | React App
28 |
29 |
30 |
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/src/views/Layout.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Body, Nav } from '@/components'
3 |
4 | class Demo extends React.Component {
5 | render() {
6 | return (
7 |
8 |
9 |
10 | 新华社北京5月27日电 中共中央政治局5月26日下午就推动形成绿色发展方式和生活方式进行第四十一次集体学习。中共中央总书记习近平在主持学习时强调,推动形成绿色发展方式和生活方式是贯彻新发展理念的必然要求,必须把生态文明建设摆在全局工作的突出地位,坚持节约资源和保护环境的基本国策,坚持节约优先、保护优先、自然恢复为主的方针,形成节约资源和保护环境的空间格局、产业结构、生产方式、生活方式,努力实现经济社会发展和生态环境保护协同共进,为人民群众创造良好生产生活环境。
11 | 学习开始时,播放了有关生态环境保护的专题片。随后,何立峰、姜大明、陈吉宁、陈政高、陈雷同志先后发言,他们结合本部门工作实际谈了对推进生态文明建设、推动绿色发展、加强环境保护等方面的体会和意见。新华社北京5月27日电 中共中央政治局5月26日下午就推动形成绿色发展方式和生活方式进行第四十一次集体学习。中共中央总书记习近平在主持学习时强调,推动形成绿色发展方式和生活方式是贯彻新发展理念的必然要求,必须把生态文明建设摆在全局工作的突出地位,坚持节约资源和保护环境的基本国策,坚持节约优先、保护优先、自然恢复为主的方针,形成节约资源和保护环境的空间格局、产业结构、生产方式、生活方式,努力实现经济社会发展和生态环境保护协同共进,为人民群众创造良好生产生活环境。
12 | 学习开始时,播放了有关生态环境保护的专题片。随后,何立峰、姜大明、陈吉宁、陈政高、陈雷同志先后发言,他们结合本部门工作实际谈了对推进生态文明建设、推动绿色发展、加强环境保护等方面的体会和意见。新华社北京5月27日电 中共中央政治局5月26日下午就推动形成绿色发展方式和生活方式进行第四十一次集体学习。中共中央总书记习近平在主持学习时强调,推动形成绿色发展方式和生活方式是贯彻新发展理念的必然要求,必须把生态文明建设摆在全局工作的突出地位,坚持节约资源和保护环境的基本国策,坚持节约优先、保护优先、自然恢复为主的方针,形成节约资源和保护环境的空间格局、产业结构、生产方式、生活方式,努力实现经济社会发展和生态环境保护协同共进,为人民群众创造良好生产生活环境。
13 | 学习开始时,播放了有关生态环境保护的专题片。随后,何立峰、姜大明、陈吉宁、陈政高、陈雷同志先后发言,他们结合本部门工作实际谈了对推进生态文明建设、推动绿色发展、加强环境保护等方面的体会和意见。新华社北京5月27日电 中共中央政治局5月26日下午就推动形成绿色发展方式和生活方式进行第四十一次集体学习。中共中央总书记习近平在主持学习时强调,推动形成绿色发展方式和生活方式是贯彻新发展理念的必然要求,必须把生态文明建设摆在全局工作的突出地位,坚持节约资源和保护环境的基本国策,坚持节约优先、保护优先、自然恢复为主的方针,形成节约资源和保护环境的空间格局、产业结构、生产方式、生活方式,努力实现经济社会发展和生态环境保护协同共进,为人民群众创造良好生产生活环境。
14 | 学习开始时,播放了有关生态环境保护的专题片。随后,何立峰、姜大明、陈吉宁、陈政高、陈雷同志先后发言,他们结合本部门工作实际谈了对推进生态文明建设、推动绿色发展、加强环境保护等方面的体会和意见。
15 |
16 | footer area
17 | other area
18 |
19 | );
20 | }
21 | }
22 |
23 | export default Demo;
24 |
--------------------------------------------------------------------------------
/src/components/remtopx/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 |
4 | export default class RemToPx extends React.Component{
5 | static propTypes = {
6 | width: PropTypes.number,
7 | height: PropTypes.number,
8 | even: PropTypes.bool,
9 | component: PropTypes.string
10 | }
11 | static defaultProps = {
12 | component: 'div',
13 | even: false
14 | }
15 | constructor (props) {
16 | super(props)
17 | this.state = {
18 | style: {}
19 | }
20 | this.handleResize = this.handleResize.bind(this)
21 | }
22 | render () {
23 | const { style, width, height, even, component, children, ...others} = this.props
24 | let Component = component
25 | return (
26 |
27 | {children}
28 |
29 | )
30 | }
31 | componentDidMount () {
32 | this.handleResize()
33 | window.addEventListener('resize', this.handleResize, false)
34 | }
35 | componentWillUnmount () {
36 | window.removeEventListener('resize', this.handleResize)
37 | }
38 | handleResize () {
39 | this.setState({
40 | style: this.getStyle()
41 | })
42 | }
43 | getStyle () {
44 | let fontSize = document.documentElement.style.fontSize
45 | let width = ''
46 | let height = ''
47 | if (fontSize) {
48 | fontSize = parseInt(fontSize, 10)
49 | if (this.props.width) {
50 | width = Math.round(fontSize * this.props.width)
51 | if (this.props.even && width % 2) {
52 | width++
53 | }
54 | }
55 | if (this.props.height) {
56 | height = Math.round(fontSize * this.props.height)
57 | if (this.props.even && height % 2) {
58 | height++
59 | }
60 | }
61 | }
62 | return {
63 | width: `${width}px`,
64 | height: `${height}px`
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/views/Preview.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Body, Nav, Preview, Img } from '@/components'
3 |
4 | class Demo extends React.Component {
5 | state = {
6 | images: [
7 | {
8 | src: 'http://assets.bittyos.com/images/swiper/01.jpg'
9 | },
10 | {
11 | src: 'http://assets.bittyos.com/images/swiper/02.jpg'
12 | },
13 | {
14 | src: 'http://assets.bittyos.com/images/swiper/03.jpg'
15 | },
16 | {
17 | src: 'http://assets.bittyos.com/images/swiper/04.jpg'
18 | },
19 | {
20 | src: 'http://assets.bittyos.com/images/swiper/05.jpg'
21 | }
22 | ]
23 | }
24 | render() {
25 | return (
26 |
27 |
28 |
29 | {this.state.images.map((item,index) => {
30 | return (
31 |
38 | )
39 | })}
40 |
41 |
42 |
43 | );
44 | }
45 | handleLoad (index, e) {
46 | let windowWidth = window.innerWidth
47 | let img = e.target
48 | let natural = {
49 | w: img.naturalWidth,
50 | h: img.naturalHeight
51 | }
52 | let item = {
53 | src: img.src,
54 | w: natural.w > windowWidth ? windowWidth : natural.w,
55 | h: natural.w > windowWidth ? natural.h / natural.w * windowWidth : natural.h
56 | }
57 | let state = {...this.state}
58 | state.images[index] = item
59 | this.setState(state)
60 | }
61 | handleClick (index) {
62 | this.refs.preview.open(index)
63 | }
64 | }
65 |
66 | export default Demo;
67 |
--------------------------------------------------------------------------------
/src/components/actionsheet/Actionsheet.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Popup from '../popup';
3 | import classnames from 'classnames';
4 | import PropTypes from 'prop-types';
5 |
6 | const Actionsheet = props => {
7 | let {children, className, title, cancelText, cancel, type, onAction, onClose, ...others} = props
8 |
9 | let handleClose = () => {
10 | onClose && onClose()
11 | }
12 | let handleClick = value => {
13 | onAction && onAction(value)
14 | handleClose()
15 | }
16 | let direction = type === 'menu' ? 'center' : 'bottom'
17 | let cloneChildren = React.Children.map(children, item => {
18 | if (item) {
19 | return React.cloneElement(item, {
20 | onClick: handleClick.bind(this, item.props.value)
21 | })
22 | }
23 | return item
24 | })
25 | let cls = classnames(["vx-actionsheet", {'vx-actionsheet--menu': type === 'menu'}, {'is-not-title': !title}, className])
26 | return (
27 |
28 |
29 | {title &&
30 | {title}
31 |
32 | }
33 |
34 | {cloneChildren}
35 |
36 | {cancel &&
37 | {cancelText}
38 |
39 | }
40 |
41 |
42 | );
43 | }
44 | Actionsheet.propTypes = {
45 | type: PropTypes.string,
46 | open: PropTypes.bool,
47 | cancel: PropTypes.bool,
48 | cancelText: PropTypes.string,
49 | title: PropTypes.string,
50 | fastClose: PropTypes.bool,
51 | onClose: PropTypes.func,
52 | onClick: PropTypes.func
53 | }
54 | Actionsheet.defaultProps = {
55 | type: 'default',
56 | open: false,
57 | cancel: false,
58 | cancelText: '取消',
59 | title: '',
60 | fastClose: true
61 | }
62 |
63 | export default Actionsheet;
64 |
--------------------------------------------------------------------------------
/src/views/Sticky.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Body, Nav, Tab, TabItem, Img, Sticky} from '@/components'
3 |
4 | class Demo extends React.Component {
5 | state = {
6 | active: 'recommed',
7 | items: [
8 | {name: 'recommed', label: '推荐'},
9 | {name: 'it', label: '科技'},
10 | {name: 'active', label: '活动'},
11 | {name: 'find', label: '发现'}
12 | ]
13 | }
14 | render() {
15 | let items = this.state.items.map((item, index) => {
16 | return {item.label}
17 | })
18 | return (
19 |
20 |
21 |
22 |
23 |
24 |
25 | {items}
26 |
27 |
28 |
29 | 新华社北京5月27日电 中共中央政治局5月26日下午就推动形成绿色发展方式和生活方式进行第四十一次集体学习。中共中央总书记习近平在主持学习时强调,推动形成绿色发展方式和生活方式是贯彻新发展理念的必然要求,必须把生态文明建设摆在全局工作的突出地位,坚持节约资源和保护环境的基本国策,坚持节约优先、保护优先、自然恢复为主的方针,形成节约资源和保护环境的空间格局、产业结构、生产方式、生活方式,努力实现经济社会发展和生态环境保护协同共进,为人民群众创造良好生产生活环境。
30 |
31 | 学习开始时,播放了有关生态环境保护的专题片。随后,何立峰、姜大明、陈吉宁、陈政高、陈雷同志先后发言,他们结合本部门工作实际谈了对推进生态文明建设、推动绿色发展、加强环境保护等方面的体会和意见。
32 | 新华社北京5月27日电 中共中央政治局5月26日下午就推动形成绿色发展方式和生活方式进行第四十一次集体学习。中共中央总书记习近平在主持学习时强调,推动形成绿色发展方式和生活方式是贯彻新发展理念的必然要求,必须把生态文明建设摆在全局工作的突出地位,坚持节约资源和保护环境的基本国策,坚持节约优先、保护优先、自然恢复为主的方针,形成节约资源和保护环境的空间格局、产业结构、生产方式、生活方式,努力实现经济社会发展和生态环境保护协同共进,为人民群众创造良好生产生活环境。
33 |
34 | 学习开始时,播放了有关生态环境保护的专题片。随后,何立峰、姜大明、陈吉宁、陈政高、陈雷同志先后发言,他们结合本部门工作实际谈了对推进生态文明建设、推动绿色发展、加强环境保护等方面的体会和意见。
35 |
36 |
37 |
38 | );
39 | }
40 | handleChange (value) {
41 | this.setState({
42 | active: value
43 | })
44 | }
45 | }
46 |
47 | export default Demo;
48 |
--------------------------------------------------------------------------------
/src/views/Img.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Nav, Body, Img} from '@/components'
3 |
4 | class Demo extends React.Component {
5 | state = {
6 | value: 0
7 | }
8 | render() {
9 | return (
10 |
11 |
12 |
13 |
14 | 新华社北京5月27日电 中共中央政治局5月26日下午就推动形成绿色发展方式和生活方式进行第四十一次集体学习。中共中央总书记习近平在主持学习时强调,推动形成绿色发展方式和生活方式是贯彻新发展理念的必然要求,必须把生态文明建设摆在全局工作的突出地位,坚持节约资源和保护环境的基本国策,坚持节约优先、保护优先、自然恢复为主的方针,形成节约资源和保护环境的空间格局、产业结构、生产方式、生活方式,努力实现经济社会发展和生态环境保护协同共进,为人民群众创造良好生产生活环境。
15 | 学习开始时,播放了有关生态环境保护的专题片。随后,何立峰、姜大明、陈吉宁、陈政高、陈雷同志先后发言,他们结合本部门工作实际谈了对推进生态文明建设、推动绿色发展、加强环境保护等方面的体会和意见。
16 |
17 | 新华社北京5月27日电 中共中央政治局5月26日下午就推动形成绿色发展方式和生活方式进行第四十一次集体学习。中共中央总书记习近平在主持学习时强调,推动形成绿色发展方式和生活方式是贯彻新发展理念的必然要求,必须把生态文明建设摆在全局工作的突出地位,坚持节约资源和保护环境的基本国策,坚持节约优先、保护优先、自然恢复为主的方针,形成节约资源和保护环境的空间格局、产业结构、生产方式、生活方式,努力实现经济社会发展和生态环境保护协同共进,为人民群众创造良好生产生活环境。
18 | 学习开始时,播放了有关生态环境保护的专题片。随后,何立峰、姜大明、陈吉宁、陈政高、陈雷同志先后发言,他们结合本部门工作实际谈了对推进生态文明建设、推动绿色发展、加强环境保护等方面的体会和意见。
19 |
20 | 新华社北京5月27日电 中共中央政治局5月26日下午就推动形成绿色发展方式和生活方式进行第四十一次集体学习。中共中央总书记习近平在主持学习时强调,推动形成绿色发展方式和生活方式是贯彻新发展理念的必然要求,必须把生态文明建设摆在全局工作的突出地位,坚持节约资源和保护环境的基本国策,坚持节约优先、保护优先、自然恢复为主的方针,形成节约资源和保护环境的空间格局、产业结构、生产方式、生活方式,努力实现经济社会发展和生态环境保护协同共进,为人民群众创造良好生产生活环境。
21 | 学习开始时,播放了有关生态环境保护的专题片。随后,何立峰、姜大明、陈吉宁、陈政高、陈雷同志先后发言,他们结合本部门工作实际谈了对推进生态文明建设、推动绿色发展、加强环境保护等方面的体会和意见。
22 |
23 |
24 |
25 | );
26 | }
27 | handleChange (value) {
28 | this.setState({
29 | value
30 | })
31 | }
32 | }
33 |
34 | export default Demo;
35 |
--------------------------------------------------------------------------------
/src/components/checkbox/Checkbox.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import classnames from 'classnames';
3 | import PropTypes from 'prop-types';
4 |
5 | const Checkbox = props => {
6 | let {children, className, style, $parent, inline, iconStyle, onChange, ...others} = props
7 | let type = $parent && $parent.max === 1 ? 'radio' : 'checkbox'
8 | let checked = others.checked
9 | let disabled = others.disabled
10 | if ($parent) {
11 | if ($parent.value instanceof Array) {
12 | checked = $parent.value.indexOf(others.value) > -1
13 | } else {
14 | checked = $parent.value === others.value
15 | }
16 | if ($parent.value.length >= $parent.max && $parent.max > 1) {
17 | disabled = $parent.value.indexOf(others.value) === -1
18 | }
19 | if ($parent.inline !== undefined) {
20 | inline = $parent.inline
21 | }
22 | if ($parent.iconStyle !== undefined) {
23 | iconStyle = $parent.iconStyle
24 | }
25 | }
26 | let handleChange = (e) => {
27 | if ($parent) {
28 | $parent.onChange && $parent.onChange(e)
29 | } else {
30 | onChange && onChange(e)
31 | }
32 | }
33 | return (
34 |
43 | );
44 | }
45 | Checkbox.propTypes = {
46 | disabled: PropTypes.bool,
47 | checked: PropTypes.bool,
48 | inline: PropTypes.bool,
49 | iconStyle: PropTypes.string,
50 | onChange: PropTypes.func
51 | }
52 | Checkbox.defaultProps = {
53 | disabled: false,
54 | checked: false,
55 | inline: false
56 | }
57 |
58 | export default Checkbox;
59 |
--------------------------------------------------------------------------------
/components.json:
--------------------------------------------------------------------------------
1 | {
2 | "index": ["./src/components"],
3 | "layout": ["./src/components/layout"],
4 | "actionsheet": ["./src/components/actionsheet"],
5 | "accordion": ["./src/components/accordion"],
6 | "swiper": ["./src/components/swiper"],
7 | "marquee": ["./src/components/marquee"],
8 | "tab": ["./src/components/tab"],
9 | "tabbar": ["./src/components/tabbar"],
10 | "sidebar": ["./src/components/sidebar"],
11 | "flexbox": ["./src/components/flexbox"],
12 | "button-tab": ["./src/components/button-tab"],
13 | "button": ["./src/components/button"],
14 | "input": ["./src/components/input"],
15 | "input-number": ["./src/components/input-number"],
16 | "password": ["./src/components/password"],
17 | "range": ["./src/components/range"],
18 | "textarea": ["./src/components/textarea"],
19 | "switch": ["./src/components/switch"],
20 | "checkbox": ["./src/components/checkbox"],
21 | "radio": ["./src/components/radio"],
22 | "select": ["./src/components/select"],
23 | "checker": ["./src/components/checker"],
24 | "divider": ["./src/components/divider"],
25 | "group": ["./src/components/group"],
26 | "cell": ["./src/components/cell"],
27 | "confirm": ["./src/components/confirm"],
28 | "prompt": ["./src/components/prompt"],
29 | "alert": ["./src/components/alert"],
30 | "popup": ["./src/components/popup"],
31 | "popup-picker": ["./src/components/popup-picker"],
32 | "toast": ["./src/components/toast"],
33 | "img": ["./src/components/img"],
34 | "index-list": ["./src/components/index-list"],
35 | "list-view": ["./src/components/list-view"],
36 | "ripple": ["./src/components/ripple"],
37 | "nav": ["./src/components/nav"],
38 | "preview": ["./src/components/preview"],
39 | "spinner": ["./src/components/spinner"],
40 | "picker": ["./src/components/picker"],
41 | "badge": ["./src/components/badge"],
42 | "swipeout": ["./src/components/swipeout"],
43 | "rater": ["./src/components/rater"],
44 | "popover": ["./src/components/popover"],
45 | "sticky": ["./src/components/sticky"],
46 | "qrcode": ["./src/components/qrcode"]
47 | }
--------------------------------------------------------------------------------
/src/views/Checker.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Body, Nav, Group, Checker, CheckerGroup } from '@/components'
3 |
4 | class Demo extends React.Component {
5 | state = {
6 | checked: false,
7 | value: ['1', '2'],
8 | options: [
9 | {
10 | value: '1',
11 | label: '篮球'
12 | },
13 | {
14 | value: '2',
15 | label: '羽毛球'
16 | },
17 | {
18 | value: '3',
19 | label: '乒乓球',
20 | disabled: true
21 | },
22 | {
23 | value: '4',
24 | label: '高尔夫'
25 | }
26 | ]
27 | }
28 | render() {
29 | let options = this.state.options.map((item, index) => {
30 | return {item.label}
31 | })
32 | return (
33 |
34 |
35 |
36 |
37 |
38 | Checker
39 |
40 |
41 |
42 |
43 |
44 | {options}
45 |
46 |
47 |
48 |
49 |
50 |
51 | {options}
52 |
53 |
54 |
55 |
56 |
57 | );
58 | }
59 | handleChange (e) {
60 | this.setState({
61 | checked: e.target.checked
62 | })
63 | }
64 | handleGroupChange (value) {
65 | this.setState({
66 | value: value
67 | })
68 | }
69 | }
70 |
71 | export default Demo;
72 |
--------------------------------------------------------------------------------
/src/views/Swipeout.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Nav, Body, Swipeout, Flexbox, FlexboxItem, Img } from '@/components'
3 | class Demo extends React.Component {
4 | constructor (props) {
5 | super(props)
6 | let list = this.getList()
7 | this.state = {
8 | list
9 | }
10 | }
11 | render() {
12 | let action = [
13 | ,
14 | ,
15 |
16 | ]
17 | return (
18 |
19 |
20 |
21 | {this.state.list.map((item,index) => {
22 | return (
23 |
24 |
25 |
26 |
27 | {item.name}(按我向左滑动)
28 | {item.date}
29 |
30 |
31 |
32 | )
33 | })}
34 |
35 |
36 | );
37 | }
38 | getList () {
39 | let result = []
40 | for (let i = 0; i < 30; i++) {
41 | result.push({
42 | src: '/images/github.png',
43 | name: `item-${Date.now()}`,
44 | date: new Date().toLocaleString()
45 | })
46 | }
47 | return result
48 | }
49 | handleCloseSwipeout () {
50 | console.log('handleCloseSwipeout')
51 | }
52 | handleOpenSwipeout () {
53 | console.log('handleOpenSwipeout')
54 | }
55 | handleAction (e) {
56 | console.log('点击了' + e.target.innerHTML)
57 | }
58 | }
59 |
60 | export default Demo;
61 |
--------------------------------------------------------------------------------
/src/views/Confirm.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Nav, Body, Confirm, Switch, Cell, Group} from '@/components'
3 |
4 | class Demo extends React.Component {
5 | state = {
6 | open: false,
7 | open2: false
8 | }
9 | render() {
10 | return (
11 |
12 |
13 |
14 |
15 |
16 |
17 | |
18 |
19 |
20 | |
21 |
22 | 点击我打开
23 | |
24 |
25 |
26 |
27 | 确认删除我么
28 |
29 |
30 |
31 | 长内容长内容长内容长内容长内容长内容长长内容长内容长内容长内容长内容长
32 | 内容长内容长内容长内容长内容长内容长内容长内容长内容长内容内容长内容长内
33 | 容长内容长内容长内容长内容长内容长内容
34 | 长内容长内容长内容长内容长内容长内容长长内容长内容长内容长内容长内容长
35 | 内容长内容长内容长内容长内容长内容长内容长内容长内容长内容内容长内容长内
36 | 容长内容长内容长内容长内容长内容长内容
37 | 长内容长内容长内容长内容长内容长内容长长内容长内容长内容长内容长内容长
38 | 内容长内容长内容长内容长内容长内容长内容长内容长内容长内容内容长内容长内
39 | 容长内容长内容长内容长内容长内容长内容
40 |
41 |
42 |
43 | );
44 | }
45 | handleChange (value) {
46 | this.setState({
47 | open: value
48 | })
49 | }
50 | handleClose () {
51 | this.handleChange(false)
52 | }
53 | handleConfirm () {
54 | this.handleChange(false)
55 | }
56 | handleChange2 (value) {
57 | this.setState({
58 | open2: value
59 | })
60 | }
61 | handleClose2 () {
62 | this.handleChange2(false)
63 | }
64 | handleConfirm2 () {
65 | this.handleChange2(false)
66 | }
67 | handleClick () {
68 | Confirm.open({
69 | message: 'Confirm'
70 | })
71 | }
72 | }
73 |
74 | export default Demo;
75 |
--------------------------------------------------------------------------------
/src/views/Prompt.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Nav, Body, Prompt, Switch, Cell, Group} from '@/components'
3 |
4 | class Demo extends React.Component {
5 | state = {
6 | open1: false,
7 | open2: false,
8 | value1: '',
9 | value2: ''
10 | }
11 | render() {
12 | return (
13 |
14 |
15 |
16 |
17 |
18 |
19 | |
20 |
21 |
22 | |
23 |
24 | 点击我打开
25 | |
26 |
27 |
28 |
34 |
40 |
41 | );
42 | }
43 | handleChange1 (value = false) {
44 | this.setState({
45 | open1: value
46 | })
47 | }
48 | handleChange2 (value = false) {
49 | this.setState({
50 | open2: value
51 | })
52 | }
53 | handleConfirm1 (value) {
54 | this.handleChange1(false)
55 | this.setState({
56 | value1: value
57 | })
58 | }
59 | handleConfirm2 (value) {
60 | this.handleChange2(false)
61 | this.setState({
62 | value2: value
63 | })
64 | }
65 | handleClick () {
66 | Prompt.open({
67 | title: '用户名称',
68 | inputProps: {value: '', placeholder: '请输入用户名'},
69 | onConfirm (value) {
70 | console.log(value)
71 | }
72 | })
73 | }
74 | }
75 |
76 | export default Demo;
77 |
--------------------------------------------------------------------------------
/src/components/popover/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import Popup from '../popup'
4 | import PropTypes from 'prop-types'
5 | import classnames from 'classnames'
6 |
7 | let Popover = props => {
8 | let {children, className, overlayOpacity, popoverClass, trigger, open,...others} = props
9 | let vnode = null
10 | let handleClose = () => {
11 | let node = ReactDOM.findDOMNode(vnode).parentNode
12 | node.parentNode && node.parentNode.removeChild(node)
13 | }
14 | let handleClick = (e) => {
15 | vnode = ReactDOM.render(
16 |
25 | {children}
26 | }>
27 | ,
28 | document.createElement('div')
29 | )
30 | let target = e.currentTarget
31 | let node = ReactDOM.findDOMNode(vnode).querySelector('.vx-popover--content')
32 | let rect = target.getBoundingClientRect()
33 | let left = rect.left + 'px'
34 | let isRight = false
35 | let isBottom = false
36 | if (rect.left > window.innerWidth / 2) {
37 | isRight = true
38 | left = rect.right - node.offsetWidth + 'px'
39 | }
40 | let top = rect.top + rect.height + 'px'
41 | if (rect.top > window.innerHeight / 2) {
42 | isBottom = true
43 | top = rect.bottom - node.offsetHeight - rect.height - 24 + 'px'
44 | }
45 | requestAnimationFrame(() => {
46 | node.style.top = top
47 | node.style.left = left
48 | node.style.visibility = ''
49 | isRight && node.classList.add('vx-popover--content-right')
50 | isBottom && node.classList.add('vx-popover--content-bottom')
51 | })
52 | }
53 | return (
54 |
55 | {trigger}
56 |
57 | )
58 | }
59 |
60 | Popover.propTypes = {
61 | open: PropTypes.bool,
62 | overlayOpacity: PropTypes.number,
63 | popoverClass: PropTypes.oneOfType([PropTypes.string, PropTypes.array])
64 | }
65 |
66 | export default Popover;
67 |
--------------------------------------------------------------------------------
/src/components/swiper/Swiper.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import classnames from 'classnames';
3 | import PropTypes from 'prop-types';
4 |
5 | class Swiper extends React.Component {
6 | static propTypes = {
7 | active: PropTypes.number,
8 | options: PropTypes.object,
9 | pagination: PropTypes.bool,
10 | prev: PropTypes.bool,
11 | next: PropTypes.bool,
12 | scrollbar: PropTypes.bool,
13 | autoplay: PropTypes.number,
14 | onChange: PropTypes.func
15 | }
16 | static defaultProps = {
17 | active: 0,
18 | autoplay: 2000,
19 | pagination: true
20 | }
21 | render () {
22 | let {children, className, onChange, pagination, prev, next, scrollbar, autoplay, ...others} = this.props
23 | return (
24 |
25 |
26 | {children}
27 |
28 | {pagination &&
}
29 | {prev &&
}
30 | {next &&
}
31 | {scrollbar &&
}
32 |
33 | );
34 | }
35 | componentWillReceiveProps (nextProps) {
36 | if (this.props.active !== nextProps.active) {
37 | this.$$swiper.slideTo(nextProps.active)
38 | }
39 | }
40 | componentDidMount () {
41 | let {active, pagination, prev, next, scrollbar, onChange} = this.props
42 | import('swiper/dist/js/swiper.min.js').then(res => {
43 | let Swiper = res.default
44 | import('swiper/dist/css/swiper.min.css')
45 | let options = Object.assign({
46 | initialSlide: active,
47 | autoplay: this.props.autoplay,
48 | autoplayDisableOnInteraction: false,
49 | onSlideChangeStart: (swiper) => {
50 | onChange && onChange(swiper.activeIndex)
51 | }
52 | }, this.props.options)
53 | if (pagination) {
54 | options.pagination = '.swiper-pagination'
55 | }
56 | if (prev) {
57 | options.prev = '.swiper-button-prev'
58 | }
59 | if (next) {
60 | options.nextButton = '.swiper-button-prev'
61 | }
62 | if (scrollbar) {
63 | options.scrollbar = '.swiper-scrollbar'
64 | }
65 | this.$$swiper = new Swiper(this.refs.$el, options)
66 | })
67 | }
68 | }
69 |
70 | export default Swiper;
71 |
--------------------------------------------------------------------------------
/src/views/Checkbox.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Body, Nav, Group, Checkbox, CheckboxGroup } from '@/components'
3 |
4 | class Demo extends React.Component {
5 | state = {
6 | checked: false,
7 | value: ['1', '2'],
8 | options: [
9 | {
10 | value: '1',
11 | label: '篮球'
12 | },
13 | {
14 | value: '2',
15 | label: '羽毛球'
16 | },
17 | {
18 | value: '3',
19 | label: '乒乓球',
20 | disabled: true
21 | },
22 | {
23 | value: '4',
24 | label: '高尔夫'
25 | }
26 | ]
27 | }
28 | render() {
29 | let options = this.state.options.map((item, index) => {
30 | return {item.label}
31 | })
32 | return (
33 |
34 |
35 |
36 |
37 | checkbox
38 |
39 |
40 |
41 | {options}
42 |
43 |
44 |
45 |
46 | {options}
47 |
48 |
49 |
50 |
51 | {options}
52 |
53 |
54 |
55 |
56 | {options}
57 |
58 |
59 |
60 |
61 | );
62 | }
63 | handleChange (e) {
64 | this.setState({
65 | checked: e.target.checked
66 | })
67 | }
68 | handleGroupChange (value) {
69 | this.setState({
70 | value: value
71 | })
72 | }
73 | }
74 |
75 | export default Demo;
76 |
--------------------------------------------------------------------------------
/src/components/input/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import classnames from 'classnames'
3 | import PropTypes from 'prop-types'
4 | import {Flexbox, FlexboxItem} from '../flexbox'
5 | import Arrow from '../arrow'
6 |
7 | export default class Input extends React.Component {
8 | static propTypes = {
9 | clear: PropTypes.bool,
10 | border: PropTypes.bool,
11 | arrow: PropTypes.bool,
12 | onChange: PropTypes.func,
13 | onInput: PropTypes.func
14 | }
15 | static defaultProps = {
16 | border: true,
17 | clear: true,
18 | arrow: false,
19 | arrowProps: {}
20 | }
21 | constructor (props) {
22 | super(props)
23 | this.state = {
24 | isFocus: false
25 | }
26 | this.handleFocus = this.handleFocus.bind(this)
27 | this.handleBlur = this.handleBlur.bind(this)
28 | this.handleChange = this.handleChange.bind(this)
29 | this.handleInput = this.handleInput.bind(this)
30 | }
31 | render () {
32 | let {children, className, style, prepend, append, arrow, arrowProps, clear, border, ...others} = this.props
33 | let getClassName = () => {
34 | return classnames([
35 | 'vx-input--wrapper',
36 | {
37 | 'is-focus': this.state.isFocus,
38 | 'is-clear': !!others.value && clear,
39 | 'vx-input--prepend': prepend,
40 | 'vx-input--append': append,
41 | 'is-disabled': others.disabled,
42 | 'is-border': border
43 | },
44 | className
45 | ])
46 | }
47 | return (
48 |
67 | )
68 | }
69 | handleChange (e) {
70 | this.props.onChange && this.props.onChange (e.target.value)
71 | }
72 | handleInput (e) {
73 | this.props.onInput && this.props.onInput (e.target.value)
74 | }
75 | handleFocus () {
76 | this.setState({
77 | isFocus: true
78 | })
79 | }
80 | handleBlur () {
81 | this.setState({
82 | isFocus: false
83 | })
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/logo.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/views/Actionsheet.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Body, Actionsheet, ActionsheetItem, Switch, Nav, Cell, Group} from '@/components'
3 |
4 | class Demo extends React.Component {
5 | state = {
6 | open1: false,
7 | open2: false,
8 | open3: false,
9 | options: [
10 | {
11 | value: '1',
12 | label: '编辑'
13 | },
14 | {
15 | value: '2',
16 | label: '收藏'
17 | },
18 | {
19 | value: '3',
20 | label: '分享'
21 | },
22 | {
23 | value: '4',
24 | label: '删除'
25 | }
26 | ]
27 | }
28 | render() {
29 | let options = this.state.options.map((item, index) => {
30 | return {item.label}
31 | })
32 | return (
33 |
34 |
35 |
36 |
37 |
38 |
39 | |
40 |
41 |
42 | |
43 |
44 |
45 | |
46 |
47 | 点击我打开
48 | |
49 |
50 |
51 |
52 | {options}
53 |
54 |
55 | {options}
56 |
57 |
58 | {options}
59 |
60 |
61 | );
62 | }
63 | handleChange (key, value) {
64 | let state = {
65 | ...this.state
66 | }
67 | state['open' + key] = value
68 | this.setState(state)
69 | }
70 | handleAction (value) {
71 | console.log('点击了' + value)
72 | }
73 | handleClose (key) {
74 | this.handleChange(key, false)
75 | }
76 | handleClick () {
77 | Actionsheet.open({
78 | title: '标题文字',
79 | options: this.state.options,
80 | onAction (value) {
81 | console.log(value)
82 | }
83 | })
84 | }
85 | }
86 |
87 | export default Demo;
88 |
--------------------------------------------------------------------------------
/src/views/ListView.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Nav, Body, ListView, Flexbox, FlexboxItem, Img, Divider } from '@/components'
3 | class Demo extends React.Component {
4 | constructor (props) {
5 | super(props)
6 | this.state = {
7 | list: [],
8 | loading: false,
9 | end: false // 是否还没有更多
10 | }
11 | }
12 | componentDidMount () {
13 | setTimeout(() => {
14 | this.setState({
15 | list: this.getList()
16 | })
17 | }, 2000)
18 | }
19 | render() {
20 | return (
21 |
22 |
23 |
24 |
30 | {this.state.list.map((item,index) => {
31 | return (
32 |
33 |
34 |
35 |
36 | {item.name}
37 | {item.date}
38 |
39 |
40 |
41 |
42 | )
43 | })}
44 |
45 |
46 |
47 | );
48 | }
49 | getList () {
50 | let result = []
51 | for (let i = 0; i < 30; i++) {
52 | result.push({
53 | src: '/images/github.png',
54 | name: `item-${Date.now()}`,
55 | date: new Date().toLocaleString()
56 | })
57 | }
58 | return result
59 | }
60 | handlePullup (e) {
61 | this.setState({
62 | loading: true
63 | }, () => {
64 | setTimeout(() => { // 模拟ajax请求
65 | let list = [...this.state.list]
66 | list = list.concat(this.getList())
67 | this.setState({
68 | loading: false,
69 | list: list,
70 | end: list.length >= 60
71 | })
72 | }, 1000)
73 | })
74 | }
75 | handlePulldown (e) {
76 | this.setState({
77 | loading: true
78 | }, () => {
79 | setTimeout(() => { // 模拟ajax请求
80 | let list= this.getList()
81 | list = list.concat(this.state.list)
82 | this.setState({
83 | loading: false,
84 | list: list
85 | })
86 | }, 1000)
87 | })
88 | }
89 | }
90 |
91 | export default Demo;
92 |
--------------------------------------------------------------------------------
/src/components/textarea/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import classnames from 'classnames'
3 | import PropTypes from 'prop-types'
4 |
5 | export default class Textarea extends React.Component {
6 | static propTypes = {
7 | onChange: PropTypes.func,
8 | enterNumber: PropTypes.bool,
9 | }
10 | defaultProps = {
11 | enterNumber: false
12 | }
13 | constructor (props) {
14 | super(props)
15 | this.state = {
16 | isFocus: false
17 | }
18 | this.handleFocus = this.handleFocus.bind(this)
19 | this.handleBlur = this.handleBlur.bind(this)
20 | this.handleChange = this.handleChange.bind(this)
21 | this.handleInput = this.handleInput.bind(this)
22 | }
23 | render () {
24 | let {children, className, style, enterNumber, ...others} = this.props
25 | return (
26 |
40 | )
41 | }
42 | componentDidMount () {
43 | this.$$textarea = this.refs.$el.querySelector('textarea')
44 | this.$$inner = this.refs.$el.querySelector('.vx-textarea--inner')
45 | this.$$shadow = this.refs.$el.querySelector('.vx-textarea--shadow')
46 | this.renderAutoHeight(this.$$textarea.value)
47 | this.$handleResize = this.handleResize.bind(this)
48 | window.addEventListener('resize', this.$handleResize, false)
49 | }
50 | componentWillUnmount () {
51 | window.removeEventListener('resize', this.$handleResize)
52 | }
53 | handleResize () {
54 | this.renderAutoHeight(this.$$textarea.value)
55 | }
56 | renderAutoHeight (value) {
57 | requestAnimationFrame(() => {
58 | this.$$shadow.innerHTML = value.replace(/(\r|\n)$/, '
s').replace(/(\r|\n)/g, '
')
59 | this.$$inner.style.height = this.$$shadow.offsetHeight + 'px'
60 | })
61 | }
62 | handleChange (e) {
63 | this.props.onChange && this.props.onChange (e.target.value)
64 | }
65 | handleInput (e) {
66 | this.renderAutoHeight(e.target.value)
67 | this.props.onInput && this.props.onInput (e.target.value)
68 | }
69 | handleFocus () {
70 | this.setState({
71 | isFocus: true
72 | })
73 | }
74 | handleBlur () {
75 | this.setState({
76 | isFocus: false
77 | })
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/components/input-number/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import classnames from 'classnames'
3 | import PropTypes from 'prop-types'
4 |
5 | export default class InputNumber extends React.Component {
6 | static propTypes = {
7 | step: PropTypes.number,
8 | buttonStep: PropTypes.number,
9 | onChange: PropTypes.func
10 | }
11 | static defaultProps = {
12 | step: 1,
13 | buttonStep: 1
14 | }
15 | constructor (props) {
16 | super(props)
17 | this.handleChange = this.handleChange.bind(this)
18 | this.handleChangeAdd = this.handleChangeAdd.bind(this, this.props.buttonStep)
19 | this.handleChangeReduce = this.handleChangeReduce.bind(this, -this.props.buttonStep)
20 | }
21 | render () {
22 | let {children, className, style, buttonStep, onChange, value, ...others} = this.props
23 | return (
24 |
25 |
26 |
31 |
32 |
33 | )
34 | }
35 | componentWillReceiveProps (nextProps) {
36 | if (this.props.value !== nextProps.value) {
37 | let node = this.refs.$el.querySelector('input')
38 | node.value = nextProps.value
39 | }
40 | }
41 | handleChangeAdd (step) {
42 | this.handleChange(this.myValue() + step)
43 | }
44 | handleChangeReduce (step) {
45 | this.handleChange(this.myValue() + step)
46 | }
47 | handleChange (e) {
48 | let value = Number(e.target ? e.target.value : e)
49 | let node = this.refs.$el.querySelector('input')
50 | let {min, max} = this.props
51 | if (isNaN(value)) {
52 | node && (node.value = this.props.value)
53 | } else {
54 | if (typeof max === 'number' && value > max) {
55 | value = max
56 | }
57 | if (typeof min === 'number' && value < min) {
58 | value = min
59 | }
60 | value = Math.round(value * this.stepRate()) / this.stepRate()
61 | node && (node.value = value)
62 | console.log('value', value)
63 | this.props.onChange && this.props.onChange (value)
64 | }
65 | }
66 | myValue () {
67 | let {value, min, max} = this.props
68 | if (value < min) {
69 | return Math.round(min * this.stepRate()) / this.stepRate()
70 | }
71 | if (value > max) {
72 | return Math.round(max * this.stepRate()) / this.stepRate()
73 | }
74 | return Math.round(value * this.stepRate()) / this.stepRate()
75 | }
76 | stepRate () {
77 | return 1 / this.props.step
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/components/accordion/AccordionItem.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import classnames from 'classnames';
4 | import Arrow from '../arrow'
5 | import Transition from 'react-transition-group/Transition'
6 |
7 | class AccordionItem extends React.Component {
8 | static propTypes = {
9 | open: PropTypes.bool
10 | }
11 | static defaultProps = {
12 | open: false
13 | }
14 | constructor (props) {
15 | super(props)
16 | this.state = {
17 | open: this.props.open
18 | }
19 | this.handleOpen = this.handleOpen.bind(this)
20 | }
21 | render () {
22 | let {children, className, title, open, value, toClose, toOpen, ...others} = this.props
23 | const transitionClass = {
24 | entering: 'accordion-slide-enter',
25 | entered: 'accordion-slide-enter-active',
26 | exiting: 'accordion-slide-leave-active',
27 | exited: 'accordion-slide-leave'
28 | }
29 | return (
30 | -1}, className])} {...others}>
31 |
35 |
-1} onEntering={this.handleEnter}>
36 | {state => {
37 | return (
38 |
41 | )
42 | }}
43 |
44 |
45 | );
46 | }
47 | componentWillMount () {
48 | this.name = Math.random().toString(36).substr(2)
49 | this.props.open && this.props.toOpen(this.name)
50 | }
51 | componentDidMount () {
52 | this.handleResize()
53 | window.addEventListener('resize', this.$handleResize, false)
54 | }
55 | componentWillUnmount () {
56 | window.removeEventListener('resize', this.$handleResize)
57 | }
58 | componentWillReceiveProps (nextProps) {
59 | if (this.props.open !== nextProps.open) {
60 | if (nextProps.open) {
61 | this.props.toOpen(this.name)
62 | } else {
63 | this.props.toClose(this.name)
64 | }
65 | }
66 | }
67 | handleResize () {
68 | if (this.props.value.indexOf(this.name) > -1) {
69 | let node = this.refs.$el.querySelector('.vx-accordion--item-bd')
70 | this.handleEnter(node)
71 | }
72 | }
73 | handleEnter (node) {
74 | requestAnimationFrame(() => {
75 | node.style.height = node.children[0].offsetHeight + 'px'
76 | })
77 | }
78 | handleOpen () {
79 | this.props.toOpen(this.name)
80 | }
81 | }
82 |
83 | export default AccordionItem;
84 |
--------------------------------------------------------------------------------
/src/views/Popup.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Body, Nav, Cell, Group, Switch, Popup} from '@/components'
3 |
4 | class Demo extends React.Component {
5 | constructor (props) {
6 | super(props)
7 | this.state = {
8 | open: false,
9 | direction: 'bottom',
10 | fullOpen: false
11 | }
12 | this.handleClose = this.handleClose.bind(this)
13 | }
14 | render() {
15 | return (
16 |
17 |
18 |
19 |
20 |
21 |
22 | |
23 |
24 |
25 | |
26 |
27 |
28 | |
29 |
30 |
31 | |
32 |
33 |
34 | |
35 |
36 |
37 | |
38 |
39 |
40 |
41 |
42 | | } />
43 |
44 |
45 |
46 |
47 | | } />
48 |
49 |
50 |
51 | );
52 | }
53 | handleChange (direction, value) {
54 | this.setState({
55 | open: value,
56 | direction
57 | })
58 | }
59 | handleClose () {
60 | this.setState({
61 | open: false
62 | })
63 | }
64 | handleFullChange (value) {
65 | this.setState({
66 | fullOpen: value
67 | })
68 | }
69 | handleFullClose () {
70 | this.setState({
71 | fullOpen: false
72 | })
73 | }
74 | }
75 |
76 | export default Demo;
77 |
--------------------------------------------------------------------------------
/src/views/Toast.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Layout, Nav, Body, Toast, Switch, Cell, Group} from '@/components'
3 |
4 | class Demo extends React.Component {
5 | state = {
6 | topOpen: false,
7 | centerOpen: false,
8 | loadingOpen: false,
9 | bottomOpen: false,
10 | failOpen: false,
11 | warnOpen: false,
12 | content: '操作成功'
13 | }
14 | render() {
15 | return (
16 |
17 |
18 |
19 |
20 |
21 |
22 | |
23 |
24 |
25 | |
26 |
27 |
28 | |
29 |
30 |
31 | |
32 |
33 |
34 | |
35 |
36 |
37 | |
38 |
39 | 点击我打开
40 | |
41 |
42 |
43 | {this.state.content}
44 | {this.state.content}
45 | 操作失败
46 | 已经操作过了
47 | Loading
48 | {this.state.content}
49 |
50 | );
51 | }
52 | handleChange (key, value) {
53 | let state = {...this.state}
54 | state[key] = value
55 | this.setState(state)
56 | }
57 | handleClose (key) {
58 | let state = {...this.state}
59 | state[key] = false
60 | this.setState(state)
61 | }
62 | handleClick () {
63 | Toast.open({
64 | type: 'loading',
65 | message: 'loading...'
66 | })
67 | }
68 | }
69 |
70 | export default Demo;
71 |
--------------------------------------------------------------------------------
/config/paths.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 | const fs = require('fs');
5 | const url = require('url');
6 |
7 | // Make sure any symlinks in the project folder are resolved:
8 | // https://github.com/facebook/create-react-app/issues/637
9 | const appDirectory = fs.realpathSync(process.cwd());
10 | const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
11 |
12 | const envPublicUrl = process.env.PUBLIC_URL;
13 |
14 | function ensureSlash(inputPath, needsSlash) {
15 | const hasSlash = inputPath.endsWith('/');
16 | if (hasSlash && !needsSlash) {
17 | return inputPath.substr(0, inputPath.length - 1);
18 | } else if (!hasSlash && needsSlash) {
19 | return `${inputPath}/`;
20 | } else {
21 | return inputPath;
22 | }
23 | }
24 |
25 | const getPublicUrl = appPackageJson =>
26 | envPublicUrl || require(appPackageJson).homepage;
27 |
28 | // We use `PUBLIC_URL` environment variable or "homepage" field to infer
29 | // "public path" at which the app is served.
30 | // Webpack needs to know it to put the right