├── .babelrc ├── .commitlintrc.js ├── .eslintrc ├── .gitattributes ├── .gitignore ├── .prettierrc ├── .storybook ├── addons.js ├── config.js ├── theme.js └── webpack.config.js ├── .stylelintrc ├── .travis.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── README.md ├── README.zh-CN.md ├── _config.yml ├── docs ├── 1e59d2330b4c6deb84b340635ed36249.ttf ├── 20fd1704ea223900efa9fd4e869efb08.woff2 ├── 8b43027f47b20503057dfbbaa9401fef.eot ├── c1e38fd9e0e74ba58f7a2b77ef29fdd3.svg ├── f691f37e57f04c152e2315ab7dbad881.woff ├── favicon.ico ├── iframe.html ├── index.html ├── main.77a4d7c4b9965b0de1db.bundle.js ├── main.e00d20381e8fbf86ce25.bundle.js ├── main.e00d20381e8fbf86ce25.bundle.js.map ├── runtime~main.707b56da4e928e093175.bundle.js ├── runtime~main.e00d20381e8fbf86ce25.bundle.js ├── runtime~main.e00d20381e8fbf86ce25.bundle.js.map ├── sb_dll │ ├── storybook_ui-manifest.json │ ├── storybook_ui_dll.LICENCE │ └── storybook_ui_dll.js ├── vendors~main.8a29a3f5b14c7cd4977f.bundle.js ├── vendors~main.e00d20381e8fbf86ce25.bundle.js ├── vendors~main.e00d20381e8fbf86ce25.bundle.js.LICENSE.txt └── vendors~main.e00d20381e8fbf86ce25.bundle.js.map ├── examples ├── accordion │ ├── index.tsx │ └── readme.md ├── actionSheet │ ├── index.tsx │ └── readme.md ├── affix │ ├── index.tsx │ └── readme.md ├── avatar │ ├── index.tsx │ └── readme.md ├── badge │ ├── index.tsx │ └── readme.md ├── button │ ├── index.tsx │ └── readme.md ├── card │ ├── index.tsx │ └── readme.md ├── checkbox │ ├── index.tsx │ └── readme.md ├── divider │ ├── index.tsx │ └── readme.md ├── grid │ ├── index.tsx │ └── readme.md ├── icon │ ├── index.tsx │ └── readme.md ├── imagePicker │ ├── index.tsx │ └── readme.md ├── input │ ├── index.tsx │ └── readme.md ├── introduce │ ├── index.tsx │ └── readme.md ├── listview │ ├── index.tsx │ └── readme.md ├── modal │ ├── index.tsx │ └── readme.md ├── noticeBar │ ├── index.tsx │ └── readme.md ├── pagination │ ├── index.tsx │ └── readme.md ├── picker │ ├── index.tsx │ └── readme.md ├── pickerPanel │ ├── index.tsx │ └── readme.md ├── popover │ ├── index.tsx │ └── readme.md ├── progress │ ├── index.tsx │ └── readme.md ├── radio │ ├── index.tsx │ └── readme.md ├── segmentedControl │ ├── index.tsx │ └── readme.md ├── slider │ ├── index.tsx │ └── readme.md ├── swipeAction │ ├── index.tsx │ └── readme.md ├── switch │ ├── index.tsx │ └── readme.md ├── tabBar │ ├── index.tsx │ └── readme.md ├── tabs │ ├── index.tsx │ └── readme.md ├── tag │ ├── index.tsx │ └── readme.md └── toast │ ├── index.tsx │ └── readme.md ├── externals.d.ts ├── gulpfile.js ├── jest.config.js ├── package-lock.json ├── package.json ├── src └── components │ ├── accordion │ ├── accordion.tsx │ ├── index.tsx │ ├── interface.tsx │ ├── panel.tsx │ └── style │ │ ├── index.scss │ │ └── index.tsx │ ├── action-sheet │ ├── actionSheet.tsx │ ├── index.tsx │ ├── interface.tsx │ └── style │ │ ├── index.scss │ │ └── index.tsx │ ├── affix │ ├── affix.tsx │ ├── index.tsx │ └── interface.tsx │ ├── avatar │ ├── avatar.tsx │ ├── index.tsx │ ├── interface.tsx │ └── style │ │ ├── index.scss │ │ └── index.tsx │ ├── badge │ ├── badge.tsx │ ├── index.tsx │ ├── interface.tsx │ └── style │ │ ├── index.scss │ │ └── index.tsx │ ├── button │ ├── button.tsx │ ├── index.tsx │ ├── interface.tsx │ └── style │ │ ├── index.scss │ │ └── index.tsx │ ├── card │ ├── card.tsx │ ├── index.tsx │ ├── interface.tsx │ └── style │ │ ├── index.scss │ │ └── index.tsx │ ├── checkbox │ ├── checkbox.tsx │ ├── checkboxGroup.tsx │ ├── index.tsx │ ├── interface.tsx │ └── style │ │ ├── index.scss │ │ └── index.tsx │ ├── divider │ ├── divider.tsx │ ├── index.tsx │ ├── interface.tsx │ └── style │ │ ├── index.scss │ │ └── index.tsx │ ├── grid │ ├── col.tsx │ ├── index.tsx │ ├── interface.tsx │ ├── row.tsx │ ├── rowContext.tsx │ └── style │ │ ├── index.scss │ │ └── index.tsx │ ├── icon │ ├── icon.tsx │ ├── iconfont │ │ ├── fonts │ │ │ ├── FontAwesome.otf │ │ │ ├── fontawesome-webfont.eot │ │ │ ├── fontawesome-webfont.svg │ │ │ ├── fontawesome-webfont.ttf │ │ │ ├── fontawesome-webfont.woff │ │ │ └── fontawesome-webfont.woff2 │ │ └── scss │ │ │ ├── _animated.scss │ │ │ ├── _bordered-pulled.scss │ │ │ ├── _core.scss │ │ │ ├── _fixed-width.scss │ │ │ ├── _icons.scss │ │ │ ├── _larger.scss │ │ │ ├── _list.scss │ │ │ ├── _mixins.scss │ │ │ ├── _path.scss │ │ │ ├── _rotated-flipped.scss │ │ │ ├── _screen-reader.scss │ │ │ ├── _stacked.scss │ │ │ ├── _variables.scss │ │ │ └── font-awesome.scss │ ├── index.tsx │ └── style │ │ ├── index.dev.scss │ │ ├── index.scss │ │ └── index.tsx │ ├── image-picker │ ├── image-picker.tsx │ ├── index.tsx │ ├── interface.tsx │ └── style │ │ ├── index.scss │ │ └── index.tsx │ ├── index.tsx │ ├── input │ ├── index.tsx │ ├── input.tsx │ ├── interface.tsx │ └── style │ │ ├── index.scss │ │ └── index.tsx │ ├── list-view │ ├── index.tsx │ ├── interface.tsx │ ├── list-view.tsx │ └── style │ │ ├── index.scss │ │ └── index.tsx │ ├── modal │ ├── index.tsx │ ├── interface.tsx │ ├── modal.tsx │ └── style │ │ ├── index.scss │ │ └── index.tsx │ ├── notice-bar │ ├── index.tsx │ ├── interface.tsx │ ├── marquee.tsx │ ├── notice-bar.tsx │ └── style │ │ ├── index.scss │ │ └── index.tsx │ ├── overlay │ ├── index.tsx │ ├── interface.tsx │ ├── overlay.tsx │ └── overlayWrapper.tsx │ ├── pagination │ ├── index.tsx │ ├── interface.tsx │ ├── pagination.tsx │ └── style │ │ ├── index.scss │ │ └── index.tsx │ ├── picker │ ├── index.tsx │ ├── interface.tsx │ ├── picker-column.tsx │ ├── picker-panel.tsx │ ├── picker.tsx │ └── style │ │ ├── index.scss │ │ └── index.tsx │ ├── popover │ ├── index.tsx │ ├── interface.tsx │ ├── item.tsx │ ├── popover.tsx │ └── style │ │ ├── base.scss │ │ ├── index.scss │ │ └── index.tsx │ ├── progress │ ├── index.tsx │ ├── interface.tsx │ ├── progress.tsx │ └── style │ │ ├── index.scss │ │ └── index.tsx │ ├── radio │ ├── index.tsx │ ├── interface.tsx │ ├── radio.tsx │ └── style │ │ ├── index.scss │ │ └── index.tsx │ ├── segmented-control │ ├── index.tsx │ ├── interface.tsx │ ├── segmented-control.tsx │ └── style │ │ ├── index.scss │ │ └── index.tsx │ ├── slider │ ├── index.tsx │ ├── interface.tsx │ ├── slider.tsx │ └── style │ │ ├── index.scss │ │ └── index.tsx │ ├── spin │ ├── index.tsx │ ├── interface.tsx │ ├── spin.tsx │ └── style │ │ ├── index.scss │ │ └── index.tsx │ ├── step │ ├── index.tsx │ ├── interface.tsx │ ├── step.tsx │ └── style │ │ ├── index.scss │ │ └── index.tsx │ ├── style │ ├── base │ │ ├── base.scss │ │ └── index.scss │ ├── core │ │ ├── core.scss │ │ ├── index.scss │ │ └── index.tsx │ ├── index.scss │ ├── index.tsx │ └── mixin │ │ ├── index.scss │ │ └── size.scss │ ├── swipe-action │ ├── index.tsx │ ├── interface.tsx │ ├── style │ │ ├── index.scss │ │ └── index.tsx │ └── swipe-action.tsx │ ├── switch │ ├── index.tsx │ ├── interface.tsx │ ├── style │ │ ├── index.scss │ │ └── index.tsx │ └── switch.tsx │ ├── tab-bar │ ├── index.tsx │ ├── interface.tsx │ ├── style │ │ ├── index.scss │ │ └── index.tsx │ └── tab-bar.tsx │ ├── tabs │ ├── index.tsx │ ├── interface.tsx │ ├── style │ │ ├── index.scss │ │ └── index.tsx │ └── tabs.tsx │ ├── tag │ ├── index.tsx │ ├── interface.tsx │ ├── style │ │ ├── index.scss │ │ └── index.tsx │ ├── tag.tsx │ └── tagChecked.tsx │ ├── toast │ ├── index.tsx │ ├── style │ │ ├── index.scss │ │ └── index.tsx │ └── toast.tsx │ └── utils │ ├── guid.ts │ ├── index.ts │ └── type.ts ├── stories ├── combination-listview.stories.js ├── datashow-accordion.stories.js ├── datashow-avatar.stories.js ├── datashow-badge.stories.js ├── datashow-card.stories.js ├── datashow-divider.stories.js ├── datashow-icon.stories.js ├── datashow-notice-bar.stories.js ├── datashow-tags.stories.js ├── feedback-action-sheet.stories.js ├── feedback-modal.stories.js ├── feedback-progress.stories.js ├── feedback-toast.stories.js ├── general-button.stories.js ├── general-checkbox.stories.js ├── general-imagePicker.stories.js ├── general-input.stories.js ├── general-picker-panel.stories.js ├── general-picker.stories.js ├── general-radio.stories.js ├── general-slider.stories.js ├── general-switch.stories.js ├── gesture-swiipe-action.stories.js ├── index.scss ├── introduce.stories.js ├── layout-grid.stories.js ├── navigation-affix.stories.js ├── navigation-pagination.stories.js ├── navigation-popover.stories.js ├── navigation-segmented-control.stories.js ├── navigation-tabbar.stories.js └── navigation-tabs.stories.js ├── tsconfig.json ├── tsconfig.test.json ├── tslint.json └── yarn-error.log /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-react", 4 | ], 5 | "plugins": ["transform-class-properties"] 6 | } -------------------------------------------------------------------------------- /.commitlintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parserPreset: { 3 | parserOpts: { 4 | headerPattern: /^(\w*)(?:\((.*)\))?:[ ]?(.*)$/, 5 | headerCorrespondence: ['type', 'scope', 'subject'] 6 | } 7 | }, 8 | rules: { 9 | 'type-empty': [2, 'never'], 10 | 'type-case': [2, 'always', 'lower-case'], 11 | 'subject-empty': [2, 'never'], 12 | 'type-enum': [2, 'always', [ 13 | 'feat', 14 | 'fix', 15 | 'docs', 16 | 'style', 17 | 'refactor', 18 | 'test', 19 | 'chore', 20 | ]] 21 | } 22 | } -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["plugin:prettier/recommended"], 3 | "plugins": [ 4 | "react-hooks" 5 | ], 6 | "rules": { 7 | "react-hooks/rules-of-hooks": "error", 8 | "react-hooks/exhaustive-deps": "warn" 9 | }, 10 | "parser": "babel-eslint" 11 | } -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.js linguist-language=typescript 2 | *.tsx linguist-language=typescript 3 | *.ts linguist-language=typescript 4 | *.scss linguist-language=typescript 5 | *.css linguist-language=typescript 6 | *.html linguist-language=typescript 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | yarn.lock 3 | /es 4 | /lib 5 | .DS_Store -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | # .prettierrc 2 | 3 | semi: false 4 | tabWidth: 2 5 | printWidth: 100 6 | singleQuote: true -------------------------------------------------------------------------------- /.storybook/addons.js: -------------------------------------------------------------------------------- 1 | import 'storybook-readme/register' 2 | import '@storybook/addon-knobs/register' 3 | import '@storybook/addon-storysource/register' 4 | import '@storybook/addon-options/register' 5 | import '@storybook/addon-links/register' 6 | // import '@storybook/addon-notes/register' 7 | import '@storybook/addon-actions/register' 8 | 9 | import '@storybook/addon-backgrounds/register' 10 | import '@storybook/addon-storysource/register' 11 | import '@storybook/addon-viewport/register' 12 | // import '@storybook/addon-notes/register-panel' 13 | import '@storybook/addon-viewport/register' 14 | -------------------------------------------------------------------------------- /.storybook/config.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { configure, addDecorator, addParameters } from '@storybook/react' 3 | import { addReadme } from 'storybook-readme' 4 | import theme from './theme' 5 | import { configureReadme } from 'storybook-readme' 6 | // import 'babel-polyfill' 7 | import { INITIAL_VIEWPORTS } from '@storybook/addon-viewport' 8 | 9 | // Load all files in the stories folder with a .js extension 10 | const req = require.context('../stories/', true, /.js$/) 11 | 12 | function loadStories() { 13 | req('./introduce.stories.js') 14 | req.keys().forEach(filename => { 15 | console.log(filename) 16 | if (filename.indexOf('introduce') === -1) { 17 | return req(filename) 18 | } 19 | }) 20 | } 21 | configureReadme({ 22 | /** 23 | * Wrapper for story. Usually used to set some styles 24 | * React: React.ReactNode 25 | * Vue: Vue component 26 | */ 27 | StoryPreview: ({ children }) =>
{children}
, 28 | 29 | /** 30 | * Wrapper for content and sidebar docs. Usually used to set some styles 31 | * React: React.ReactNode 32 | * Vue: Vue component 33 | */ 34 | DocPreview: ({ children }) =>
{children}
, 35 | 36 | /** 37 | * Wrapper for hedaer docs. Usually used to set some styles 38 | * React: React.ReactNode 39 | * Vue: Vue component 40 | */ 41 | HeaderPreview: ({ children }) =>
{children}
, 42 | 43 | /** 44 | * Wrapper for footer docs. Usually used to set some styles 45 | * React: React.ReactNode 46 | * Vue: Vue component 47 | */ 48 | FooterPreview: ({ children }) =>
{children}
, 49 | 50 | /** 51 | * Header docs in markdown format 52 | */ 53 | header: '', 54 | 55 | /** 56 | * Footer docs in markdown format 57 | */ 58 | footer: '' 59 | }) 60 | addParameters({ 61 | viewport: { 62 | viewports: INITIAL_VIEWPORTS 63 | }, 64 | readme: { 65 | codeTheme: 'github' 66 | }, 67 | options: { 68 | theme: theme, 69 | // isFullscreen: false, 70 | panelPosition: 'right' 71 | } 72 | }) 73 | 74 | addDecorator(story =>
{story()}
) 75 | addDecorator(addReadme) 76 | configure(loadStories, module) 77 | -------------------------------------------------------------------------------- /.storybook/theme.js: -------------------------------------------------------------------------------- 1 | import { create } from '@storybook/theming' 2 | 3 | export default create({ 4 | base: 'light', 5 | 6 | colorPrimary: 'hotpink', 7 | colorSecondary: 'deepskyblue', 8 | 9 | // UI 10 | appBg: 'white', 11 | appContentBg: 'white', 12 | appBorderColor: 'grey', 13 | appBorderRadius: 4, 14 | 15 | // Typography 16 | fontBase: '"Open Sans", sans-serif', 17 | fontCode: 'monospace', 18 | 19 | // Text colors 20 | textColor: 'black', 21 | textInverseColor: 'rgba(255,255,255,0.9)', 22 | 23 | // Toolbar default and active colors 24 | barTextColor: 'silver', 25 | barSelectedColor: 'black', 26 | barBg: 'white', 27 | 28 | // Form colors 29 | inputBg: 'white', 30 | inputBorder: 'silver', 31 | inputTextColor: 'black', 32 | inputBorderRadius: 4, 33 | 34 | brandTitle: 'CP Design', 35 | brandUrl: '#' 36 | }) 37 | -------------------------------------------------------------------------------- /.storybook/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | module.exports = { 4 | module: { 5 | rules: [ 6 | { 7 | test: /\.stories\.(jsx|js)?$/, 8 | loaders: [require.resolve('@storybook/addon-storysource/loader')], 9 | enforce: 'pre' 10 | }, 11 | { 12 | test: /\.md$/, 13 | use: [ 14 | { 15 | loader: 'markdown-loader' 16 | } 17 | ] 18 | }, 19 | // { 20 | // test: /story\.js$/, 21 | // loaders: [require.resolve('@storybook/addon-storysource/loader')], 22 | // enforce: 'pre', 23 | // }, 24 | { 25 | test: /\.less$/, 26 | use: ['style-loader', 'css-loader', { loader: 'less-loader' }], 27 | include: /node_modules/ 28 | }, 29 | { 30 | test: /\.(css|scss)$/, 31 | use: [ 32 | { loader: 'style-loader' }, 33 | { 34 | loader: 'css-loader', 35 | options: { importLoaders: 2 } 36 | }, 37 | { 38 | loader: 'postcss-loader', 39 | options: { 40 | plugins: () => [ 41 | require('autoprefixer')({ 42 | overrideBrowserslist: ['last 1 version', 'ie >= 11'] 43 | }) 44 | ] 45 | } 46 | }, 47 | { 48 | loader: 'sass-loader', 49 | options: { 50 | includePaths: [path.resolve(__dirname, '..', 'node_modules')] 51 | } 52 | } 53 | ] 54 | }, 55 | { 56 | test: /\.(png|jpg)$/, 57 | loader: 'url-loader?limit=8192' 58 | }, 59 | { 60 | test: /\.(ts|tsx)$/, 61 | include: path.resolve(__dirname, '../'), 62 | loader: 'awesome-typescript-loader' 63 | }, 64 | { 65 | test: /\.(ttf|woff|eot|svg|woff2)$/, 66 | loader: require.resolve('file-loader') 67 | } 68 | ] 69 | }, 70 | resolve: { 71 | extensions: ['.ts', '.tsx', '.js', '.jsx'] 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /.stylelintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "stylelint-config-standard", 3 | "plugins": ["stylelint-scss"], 4 | "rules": { 5 | "at-rule-no-unknown": null, 6 | "color-hex-case": null, 7 | "block-closing-brace-newline-after": null, 8 | "at-rule-empty-line-before":null, 9 | "number-no-trailing-zeros": null, 10 | "no-empty-source": null, 11 | "unit-case": null, 12 | "scss/at-rule-no-unknown": true, 13 | "font-family-no-missing-generic-family-keyword": null 14 | } 15 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - 8 5 | 6 | before_install: 7 | - yarn add codecov.io coveralls 8 | 9 | after_success: 10 | - cat ./coverage/lcov.info | ./node_modules/codecov.io/bin/codecov.io.js 11 | - cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js 12 | 13 | branches: 14 | only: 15 | - master -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | A configurable Mobile UI by React Hooks 2 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-tactile -------------------------------------------------------------------------------- /docs/1e59d2330b4c6deb84b340635ed36249.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10086XIAOZHANG/CP-DESIGN/9971e3f9cf0ae1b311ceb6135cb1ffb812c3640b/docs/1e59d2330b4c6deb84b340635ed36249.ttf -------------------------------------------------------------------------------- /docs/20fd1704ea223900efa9fd4e869efb08.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10086XIAOZHANG/CP-DESIGN/9971e3f9cf0ae1b311ceb6135cb1ffb812c3640b/docs/20fd1704ea223900efa9fd4e869efb08.woff2 -------------------------------------------------------------------------------- /docs/8b43027f47b20503057dfbbaa9401fef.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10086XIAOZHANG/CP-DESIGN/9971e3f9cf0ae1b311ceb6135cb1ffb812c3640b/docs/8b43027f47b20503057dfbbaa9401fef.eot -------------------------------------------------------------------------------- /docs/f691f37e57f04c152e2315ab7dbad881.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10086XIAOZHANG/CP-DESIGN/9971e3f9cf0ae1b311ceb6135cb1ffb812c3640b/docs/f691f37e57f04c152e2315ab7dbad881.woff -------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10086XIAOZHANG/CP-DESIGN/9971e3f9cf0ae1b311ceb6135cb1ffb812c3640b/docs/favicon.ico -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | Storybook
-------------------------------------------------------------------------------- /docs/main.77a4d7c4b9965b0de1db.bundle.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[0],{0:function(n,o,c){c(562),c(704),n.exports=c(1429)},1:function(n,o){},1429:function(n,o,c){"use strict";c.r(o);c(1430),c(1465),c(533),c(1575),c(1578),c(1581),c(1636),c(549)}},[[0,1,2]]]); -------------------------------------------------------------------------------- /docs/main.e00d20381e8fbf86ce25.bundle.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"main.e00d20381e8fbf86ce25.bundle.js","sources":["webpack:///main.e00d20381e8fbf86ce25.bundle.js"],"mappings":"AAAA","sourceRoot":""} -------------------------------------------------------------------------------- /docs/runtime~main.707b56da4e928e093175.bundle.js: -------------------------------------------------------------------------------- 1 | !function(e){function r(r){for(var n,l,f=r[0],i=r[1],a=r[2],c=0,s=[];c { 6 | console.log(item) 7 | return { 8 | key: `${index}`, 9 | title: `测试title${index}`, 10 | content: '测试内容', 11 | icon: 12 | } 13 | }) 14 | const onChange = (expandedKeys: string[]) => { 15 | console.log(expandedKeys) 16 | } 17 | return ( 18 |
19 |

Accordion 手风琴

20 |

基本模式

21 | 22 | 23 | 29 | 30 | 31 |

手风琴模式

32 | 33 | 34 | 41 | 42 | 43 |
44 | ) 45 | } 46 | -------------------------------------------------------------------------------- /examples/affix/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import { Affix, Button } from '../../src/components' 3 | import { action } from '@storybook/addon-actions' 4 | export default function AffixDemo() { 5 | return ( 6 |
7 |

Affix 固钉

8 |

Basic

9 |
16 | 17 | 18 | 19 |
26 | 27 | 28 | 29 |
36 | 37 | 38 | 39 |
46 |
47 | ) 48 | } 49 | -------------------------------------------------------------------------------- /examples/affix/readme.md: -------------------------------------------------------------------------------- 1 | # Affix 固钉 2 | 3 | 主要用于固定某个部分 4 | 5 | ## 引入组件 6 | 7 | ```jsx 8 | import { Affix } from 'cp-design' 9 | ``` 10 | 11 | ## Demo 代码 12 | 13 | ```jsx 14 | export default function AffixDemo() { 15 | return ( 16 |
17 |
24 | 25 | 26 | 27 |
34 | 35 | 36 | 37 |
44 | 45 | 46 | 47 |
54 |
55 | ) 56 | } 57 | ``` 58 | 59 | ## Api 60 | 61 | | 属性 | 说明 | 类型 | 默认值 | 可选 | 62 | | ------------ | :----------------------------------: | :----------------------: | ------: | :--: | 63 | | offsetTop | 距离窗口底部达到指定偏移量后触发 | number | -- | -- | 64 | | offsetButtom | 距离窗口底部达到指定偏移量后触发 | number | -- | -- | 65 | | container | 容器 | fun() => HTMLElement | -- | -- | 66 | | onChange | 固定状态发生改变的回调,css 下不生效 | (fixed: boolean) => void | -- | -- | 67 | | useSticky | 是否使用 js 行为设置 sticky | boolean | `false` | -- | 68 | -------------------------------------------------------------------------------- /examples/avatar/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import { Avatar } from '../../src/components' 3 | 4 | export default function AvatarDemo() { 5 | return ( 6 |
7 |

Avatar 头像

8 |

基本

9 | 10 | 11 | 12 | 13 | U 14 | 15 | 16 | 17 | 22 |
23 | ) 24 | } 25 | -------------------------------------------------------------------------------- /examples/avatar/readme.md: -------------------------------------------------------------------------------- 1 | # Avatar 头像 2 | 3 | 头像的展示 4 | 5 | ## 引入组件 6 | 7 | ```jsx 8 | import { Avatar } from 'cp-design' 9 | ``` 10 | 11 | ## Demo 代码 12 | 13 | ```jsx 14 | export default function AvatarDemo() { 15 | return ( 16 |
17 | 18 | 19 | 20 | U 21 | 22 | 23 | 24 | 29 |
30 | ) 31 | } 32 | ``` 33 | 34 | ## Api 35 | 36 | | 属性 | 说明 | 类型 | 默认值 | 可选 | 37 | | ------- | :----------------: | :------------------------: | -------: | :--: | 38 | | size | 大小, 尺寸 | `large`, `normal`, `small` | `normal` | -- | 39 | | shape | 形状 | `circle`, `square` | `circle` | -- | 40 | | src | 图片的地址 | string | -- | -- | 41 | | icon | 图标的名称 | string | -- | -- | 42 | | alt | 图片不显示的占位 | string | -- | -- | 43 | | onError | 图片加载失败的回调 | fun():void | -- | -- | 44 | | onClick | 点击头像的回调 | fun() : void | -- | -- | 45 | | style | 自定义样式 | Object | -- | -- | 46 | -------------------------------------------------------------------------------- /examples/button/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import { Button, Row, Col } from '../../src/components' 3 | import { action } from '@storybook/addon-actions' 4 | export default function ButtonDemo() { 5 | return ( 6 |
7 |

Button 按钮

8 |

类型、尺寸

9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 24 | 25 | 26 | 27 | 28 | 31 | 32 | 33 | 34 | 35 | 38 | 39 | 40 | 41 | 42 | 45 | 46 | 47 | 48 | 49 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 |
60 | ) 61 | } 62 | -------------------------------------------------------------------------------- /examples/card/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import { Card, Row, Col, Icon } from '../../src/components' 3 | import { action } from '@storybook/addon-actions' 4 | export default function ButtonDemo() { 5 | return ( 6 |
7 |

Card 卡片

8 |

默认

9 | 10 | 11 | 这是内容这是内容这是内容这是内容这是内容 12 | 13 | 14 |

Card 通栏样式

15 | 16 | 17 | } style={{ width: 300 }}> 18 | 这是内容这是内容这是内容这是内容这是内容 19 | 20 | 21 | 22 | 23 | 24 | } 27 | actions={[ 28 | { 29 | content:
这是底部1
, 30 | onClick: action('这是底部1') 31 | }, 32 | { 33 | content:
这是底部2
, 34 | onClick: action('这是底部2') 35 | }, 36 | { 37 | content:
这是底部3
, 38 | onClick: action('这是底部3') 39 | } 40 | ]} 41 | style={{ width: 300, marginTop: 20 }} 42 | > 43 | 这是内容这是内容这是内容这是内容这是内容这是内容这是内容这是内容这是内容这是内容 44 |
45 | 46 |
47 | 48 | 49 | 50 |
51 | 52 |
53 |
This is the description
54 |
Thank you, design
55 |
56 |
57 |
58 | 59 |
60 |
61 | ) 62 | } 63 | -------------------------------------------------------------------------------- /examples/checkbox/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import { Checkbox, CheckboxGroup, Row, Col } from '../../src/components' 3 | // import { action } from '@storybook/addon-actions' 4 | export default function ButtonDemo() { 5 | const data = [ 6 | { value: '0', label: 'Ph.D.', check: true }, 7 | { value: '1', label: 'Bachelor', check: false }, 8 | { value: '2', label: 'College diploma', check: false } 9 | ] 10 | const onChange = (val: string | number) => { 11 | console.log(val) 12 | } 13 | return ( 14 |
15 |

Checkbox 复选框

16 |

基本

17 | {data.map(i => ( 18 | 19 | 20 | onChange(i.value)} checked={i.check}> 21 | {i.label} 22 | 23 | 24 | 25 | ))} 26 | 27 | 28 | 29 | UndergraduateAuxiliary text 30 | 31 | 32 | 33 | 34 | 35 | 36 | UndergraduateAuxiliary text 37 | 38 | 39 | 40 |
41 | ) 42 | } 43 | -------------------------------------------------------------------------------- /examples/checkbox/readme.md: -------------------------------------------------------------------------------- 1 | # Checkbox 复选框 2 | 3 | 复选框的展示 4 | 5 | ## 引入组件 6 | 7 | ```jsx 8 | import * as React from 'react' 9 | import { Checkbox, Checkou, Row, Col } from 'cp-design' 10 | ``` 11 | 12 | ## Demo 代码 13 | 14 | ```jsx 15 | export default function CheckboxDemo() { 16 | return ( 17 |
18 | {data.map(i => ( 19 | 20 | 21 | onChange(i.value)} checked={i.check}> 22 | {i.label} 23 | 24 | 25 | 26 | ))} 27 | 28 | 29 | 30 | UndergraduateAuxiliary text 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | UndergraduateAuxiliary text 39 | 40 | 41 | 42 |
43 | ) 44 | } 45 | ``` 46 | 47 | ## Api 48 | 49 | ##### Checkbox 50 | 51 | | 属性 | 说明 | 类型 | 默认值 | 可选 | 52 | | -------------- | :-----------------------: | :--------------: | -----: | :--: | 53 | | defaultChecked | 初始是否选中 | Boolean | -- | -- | 54 | | checked | 指定当前是否选中 | Boolean | -- | -- | 55 | | disabled | 设置禁用 | Boolean | -- | -- | 56 | | onChange | change 事件触发的回调函数 | (e: Event): void | -- | -- | 57 | 58 | ##### checkboxGroup 59 | 60 | | 属性 | 说明 | 类型 | 默认值 | 可选 | 61 | | ------------ | :-----------------------------: | :--------------: | -----: | :--: | 62 | | defaultValue | 默认值字符串数组 | string[] | -- | -- | 63 | | value | 指定选中 的项 | string[] | -- | -- | 64 | | disabled | 设置禁用 ,全部不可用 默认 false | Boolean | -- | -- | 65 | | onChange | change 事件触发的回调函数 | (e: Event): void | -- | -- | 66 | -------------------------------------------------------------------------------- /examples/divider/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import { Divider, Row, Col } from '../../src/components' 3 | // import { action } from '@storybook/addon-actions' 4 | export default function ButtonDemo() { 5 | return ( 6 |
7 |

Divider 分割线

8 |

基本

9 | 10 | 11 |

12 | Steven Paul Jobs was an American entrepreneur and business magnate. He was the chairman, 13 | chief executive officer, and a co-founder of Apple Inc. 14 |

15 | 16 |

17 | Steven Paul Jobs was an American entrepreneur and business magnate. He was the chairman, 18 | chief executive officer, and a co-founder of Apple Inc. 19 |

20 | With Text 21 |

22 | Steven Paul Jobs was an American entrepreneur and business magnate. He was the chairman, 23 | chief executive officer, and a co-founder of Apple Inc. 24 |

25 | 26 |

27 | Steven Paul Jobs was an American entrepreneur and business magnate. He was the chairman, 28 | chief executive officer, and a co-founder of Apple Inc. 29 |

30 | Left Text 31 |

32 | Steven Paul Jobs was an American entrepreneur and business magnate. He was the chairman, 33 | chief executive officer, and a co-founder of Apple Inc. 34 |

35 | Right Text 36 |

37 | Steven Paul Jobs was an American entrepreneur and business magnate. He was the chairman, 38 | chief executive officer, and a co-founder of Apple Inc. 39 |

40 | 41 |
42 | 43 | 44 |

45 | Text 46 | 47 | Link 48 | 49 | Link 50 |

51 | 52 |
53 |
54 | ) 55 | } 56 | -------------------------------------------------------------------------------- /examples/icon/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import { Icon, Row, Col } from '../../src/components' 3 | // import { action } from '@storybook/addon-actions' 4 | export default function ButtonDemo() { 5 | const list = [ 6 | 'caret-square-o-down', 7 | 'circle-o-notch', 8 | 'cog', 9 | 'align-right', 10 | 'pencil', 11 | 'cog', 12 | 'lign-left', 13 | 'align-center', 14 | 'spinner fa-pulse', 15 | 'home', 16 | 'angle-down', 17 | 'long-arrow-up' 18 | ] 19 | const data = list.map(item => ({ 20 | icon: , 21 | text: item 22 | })) 23 | return ( 24 |
25 |

Icon 图标

26 |

基本

27 | {data.map((item, index) => { 28 | if (index !== 0 && (index + 1) % 3 === 0) { 29 | return ( 30 | 31 | 32 | {data[index - 2].icon} 33 |

{data[index - 2].text}

34 | 35 | 36 | {data[index - 1].icon} 37 |

{data[index - 1].text}

38 | 39 | 40 | {item.icon} 41 |

{data[index].text}

42 | 43 |
44 | ) 45 | } 46 | return null 47 | })} 48 |

大小

49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 |

颜色

64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 |
79 | ) 80 | } 81 | -------------------------------------------------------------------------------- /examples/imagePicker/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import { ImagePicker, Icon, Row, Col } from '../../src/components' 3 | import { OperationType, FileItemProps } from '../../src/components/image-picker/interface' 4 | const { useState } = React 5 | 6 | export default function ImagePickerDemo() { 7 | const [files, setFiles] = useState>([]) 8 | const [previewFile, setPreviewFile] = useState({}) 9 | const [isShowPreviewFile, setIsShowPreviewFile] = useState(false) 10 | const [multifiles, setMultiFiles] = useState>([]) 11 | const handleChange = (files: Array<{}>) => { 12 | console.log(files) 13 | setFiles(files) 14 | } 15 | const handleMultiChange = (files: Array, operation: OperationType) => { 16 | console.log(files, operation) 17 | setMultiFiles([...files]) 18 | } 19 | const onPreview = (file: FileItemProps) => { 20 | setPreviewFile(file) 21 | setIsShowPreviewFile(true) 22 | } 23 | return ( 24 |
25 |

ImagePicker 图片选择器

26 |

基本

27 | {isShowPreviewFile && ( 28 |
42 |
{ 45 | setIsShowPreviewFile(false) 46 | }} 47 | > 48 | 49 |
50 | 51 |
52 | )} 53 | 54 | 55 | 56 | 57 | 58 |

多选

59 | 60 | 61 | 62 | 63 | 64 |

禁用

65 | 66 | 67 | 68 | 69 | 70 |
71 | ) 72 | } 73 | -------------------------------------------------------------------------------- /examples/introduce/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | export default function ButtonDemo() { 3 | return ( 4 |
5 |

Getting started

6 |

This guide will help you render components and applications with React for Web.

7 |

Characteristics and advantages 特性和优势

8 |
    9 |
  • UI 样式高度可配置,拓展性更强,轻松适应各类产品风格
  • 10 |
  • 使用 TypeScript 开发,提供类型定义文件,支持类型及属性智能提示,方便业务开发
  • 11 |
  • 全面兼容 react / preact
  • 12 |
  • 引入Font Awesome 图标字体库 等优化方案,一体式开发
  • 13 |
14 |

Install 安装

15 |

$ npm install cp-design --save

16 |

或者

17 |

$ yarn add cp-design

18 |

User 组件使用实例:

19 |

20 |

21 |           
22 |             {
23 |               "import {Button} from 'cp-design';\nReactDOM.render(, mountNode);"
24 |             }
25 |           
26 |         
27 |

28 |

浏览器支持

29 |
    30 |
  • iOS
  • 31 |
  • Android 4.0+
  • 32 |
33 |

✨ Notice 注意

34 |

在组件库中使用了 SASS,在安装的时候记得安装 node-sass

35 |

$ npm install node-sass -D

36 |

或者

37 |

$ yarn add node-sass -D

38 |

Author Email

39 |

fcj_zhang@163.com

40 |

Blog address

41 |

42 | 浮云随笔 43 |

44 |

Github

45 |

46 | CP-DESIGN 47 |

48 |
49 | ) 50 | } 51 | -------------------------------------------------------------------------------- /examples/introduce/readme.md: -------------------------------------------------------------------------------- 1 | ### Getting started 2 | 3 | This guide will help you render components and applications with React Native for Web. 4 | 5 | If you're not familiar with setting up a new React web project, please refer to the React documentation. 6 | -------------------------------------------------------------------------------- /examples/modal/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import { Modal, Button, Row, Col } from '../../src/components' 3 | const { useState } = React 4 | export default function ModalDemo() { 5 | const [modal1, setModal1] = useState(false) 6 | const [modal2, setModal2] = useState(false) 7 | const showModal1 = (e: React.MouseEvent) => { 8 | e.preventDefault() 9 | setModal1(true) 10 | } 11 | const showModal2 = (e: React.MouseEvent) => { 12 | e.preventDefault() 13 | setModal2(true) 14 | } 15 | return ( 16 |
17 | { 23 | setModal1(false) 24 | }} 25 | > 26 |
27 | scoll content... 28 |
29 | scoll content... 30 |
31 | scoll content... 32 |
33 | scoll content... 34 |
35 | scoll content... 36 |
37 | scoll content... 38 |
39 |
40 |
41 | { 46 | setModal2(false) 47 | }} 48 | onOk={() => { 49 | alert('afterOK') 50 | setModal2(false) 51 | }} 52 | > 53 |
54 | scoll content... 55 |
56 | scoll content... 57 |
58 | scoll content... 59 |
60 | scoll content... 61 |
62 | scoll content... 63 |
64 | scoll content... 65 |
66 |
67 |
68 |

Modal 对话框

69 |

基本

70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 |
81 | ) 82 | } 83 | -------------------------------------------------------------------------------- /examples/noticeBar/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import { NoticeBar, Icon, Row, Col } from '../../src/components' 3 | // import { action } from '@storybook/addon-actions' 4 | export default function NoticeBarDemo() { 5 | return ( 6 |
7 |

NoticeBar 通告栏

8 |

基本

9 | 10 | 11 | 12 | Notice: The arrival time of incomes and transfers of Yu 'E Bao will be delayed 13 | during National Day. 14 | 15 | 16 | 17 | 18 | 19 | alert('1')}> 20 | Notice: The arrival time of incomes and transfers of Yu 'E Bao will be delayed 21 | during National Day. 22 | 23 | 24 | 25 | 26 | 27 | 28 | 不再提示}> 29 | Closable demo for `actionText`. 30 | 31 | 32 | 33 | 34 | 35 | }> 36 | Customized icon. 37 | 38 | 39 | 40 |
41 | ) 42 | } 43 | -------------------------------------------------------------------------------- /examples/pagination/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import { Pagination, Row, Col } from '../../src/components' 3 | const { useState } = React 4 | export default function PaginationDemo() { 5 | const [current1, setCurrent1] = useState(1) 6 | const [current2, setCurrent2] = useState(1) 7 | const [current3, setCurrent3] = useState(1) 8 | const onChange1 = (page: string | number) => { 9 | if (typeof page === 'string') { 10 | setCurrent1(Number(page)) 11 | } else { 12 | setCurrent1(page) 13 | } 14 | } 15 | const onChange2 = (page: string | number) => { 16 | if (typeof page === 'string') { 17 | setCurrent2(Number(page)) 18 | } else { 19 | setCurrent2(page) 20 | } 21 | } 22 | const onChange3 = (page: string | number) => { 23 | if (typeof page === 'string') { 24 | setCurrent3(Number(page)) 25 | } else { 26 | setCurrent3(page) 27 | } 28 | } 29 | return ( 30 |
31 |

Pagination 分页器

32 |

基本

33 | 34 | 35 | 36 | 37 | 38 |

Hide number

39 | 40 | 41 | 49 | 50 | 51 |

Point style

52 | 53 | 54 | 61 | 62 | 63 |
64 | ) 65 | } 66 | -------------------------------------------------------------------------------- /examples/pickerPanel/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import { PickerPanel, Row, Col } from '../../src/components' 3 | const { useState } = React 4 | export default function PickerPanelDemo() { 5 | const [valueGroups, setValueGroups] = useState({ 6 | title: 'Mr.', 7 | firstName: 'Micheal', 8 | secondName: 'Jordan' 9 | }) 10 | 11 | const optionGroups = { 12 | title: ['Mr.', 'Mrs.', 'Ms.', 'Dr.'], 13 | firstName: ['John', 'Micheal', 'Elizabeth'], 14 | secondName: ['Lennon', 'Jackson', 'Jordan', 'Legend', 'Taylor'] 15 | } 16 | 17 | const handleChange = (name: string, value: string) => { 18 | console.log(name, value) 19 | setValueGroups({ 20 | ...valueGroups, 21 | [name]: value 22 | }) 23 | } 24 | return ( 25 |
26 |

PickerPanel 选择器

27 |

基本

28 | 29 | 30 | 35 | 36 | 37 |
38 | ) 39 | } 40 | -------------------------------------------------------------------------------- /examples/pickerPanel/readme.md: -------------------------------------------------------------------------------- 1 | # PickerPanel 选择器 2 | 3 | 选择器的展示 4 | 5 | ## 引入组件 6 | 7 | ```jsx 8 | import * as React from 'react' 9 | import { PickerPanel, Row, Col } from 'cp-design' 10 | ``` 11 | 12 | ## Demo 代码 13 | 14 | ```jsx 15 | const { useState } = React 16 | export default function PickerPanelDemo() { 17 | const [valueGroups, setValueGroups] = useState({ 18 | title: 'Mr.', 19 | firstName: 'Micheal', 20 | secondName: 'Jordan' 21 | }) 22 | 23 | const optionGroups = { 24 | title: ['Mr.', 'Mrs.', 'Ms.', 'Dr.'], 25 | firstName: ['John', 'Micheal', 'Elizabeth'], 26 | secondName: ['Lennon', 'Jackson', 'Jordan', 'Legend', 'Taylor'] 27 | } 28 | 29 | const handleChange = (name: string, value: string) => { 30 | console.log(name, value) 31 | setValueGroups({ 32 | ...valueGroups, 33 | [name]: value 34 | }) 35 | } 36 | return ( 37 |
38 |

PickerPanel 选择器

39 |

基本

40 | 41 | 42 | 47 | 48 | 49 |
50 | ) 51 | } 52 | ``` 53 | 54 | ## Api 55 | 56 | | 属性 | 说明 | 类型 | 默认值 | 可选 | 57 | | ------------ | :----------------------------------------: | :-----------------------------------: | -----: | :--: | 58 | | optionGroups | 数据集合 key 对应数组集合 | object | -- | -- | 59 | | valueGroups | value 对象类型,key 和数据集合中 key 相对应 | object | -- | -- | 60 | | onChange | 选中后的回调 | (name: string, value: string) => void | -- | -- | 61 | | prefixCls | class 前缀 默认 cp-ui-picker-panel | string | -- | -- | 62 | | className | 样式类名 | fun():void | -- | -- | 63 | | onClick | 点击回调函数 | (name: string, value: string) => void | -- | -- | 64 | | itemHeight | 子项行高度 | number | 36 | -- | 65 | | height | 弹层高度 | number | 216 | -- | 66 | -------------------------------------------------------------------------------- /examples/popover/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import { Popover, Icon, Row, Col } from '../../src/components' 3 | const { PopoverWapper, PopoverItem } = Popover 4 | const { useState } = React 5 | export default function PopoverDemo() { 6 | const [visible, setVisible] = useState(true) 7 | const [selected, setSelected] = useState('') 8 | console.log(selected) 9 | const onSelect = (opt: any) => { 10 | setSelected(opt.props.value) 11 | setVisible(false) 12 | } 13 | const handleVisibleChange = (visible: boolean) => { 14 | setVisible(visible) 15 | } 16 | return ( 17 |
18 |

Popover 气泡

19 |

基本

20 | 28 | NavBar 29 | 30 | } data-seed="logId"> 35 | Chart 36 | , 37 | } 40 | style={{ whiteSpace: 'nowrap' }} 41 | > 42 | My Qrcode 43 | , 44 | }> 45 | Help 46 | 47 | ]} 48 | align={{ 49 | overflow: { adjustY: 0, adjustX: 0 } 50 | }} 51 | onVisibleChange={handleVisibleChange} 52 | onSelect={onSelect} 53 | > 54 |
55 | 56 |
57 |
58 | 59 |
60 |
61 | ) 62 | } 63 | -------------------------------------------------------------------------------- /examples/progress/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import { Progress, Row, Col } from '../../src/components' 3 | export default function ProgressDemo() { 4 | return ( 5 |
6 |

Progress 进度条

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 | { 36 | return null 37 | }} 38 | type="circle" 39 | /> 40 | 41 | 42 | 43 | 44 | 45 |
46 | ) 47 | } 48 | -------------------------------------------------------------------------------- /examples/radio/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import { Radio, Icon, Row, Col } from '../../src/components' 3 | const { useState } = React 4 | export default function RadioDemo() { 5 | const [checked, setChecked] = useState(false) 6 | const [value, setValue] = useState(0) 7 | const data = [ 8 | { value: 0, label: 'credit-card', icon: }, 9 | { 10 | value: 1, 11 | label: 'cc-paypal', 12 | icon: 13 | }, 14 | { value: 2, label: 'paypal', icon: } 15 | ] 16 | const changeRadio = (checked: boolean) => { 17 | console.log('checkbox', checked) 18 | setChecked(!checked) 19 | } 20 | const onChange = (value: number) => { 21 | console.log('checkbox') 22 | setValue(value) 23 | } 24 | return ( 25 |
26 |

Radio 单选框

27 |

基本

28 | 29 | 30 | 31 | Radio demo(dustomized style) 32 | 33 | 34 | Agree 35 | 36 | 37 | 38 |

禁用

39 | 40 | 41 | 42 | Radio demo(dustomized style) 43 | 44 | 禁用 45 | 46 | 47 |

多项选择

48 | {data.map(i => ( 49 |
{ 52 | onChange(i.value) 53 | }} 54 | > 55 | 63 | {i.icon} 64 | 65 | 66 | 67 | 68 |
69 | ))} 70 |
71 | ) 72 | } 73 | -------------------------------------------------------------------------------- /examples/segmentedControl/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import { SegmentedControl, Row, Col } from '../../src/components' 3 | export default function SegmentedControlDemo() { 4 | const onChange = (index: number, value: string) => { 5 | console.log(`selectedIndex:${index},selectedValue:${value}`) 6 | } 7 | const onValueChange = (value: string) => { 8 | console.log(value) 9 | } 10 | return ( 11 |
12 |

SegmentedControl 分段器

13 |

Simplest

14 | 15 | 16 | 17 | 18 | 19 |

disabled

20 | 21 | 22 | 23 | 24 | 25 |

SelectedIndex

26 | 27 | 28 | 29 | 30 | 31 |

TintColor

32 | 37 |

onChange/onValueChange

38 | 43 |
44 | ) 45 | } 46 | -------------------------------------------------------------------------------- /examples/slider/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import { Slider, Row, Col } from '../../src/components' 3 | // import { action } from '@storybook/addon-actions' 4 | const { useState } = React 5 | export default function SliderDemo() { 6 | const [value, setValue] = useState(33) 7 | const [value1, setValue1] = useState(33) 8 | const log = (name: string, value: number) => { 9 | console.log(`${name}: ${value}`) 10 | setValue(value) 11 | } 12 | const log1 = (name: string, value: number) => { 13 | console.log(`${name}: ${value}`) 14 | setValue1(value) 15 | } 16 | return ( 17 |
18 |

Slider 滑动输入条

19 |

基本

20 | 21 | 22 | { 27 | log('change', value ?? 0) 28 | }} 29 | onAfterChange={value => { 30 | log('afterchange', value ?? 0) 31 | }} 32 | /> 33 | 34 | 35 |

Disabled slider

36 | 37 | 38 | { 44 | log1('change', value1 ?? 0) 45 | }} 46 | onAfterChange={value1 => { 47 | log1('afterchange', value1 ?? 0) 48 | }} 49 | /> 50 | 51 | 52 |

Slider with customized color

53 | 54 | 55 | 76 | 77 | 78 |
79 | ) 80 | } 81 | -------------------------------------------------------------------------------- /examples/tag/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import { Tag, Row, Col } from '../../src/components' 3 | const { useState } = React 4 | export default function TagDemo() { 5 | const [checked, setChecked] = useState(false) 6 | const onChange = (checked: boolean) => { 7 | setChecked(checked) 8 | } 9 | return ( 10 |
11 |

Tag 标签

12 |

基本

13 | 14 | 15 | 16 | Selected 17 | 18 | 19 | 20 |

关闭

21 | 22 | 23 | console.log('close')}> 24 | Closable 25 | 26 | 27 | 28 |

尺寸

29 | 30 | 31 | Basic 32 | 33 | Basic 34 | 35 | 36 | Basic 37 | 38 | 39 | 40 |

颜色

41 | 42 | 43 | Basic 44 | 45 | Basic 46 | 47 | 48 | Basic 49 | 50 | 51 | Basic 52 | 53 | 54 | Basic 55 | 56 | 57 | Basic 58 | 59 | 60 | 61 |

大小

62 | 63 | 64 | 65 | Basic 66 | 67 | 68 | Basic 69 | 70 | 71 | Basic 72 | 73 | 74 | 75 |
76 | ) 77 | } 78 | -------------------------------------------------------------------------------- /examples/toast/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import { Button, Toast, Icon, Row, Col } from '../../src/components' 3 | // import { action } from '@storybook/addon-actions' 4 | export default function ToastDemo() { 5 | const showToast = () => { 6 | Toast.info('This is a toast tips !!!', 3) 7 | } 8 | const showToastNoMask = () => { 9 | Toast.info('Toast without mask !!!', 2, undefined, false) 10 | } 11 | const customIcon = () => { 12 | return 13 | } 14 | const successToast = () => { 15 | Toast.success('Load success !!!', 1) 16 | } 17 | const failToast = () => { 18 | Toast.fail('Load failed !!!', 1) 19 | } 20 | const offline = () => { 21 | Toast.offline('Network connection failed !!!', 1) 22 | } 23 | const loadingToast = () => { 24 | Toast.loading('Loading...', 1, () => { 25 | console.log('Load complete !!!') 26 | }) 27 | } 28 | return ( 29 |
30 |

Toast 轻提示

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 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 |
68 | ) 69 | } 70 | -------------------------------------------------------------------------------- /externals.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'rc-util*' 2 | declare module 'rc-slider' 3 | declare module 'rmc-notification' 4 | declare module 'better-scroll' 5 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp') 2 | var ts = require('gulp-typescript') 3 | var del = require('del') 4 | var fileLoader = require('gulp-file-loader') 5 | var rename = require('gulp-rename') 6 | function compileTS(dir, esModule) { 7 | var tsProject = ts.createProject('tsconfig.json', { module: esModule ? 'ES2015' : 'CommonJS' }) 8 | return tsProject 9 | .src() 10 | .pipe(tsProject()) 11 | .pipe(gulp.dest(dir)) 12 | } 13 | 14 | function styles() { 15 | return gulp 16 | .src(['./src/components/**/*.scss']) 17 | .pipe(gulp.dest('es')) 18 | .pipe(gulp.dest('lib')) 19 | } 20 | function fonts() { 21 | return gulp 22 | .src([ 23 | './src/components/**/*.eot', 24 | './src/components/**/*.svg', 25 | './src/components/**/*.ttf', 26 | './src/components/**/*.woff', 27 | './src/components/**/*.woff2', 28 | './src/components/**/*.otf' 29 | ]) 30 | .pipe(gulp.dest('es')) 31 | .pipe(gulp.dest('lib')) 32 | } 33 | function compileES() { 34 | return compileTS('es', true) 35 | } 36 | 37 | function compileCJS() { 38 | // return gulp.parallel(() => compileTS('lib', false), styles) 39 | return compileTS('lib', false) 40 | } 41 | 42 | function clean() { 43 | return del(['es', 'lib']) 44 | } 45 | 46 | exports.default = gulp.series(clean, styles, gulp.parallel(compileCJS, compileES, fonts)) 47 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transform: { 3 | '.(ts|tsx)': 'ts-jest', 4 | }, 5 | moduleNameMapper: { 6 | "\\.(css|less)$": "identity-obj-proxy" 7 | }, 8 | testPathIgnorePatterns: ['/node_modules/', 'node', '/es/', '/lib/'], 9 | testRegex: '(/test/.*|\\.(test|spec))\\.(ts|tsx|js)$', 10 | moduleFileExtensions: ['ts', 'tsx', 'js', 'json'], 11 | }; -------------------------------------------------------------------------------- /src/components/accordion/index.tsx: -------------------------------------------------------------------------------- 1 | import Accordion from './accordion' 2 | 3 | export default Accordion 4 | -------------------------------------------------------------------------------- /src/components/accordion/interface.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | export interface Data { 4 | // key 默认为数组下标从0开始 5 | key?: string 6 | title?: React.ReactNode 7 | content?: React.ReactNode 8 | icon?: React.ReactNode 9 | // 默认为false 10 | disabled?: boolean 11 | // 右边的打开状态下的图标 12 | rightOpenIcon?: React.ReactNode 13 | // 右边的关闭状态下的图标 14 | rightCloseIcon?: React.ReactNode 15 | } 16 | 17 | export interface PanelProps { 18 | // icon 展开的图标可以配置 19 | icon?: React.ReactNode 20 | // 右边的打开状态下的图标 21 | rightOpenIcon?: React.ReactNode 22 | // 右边的关闭状态下的图标 23 | rightCloseIcon?: React.ReactNode 24 | // title 标题 25 | title?: React.ReactNode 26 | // content 内容 27 | content?: React.ReactNode 28 | // disabled 不可选区域 默认为false 29 | disabled: boolean 30 | // 默认 expanded 是否展开 31 | defaultExpanded: boolean 32 | // prefixCls 33 | prefixCls: string 34 | // onChange 35 | onChange: (expanded: boolean) => void 36 | } 37 | 38 | export interface AccordionProps { 39 | className?: string 40 | style?: React.CSSProperties 41 | // border 是否有边框 默认为true 42 | border: boolean 43 | // 当前激活的key 44 | activeKey: string[] 45 | // accordion 手风琴模式,手风琴模式下只能展开一个 默认为false 46 | accordion: boolean 47 | // dataSource 渲染元素 包括title和content 48 | dataSource: Array 49 | // onChange 切换面板时候的回调, true表示展开,false表示缩回,key表示当前操作的对象,如果不在expandedKeys数组,说明是关闭操作 50 | onChange: (expandedKeys: string[], key: string) => void 51 | } 52 | -------------------------------------------------------------------------------- /src/components/accordion/style/index.scss: -------------------------------------------------------------------------------- 1 | $panel: 'cp-ui-panel'; 2 | $accordion: 'cp-ui-accordion'; 3 | 4 | .#{$accordion} { 5 | font-size: 14px; 6 | font-variant: tabular-nums; 7 | line-height: 1.5; 8 | color: rgba(0, 0, 0, 0.65); 9 | -webkit-box-sizing: border-box; 10 | box-sizing: border-box; 11 | margin: 0; 12 | padding: 0; 13 | list-style: none; 14 | background-color: #fafafa; 15 | border-radius: 4px; 16 | 17 | &-border { 18 | border: 1px solid #d9d9d9; 19 | border-bottom: 0; 20 | } 21 | 22 | .#{$panel} { 23 | border-bottom: 1px solid #d9d9d9; 24 | 25 | &-title { 26 | display: flex; 27 | align-items: center; 28 | padding: 12px; 29 | cursor: pointer; 30 | 31 | .cp-ui-icon { 32 | font-size: 12px; 33 | transition: all 0.3s; 34 | } 35 | 36 | &-content { 37 | margin-left: 10px; 38 | } 39 | 40 | 41 | } 42 | 43 | &-right-icon { 44 | flex: 1; 45 | text-align: right; 46 | align-self: center; 47 | 48 | .cp-ui-icon { 49 | font-size: 1rem; 50 | } 51 | } 52 | 53 | &-body { 54 | padding: 0 12px; 55 | background: #fff; 56 | overflow: hidden; 57 | transition: all 0.3s cubic-bezier(0.23, 1, 0.32, 1); 58 | 59 | &.#{$panel}-body-inactive { 60 | opacity: 0; 61 | height: 0; 62 | } 63 | 64 | &.#{$panel}-body-active { 65 | height: auto; 66 | opacity: 1; 67 | padding: 16px 12px; 68 | } 69 | } 70 | 71 | &-expanded {} 72 | 73 | &-disabled { 74 | .#{$panel}-title { 75 | cursor: not-allowed; 76 | opacity: 0.5; 77 | } 78 | } 79 | } 80 | } -------------------------------------------------------------------------------- /src/components/accordion/style/index.tsx: -------------------------------------------------------------------------------- 1 | import '../../style/index.scss' 2 | import './index.scss' 3 | -------------------------------------------------------------------------------- /src/components/action-sheet/index.tsx: -------------------------------------------------------------------------------- 1 | import actionSheet from './actionSheet' 2 | export default actionSheet 3 | -------------------------------------------------------------------------------- /src/components/action-sheet/interface.tsx: -------------------------------------------------------------------------------- 1 | export interface ActionsItemType { 2 | // 确认唯一值 不传默认从0递增 3 | key?: string 4 | content: string | React.ReactNode 5 | // action 点击 6 | onClick: ItemClickProps 7 | } 8 | export type noop = (e: React.MouseEvent) => void 9 | 10 | export type ItemClickProps = (key: string, item: ActionsItemType) => void 11 | 12 | export interface ActionSheetProps { 13 | // actions 数组 14 | actions: Array 15 | // 取消action文案 16 | cancelText?: string | React.ReactNode 17 | // 取消按钮点击回调 18 | onCancel?: noop 19 | // 是否点击modal关闭 20 | closeOnClickModal?: boolean 21 | } 22 | -------------------------------------------------------------------------------- /src/components/action-sheet/style/index.scss: -------------------------------------------------------------------------------- 1 | @import '../../style/index.scss'; 2 | $action-sheet: 'cp-ui-action-sheet'; 3 | 4 | .#{$action-sheet} { 5 | 6 | @-webkit-keyframes down-to-up 7 | 8 | /* Safari and Chrome */ 9 | { 10 | 0% { 11 | bottom: -300px; 12 | } 13 | 14 | 100% { 15 | bottom: 0; 16 | } 17 | } 18 | 19 | position: fixed; 20 | z-index: 999; 21 | left: 0; 22 | right: 0; 23 | bottom: 0; 24 | top: 0; 25 | background: rgba(0, 0, 0, .4); 26 | 27 | &-container { 28 | position: absolute; 29 | bottom: 0; 30 | left: 0; 31 | right: 0; 32 | background: rgba(246, 246, 246, 1); 33 | animation: down-to-up 0.3s; 34 | -webkit-animation: down-to-up 0.3s; 35 | animation-fill-mode: forwards; 36 | 37 | .#{$action-sheet}-select-choose { 38 | &-list { 39 | position: relative; 40 | text-align: center; 41 | font-size: 16px; 42 | 43 | a { 44 | display: block; 45 | padding: 20px 0; 46 | color: #333; 47 | background: #fff; 48 | text-decoration: none; 49 | 50 | &:hover { 51 | color: $color-brand-normal; 52 | background: rgba(247, 247, 247, 1); 53 | } 54 | } 55 | 56 | &:after { 57 | content: " "; 58 | display: block; 59 | position: absolute; 60 | left: 0; 61 | right: 0; 62 | bottom: 0; 63 | height: 1px; 64 | background: rgba(223, 226, 230, 1); 65 | transform: scaleY(.5); 66 | } 67 | } 68 | 69 | .#{$action-sheet}-on { 70 | a { 71 | color: #FF7000; 72 | background: rgba(247, 247, 247, 1); 73 | 74 | } 75 | } 76 | } 77 | } 78 | 79 | &-select-chancel { 80 | margin-top: 12px; 81 | font-size: 16px; 82 | 83 | a { 84 | padding: 12px 0; 85 | display: block; 86 | color: #999; 87 | text-align: center; 88 | background: #fff; 89 | text-decoration: none; 90 | 91 | 92 | } 93 | } 94 | } -------------------------------------------------------------------------------- /src/components/action-sheet/style/index.tsx: -------------------------------------------------------------------------------- 1 | import '../../style/index' 2 | import './index.scss' 3 | -------------------------------------------------------------------------------- /src/components/affix/index.tsx: -------------------------------------------------------------------------------- 1 | import Affix from './affix' 2 | 3 | export default Affix 4 | -------------------------------------------------------------------------------- /src/components/affix/interface.tsx: -------------------------------------------------------------------------------- 1 | export interface AffixProps { 2 | // 距离窗口顶部达到指定偏移量后触发 3 | offsetTop?: number 4 | // 距离窗口底部达到指定偏移量后触发 5 | offsetBottom?: number 6 | // container 7 | container?: () => HTMLElement 8 | // onChange 固定状态改变时候的回调函数 9 | onChange: (fixed: boolean) => void 10 | // useFix 是否使用定位,不使用的话将会用position: 'sticky',css 总是比js更快 11 | useSticky: boolean 12 | // prefixCls 13 | prefixCls: string 14 | } 15 | -------------------------------------------------------------------------------- /src/components/avatar/avatar.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import ClassNames from 'classnames' 3 | import { AvatarProps } from './interface' 4 | import Icon from '../icon' 5 | 6 | import './style/index.scss' 7 | 8 | const noop = () => {} 9 | 10 | const prefixCls = 'cp-ui-avatar' 11 | 12 | const defaultProps: AvatarProps = { 13 | size: 'normal', 14 | shape: 'circle', 15 | onError: noop, 16 | onClick: noop 17 | } 18 | 19 | const getClassNames = ({ size, shape, src, icon }: AvatarProps) => { 20 | return ClassNames(prefixCls, { 21 | [`${prefixCls}-${size}`]: !!size && typeof size === 'string', 22 | [`${prefixCls}-${shape}`]: !!shape, 23 | [`${prefixCls}-image`]: src, 24 | [`${prefixCls}-icon`]: icon 25 | }) 26 | } 27 | 28 | const getChildren = ({ icon, src, alt, children, srcSet, onError }: AvatarProps) => { 29 | let childrenNode = children 30 | if (icon) { 31 | childrenNode = 32 | } else if (src) { 33 | childrenNode = {alt} 34 | } 35 | return childrenNode 36 | } 37 | 38 | const getStyle = ({ size, icon }: AvatarProps) => { 39 | let _style: any = {} 40 | if (typeof size === 'number') { 41 | _style.height = size 42 | _style.width = size 43 | _style.lineHeight = `${size}px` 44 | _style.fontSize = icon ? size / 2 : 18 45 | } 46 | return _style 47 | } 48 | 49 | const Avatar: React.FC & { defaultProps: Partial } = props => { 50 | const classStr = getClassNames(props) 51 | const _style = getStyle(props) 52 | return ( 53 | 54 | {getChildren(props)} 55 | 56 | ) 57 | } 58 | 59 | Avatar.defaultProps = defaultProps 60 | 61 | export default Avatar 62 | -------------------------------------------------------------------------------- /src/components/avatar/index.tsx: -------------------------------------------------------------------------------- 1 | import Avatar from './avatar' 2 | 3 | export default Avatar 4 | -------------------------------------------------------------------------------- /src/components/avatar/interface.tsx: -------------------------------------------------------------------------------- 1 | export type SizeType = 'large' | 'normal' | 'small' 2 | export type ShapeType = 'square' | 'circle' 3 | 4 | export interface AvatarProps { 5 | // 尺寸大小 默认为normal 6 | size: SizeType | number 7 | // 形状 默认为circle 8 | shape: ShapeType 9 | // src 图片的地址 10 | src?: string 11 | style?: object 12 | // srcSet 13 | srcSet?: string 14 | // icon 可参考Icon组件 15 | icon?: string 16 | // alt 图片不显示的占位 17 | alt?: string 18 | children?: any 19 | // onError 图片加载失败的回调 20 | onError: () => void 21 | // onClick 点击头像 22 | onClick: () => void 23 | } 24 | -------------------------------------------------------------------------------- /src/components/avatar/style/index.scss: -------------------------------------------------------------------------------- 1 | @import '../../style/index.scss'; 2 | $avatar: 'cp-ui-avatar'; 3 | 4 | .#{$avatar} { 5 | box-sizing: border-box; 6 | margin: 0; 7 | padding: 0; 8 | list-style: none; 9 | display: inline-block; 10 | text-align: center; 11 | background: #ccc; 12 | color: #fff; 13 | white-space: nowrap; 14 | position: relative; 15 | overflow: hidden; 16 | vertical-align: middle; 17 | width: 32px; 18 | height: 32px; 19 | line-height: 32px; 20 | 21 | .avatar_ava { 22 | display: flex; 23 | align-items: center; 24 | justify-content: center; 25 | width: 100%; 26 | height: 100%; 27 | } 28 | 29 | &-large { 30 | width: 48px; 31 | height: 48px; 32 | 33 | .cp-ui-icon { 34 | font-size: 24px !important; 35 | } 36 | } 37 | 38 | &-small { 39 | width: 24px; 40 | height: 24px; 41 | 42 | .cp-ui-icon { 43 | font-size: 12px !important; 44 | } 45 | } 46 | 47 | &-normal { 48 | .cp-ui-icon { 49 | font-size: 18px !important; 50 | } 51 | } 52 | 53 | &-square { 54 | @include round($border-radius-large); 55 | } 56 | 57 | &-circle { 58 | @include round(50%); 59 | } 60 | 61 | &-image { 62 | img { 63 | width: 100%; 64 | height: 100%; 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /src/components/avatar/style/index.tsx: -------------------------------------------------------------------------------- 1 | import '../../style/index' 2 | import './index.scss' 3 | -------------------------------------------------------------------------------- /src/components/badge/badge.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import ClassNames from 'classnames' 3 | import { BadgeProps } from './interface' 4 | 5 | import './style/index.scss' 6 | 7 | const defaultProps: BadgeProps = { 8 | dot: false, 9 | overflowCount: 99, 10 | prefixCls: 'cp-ui-badge', 11 | corner: false 12 | } 13 | 14 | const getClassNames = ({ status, prefixCls, children }: BadgeProps) => { 15 | return ClassNames(prefixCls, { 16 | [`${prefixCls}-${status}`]: status, 17 | [`${prefixCls}-no-wrapper`]: !children 18 | }) 19 | } 20 | const getOutStyle = (style: React.CSSProperties, corner: boolean) => { 21 | let _style: React.CSSProperties = {} 22 | if (!!corner) { 23 | _style.width = '100%' 24 | } 25 | _style = Object.assign(style, _style) 26 | return _style 27 | } 28 | const renderCount = ({ text, overflowCount, dot, prefixCls, corner, style }: BadgeProps) => { 29 | // dot 和 text都存在的时候优先dot 30 | if (dot) { 31 | return 32 | } 33 | 34 | if (text) { 35 | let content: any 36 | const classStr = ClassNames(`${prefixCls}-text`, { 37 | [`${prefixCls}-custom`]: typeof text !== 'number', 38 | [`${prefixCls}-corner`]: !!corner 39 | }) 40 | if (typeof text === 'number') { 41 | content = text <= overflowCount ? text : `${overflowCount}+` 42 | } else { 43 | content = text 44 | } 45 | return ( 46 | 47 | {content} 48 | 49 | ) 50 | } 51 | return null 52 | } 53 | 54 | const Badge: React.FC & { defaultProps: Partial } = props => { 55 | const { children, corner, outStyle } = props 56 | return ( 57 |
58 | {children} 59 | {renderCount(props)} 60 |
61 | ) 62 | } 63 | 64 | Badge.defaultProps = defaultProps 65 | 66 | export default Badge 67 | -------------------------------------------------------------------------------- /src/components/badge/index.tsx: -------------------------------------------------------------------------------- 1 | import Badge from './badge' 2 | 3 | export default Badge 4 | -------------------------------------------------------------------------------- /src/components/badge/interface.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | export type Status = 'success' | 'default' | 'process' | 'warning' | 'error' 4 | 5 | export interface BadgeProps { 6 | // text 展示的数字, 可以进行自定义 7 | text?: React.ReactNode 8 | // 营销样式 9 | hot?: boolean 10 | // dot 不展示数字 只展示小红点 默认为`false` 11 | dot: boolean 12 | // overflowCount 封顶的数字 默认99, 超过的用99+表示 13 | overflowCount: number 14 | // status 状态点 这个值对dot生效 15 | status?: Status 16 | // prefixCls 17 | prefixCls: string 18 | // style 19 | style?: React.CSSProperties 20 | // 外围样式outstyle 21 | outStyle?: React.CSSProperties 22 | // children 23 | children?: React.ReactNode 24 | //置于角落 25 | corner: boolean 26 | } 27 | -------------------------------------------------------------------------------- /src/components/badge/style/index.scss: -------------------------------------------------------------------------------- 1 | @import '../../style/index.scss'; 2 | $badge: 'cp-ui-badge'; 3 | 4 | .#{$badge} { 5 | display: inline-block; 6 | position: relative; 7 | 8 | &-text { 9 | position: absolute; 10 | right: 0; 11 | top: 0; 12 | transform: translate(50%, -50%); 13 | height: 20px; 14 | border-radius: 10px; 15 | background: $color-brand-normal; 16 | color: #fff; 17 | line-height: 20px; 18 | text-align: center; 19 | padding: 0 6px; 20 | font-size: 12px; 21 | font-weight: normal; 22 | white-space: nowrap; 23 | -webkit-box-shadow: 0 0 0 1px #fff; 24 | box-shadow: 0 0 0 1px #fff; 25 | z-index: 10; 26 | } 27 | 28 | &-dot { 29 | height: 6px; 30 | width: 6px; 31 | border-radius: 100%; 32 | background: $color-brand-normal; 33 | z-index: 10; 34 | -webkit-box-shadow: 0 0 0 1px #fff; 35 | box-shadow: 0 0 0 1px #fff; 36 | position: absolute; 37 | right: 0; 38 | top: 0; 39 | transform: translate(50%, -50%); 40 | } 41 | 42 | &-corner { 43 | width: 5 * 12px; 44 | position: absolute; 45 | right: -2 * 12px; 46 | background-color: $color-brand-normal; 47 | color: '#fff'; 48 | white-space: nowrap; 49 | transform: rotate(45deg); 50 | text-align: center; 51 | font-size: 12px; 52 | 53 | &-wrapper { 54 | overflow: hidden; 55 | } 56 | } 57 | 58 | &-success { 59 | .#{$badge}-dot { 60 | background-color: $color-success-deep; 61 | } 62 | } 63 | 64 | &-error { 65 | .#{$badge}-dot { 66 | background-color: $color-error-deep; 67 | } 68 | } 69 | 70 | &-warning { 71 | .#{$badge}-dot { 72 | background-color: $color-warning-deep; 73 | } 74 | } 75 | 76 | &-process { 77 | .#{$badge}-dot { 78 | background-color: $color-notice-deep; 79 | } 80 | } 81 | 82 | &-default { 83 | .#{$badge}-dot { 84 | background-color: $color-line-deep; 85 | } 86 | } 87 | 88 | &-no-wrapper { 89 | .#{$badge}-text { 90 | display: block; 91 | position: relative; 92 | top: auto; 93 | right: auto; 94 | transform: none; 95 | } 96 | } 97 | } -------------------------------------------------------------------------------- /src/components/badge/style/index.tsx: -------------------------------------------------------------------------------- 1 | import '../../style/index' 2 | import './index.scss' 3 | -------------------------------------------------------------------------------- /src/components/button/button.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import ClassNames from 'classnames' 3 | import Icon from '../icon' 4 | import { ButtonProps } from './interface' 5 | import './style/index.scss' 6 | 7 | const defaultProps: ButtonProps = { 8 | disabled: false, 9 | loading: false, 10 | size: 'normal', 11 | prefixCls: 'cp-ui-btn', 12 | type: 'primary' 13 | } 14 | 15 | const getClassName = ({ className, loading, disabled, type, size, prefixCls }: ButtonProps) => { 16 | const classStr = ClassNames(prefixCls, className, { 17 | [`${prefixCls}-warning`]: type === 'warning', 18 | [`${prefixCls}-primary`]: type === 'primary', 19 | [`${prefixCls}-ghost`]: type === 'ghost', 20 | [`${prefixCls}-large`]: size === 'large', 21 | [`${prefixCls}-normal`]: size === 'normal', 22 | [`${prefixCls}-small`]: size === 'small', 23 | [`${prefixCls}-loading`]: loading, 24 | [`${prefixCls}-disabled`]: disabled 25 | }) 26 | return classStr 27 | } 28 | 29 | const renderLoading = ({ loading }: ButtonProps) => { 30 | if (loading) { 31 | return 32 | } 33 | return null 34 | } 35 | 36 | const renderIcon = ({ icon }: ButtonProps) => { 37 | if (icon) { 38 | return {icon} 39 | } 40 | return null 41 | } 42 | 43 | // 解决ts 写了defaultProps 使用仍然需要必填的问题 44 | const Button: React.FC & { defaultProps: Partial } = props => { 45 | const { style, onClick, disabled, prefixCls, children } = props 46 | return ( 47 | 60 | ) 61 | } 62 | 63 | Button.defaultProps = defaultProps 64 | 65 | export default Button 66 | -------------------------------------------------------------------------------- /src/components/button/index.tsx: -------------------------------------------------------------------------------- 1 | import Button from './button' 2 | 3 | export default Button 4 | -------------------------------------------------------------------------------- /src/components/button/interface.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | type buttonType = 'warning' | 'primary' | 'ghost' 4 | type sizeType = 'large' | 'normal' | 'small' 5 | export interface ButtonProps { 6 | // button的类型 默认primary 7 | type: buttonType 8 | // button的尺寸,默认normal 9 | size: sizeType 10 | // disabled 默认为false 11 | disabled: boolean 12 | // 按钮的loading态 默认为false 13 | loading: boolean 14 | // onClick 15 | onClick?: React.MouseEventHandler 16 | // 前缀 17 | prefixCls: string 18 | // 类名 19 | className?: string 20 | // style 21 | style?: object 22 | // icon 23 | icon?: React.ReactNode 24 | 25 | children?: React.ReactNode 26 | } 27 | -------------------------------------------------------------------------------- /src/components/button/style/index.scss: -------------------------------------------------------------------------------- 1 | @import '../../style/index.scss'; 2 | 3 | $btn: 'cp-ui-btn'; 4 | 5 | .#{$btn}-button_btn { 6 | display: inline-block; 7 | width: 100%; 8 | 9 | .#{$btn} { 10 | font-size: $font-size-normal; 11 | display: flex; 12 | align-items: center; 13 | justify-content: center; 14 | cursor: pointer; 15 | outline: none; 16 | border-radius: $border-radius-normal; 17 | height: 32px; 18 | line-height: $line-height-normal; 19 | padding: 0 15px; 20 | background: $color-brand-normal; 21 | border: 0; 22 | color: #fff; 23 | transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1); 24 | 25 | &:hover:not(:disabled) { 26 | opacity: 0.8; 27 | } 28 | 29 | &:active { 30 | background: $color-brand-deep; 31 | } 32 | 33 | &.#{$btn}-warning { 34 | background: $color-warning-deep; 35 | 36 | &:active { 37 | background: $color-warning-weight; 38 | } 39 | } 40 | 41 | &.#{$btn}-ghost { 42 | background: #fff; 43 | color: $color-text-title-content-1; 44 | border-width: 1px; 45 | border-style: solid; 46 | border-color: $color-text-title-content-1; 47 | 48 | &:hover { 49 | border-color: $color-brand-normal; 50 | color: $color-brand-normal; 51 | } 52 | 53 | &:active { 54 | border-color: $color-brand-deep; 55 | color: $color-brand-deep; 56 | } 57 | } 58 | 59 | &.#{$btn}-large { 60 | font-size: $font-size-large; 61 | height: 36px; 62 | } 63 | 64 | &.#{$btn}-small { 65 | font-size: $font-size-small; 66 | height: 28px; 67 | } 68 | 69 | &.#{$btn}-disabled { 70 | background: $color-text-disabled; 71 | cursor: not-allowed; 72 | } 73 | 74 | .cp-ui-icon { 75 | margin-right: 5px; 76 | font-size: 16px; 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /src/components/button/style/index.tsx: -------------------------------------------------------------------------------- 1 | import '../../style/index' 2 | import './index.scss' 3 | -------------------------------------------------------------------------------- /src/components/card/card.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import ClassNames from 'classnames' 3 | import { CardProps } from './interface' 4 | 5 | import './style/index.scss' 6 | 7 | const noop = () => {} 8 | 9 | const defaultProps: CardProps = { 10 | actions: [], 11 | prefixCls: 'cp-ui-card', 12 | onExtraClick: noop 13 | } 14 | 15 | const renderActions = ({ actions, prefixCls }: CardProps) => { 16 | if (actions && actions.length) { 17 | return ( 18 |
19 | {actions.map((action, index) => { 20 | return ( 21 |
26 | {action.content} 27 |
28 | ) 29 | })} 30 |
31 | ) 32 | } 33 | return null 34 | } 35 | 36 | const Card: React.FC & { defaultProps: Partial } = props => { 37 | const { prefixCls, title, extra, children, className, style, onExtraClick } = props 38 | const classStr = ClassNames(prefixCls, className) 39 | let styleCopy = style || {} 40 | return ( 41 |
42 | {title ? ( 43 |
44 |
{title}
45 | {extra ? ( 46 |
47 | {extra} 48 |
49 | ) : null} 50 |
51 | ) : null} 52 | {children ?
{children}
: null} 53 | {renderActions(props)} 54 |
55 | ) 56 | } 57 | 58 | Card.defaultProps = defaultProps 59 | 60 | export default Card 61 | -------------------------------------------------------------------------------- /src/components/card/index.tsx: -------------------------------------------------------------------------------- 1 | import Card from './card' 2 | 3 | export default Card 4 | -------------------------------------------------------------------------------- /src/components/card/interface.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | export interface Action { 4 | content?: React.ReactNode 5 | onClick?: () => void 6 | } 7 | 8 | export interface CardProps { 9 | // title 标题 10 | title?: React.ReactNode 11 | // extra 额外的部分 12 | extra?: React.ReactNode 13 | // style 自定义的样式 14 | style?: React.CSSProperties 15 | // className 16 | className?: string 17 | // actions 底部的操作 18 | actions: Array 19 | // prefixCls 20 | prefixCls: string 21 | // onExtraClick 22 | onExtraClick: () => void 23 | } 24 | -------------------------------------------------------------------------------- /src/components/card/style/index.scss: -------------------------------------------------------------------------------- 1 | $card: 'cp-ui-card'; 2 | 3 | .#{$card} { 4 | font-size: 14px; 5 | line-height: 1.5; 6 | color: rgba(0, 0, 0, 0.65); 7 | -webkit-box-sizing: border-box; 8 | box-sizing: border-box; 9 | margin: 0; 10 | padding: 0; 11 | list-style: none; 12 | background: #fff; 13 | border-radius: 4px; 14 | position: relative; 15 | -webkit-transition: all 0.3s; 16 | transition: all 0.3s; 17 | border: 1px solid #e8e8e8; 18 | 19 | &-header { 20 | background: transparent; 21 | border-bottom: 1px solid #e8e8e8; 22 | padding: 12px 12px; 23 | border-radius: 2px 2px 0 0; 24 | font-size: 16px; 25 | color: rgba(0, 0, 0, 0.85); 26 | display: flex; 27 | } 28 | 29 | &-title { 30 | flex: 1; 31 | } 32 | 33 | &-extra { 34 | cursor: pointer; 35 | } 36 | 37 | &-actions { 38 | display: flex; 39 | justify-content: center; 40 | border-top: 1px solid #e8e8e8; 41 | 42 | &-item { 43 | flex: 1; 44 | padding: 8px; 45 | text-align: center; 46 | border-left: 1px solid #e8e8e8; 47 | cursor: pointer; 48 | 49 | &:first-child { 50 | border-left: 0; 51 | } 52 | } 53 | } 54 | 55 | &-body { 56 | padding: 12px; 57 | } 58 | } -------------------------------------------------------------------------------- /src/components/card/style/index.tsx: -------------------------------------------------------------------------------- 1 | import '../../style/index.scss' 2 | import './index.scss' 3 | -------------------------------------------------------------------------------- /src/components/checkbox/checkboxGroup.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | // import ClassNames from 'classnames' 3 | import { CheckGroupProps, CheckboxProps } from './interface' 4 | import Checkbox from './checkbox' 5 | 6 | const noop = () => {} 7 | 8 | const prefixCls = 'cp-ui-checkbox' 9 | 10 | const defaultProps: CheckGroupProps = { 11 | onChange: noop, 12 | defaultValue: [], 13 | disabled: false, 14 | options: [], 15 | value: [] 16 | } 17 | 18 | const getNewValue = (value: string[], defaultValue: string[], props: CheckGroupProps) => { 19 | if ('value' in props) { 20 | return value 21 | } else { 22 | return defaultValue 23 | } 24 | } 25 | 26 | const handleChange = ({ newValue, value, checked, onChange }: any) => { 27 | const newValueCopy = newValue.slice() 28 | if (checked) { 29 | newValueCopy.push(value) 30 | } else { 31 | newValueCopy.splice(newValue.indexOf(value), 1) 32 | } 33 | onChange(newValueCopy) 34 | } 35 | 36 | const renderOptions = (props: CheckGroupProps) => { 37 | const { value, defaultValue, options, onChange } = props 38 | const newValue = getNewValue(value, defaultValue, props) 39 | if (options && options.length > 0) { 40 | return ( 41 | 42 | {options.map((option, index) => { 43 | const value = option.value 44 | return ( 45 | handleChange({ newValue, value, checked, onChange })} 49 | > 50 | {option.label} 51 | 52 | ) 53 | })} 54 | 55 | ) 56 | } 57 | return null 58 | } 59 | 60 | const CheckboxGroup: React.FC & { 61 | defaultProps: Partial 62 | checkbox: React.FC & { defaultProps: Partial } 63 | } = props => { 64 | return
{renderOptions(props)}
65 | } 66 | CheckboxGroup.checkbox = Checkbox 67 | CheckboxGroup.defaultProps = defaultProps 68 | 69 | export default CheckboxGroup 70 | -------------------------------------------------------------------------------- /src/components/checkbox/index.tsx: -------------------------------------------------------------------------------- 1 | import CheckboxGroup from './checkboxGroup' 2 | import Checkbox from './checkbox' 3 | export { CheckboxGroup, Checkbox } 4 | -------------------------------------------------------------------------------- /src/components/checkbox/interface.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * checkbox interface 3 | */ 4 | export interface CheckboxProps { 5 | // 是否被选中 默认为false 6 | checked?: boolean 7 | // onChange 变化时候发生的回调 8 | onChange: (e: Event) => void 9 | // autofocus 默认聚焦状态 10 | autoFocus?: boolean 11 | // disabled 默认为false 12 | disabled?: boolean 13 | // className 14 | className?: string 15 | // 半选状态 默认为false 16 | indeterminate?: boolean 17 | // 默认选中 默认为false 18 | defaultChecked?: boolean 19 | // onBlur 20 | onBlur?: (e: React.ChangeEvent) => void 21 | // onFocus 22 | onFocus?: (e: React.ChangeEvent) => void 23 | // prefixCls 24 | prefixCls?: string 25 | // onClick 26 | onClick?: React.MouseEventHandler 27 | // onMouseEnter 28 | onMouseEnter?: React.MouseEventHandler 29 | // onMouseLeave 30 | onMouseLeave?: React.MouseEventHandler 31 | // onKeyPress 32 | onKeyPress?: React.KeyboardEventHandler 33 | // onKeyDown 34 | onKeyDown?: React.KeyboardEventHandler 35 | children?: React.ReactNode 36 | } 37 | 38 | interface OptionValue { 39 | label: string | number 40 | value: any 41 | } 42 | 43 | /** 44 | * checkboxGroup 45 | */ 46 | export interface CheckGroupProps { 47 | // onChange 48 | onChange: (checkedValue: any) => void 49 | // defaultValue 默认值 50 | defaultValue: string[] 51 | // disabled 失效 全部不可用 默认false 52 | disabled: boolean 53 | // 配置的选项 54 | options: Array 55 | // value 指定选中 的项 56 | value: string[] 57 | } 58 | -------------------------------------------------------------------------------- /src/components/checkbox/style/index.tsx: -------------------------------------------------------------------------------- 1 | import '../../style/index.scss' 2 | import './index.scss' 3 | -------------------------------------------------------------------------------- /src/components/divider/divider.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import classNames from 'classnames' 3 | import { DivideProps } from './interface' 4 | 5 | import './style/index.scss' 6 | 7 | const defaultProps: DivideProps = { 8 | type: 'horizontal', 9 | orientation: 'center', 10 | dashed: false 11 | } 12 | 13 | const prefixCls = 'cp-ui-divider' 14 | 15 | const getClassNames = ({ type, orientation, dashed, className, children }: DivideProps) => { 16 | return classNames(prefixCls, className, { 17 | [`${prefixCls}-${type}`]: type, 18 | [`${prefixCls}-${orientation}`]: children ? orientation : false, 19 | [`${prefixCls}-dashed`]: dashed 20 | }) 21 | } 22 | 23 | const Divide: React.FC & { defaultProps: Partial } = props => { 24 | const classStr = getClassNames(props) 25 | const { children } = props 26 | return ( 27 |
28 | {children ? {children} : null} 29 |
30 | ) 31 | } 32 | 33 | Divide.defaultProps = defaultProps 34 | 35 | export default Divide 36 | -------------------------------------------------------------------------------- /src/components/divider/index.tsx: -------------------------------------------------------------------------------- 1 | import Divider from './divider' 2 | 3 | export default Divider 4 | -------------------------------------------------------------------------------- /src/components/divider/interface.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | export interface DivideProps { 4 | // 类名 5 | className?: string 6 | // dashed 是否为虚线 默认为false 7 | dashed: boolean 8 | // orientation 分割线标题的位置,默认为center 9 | orientation: OrientationEnum 10 | // type 分割线的类型,水平还是垂直类型,默认为水平位置 11 | type: DivideTypeEnum 12 | children?: React.ReactNode 13 | } 14 | 15 | export type OrientationEnum = 'left' | 'right' | 'center' 16 | 17 | export type DivideTypeEnum = 'horizontal' | 'vertical' 18 | -------------------------------------------------------------------------------- /src/components/divider/style/index.tsx: -------------------------------------------------------------------------------- 1 | import '../../style/index.scss' 2 | import './index.scss' 3 | -------------------------------------------------------------------------------- /src/components/grid/col.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import ClassNames from 'classnames' 3 | import RowContext from './rowContext' 4 | import { ColProps } from './interface' 5 | import './style/index.scss' 6 | 7 | const { useContext } = React 8 | 9 | const defaultProps: ColProps = { 10 | offset: 0 11 | } 12 | 13 | const prefixCls = 'cp-ui-col' 14 | 15 | const getStyle = ({ style }: ColProps) => { 16 | const { gutter } = useContext(RowContext) 17 | const styleCopy = { 18 | paddingLeft: (gutter as number) / 2, 19 | paddingRight: (gutter as number) / 2, 20 | ...style 21 | } 22 | return styleCopy 23 | } 24 | 25 | const getClassNames = ({ offset, span, className }: ColProps) => { 26 | return ClassNames(className, { 27 | [`${prefixCls}-offset-${offset}`]: !!offset, 28 | [`${prefixCls}-${span}`]: span !== undefined 29 | }) 30 | } 31 | 32 | const Col: React.FC & { defaultProps: Partial } = props => { 33 | const style = getStyle(props) 34 | const classStr = getClassNames(props) 35 | return ( 36 |
37 | {props.children} 38 |
39 | ) 40 | } 41 | 42 | Col.defaultProps = defaultProps 43 | 44 | export default Col 45 | -------------------------------------------------------------------------------- /src/components/grid/index.tsx: -------------------------------------------------------------------------------- 1 | import Row from './row' 2 | import Col from './col' 3 | 4 | export { Row, Col } 5 | -------------------------------------------------------------------------------- /src/components/grid/interface.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | /** 4 | * 垂直对齐方式 5 | * top: 顶部对齐 6 | * middle: 居中对齐 7 | * bottom: 底部对齐 8 | * baseline: 按第一行文字基线对齐 9 | * stretch: 未设置高度或设为 auto,将占满整个容器的高度 10 | */ 11 | type alignType = 'top' | 'middle' | 'bottom' | 'baseline' | 'stretch' 12 | 13 | /** 14 | * 水平对齐方式 15 | * start: 左对齐 16 | * end: 右对齐 17 | * center: 居中对齐 18 | * space-around: 每列具有相同的左右间距,行两端间距是列间距的二分之一 19 | * space-between: 两端对齐,列之间间距相等 20 | */ 21 | type justifyType = 'start' | 'end' | 'center' | 'space-around' | 'space-between' 22 | 23 | /** 24 | * 子元素的换行方式,可选nowrap,wrap,wrap-reverse 25 | */ 26 | type wrapType = 'nowrap' | 'wrap' | 'wrap-reverse' 27 | 28 | /** 29 | * 栅格占位 30 | */ 31 | type spanTypeNumber = 32 | | 1 33 | | 2 34 | | 3 35 | | 4 36 | | 5 37 | | 6 38 | | 7 39 | | 8 40 | | 9 41 | | 10 42 | | 11 43 | | 12 44 | | 13 45 | | 14 46 | | 15 47 | | 16 48 | | 17 49 | | 18 50 | | 19 51 | | 20 52 | | 21 53 | | 22 54 | | 23 55 | | 24 56 | 57 | // 布局为flex布局 58 | export interface RowProps extends React.HTMLAttributes { 59 | // 垂直对齐方式 60 | align: alignType 61 | // 列间隔, 支持响应式,可参考bootstrap的响应式{xs: 16, md: 24, lg: 32} 62 | gutter: number | object 63 | // 水平对齐方式 64 | justify: justifyType 65 | // 子元素的换行方式 66 | wrap?: wrapType 67 | } 68 | 69 | export interface ColProps extends React.HTMLAttributes { 70 | // 栅格左侧的间隔格数,间隔内不可以有栅格 默认为0 71 | offset: number 72 | // 列宽度,栅格占位数 73 | span?: spanTypeNumber 74 | } 75 | -------------------------------------------------------------------------------- /src/components/grid/row.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import ClassNames from 'classnames' 3 | import RowContext from './rowContext' 4 | import { RowProps } from './interface' 5 | import './style/index.scss' 6 | 7 | const defaultProps: RowProps = { 8 | align: 'top', 9 | gutter: 0, 10 | justify: 'start' 11 | } 12 | 13 | const prefixCls = 'cp-ui-row' 14 | 15 | const getClassNames = ({ align, justify, wrap }: RowProps) => { 16 | return ClassNames(prefixCls, { 17 | [`${prefixCls}-${align}`]: !!align, 18 | [`${prefixCls}-${justify}`]: !!justify, 19 | [`${prefixCls}-nowrap`]: wrap === 'nowrap', 20 | [`${prefixCls}-wrap`]: wrap === 'wrap', 21 | [`${prefixCls}-wrap-reverse`]: wrap === 'wrap-reverse' 22 | }) 23 | } 24 | 25 | const Row: React.FC & { defaultProps: Partial } = props => { 26 | const { children, style, gutter } = props 27 | const classStr = getClassNames(props) 28 | const rowStyle = 29 | (gutter as number) > 0 30 | ? { 31 | marginLeft: (gutter as number) / -2, 32 | marginRight: (gutter as number) / -2, 33 | ...style 34 | } 35 | : style 36 | return ( 37 | 38 |
39 | {children} 40 |
41 |
42 | ) 43 | } 44 | 45 | Row.defaultProps = defaultProps 46 | 47 | export default Row 48 | -------------------------------------------------------------------------------- /src/components/grid/rowContext.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | const { createContext } = React 4 | 5 | export interface RowContextProps { 6 | gutter?: number | object 7 | } 8 | 9 | const RowContext: React.Context = createContext({}) 10 | 11 | export default RowContext 12 | -------------------------------------------------------------------------------- /src/components/grid/style/index.scss: -------------------------------------------------------------------------------- 1 | @import '../../style/index.scss'; 2 | 3 | $row: 'cp-ui-row'; 4 | $col: 'cp-ui-col'; 5 | 6 | .#{$row} { 7 | display: flex; 8 | 9 | &-top { 10 | align-items: flex-start; 11 | } 12 | 13 | &-middle { 14 | align-items: center; 15 | } 16 | 17 | &-bottom { 18 | align-items: flex-end; 19 | } 20 | 21 | &-baseline { 22 | align-items: baseline; 23 | } 24 | 25 | &-stretch { 26 | align-items: stretch; 27 | } 28 | 29 | &-start { 30 | justify-content: flex-start; 31 | } 32 | 33 | &-end { 34 | justify-content: flex-end; 35 | } 36 | 37 | &-center { 38 | justify-content: center; 39 | } 40 | 41 | &-space-around { 42 | justify-content: space-around; 43 | } 44 | 45 | &-space-between { 46 | justify-content: space-between; 47 | } 48 | 49 | &-nowrap { 50 | flex-wrap: nowrap; 51 | } 52 | 53 | &-wrap { 54 | flex-wrap: wrap; 55 | } 56 | 57 | &-wrap-reverse { 58 | flex-wrap: wrap-reverse; 59 | } 60 | 61 | .#{cp-ui-col} { 62 | @for $var from 1 to 25 { 63 | &-#{$var} { 64 | width: ($var * 100 / 24) * 1%; 65 | } 66 | 67 | &-offset-#{$var} { 68 | margin-left: ($var * 100 / 24) * 1%; 69 | } 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /src/components/grid/style/index.tsx: -------------------------------------------------------------------------------- 1 | import '../../style/index' 2 | import './index.scss' 3 | -------------------------------------------------------------------------------- /src/components/icon/icon.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import ClassNames from 'classnames' 3 | import * as warning from 'warning' 4 | import './style' 5 | 6 | const noop = () => {} 7 | 8 | export interface IconProps extends React.HTMLAttributes { 9 | size?: string | number 10 | type?: string 11 | prefixCls: string 12 | className?: string 13 | //是否循环旋转 14 | spin?: boolean 15 | //是否旋转 16 | rotate?: boolean 17 | rotateDegree?: 0 | 90 | 180 | 270 | 360 18 | //是否翻转 19 | flip?: boolean 20 | flipOrder?: 'horizontal' | 'vertical' 21 | color?: string 22 | onClick: (e: React.MouseEvent) => void 23 | } 24 | 25 | const defaultProps: IconProps = { 26 | prefixCls: 'cp-ui-icon', 27 | onClick: noop 28 | } 29 | 30 | const handleClick = (e: React.MouseEvent, { onClick }: IconProps) => { 31 | onClick(e) 32 | } 33 | 34 | const Icon: React.FC & { defaultProps: Partial } = props => { 35 | const { 36 | prefixCls, 37 | type, 38 | size, 39 | color, 40 | spin, 41 | rotate, 42 | rotateDegree, 43 | flip, 44 | flipOrder, 45 | className, 46 | ...rest 47 | } = props 48 | warning(!!type, 'type should be required for icon') 49 | const classStr = ClassNames(prefixCls, className, 'fa', `fa-${type}`, { 50 | [`fa-spin`]: !!spin, 51 | [`fa-rotate-${rotateDegree}`]: !!rotate, 52 | [`fa-flip-${flipOrder}`]: !!flip 53 | }) 54 | let style: React.CSSProperties = { 55 | color 56 | } 57 | if (size) { 58 | style.fontSize = size 59 | } 60 | 61 | return handleClick(e, props)} {...rest}> 62 | } 63 | 64 | Icon.defaultProps = defaultProps 65 | 66 | export default Icon 67 | -------------------------------------------------------------------------------- /src/components/icon/iconfont/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10086XIAOZHANG/CP-DESIGN/9971e3f9cf0ae1b311ceb6135cb1ffb812c3640b/src/components/icon/iconfont/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /src/components/icon/iconfont/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10086XIAOZHANG/CP-DESIGN/9971e3f9cf0ae1b311ceb6135cb1ffb812c3640b/src/components/icon/iconfont/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /src/components/icon/iconfont/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10086XIAOZHANG/CP-DESIGN/9971e3f9cf0ae1b311ceb6135cb1ffb812c3640b/src/components/icon/iconfont/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /src/components/icon/iconfont/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10086XIAOZHANG/CP-DESIGN/9971e3f9cf0ae1b311ceb6135cb1ffb812c3640b/src/components/icon/iconfont/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /src/components/icon/iconfont/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10086XIAOZHANG/CP-DESIGN/9971e3f9cf0ae1b311ceb6135cb1ffb812c3640b/src/components/icon/iconfont/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /src/components/icon/iconfont/scss/_animated.scss: -------------------------------------------------------------------------------- 1 | // Spinning Icons 2 | // -------------------------- 3 | 4 | .#{$fa-css-prefix}-spin { 5 | -webkit-animation: fa-spin 2s infinite linear; 6 | animation: fa-spin 2s infinite linear; 7 | } 8 | 9 | .#{$fa-css-prefix}-pulse { 10 | -webkit-animation: fa-spin 1s infinite steps(8); 11 | animation: fa-spin 1s infinite steps(8); 12 | } 13 | 14 | @-webkit-keyframes fa-spin { 15 | 0% { 16 | -webkit-transform: rotate(0deg); 17 | transform: rotate(0deg); 18 | } 19 | 100% { 20 | -webkit-transform: rotate(359deg); 21 | transform: rotate(359deg); 22 | } 23 | } 24 | 25 | @keyframes fa-spin { 26 | 0% { 27 | -webkit-transform: rotate(0deg); 28 | transform: rotate(0deg); 29 | } 30 | 100% { 31 | -webkit-transform: rotate(359deg); 32 | transform: rotate(359deg); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/components/icon/iconfont/scss/_bordered-pulled.scss: -------------------------------------------------------------------------------- 1 | // Bordered & Pulled 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-border { 5 | padding: .2em .25em .15em; 6 | border: solid .08em $fa-border-color; 7 | border-radius: .1em; 8 | } 9 | 10 | .#{$fa-css-prefix}-pull-left { float: left; } 11 | .#{$fa-css-prefix}-pull-right { float: right; } 12 | 13 | .#{$fa-css-prefix} { 14 | &.#{$fa-css-prefix}-pull-left { margin-right: .3em; } 15 | &.#{$fa-css-prefix}-pull-right { margin-left: .3em; } 16 | } 17 | 18 | /* Deprecated as of 4.4.0 */ 19 | .pull-right { float: right; } 20 | .pull-left { float: left; } 21 | 22 | .#{$fa-css-prefix} { 23 | &.pull-left { margin-right: .3em; } 24 | &.pull-right { margin-left: .3em; } 25 | } 26 | -------------------------------------------------------------------------------- /src/components/icon/iconfont/scss/_core.scss: -------------------------------------------------------------------------------- 1 | // Base Class Definition 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix} { 5 | display: inline-block; 6 | font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/components/icon/iconfont/scss/_fixed-width.scss: -------------------------------------------------------------------------------- 1 | // Fixed Width Icons 2 | // ------------------------- 3 | .#{$fa-css-prefix}-fw { 4 | width: (18em / 14); 5 | text-align: center; 6 | } 7 | -------------------------------------------------------------------------------- /src/components/icon/iconfont/scss/_larger.scss: -------------------------------------------------------------------------------- 1 | // Icon Sizes 2 | // ------------------------- 3 | 4 | /* makes the font 33% larger relative to the icon container */ 5 | .#{$fa-css-prefix}-lg { 6 | font-size: (4em / 3); 7 | line-height: (3em / 4); 8 | vertical-align: -15%; 9 | } 10 | .#{$fa-css-prefix}-2x { font-size: 2em; } 11 | .#{$fa-css-prefix}-3x { font-size: 3em; } 12 | .#{$fa-css-prefix}-4x { font-size: 4em; } 13 | .#{$fa-css-prefix}-5x { font-size: 5em; } 14 | -------------------------------------------------------------------------------- /src/components/icon/iconfont/scss/_list.scss: -------------------------------------------------------------------------------- 1 | // List Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-ul { 5 | padding-left: 0; 6 | margin-left: $fa-li-width; 7 | list-style-type: none; 8 | > li { position: relative; } 9 | } 10 | .#{$fa-css-prefix}-li { 11 | position: absolute; 12 | left: -$fa-li-width; 13 | width: $fa-li-width; 14 | top: (2em / 14); 15 | text-align: center; 16 | &.#{$fa-css-prefix}-lg { 17 | left: -$fa-li-width + (4em / 14); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/components/icon/iconfont/scss/_mixins.scss: -------------------------------------------------------------------------------- 1 | // Mixins 2 | // -------------------------- 3 | 4 | @mixin fa-icon() { 5 | display: inline-block; 6 | font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | } 13 | 14 | @mixin fa-icon-rotate($degrees, $rotation) { 15 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation})"; 16 | -webkit-transform: rotate($degrees); 17 | -ms-transform: rotate($degrees); 18 | transform: rotate($degrees); 19 | } 20 | 21 | @mixin fa-icon-flip($horiz, $vert, $rotation) { 22 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}, mirror=1)"; 23 | -webkit-transform: scale($horiz, $vert); 24 | -ms-transform: scale($horiz, $vert); 25 | transform: scale($horiz, $vert); 26 | } 27 | 28 | 29 | // Only display content to screen readers. A la Bootstrap 4. 30 | // 31 | // See: http://a11yproject.com/posts/how-to-hide-content/ 32 | 33 | @mixin sr-only { 34 | position: absolute; 35 | width: 1px; 36 | height: 1px; 37 | padding: 0; 38 | margin: -1px; 39 | overflow: hidden; 40 | clip: rect(0,0,0,0); 41 | border: 0; 42 | } 43 | 44 | // Use in conjunction with .sr-only to only display content when it's focused. 45 | // 46 | // Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1 47 | // 48 | // Credit: HTML5 Boilerplate 49 | 50 | @mixin sr-only-focusable { 51 | &:active, 52 | &:focus { 53 | position: static; 54 | width: auto; 55 | height: auto; 56 | margin: 0; 57 | overflow: visible; 58 | clip: auto; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/components/icon/iconfont/scss/_path.scss: -------------------------------------------------------------------------------- 1 | /* FONT PATH 2 | * -------------------------- */ 3 | 4 | @font-face { 5 | font-family: 'FontAwesome'; 6 | src: url('#{$fa-font-path}/fontawesome-webfont.eot?v=#{$fa-version}'); 7 | src: url('#{$fa-font-path}/fontawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'), 8 | url('#{$fa-font-path}/fontawesome-webfont.woff2?v=#{$fa-version}') format('woff2'), 9 | url('#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}') format('woff'), 10 | url('#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'), 11 | url('#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg'); 12 | // src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts 13 | font-weight: normal; 14 | font-style: normal; 15 | } 16 | -------------------------------------------------------------------------------- /src/components/icon/iconfont/scss/_rotated-flipped.scss: -------------------------------------------------------------------------------- 1 | // Rotated & Flipped Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-rotate-90 { @include fa-icon-rotate(90deg, 1); } 5 | .#{$fa-css-prefix}-rotate-180 { @include fa-icon-rotate(180deg, 2); } 6 | .#{$fa-css-prefix}-rotate-270 { @include fa-icon-rotate(270deg, 3); } 7 | 8 | .#{$fa-css-prefix}-flip-horizontal { @include fa-icon-flip(-1, 1, 0); } 9 | .#{$fa-css-prefix}-flip-vertical { @include fa-icon-flip(1, -1, 2); } 10 | 11 | // Hook for IE8-9 12 | // ------------------------- 13 | 14 | :root .#{$fa-css-prefix}-rotate-90, 15 | :root .#{$fa-css-prefix}-rotate-180, 16 | :root .#{$fa-css-prefix}-rotate-270, 17 | :root .#{$fa-css-prefix}-flip-horizontal, 18 | :root .#{$fa-css-prefix}-flip-vertical { 19 | filter: none; 20 | } 21 | -------------------------------------------------------------------------------- /src/components/icon/iconfont/scss/_screen-reader.scss: -------------------------------------------------------------------------------- 1 | // Screen Readers 2 | // ------------------------- 3 | 4 | .sr-only { @include sr-only(); } 5 | .sr-only-focusable { @include sr-only-focusable(); } 6 | -------------------------------------------------------------------------------- /src/components/icon/iconfont/scss/_stacked.scss: -------------------------------------------------------------------------------- 1 | // Stacked Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-stack { 5 | position: relative; 6 | display: inline-block; 7 | width: 2em; 8 | height: 2em; 9 | line-height: 2em; 10 | vertical-align: middle; 11 | } 12 | .#{$fa-css-prefix}-stack-1x, .#{$fa-css-prefix}-stack-2x { 13 | position: absolute; 14 | left: 0; 15 | width: 100%; 16 | text-align: center; 17 | } 18 | .#{$fa-css-prefix}-stack-1x { line-height: inherit; } 19 | .#{$fa-css-prefix}-stack-2x { font-size: 2em; } 20 | .#{$fa-css-prefix}-inverse { color: $fa-inverse; } 21 | -------------------------------------------------------------------------------- /src/components/icon/iconfont/scss/font-awesome.scss: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome 3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) 4 | */ 5 | 6 | @import "variables"; 7 | @import "mixins"; 8 | @import "path"; 9 | @import "core"; 10 | @import "larger"; 11 | @import "fixed-width"; 12 | @import "list"; 13 | @import "bordered-pulled"; 14 | @import "animated"; 15 | @import "rotated-flipped"; 16 | @import "stacked"; 17 | @import "icons"; 18 | @import "screen-reader"; 19 | -------------------------------------------------------------------------------- /src/components/icon/index.tsx: -------------------------------------------------------------------------------- 1 | import Icon from './icon' 2 | 3 | export default Icon 4 | -------------------------------------------------------------------------------- /src/components/icon/style/index.dev.scss: -------------------------------------------------------------------------------- 1 | @import '../../style/index.scss'; 2 | $fa-font-path: "../iconfont/fonts"; 3 | @import "../iconfont/scss/font-awesome.scss"; 4 | $icon: 'cp-ui-icon'; -------------------------------------------------------------------------------- /src/components/icon/style/index.scss: -------------------------------------------------------------------------------- 1 | @import '../../style/index.scss'; 2 | $fa-font-path: "../fonts"; 3 | @import "../iconfont/scss/font-awesome.scss"; 4 | $icon: 'cp-ui-icon'; -------------------------------------------------------------------------------- /src/components/icon/style/index.tsx: -------------------------------------------------------------------------------- 1 | import '../../style/index' 2 | 3 | if (process.env.NODE_ENV === 'dev') { 4 | require('./index.dev.scss') 5 | } else { 6 | require('./index.scss') 7 | } 8 | -------------------------------------------------------------------------------- /src/components/image-picker/index.tsx: -------------------------------------------------------------------------------- 1 | import ImagePicker from './image-picker' 2 | 3 | export default ImagePicker 4 | -------------------------------------------------------------------------------- /src/components/image-picker/interface.tsx: -------------------------------------------------------------------------------- 1 | export type OperationType = 'add' | 'remove' 2 | export interface FileItemProps { 3 | // 本地FileReader生成dataurl链接 4 | url?: string 5 | // 文件元素标识 6 | index?: number 7 | // 方向 8 | orientation?: number 9 | // 文件 10 | file?: File 11 | // 内置_type,默认为add图标 12 | _type?: string 13 | } 14 | export interface ImagePickerProps { 15 | // onChange 16 | onChange: (files: Array, operation: OperationType, index?: number) => void 17 | // files 18 | fileList: Array 19 | // 是否允许多张 默认为false 20 | multiple: boolean 21 | // maxLength 最大长度 22 | maxLength?: number 23 | // accept 接受上传的文件类型 默认为image/* 24 | accept: string 25 | // disabled 是否禁用 默认为false 26 | disabled: boolean 27 | // className 28 | className?: string 29 | // selectable 是否显示可添加按钮 默认为true 30 | selectable: boolean 31 | // 选择失败触发的回调 32 | onFail: (reason?: string) => void 33 | // preview 是否开启预览 默认为false 34 | preview: boolean 35 | // 是否隐藏删除按钮 默认为false 36 | disableDelete: boolean 37 | // onPreview 点击预览的回调 两个参数 38 | onPreview: (file: FileItemProps, index?: number) => void 39 | // 删除时候的回调 40 | onRemove: (file: FileItemProps, index?: number) => void 41 | } 42 | -------------------------------------------------------------------------------- /src/components/image-picker/style/index.tsx: -------------------------------------------------------------------------------- 1 | import '../../style/index' 2 | import './index.scss' 3 | -------------------------------------------------------------------------------- /src/components/index.tsx: -------------------------------------------------------------------------------- 1 | import Icon from './icon' 2 | import Button from './button' 3 | import Input from './input' 4 | import { Row, Col } from './grid' 5 | import Affix from './affix' 6 | import Avatar from './avatar' 7 | import Badge from './badge' 8 | import Card from './card' 9 | import { CheckboxGroup, Checkbox } from './checkbox' 10 | import Accordion from './accordion' 11 | import Divider from './divider' 12 | import Toast from './toast' 13 | import Modal from './modal' 14 | import Overlay from './overlay' 15 | import Pagination from './pagination' 16 | import Progress from './progress' 17 | import { Radio } from './radio' 18 | import Slider from './slider' 19 | import Spin from './spin' 20 | import Step from './step' 21 | import Switch from './switch' 22 | import Tabs from './tabs' 23 | import Tag from './tag' 24 | import ImagePicker from './image-picker' 25 | import ActionSheet from './action-sheet' 26 | import TabBar from './tab-bar' 27 | import { PickerPanel, Picker } from './picker' 28 | import SegmentedControl from './segmented-control' 29 | import Popover from './popover' 30 | import NoticeBar from './notice-bar' 31 | import SwipeAction from './swipe-action' 32 | import ListView from './list-view' 33 | export { 34 | Icon, 35 | Button, 36 | Input, 37 | Row, 38 | Col, 39 | Affix, 40 | Avatar, 41 | Badge, 42 | Card, 43 | CheckboxGroup, 44 | Checkbox, 45 | Accordion, 46 | Divider, 47 | Modal, 48 | Overlay, 49 | Pagination, 50 | Progress, 51 | Radio, 52 | Slider, 53 | Step, 54 | Spin, 55 | Switch, 56 | Tabs, 57 | Tag, 58 | ImagePicker, 59 | Toast, 60 | ActionSheet, 61 | TabBar, 62 | PickerPanel, 63 | Picker, 64 | SegmentedControl, 65 | Popover, 66 | NoticeBar, 67 | SwipeAction, 68 | ListView 69 | } 70 | -------------------------------------------------------------------------------- /src/components/input/index.tsx: -------------------------------------------------------------------------------- 1 | import Input from './input' 2 | 3 | export default Input 4 | -------------------------------------------------------------------------------- /src/components/input/interface.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import { Omit } from '../utils/type' 3 | 4 | type InputType = 'text' | 'number' | 'mobile' | 'bankCard' | 'password' 5 | type OmitProps = 'type' | 'prefix' | 'onChange' | 'onBlur' | 'value' | 'defaultValue' 6 | 7 | // 对omit的具体用法可以查看typescript的官网关于picker和exclude的用法,就是集合的概念 8 | export interface InputProps extends Omit, OmitProps> { 9 | // 当前值 10 | value?: string 11 | // 默认值 12 | defaultValue?: string 13 | //获取元素组件的ref 14 | getInputRef?: (ele: HTMLInputElement) => void 15 | // 类型 16 | type: InputType 17 | // prefix 18 | prefix?: React.ReactNode 19 | // 内嵌input前缀 20 | inlinePrefix?: React.ReactNode 21 | // 内嵌input前缀 22 | inlineSuffix?: React.ReactNode 23 | // suffix11 24 | suffix?: React.ReactNode 25 | // 错误提示 26 | error?: React.ReactNode 27 | // 是否禁用输入框 28 | disabled?: boolean 29 | // clear 是否显示清除 默认为false 30 | clear: boolean 31 | // 前置点击 32 | addonBefore?: React.ReactNode 33 | // 后置点击 34 | addonAfter?: React.ReactNode 35 | // onChange 36 | onChange: (value: string) => void 37 | // onBlur 38 | onBlur: (value?: string, e?: React.FocusEvent) => void 39 | } 40 | -------------------------------------------------------------------------------- /src/components/input/style/index.tsx: -------------------------------------------------------------------------------- 1 | import '../../style/index' 2 | import './index.scss' 3 | -------------------------------------------------------------------------------- /src/components/list-view/index.tsx: -------------------------------------------------------------------------------- 1 | import ListView from './list-view' 2 | export default ListView 3 | -------------------------------------------------------------------------------- /src/components/list-view/interface.tsx: -------------------------------------------------------------------------------- 1 | export interface PullDownRefreshProps { 2 | setMove: React.Dispatch> 3 | setTranslateY: React.Dispatch> 4 | setPullDownStatus: React.Dispatch> 5 | listViewStatusRefs: React.MutableRefObject<{ 6 | scrollTop: number 7 | touchX: number 8 | touchY: number 9 | time: number 10 | type: string 11 | pullDownDoneBacking: boolean 12 | }> 13 | } 14 | export interface RefreshContainer { 15 | text: string 16 | icon: string | React.ReactNode 17 | } 18 | export interface RefreshTips { 19 | loading?: RefreshContainer 20 | success?: RefreshContainer 21 | error?: RefreshContainer 22 | actionRelease?: string 23 | actionDown?: string 24 | } 25 | export interface UpLoadTips { 26 | loading: string | React.ReactNode 27 | success?: string | React.ReactNode 28 | error?: string | React.ReactNode 29 | } 30 | export interface ListViewProps { 31 | //下拉加载注册的方法 32 | pullDownRefresh?: () => void 33 | //上拉加载注册的方法 34 | pullUpLoad?: () => Promise 35 | //下拉加载是否有数据 36 | noMore: boolean 37 | //下拉加载没有数据时的提示 38 | noMoreTip?: string | React.ReactElement 39 | //内容必须大于外层容器 40 | children?: React.ReactElement 41 | //外层容器调用listview的方法 42 | listViewHandleRefs?: React.MutableRefObject 43 | //类名 44 | className?: string 45 | //前缀 46 | prefixCls?: string 47 | //样式 48 | style?: React.CSSProperties 49 | //下拉刷新文案 50 | refreshTips?: RefreshTips 51 | //上拉加载文案 52 | upLoadTips?: UpLoadTips 53 | } 54 | export interface ListViewHandlesProps { 55 | //初始化可调用上拉加载 56 | pullDownRefreshRenderData: () => void 57 | } 58 | -------------------------------------------------------------------------------- /src/components/list-view/style/index.scss: -------------------------------------------------------------------------------- 1 | @import '../../style/index.scss'; 2 | 3 | $list-view: 'cp-ui-list-view'; 4 | .#{$list-view} { 5 | * { 6 | touch-action: initial; 7 | } 8 | @mixin pullBox() { 9 | height: 30px; 10 | line-height: 30px; 11 | text-align: center; 12 | font-size: 12px; 13 | color: #999; 14 | position: relative; 15 | 16 | img { 17 | width: auto; 18 | height: 16px; 19 | vertical-align: -4px; 20 | margin-right: 10px; 21 | transition: transform 0.3s ease; 22 | } 23 | } 24 | 25 | position: absolute; 26 | top: 0; 27 | bottom: 0; 28 | width: 100%; 29 | overflow-y: auto; 30 | scrollbar-width: none; 31 | -webkit-overflow-scrolling: touch; 32 | -ms-overflow-style: none; 33 | overflow: -moz-scrollbars-none; 34 | 35 | &::-webkit-scrollbar { 36 | width: 0 !important; 37 | } 38 | 39 | &-pull-down-tip, 40 | &-pull-up-tip { 41 | @include pullBox(); 42 | } 43 | 44 | &-pull-down-tip { 45 | margin-top: -30px; 46 | } 47 | 48 | .back_top { 49 | position: absolute; 50 | bottom: 10px; 51 | right: 10px; 52 | z-index: 2; 53 | display: none; 54 | 55 | i { 56 | font-size: 44px; 57 | color: #1296db; 58 | } 59 | 60 | img { 61 | width: 42px; 62 | height: 42px; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/components/list-view/style/index.tsx: -------------------------------------------------------------------------------- 1 | import '../../style/index' 2 | import './index.scss' 3 | -------------------------------------------------------------------------------- /src/components/modal/index.tsx: -------------------------------------------------------------------------------- 1 | import Modal from './modal' 2 | 3 | export default Modal 4 | -------------------------------------------------------------------------------- /src/components/modal/interface.tsx: -------------------------------------------------------------------------------- 1 | export interface ModalProps { 2 | // prefixCls 3 | prefixCls: string 4 | // 类名 5 | className?: string 6 | // 弹出层名字 7 | maskClassName?: string 8 | // animationName 区域动画 默认为fade 9 | animationName?: string 10 | // 弹出层动画类名 默认为fade 11 | maskAnimationName?: string 12 | // visible 是否可见 默认为false 13 | visible: boolean 14 | // title 15 | title?: React.ReactNode 16 | // maskClosable 默认为true 点击浮层是否允许关闭 17 | maskClosable: boolean 18 | // children 内容区域 19 | children?: React.ReactNode 20 | // closable 是否显示叉号 默认为true 21 | closable: boolean 22 | // okText 确认文本 默认为确认 23 | okText: React.ReactNode 24 | // cancelText 取消文本 默认为取消 25 | cancelText: React.ReactNode 26 | // onOk 点击确定按钮的回调 27 | onOk: () => void 28 | // onCancel 点击遮罩层或右上角叉或取消按钮的回调 29 | onCancel: () => void 30 | // destroy 是否销毁 默认为true 关闭后默认销毁 31 | destroy: boolean 32 | // closeIcon 取消的Icon 33 | closeIcon?: React.ReactNode 34 | // footer 35 | footer?: React.ReactNode 36 | } 37 | -------------------------------------------------------------------------------- /src/components/modal/style/index.tsx: -------------------------------------------------------------------------------- 1 | import '../../style/index' 2 | import './index.scss' 3 | -------------------------------------------------------------------------------- /src/components/notice-bar/index.tsx: -------------------------------------------------------------------------------- 1 | import NoticeBar from './notice-bar' 2 | 3 | export default NoticeBar 4 | -------------------------------------------------------------------------------- /src/components/notice-bar/interface.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | export interface NoticeBarPropsType { 4 | mode?: 'closable' | 'link' 5 | onClick?: () => void 6 | icon?: React.ReactElement | null 7 | action?: React.ReactElement 8 | } 9 | export interface NoticeBarProps extends NoticeBarPropsType { 10 | marqueeProps?: MarqueeProps 11 | className?: string 12 | prefixCls?: string 13 | style?: React.CSSProperties 14 | } 15 | export interface MarqueeProps { 16 | prefixCls?: string 17 | text?: string 18 | loop?: boolean 19 | leading?: number 20 | trailing?: number 21 | className?: string 22 | fps?: number 23 | style?: React.CSSProperties 24 | } 25 | -------------------------------------------------------------------------------- /src/components/notice-bar/style/index.scss: -------------------------------------------------------------------------------- 1 | $cp-ui-notice: 'cp-ui-notice-bar'; 2 | @import '../../style/index.scss'; 3 | 4 | .#{$cp-ui-notice} { 5 | background-color: rgba(132, 130, 129, 0.02); 6 | height: 36px; 7 | overflow: hidden; 8 | font-size: 14px; 9 | line-height: 36px; 10 | color: $color-brand-normal; 11 | display: -webkit-box; 12 | display: -webkit-flex; 13 | display: -ms-flexbox; 14 | display: flex; 15 | 16 | &-content { 17 | -webkit-box-flex: 1; 18 | -webkit-flex: 1; 19 | -ms-flex: 1; 20 | flex: 1; 21 | margin: auto 15px; 22 | width: auto; 23 | overflow: hidden; 24 | text-overflow: ellipsis; 25 | white-space: nowrap; 26 | } 27 | 28 | &-icon { 29 | margin-left: 5px; 30 | display: flex; 31 | align-items: center; 32 | 33 | & + div { 34 | margin-left: 5px; 35 | } 36 | } 37 | 38 | &-operation { 39 | display: flex; 40 | align-items: center; 41 | padding-right: 8px; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/components/notice-bar/style/index.tsx: -------------------------------------------------------------------------------- 1 | import '../../style/index' 2 | import './index.scss' 3 | -------------------------------------------------------------------------------- /src/components/overlay/index.tsx: -------------------------------------------------------------------------------- 1 | import Overlay from './overlayWrapper' 2 | 3 | export default Overlay 4 | -------------------------------------------------------------------------------- /src/components/overlay/interface.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | export interface OverlayProps { 4 | // prefixCls 5 | prefixCls: string 6 | // 类名 7 | className?: string 8 | // 弹出层名字 9 | maskClassName?: string 10 | // animationName 区域动画 默认为fade 11 | animationName: string 12 | // 弹出层动画类名 默认为fade 13 | maskAnimationName: string 14 | // visible 是否可见 默认为false 15 | visible: boolean 16 | // header 是否显示头部 17 | header?: React.ReactNode 18 | // mask 是否显示浮层 默认不显示浮层 19 | mask: boolean 20 | // maskClosable 默认为false 点击浮层是否允许关闭 21 | maskClosable: boolean 22 | // children 内容区域 23 | children?: React.ReactNode 24 | // closable 是否显示叉号 默认为false 25 | closable: boolean 26 | // close 关闭的节点可以自行定义 27 | close?: React.ReactNode 28 | // footer 29 | footer?: React.ReactNode 30 | // autoFix 是否开启自适应 在超出边界的时候会自动调整方向 默认为false 31 | autoFix: boolean 32 | // 关闭的回调,点击浮层关闭或者关闭按钮关闭都会调用此函数 33 | onClose: () => void 34 | // destroy 是否销毁 默认为true 关闭后默认销毁 35 | destroy: boolean 36 | // style 样式 37 | style?: React.CSSProperties 38 | // zIndex 层级 默认999 39 | zIndex?: number 40 | } 41 | 42 | export type Trigger = 'click' | 'hover' 43 | export type Direction = 44 | | 'top' 45 | | 'left' 46 | | 'bottom' 47 | | 'right' 48 | | 'leftBottom' 49 | | 'leftTop' 50 | | 'rightTop' 51 | | 'rightBottom' 52 | | 'topLeft' 53 | | 'topRight' 54 | | 'bottomLeft' 55 | | 'bottomRight' 56 | // 带有位置的一类 57 | export interface PopupProps { 58 | // 触发方式 59 | trigger: Trigger 60 | // direction 61 | direction: Direction 62 | // className 63 | className?: string 64 | // style 65 | style?: React.CSSProperties 66 | // children 67 | children?: React.ReactNode 68 | // visible 是否显示, dropdown, tooltip,popover可以在此基础上封装 默认为false 69 | visible: boolean 70 | } 71 | -------------------------------------------------------------------------------- /src/components/overlay/overlayWrapper.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import { createPortal } from 'react-dom' 3 | import { CSSTransition } from 'react-transition-group' 4 | import { OverlayProps } from './interface' 5 | import Overlay from './overlay' 6 | 7 | const noop = () => {} 8 | const { useState } = React 9 | 10 | const defaultProps: OverlayProps = { 11 | prefixCls: 'cp-ui-overlay', 12 | visible: false, 13 | mask: true, 14 | maskClosable: true, 15 | closable: false, 16 | autoFix: false, 17 | destroy: true, 18 | onClose: noop, 19 | maskAnimationName: 'fade', 20 | animationName: 'fade' 21 | } 22 | 23 | const setBodyStyle = (visible: boolean) => { 24 | document.body.style.overflow = visible ? 'hidden' : 'auto' 25 | } 26 | 27 | const OverlayWrapper: React.FC & { defaultProps: Partial } = props => { 28 | const [firstTime, setFirstTime] = useState(true) 29 | const { visible, destroy, prefixCls } = props 30 | 31 | if (visible) { 32 | if (firstTime) { 33 | setFirstTime(false) 34 | } 35 | } 36 | 37 | // 处理destroy为false的时候第一次没动画的问题 38 | const getUnmount = () => { 39 | let props: any = {} 40 | if (destroy) { 41 | props.unmountOnExit = true 42 | } else { 43 | if (firstTime) { 44 | props.unmountOnExit = true 45 | } else { 46 | props.unmountOnExit = false 47 | } 48 | } 49 | return props 50 | } 51 | 52 | if (!destroy) { 53 | setBodyStyle(visible) 54 | } 55 | return createPortal( 56 | 62 | 63 | , 64 | document.body 65 | ) 66 | } 67 | 68 | OverlayWrapper.defaultProps = defaultProps 69 | 70 | export default OverlayWrapper 71 | -------------------------------------------------------------------------------- /src/components/pagination/index.tsx: -------------------------------------------------------------------------------- 1 | import Pagination from './pagination' 2 | 3 | export default Pagination 4 | -------------------------------------------------------------------------------- /src/components/pagination/interface.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | export type SizeProps = 'small' | 'medium' | 'large' 4 | 5 | /** 6 | * 此组件完全受控 7 | */ 8 | export interface PaginationProps { 9 | // 当前页数 默认为1 10 | current: number 11 | // onChange 12 | onChange: (page: string | number) => void 13 | // pageSize 每页的条数 默认为10条 14 | pageSize: number 15 | // total 数据总数 默认为0 16 | total: number 17 | // size 默认为middle 18 | size: SizeProps 19 | // className 类名 20 | className?: string 21 | // pre 上一步 可以自定义 22 | preStep?: React.ReactNode 23 | // next 下一步 可以自定义 24 | nextStep?: React.ReactNode 25 | // 是否隐藏数值 26 | simple?: boolean 27 | // mode 形态,可选number,pointer 28 | mode?: 'number' | 'pointer' 29 | } 30 | -------------------------------------------------------------------------------- /src/components/pagination/style/index.tsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10086XIAOZHANG/CP-DESIGN/9971e3f9cf0ae1b311ceb6135cb1ffb812c3640b/src/components/pagination/style/index.tsx -------------------------------------------------------------------------------- /src/components/picker/index.tsx: -------------------------------------------------------------------------------- 1 | import PickerPanel from './picker-panel' 2 | import Picker from './picker' 3 | export { PickerPanel, Picker } 4 | -------------------------------------------------------------------------------- /src/components/picker/interface.tsx: -------------------------------------------------------------------------------- 1 | export interface PickerColumnProps { 2 | options: string[] 3 | name: string 4 | value: string 5 | itemHeight: number 6 | columnHeight: number 7 | onChange: (name: string, value: string) => void 8 | onClick: (name: string, value: string) => void 9 | } 10 | export interface PickerPanelProps { 11 | //数据集合key对应数组集合 12 | optionGroups: object 13 | //value对象类型,key和数据集合中key相对应 14 | valueGroups: object 15 | //选中后的回调 16 | onChange: (name: string, value: string) => void 17 | //点击后的回调 18 | onClick: (name: string, value: string) => void 19 | //行高度 20 | itemHeight: number 21 | //弹层高度 22 | height: number 23 | } 24 | export interface PickerItemProps { 25 | value: string 26 | label: string 27 | children?: PickerItemProps[] 28 | } 29 | export interface PickerProps { 30 | //数据集合key对应数组集合 31 | data: object 32 | //value对象类型,key和数据集合中key相对应 33 | valueGroups: object 34 | //选中后的回调 35 | onChange: (name: string, value: string) => void 36 | //当显隐状态变化时回调函数 37 | onVisibleChange?: (visible: boolean) => void 38 | //选中的文案 39 | okText: string | React.ReactElement 40 | //取消选中的文案 41 | dismissText: string | React.ReactElement 42 | //标题 43 | title: string | React.ReactElement 44 | //点击选中时执行的回调 45 | onOk?: (value: object) => void 46 | //点击取消时执行的回调 47 | onDismiss?: () => void 48 | } 49 | -------------------------------------------------------------------------------- /src/components/picker/picker-panel.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import ClassNames from 'classnames' 3 | import PickerColumn from './picker-column' 4 | import { PickerPanelProps } from './interface' 5 | import './style' 6 | const prefixCls = 'cp-ui-picker-panel' 7 | 8 | const defaultProps = { 9 | onClick: () => {}, 10 | itemHeight: 36, 11 | height: 216 12 | } 13 | const renderInner = (props: PickerPanelProps) => { 14 | const { optionGroups, valueGroups, itemHeight, height, onChange, onClick } = props 15 | 16 | const highlightStyle = { 17 | height: itemHeight, 18 | marginTop: -(itemHeight / 2) 19 | } 20 | 21 | const columnNodes = [] 22 | for (let name in optionGroups) { 23 | if (optionGroups.hasOwnProperty(name)) { 24 | columnNodes.push( 25 | 35 | ) 36 | } 37 | } 38 | return ( 39 |
40 | {columnNodes} 41 |
42 |
43 | ) 44 | } 45 | const getClassNames = () => { 46 | return ClassNames(prefixCls, `${prefixCls}-container`) 47 | } 48 | const PickerPanel: React.FC & { 49 | defaultProps: Partial 50 | } = props => { 51 | const { height } = props 52 | 53 | const style: React.CSSProperties = { 54 | height: height 55 | } 56 | const classStr = getClassNames() 57 | return ( 58 |
59 | {renderInner(props)} 60 |
61 | ) 62 | } 63 | 64 | PickerPanel.defaultProps = defaultProps 65 | 66 | export default PickerPanel 67 | -------------------------------------------------------------------------------- /src/components/picker/style/index.tsx: -------------------------------------------------------------------------------- 1 | import '../../style/index' 2 | import './index.scss' 3 | -------------------------------------------------------------------------------- /src/components/popover/index.tsx: -------------------------------------------------------------------------------- 1 | import PopoverWapper from './popover' 2 | import PopoverItem from './item' 3 | export default { PopoverWapper, PopoverItem } 4 | -------------------------------------------------------------------------------- /src/components/popover/interface.tsx: -------------------------------------------------------------------------------- 1 | export interface PopoverPropsType { 2 | onSelect?: (node: any, index?: number) => void 3 | overlay: React.ReactNode 4 | disabled?: boolean 5 | } 6 | type PlacementProps = 7 | | 'left' 8 | | 'right' 9 | | 'top' 10 | | 'bottom' 11 | | 'topLeft' 12 | | 'topRight' 13 | | 'bottomLeft' 14 | | 'bottomRight' 15 | export interface PopOverPropsType extends PopoverPropsType { 16 | prefixCls: string 17 | placement: PlacementProps 18 | visible?: boolean 19 | onVisibleChange?: (visible: boolean) => void 20 | align?: {} 21 | mask?: boolean 22 | } 23 | 24 | export interface PopoverItemProps { 25 | className?: string 26 | prefixCls?: string 27 | icon?: React.ReactNode 28 | disabled?: boolean 29 | firstItem?: string 30 | activeStyle?: React.CSSProperties 31 | style?: React.CSSProperties 32 | } 33 | -------------------------------------------------------------------------------- /src/components/popover/item.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import Classnames from 'classnames' 3 | import { PopoverItemProps } from './interface' 4 | 5 | const defaultProps = { 6 | prefixCls: 'cp-ui-popover', 7 | disabled: false 8 | } 9 | 10 | const getClassNames = ({ prefixCls, className, disabled }: PopoverItemProps) => { 11 | return Classnames(`${prefixCls}-item`, className, { 12 | [`${prefixCls}-item-disabled`]: disabled 13 | }) 14 | } 15 | 16 | const Item: React.FC & { 17 | defaultProps: Partial 18 | itemName: string 19 | } = props => { 20 | const { 21 | children, 22 | className, 23 | prefixCls, 24 | icon, 25 | disabled, 26 | firstItem, 27 | activeStyle, 28 | ...restProps 29 | } = props 30 | const classStr = getClassNames(props) 31 | 32 | return ( 33 |
34 |
35 | {icon ? ( 36 | 39 | ) : null} 40 | {children} 41 |
42 |
43 | ) 44 | } 45 | 46 | Item.defaultProps = defaultProps 47 | Item.itemName = 'PopoverItem' 48 | 49 | export default Item 50 | -------------------------------------------------------------------------------- /src/components/popover/popover.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import Tooltip from 'rmc-tooltip' 3 | import { PopOverPropsType } from './interface' 4 | import './style' 5 | 6 | const recursiveCloneChildren = ( 7 | children: any, 8 | cb = (ch: React.ReactChild, _: number) => ch 9 | ): React.ReactChild[] => { 10 | return React.Children.map(children, (child, index) => { 11 | const newChild = cb(child, index) 12 | if ( 13 | typeof newChild !== 'string' && 14 | typeof newChild !== 'number' && 15 | newChild && 16 | newChild.props && 17 | newChild.props.children 18 | ) { 19 | return React.cloneElement(newChild, {}, recursiveCloneChildren(newChild.props.children, cb)) 20 | } 21 | return newChild 22 | }) 23 | } 24 | 25 | const defaultProps = { 26 | prefixCls: 'cp-ui-popover' 27 | } 28 | 29 | const Popover: React.FC & { 30 | defaultProps: Partial 31 | } = props => { 32 | const { 33 | overlay, 34 | onSelect = () => {}, 35 | align = { overflow: { adjustY: 0, adjustX: 0 } }, 36 | placement = 'bottomRight', 37 | ...restProps 38 | } = props 39 | 40 | const overlayNode = recursiveCloneChildren(overlay, (child, index) => { 41 | const extraProps: any = { firstItem: false } 42 | if ( 43 | child && 44 | typeof child !== 'string' && 45 | typeof child !== 'number' && 46 | child.type && 47 | // Fixme: not sure where the `itemName` came from. 48 | (child.type as any).itemName === 'PopoverItem' && 49 | !child.props.disabled 50 | ) { 51 | extraProps.onClick = () => onSelect(child, index) 52 | extraProps.firstItem = index === 0 53 | return React.cloneElement(child, extraProps) 54 | } 55 | return child 56 | }) 57 | const wrapperNode =
{overlayNode}
58 | 59 | return 60 | } 61 | Popover.defaultProps = defaultProps 62 | export default Popover 63 | -------------------------------------------------------------------------------- /src/components/popover/style/base.scss: -------------------------------------------------------------------------------- 1 | @import '../../style/index.scss'; 2 | $popover: cp-ui-popover; 3 | $popover-arrow-width: 7 * $hd; 4 | 5 | // Base class 6 | .#{$popover} { 7 | position: absolute; 8 | z-index: 1999; 9 | 10 | &-hidden { 11 | display: none; 12 | } 13 | 14 | &-mask { 15 | position: fixed; 16 | top: 0; 17 | right: 0; 18 | left: 0; 19 | bottom: 0; 20 | background-color: rgba(0, 0, 0, 0.4); 21 | height: 100%; 22 | z-index: 999; 23 | 24 | &-hidden { 25 | display: none; 26 | } 27 | } 28 | 29 | &-placement-top &-arrow, 30 | &-placement-topLeft &-arrow, 31 | &-placement-topRight &-arrow { 32 | transform: rotate(225deg); 33 | bottom: -$popover-arrow-width/2; 34 | } 35 | 36 | &-placement-top &-arrow { 37 | left: 50%; 38 | } 39 | 40 | &-placement-topLeft &-arrow { 41 | left: 8px; 42 | } 43 | 44 | &-placement-topRight &-arrow { 45 | right: 8px; 46 | } 47 | 48 | &-placement-right &-arrow, 49 | &-placement-rightTop &-arrow, 50 | &-placement-rightBottom &-arrow { 51 | transform: rotate(-45deg); 52 | left: -$popover-arrow-width/2; 53 | } 54 | 55 | &-placement-right &-arrow { 56 | top: 50%; 57 | } 58 | 59 | &-placement-rightTop &-arrow { 60 | top: 8px; 61 | } 62 | 63 | &-placement-rightBottom &-arrow { 64 | bottom: 8px; 65 | } 66 | 67 | &-placement-left &-arrow, 68 | &-placement-leftTop &-arrow, 69 | &-placement-leftBottom &-arrow { 70 | transform: rotate(135deg); 71 | right: -$popover-arrow-width/2; 72 | } 73 | 74 | &-placement-left &-arrow { 75 | top: 50%; 76 | } 77 | 78 | &-placement-leftTop &-arrow { 79 | top: 8px; 80 | } 81 | 82 | &-placement-leftBottom &-arrow { 83 | bottom: 8px; 84 | } 85 | 86 | &-placement-bottom &-arrow, 87 | &-placement-bottomLeft &-arrow, 88 | &-placement-bottomRight &-arrow { 89 | top: -$popover-arrow-width/2; 90 | } 91 | 92 | &-placement-bottom &-arrow { 93 | left: 50%; 94 | } 95 | 96 | &-placement-bottomLeft &-arrow { 97 | left: 8px; 98 | } 99 | 100 | &-placement-bottomRight &-arrow { 101 | right: 8px; 102 | } 103 | // Arrows 104 | &-arrow { 105 | position: absolute; 106 | width: 7px; 107 | height: 7px; 108 | background-color: rgb(255, 255, 255); 109 | transform: rotate(45deg); 110 | z-index: 0; 111 | box-shadow: rgba(0, 0, 0, 0.21) 0 0 2px; 112 | border-radius: 1px; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/components/popover/style/index.scss: -------------------------------------------------------------------------------- 1 | @import './base'; 2 | 3 | .#{$popover} { 4 | &-inner { 5 | font-size: 15px; 6 | color: rgb(0, 0, 0); 7 | background-color: rgb(255, 255, 255); 8 | box-shadow: rgba(0, 0, 0, 0.21) 0 0 2px; 9 | border-radius: 3px; 10 | overflow: hidden; 11 | 12 | &-wrapper { 13 | position: relative; 14 | background-color: rgb(255, 255, 255); 15 | } 16 | } 17 | 18 | &-item { 19 | padding: 0 8px; 20 | 21 | &-container { 22 | position: relative; 23 | display: flex; 24 | -webkit-box-align: center; 25 | align-items: center; 26 | height: 39px; 27 | box-sizing: border-box; 28 | padding: 0 8px; 29 | } 30 | 31 | &:not(:first-child) { 32 | .#{$popover}-item-container { 33 | border-top: none; 34 | } 35 | } 36 | 37 | &-active { 38 | .#{$popover}-item-container { 39 | border-top: 0; 40 | } 41 | } 42 | 43 | &.#{$popover}-item-active+.#{$popover}-item .#{$popover}-item-container { 44 | border-top: 0; 45 | } 46 | 47 | &.#{$popover}-item-active { 48 | background-color: #ddd; 49 | } 50 | 51 | &.#{$popover}-item-active.#{$popover}-item-fix-active-arrow { 52 | position: relative; 53 | } 54 | 55 | &.#{$popover}-item-disabled { 56 | color: $color-text-disabled; 57 | 58 | &.#{$popover}-item-active { 59 | background-color: transparent; 60 | } 61 | } 62 | 63 | &-icon { 64 | margin-right: 8px; 65 | width: 18px; 66 | height: 18px; 67 | } 68 | 69 | &-content { 70 | line-height: 18px; 71 | height: 18px; 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/components/popover/style/index.tsx: -------------------------------------------------------------------------------- 1 | import '../../style/index' 2 | import './index.scss' 3 | -------------------------------------------------------------------------------- /src/components/progress/index.tsx: -------------------------------------------------------------------------------- 1 | import Progress from './progress' 2 | 3 | export default Progress 4 | -------------------------------------------------------------------------------- /src/components/progress/interface.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | export type SizeType = 'small' | 'medium' | 'large' 4 | 5 | export type Type = 'line' | 'circle' 6 | 7 | export type StatusType = 'normal' | 'success' | 'error' 8 | 9 | export interface ProgressProps { 10 | // 尺寸 默认为normal 11 | size: SizeType 12 | // type 类型 默认为line 13 | type: Type 14 | // percent 当前的进度 默认为 0 15 | percent: number 16 | // showInfo 是否显示进度条的数值, 默认为true 17 | showInfo: boolean 18 | // status 状态 错误的时候是红色 19 | status: StatusType 20 | // width 进度条的宽度 21 | width?: number 22 | // activeColor 23 | activeColor?: string 24 | // 圆形的时候的文本渲染函数 25 | textRender?: (percent: number) => React.ReactNode 26 | // 进度条的位置,fixed 将浮出固定在最顶层 27 | position: 'fixed' | 'normal' 28 | //是否显示未填充的轨道 默认是true 29 | unfilled: boolean 30 | } 31 | -------------------------------------------------------------------------------- /src/components/progress/style/index.tsx: -------------------------------------------------------------------------------- 1 | import '../../style/index' 2 | import './index.scss' 3 | -------------------------------------------------------------------------------- /src/components/radio/index.tsx: -------------------------------------------------------------------------------- 1 | import Radio from './radio' 2 | export { Radio } 3 | -------------------------------------------------------------------------------- /src/components/radio/interface.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | export interface RadioProps { 4 | // 自动获取焦点 默认false 5 | autoFocus: boolean 6 | // checked 指定当前是否选中 默认false 7 | checked: boolean 8 | // 默认 初始化为false 9 | defaultChecked: boolean 10 | // disabled 不可用状态 默认为false 11 | disabled: boolean 12 | // onChange 13 | onChange: (checked: boolean) => void 14 | // className 15 | className?: string 16 | // 单选框颜色 17 | color: string 18 | } 19 | 20 | export interface OptionTypes { 21 | label?: React.ReactNode 22 | value?: any 23 | disabled?: boolean 24 | } 25 | 26 | export type func = (value: any) => void 27 | -------------------------------------------------------------------------------- /src/components/radio/radio.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import ClassNames from 'classnames' 3 | import { RadioProps, func } from './interface' 4 | 5 | import './style/index.scss' 6 | import Icon from '../icon' 7 | const noop = () => {} 8 | 9 | const prefixCls = 'cp-ui-radio' 10 | 11 | const defaultProps: RadioProps = { 12 | onChange: noop, 13 | checked: false, 14 | disabled: false, 15 | defaultChecked: false, 16 | autoFocus: false, 17 | color: '#ff5454' 18 | } 19 | 20 | const getClassNames = ({ checked, disabled, autoFocus, className }: RadioProps) => { 21 | return ClassNames(prefixCls, className, { 22 | [`${prefixCls}-checked`]: checked, 23 | [`${prefixCls}-disabled`]: disabled, 24 | [`${prefixCls}-focus`]: autoFocus 25 | }) 26 | } 27 | 28 | const handleChange = (onChange: func, radioChecked: boolean) => { 29 | onChange(radioChecked) 30 | } 31 | const renderIcon = (radioChecked: boolean, color: string, disabled: boolean) => { 32 | if (disabled) { 33 | return 34 | } 35 | return 36 | } 37 | const Radio: React.FC & { defaultProps: Partial } = props => { 38 | const propsCopy = { ...props } 39 | const { children, onChange, color, ...rest } = propsCopy 40 | const isChecked = 41 | propsCopy.checked !== undefined ? propsCopy.checked : propsCopy.defaultChecked ?? false 42 | const classStr = getClassNames(props) 43 | return ( 44 | 58 | ) 59 | } 60 | 61 | Radio.defaultProps = defaultProps 62 | 63 | export default Radio 64 | -------------------------------------------------------------------------------- /src/components/radio/style/index.scss: -------------------------------------------------------------------------------- 1 | @import '../../style/index.scss'; 2 | 3 | $radio: 'cp-ui-radio'; 4 | 5 | .#{$radio} { 6 | font-size: $font-size-normal; 7 | font-variant: tabular-nums; 8 | line-height: $line-height-normal; 9 | color: rgba(0, 0, 0, 0.65); 10 | -webkit-box-sizing: border-box; 11 | box-sizing: border-box; 12 | margin: 0; 13 | padding: 0; 14 | list-style: none; 15 | cursor: pointer; 16 | display: inline-block; 17 | 18 | 19 | 20 | &-select { 21 | font-size: $font-size-normal; 22 | font-variant: tabular-nums; 23 | color: rgba(0, 0, 0, 0.65); 24 | -webkit-box-sizing: border-box; 25 | box-sizing: border-box; 26 | margin: 0; 27 | padding: 0; 28 | list-style: none; 29 | white-space: nowrap; 30 | cursor: pointer; 31 | outline: none; 32 | display: inline-block; 33 | line-height: 1; 34 | position: relative; 35 | vertical-align: bottom; 36 | top: -0.09em; 37 | 38 | input { 39 | position: absolute; 40 | left: 0; 41 | z-index: 1; 42 | cursor: pointer; 43 | opacity: 0; 44 | top: 0; 45 | bottom: 0; 46 | right: 0; 47 | width: 100%; 48 | height: 100%; 49 | } 50 | } 51 | 52 | &-label { 53 | padding: 0 8px; 54 | } 55 | 56 | &-checked { 57 | 58 | .#{$radio}-select { 59 | &::after { 60 | position: absolute; 61 | top: 0; 62 | left: 0; 63 | width: 100%; 64 | height: 100%; 65 | border-radius: 2px; 66 | border: 1px solid $color-brand-normal; 67 | content: ''; 68 | -webkit-animation: antCheckboxEffect 0.36s ease-in-out; 69 | animation: antCheckboxEffect 0.36s ease-in-out; 70 | -webkit-animation-fill-mode: both; 71 | animation-fill-mode: both; 72 | visibility: hidden; 73 | } 74 | } 75 | } 76 | 77 | &-disabled { 78 | cursor: not-allowed; 79 | 80 | .#{$radio}-select { 81 | cursor: not-allowed; 82 | } 83 | 84 | } 85 | 86 | input[type='radio'][disabled] { 87 | cursor: not-allowed; 88 | } 89 | } -------------------------------------------------------------------------------- /src/components/radio/style/index.tsx: -------------------------------------------------------------------------------- 1 | import '../../style/index' 2 | import './index.scss' 3 | -------------------------------------------------------------------------------- /src/components/segmented-control/index.tsx: -------------------------------------------------------------------------------- 1 | import SegmentedControl from './segmented-control' 2 | export default SegmentedControl 3 | -------------------------------------------------------------------------------- /src/components/segmented-control/interface.tsx: -------------------------------------------------------------------------------- 1 | export interface SegmentedControlProps extends SegmentedControlPropsType { 2 | prefixCls?: string 3 | className?: string 4 | style?: React.CSSProperties 5 | } 6 | 7 | export interface SegmentedControlPropsType { 8 | tintColor?: string 9 | disabled?: boolean 10 | selectedIndex: number 11 | values: string[] 12 | onChange?: (index: number, value: string) => void 13 | onValueChange?: (value: string) => void 14 | } 15 | -------------------------------------------------------------------------------- /src/components/segmented-control/style/index.scss: -------------------------------------------------------------------------------- 1 | @import '../../style/index.scss'; 2 | 3 | $cp-ui-segment: 'cp-ui-segment'; 4 | 5 | .#{$cp-ui-segment} { 6 | display: flex; 7 | border-radius: 5px; 8 | overflow: hidden; 9 | min-height: 27px; 10 | opacity: 1; 11 | 12 | &-disabled { 13 | opacity: 0.5; 14 | } 15 | 16 | &-item { 17 | display: flex; 18 | flex: 1; 19 | justify-content: center; 20 | align-items: center; 21 | color: $color-brand-normal; 22 | font-size: $font-size-normal; 23 | line-height: $line-height-normal; 24 | transition: background 0.2s; 25 | position: relative; 26 | border: 1px solid $color-brand-normal; 27 | width: 100%; 28 | box-sizing: border-box; 29 | border-left-width: 0; 30 | cursor: pointer; 31 | 32 | &-tintcolor { 33 | border-color: $color-brand-normal; 34 | } 35 | 36 | &:first-child { 37 | border-left-width: 1px; 38 | border-radius: 5px 0 0 5px; 39 | } 40 | 41 | &:last-child { 42 | border-radius: 0 5px 5px 0; 43 | } 44 | 45 | &-selected { 46 | background: $color-brand-normal; 47 | color: $color-shadow-normal; 48 | } 49 | 50 | &-active { 51 | .#{$cp-ui-segment}-item-inner { 52 | position: absolute; 53 | top: 0; 54 | left: 0; 55 | height: 100%; 56 | width: 100%; 57 | opacity: 0.1; 58 | transition: background 0.2s; 59 | background-color: $color-brand-normal; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/components/segmented-control/style/index.tsx: -------------------------------------------------------------------------------- 1 | import '../../style/index' 2 | import './index.scss' 3 | -------------------------------------------------------------------------------- /src/components/slider/index.tsx: -------------------------------------------------------------------------------- 1 | import Slider from './slider' 2 | 3 | export default Slider 4 | -------------------------------------------------------------------------------- /src/components/slider/interface.tsx: -------------------------------------------------------------------------------- 1 | interface SliderProps { 2 | // onChange 发生变化时候的回调 3 | onChange?: (value?: number) => void 4 | // 与 ontouchend 触发时机一致,把当前值作为参数传入。 5 | onAfterChange?: (value?: number) => void 6 | // 设置初始取值 7 | defaultValue?: number 8 | tipFormatter?: (value?: string) => React.ReactNode 9 | // 设置当前取值 10 | value?: number 11 | // 最小值 默认0 12 | min?: number 13 | // 最大值 默认0 14 | max?: number 15 | // 步长,取值必须大于 0,并且可被 (max - min) 整除。当 marks 不为空对象时,可以设置 step 为 null,此时 Slider 的可选值仅有 marks 标出来的部分 16 | step?: number 17 | //滑块为禁用状态,默认为false 18 | disabled?: boolean 19 | handle?: any 20 | } 21 | export interface SliderPropsType extends SliderProps { 22 | prefixCls?: string 23 | //刻度标记,key 的类型必须为 Number 且取值在闭区间 min, max 内 24 | marks?: { [key: number]: string } 25 | //是否只能拖拽到刻度上 默认false 26 | dots?: boolean 27 | included?: boolean 28 | maximumTrackStyle?: React.CSSProperties 29 | minimumTrackStyle?: React.CSSProperties 30 | handleStyle?: React.CSSProperties 31 | trackStyle?: React.CSSProperties 32 | railStyle?: React.CSSProperties 33 | style?: React.CSSProperties 34 | } 35 | -------------------------------------------------------------------------------- /src/components/slider/slider.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import RcSlider from 'rc-slider' 3 | import { SliderPropsType } from './interface' 4 | import { omit } from '../utils' 5 | 6 | import './style' 7 | 8 | const defaultProps: SliderPropsType = { 9 | prefixCls: 'cp-ui-slider' 10 | } 11 | 12 | const omitProps = (props: SliderPropsType) => { 13 | const excludeProps = ['prefixCls'] 14 | return omit(props, excludeProps) 15 | } 16 | const Slider: React.FC & { defaultProps: Partial } = props => { 17 | const { prefixCls } = props 18 | const otherProps = omitProps(props) 19 | console.log(otherProps) 20 | return ( 21 |
22 | 23 |
24 | ) 25 | } 26 | Slider.defaultProps = defaultProps 27 | 28 | export default Slider 29 | -------------------------------------------------------------------------------- /src/components/slider/style/index.scss: -------------------------------------------------------------------------------- 1 | @import '../../style/index.scss'; 2 | 3 | $slide: 'cp-ui-slider'; 4 | $rc-slider:'rc-slider'; 5 | 6 | .#{$slide} { 7 | .#{$rc-slider} { 8 | &-track { 9 | background: $color-brand-normal; 10 | } 11 | 12 | &-handle { 13 | border: solid 2px $color-brand-normal; 14 | } 15 | 16 | &-disabled { 17 | background: none; 18 | 19 | .#{$rc-slider}-track { 20 | background: $color-brand-shallow-low; 21 | } 22 | 23 | .#{$rc-slider}-handle { 24 | border: solid 2px $color-brand-shallow-low; 25 | } 26 | } 27 | } 28 | 29 | 30 | } -------------------------------------------------------------------------------- /src/components/slider/style/index.tsx: -------------------------------------------------------------------------------- 1 | import '../../style/index' 2 | import 'rc-slider/assets/index.css' 3 | import './index.scss' 4 | -------------------------------------------------------------------------------- /src/components/spin/index.tsx: -------------------------------------------------------------------------------- 1 | import Spin from './spin' 2 | 3 | export default Spin 4 | -------------------------------------------------------------------------------- /src/components/spin/interface.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | export type SizeType = 'small' | 'normal' 4 | 5 | export interface SpinProps { 6 | // 自定义的指示符 7 | indicator?: React.ReactNode 8 | // 尺寸 9 | size: SizeType 10 | // spinning 是否在加载状态中 默认true 11 | spinning: boolean 12 | // tip 当有children的时候自定义文案 13 | tip?: string 14 | // 是否全屏展示 默认为false, 暂时没用等Modal 15 | fullScreen: boolean 16 | // children 17 | children?: React.ReactNode 18 | // color颜色 自定义loading的颜色,如果自定义了指示符,此属性无效 19 | color?: string 20 | } 21 | -------------------------------------------------------------------------------- /src/components/spin/spin.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import ClassNames from 'classnames' 3 | import { SpinProps } from './interface' 4 | 5 | import './style/index.scss' 6 | 7 | const defaultProps: Partial = { 8 | spinning: true, 9 | size: 'normal', 10 | fullScreen: false 11 | } 12 | 13 | const prefixCls = 'cp-ui-spin' 14 | 15 | const getClassNames = ({ size, fullScreen, children }: SpinProps) => { 16 | return ClassNames(prefixCls, { 17 | [`${prefixCls}-${size}`]: size, 18 | [`${prefixCls}-fullScreen`]: fullScreen, 19 | [`${prefixCls}-wrapper`]: children 20 | }) 21 | } 22 | 23 | const renderIndicator = ({ indicator, color }: SpinProps) => { 24 | const style: any = {} 25 | if (color) { 26 | style.background = color 27 | } 28 | return ( 29 |
30 | {indicator || ( 31 |
32 | 33 | 34 | 35 | 36 |
37 | )} 38 |
39 | ) 40 | } 41 | 42 | const renderChildren = ({ children }: SpinProps) => { 43 | if (children) { 44 | return
{children}
45 | } 46 | return null 47 | } 48 | 49 | const renderComponent = (props: SpinProps) => { 50 | const { tip } = props 51 | const classStr = getClassNames(props) 52 | return ( 53 |
54 |
55 |
56 | {renderIndicator(props)} 57 | {tip ?
{tip}
: null} 58 |
59 |
60 | {renderChildren(props)} 61 |
62 | ) 63 | } 64 | 65 | const Spin: React.FC = props => { 66 | // 这里这么写是为了预留fullScreen使用 67 | return renderComponent(props) 68 | } 69 | 70 | Spin.defaultProps = defaultProps 71 | 72 | export default Spin 73 | -------------------------------------------------------------------------------- /src/components/spin/style/index.tsx: -------------------------------------------------------------------------------- 1 | import '../../style/index' 2 | import './index.scss' 3 | -------------------------------------------------------------------------------- /src/components/step/index.tsx: -------------------------------------------------------------------------------- 1 | import Step from './step' 2 | 3 | export default Step 4 | -------------------------------------------------------------------------------- /src/components/step/interface.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | export type StatusTypes = 'wait' | 'process' | 'finish' | 'error' 4 | 5 | export interface StepProps { 6 | // step的标题 7 | title?: React.ReactNode 8 | // step的描述信息 9 | describe?: React.ReactNode 10 | // 前置的图标,可以放入任何 11 | icon?: React.ReactNode 12 | // status 状态 13 | status: StatusTypes 14 | } 15 | 16 | export type DirectionType = 'horizontal' | 'vertical' 17 | 18 | export type SizeType = 'small' | 'normal' 19 | 20 | export type labelPlacement = 'horizontal' | 'vertical' 21 | 22 | export interface StepsProps { 23 | // 方向 24 | direction: DirectionType 25 | // current 当前值 默认为 0 26 | current: string | number 27 | // size 默认normal 28 | size: SizeType 29 | // className 30 | className?: string 31 | // labelPlacement 字的描述位置 32 | labelPlacement: labelPlacement 33 | // options 34 | options: Array 35 | // color 可自行设置step颜色 36 | color?: string 37 | } 38 | -------------------------------------------------------------------------------- /src/components/step/style/index.tsx: -------------------------------------------------------------------------------- 1 | import '../../style/index' 2 | import './index.scss' 3 | -------------------------------------------------------------------------------- /src/components/style/base/index.scss: -------------------------------------------------------------------------------- 1 | @import './base.scss'; 2 | -------------------------------------------------------------------------------- /src/components/style/core/core.scss: -------------------------------------------------------------------------------- 1 | @import '../base/index.scss'; 2 | 3 | *:focus { 4 | outline: none !important; 5 | } 6 | 7 | html, 8 | body { 9 | font-family: $font-family; 10 | font-size: $font-size-normal; 11 | } 12 | 13 | a { 14 | background-color: transparent; 15 | } 16 | 17 | button, 18 | select { 19 | /* 1 */ 20 | text-transform: none; 21 | } 22 | 23 | button, 24 | input { 25 | /* 1 */ 26 | overflow: visible; 27 | } 28 | 29 | button, 30 | input, 31 | optgroup, 32 | select, 33 | textarea { 34 | font-family: inherit; 35 | /* 1 */ 36 | font-size: 100%; 37 | /* 1 */ 38 | line-height: 1.15; 39 | /* 1 */ 40 | margin: 0; 41 | /* 2 */ 42 | } 43 | 44 | img { 45 | border-style: none; 46 | } 47 | 48 | button, 49 | [type="button"], 50 | [type="reset"], 51 | [type="submit"] { 52 | -webkit-appearance: button; 53 | } 54 | 55 | /** 56 | * Remove the inner border and padding in Firefox. 57 | */ 58 | 59 | button::-moz-focus-inner, 60 | [type="button"]::-moz-focus-inner, 61 | [type="reset"]::-moz-focus-inner, 62 | [type="submit"]::-moz-focus-inner { 63 | border-style: none; 64 | padding: 0; 65 | } 66 | 67 | textarea { 68 | overflow: auto; 69 | } 70 | 71 | [type="checkbox"], 72 | [type="radio"] { 73 | box-sizing: border-box; 74 | /* 1 */ 75 | padding: 0; 76 | /* 2 */ 77 | } 78 | 79 | /** 80 | * Correct the cursor style of increment and decrement buttons in Chrome. 81 | */ 82 | 83 | [type="number"]::-webkit-inner-spin-button, 84 | [type="number"]::-webkit-outer-spin-button { 85 | height: auto; 86 | } 87 | 88 | /** 89 | * 1. Correct the odd appearance in Chrome and Safari. 90 | * 2. Correct the outline style in Safari. 91 | */ 92 | 93 | [type="search"] { 94 | -webkit-appearance: textfield; 95 | /* 1 */ 96 | outline-offset: -2px; 97 | /* 2 */ 98 | } 99 | 100 | /** 101 | * Remove the inner padding in Chrome and Safari on macOS. 102 | */ 103 | 104 | [type="search"]::-webkit-search-decoration { 105 | -webkit-appearance: none; 106 | } 107 | 108 | /** 109 | * 1. Correct the inability to style clickable types in iOS and Safari. 110 | * 2. Change font properties to `inherit` in Safari. 111 | */ 112 | 113 | ::-webkit-file-upload-button { 114 | -webkit-appearance: button; 115 | /* 1 */ 116 | font: inherit; 117 | /* 2 */ 118 | } -------------------------------------------------------------------------------- /src/components/style/core/index.scss: -------------------------------------------------------------------------------- 1 | @import './core.scss'; 2 | -------------------------------------------------------------------------------- /src/components/style/core/index.tsx: -------------------------------------------------------------------------------- 1 | import './index.scss' 2 | -------------------------------------------------------------------------------- /src/components/style/index.scss: -------------------------------------------------------------------------------- 1 | @import './base/index.scss'; 2 | @import './mixin/index.scss'; 3 | -------------------------------------------------------------------------------- /src/components/style/index.tsx: -------------------------------------------------------------------------------- 1 | import './index.scss' 2 | import './core/index' 3 | -------------------------------------------------------------------------------- /src/components/style/mixin/index.scss: -------------------------------------------------------------------------------- 1 | @import './size.scss'; 2 | -------------------------------------------------------------------------------- /src/components/style/mixin/size.scss: -------------------------------------------------------------------------------- 1 | @mixin round($radius: 3px) { 2 | border-radius: $radius; 3 | } 4 | 5 | @mixin size($width, $height) { 6 | width: $width; 7 | height: $height; 8 | } 9 | 10 | @mixin center { 11 | position: absolute; 12 | top: 50%; 13 | left: 50%; 14 | transform: translate(-50%, -50%); 15 | } 16 | -------------------------------------------------------------------------------- /src/components/swipe-action/index.tsx: -------------------------------------------------------------------------------- 1 | import SwipeAction from './swipe-action' 2 | export default SwipeAction 3 | -------------------------------------------------------------------------------- /src/components/swipe-action/interface.tsx: -------------------------------------------------------------------------------- 1 | export interface BtnProps { 2 | text: string 3 | onPress: () => void 4 | style?: React.CSSProperties 5 | className?: string 6 | } 7 | export interface SwipeActionProps { 8 | style?: React.CSSProperties 9 | className?: string 10 | prefixCls: string 11 | right: BtnProps[] 12 | autoClose: boolean 13 | onOpen?: () => void 14 | disabled?: boolean 15 | onClose?: () => void 16 | } 17 | -------------------------------------------------------------------------------- /src/components/swipe-action/style/index.scss: -------------------------------------------------------------------------------- 1 | @import '../../style/index.scss'; 2 | 3 | $swipe-action: 'cp-ui-swipe-action'; 4 | 5 | .#{$swipe-action} { 6 | * { 7 | touch-action: none; 8 | } 9 | 10 | &.#{$swipe-action}-wrap { 11 | width: 100%; 12 | font-size: 14px; 13 | position: relative; 14 | 15 | .#{$swipe-action}-content { 16 | position: relative; 17 | z-index: 110; 18 | display: block; 19 | } 20 | 21 | .#{$swipe-action}-button { 22 | color: #fff; 23 | display: flex; 24 | flex-direction: column; 25 | align-items: center; 26 | width: 70px; 27 | position: absolute; 28 | top: 0; 29 | right: 0; 30 | background-color: rgb(221, 221, 221); 31 | height: 100%; 32 | justify-content: center; 33 | 34 | &:not(:last-child) { 35 | background-color: red; 36 | border-right: 1px solid #fff; 37 | } 38 | } 39 | 40 | +.#{$swipe-action}-wrap { 41 | border-top: 1px solid #cfcfcf; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/components/swipe-action/style/index.tsx: -------------------------------------------------------------------------------- 1 | import '../../style/index' 2 | import './index.scss' 3 | -------------------------------------------------------------------------------- /src/components/switch/index.tsx: -------------------------------------------------------------------------------- 1 | import Switch from './switch' 2 | 3 | export default Switch 4 | -------------------------------------------------------------------------------- /src/components/switch/interface.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * switch 3 | */ 4 | 5 | export interface SwitchProps { 6 | // className 7 | className?: string 8 | // prefixCls 9 | prefixCls: string 10 | // color 可配置颜色 11 | color: string 12 | // checked 默认为false 13 | checked: boolean 14 | // onChange 变化时候的回调 15 | onChange: (checked: boolean) => void 16 | // size 尺寸 默认为normal 17 | size?: number 18 | // disabled 默认为false 19 | disabled: boolean 20 | //platform 设定组件的平台特有样式, 可选值为 android, ios, 默认为 ios 21 | platform: 'ios' | 'android' 22 | } 23 | -------------------------------------------------------------------------------- /src/components/switch/style/index.tsx: -------------------------------------------------------------------------------- 1 | import '../../style/index' 2 | import './index.scss' 3 | -------------------------------------------------------------------------------- /src/components/switch/switch.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import ClassNames from 'classnames' 3 | import { SwitchProps } from './interface' 4 | 5 | import './style/index.scss' 6 | 7 | const noop = () => {} 8 | 9 | const defaultProps: SwitchProps = { 10 | disabled: false, 11 | checked: false, 12 | onChange: noop, 13 | prefixCls: 'cp-ui-switch', 14 | color: '#ff5454', 15 | platform: 'ios' 16 | } 17 | 18 | const getClassName = ({ checked, disabled, prefixCls, platform }: SwitchProps) => { 19 | return ClassNames(prefixCls, `${prefixCls}-checked-${platform}`, { 20 | [`${prefixCls}-checked`]: checked, 21 | [`${prefixCls}-disabled`]: disabled 22 | }) 23 | } 24 | 25 | const handleChange = (e: React.ChangeEvent, { onChange }: SwitchProps) => { 26 | const checked = e.target.checked 27 | onChange(checked) 28 | } 29 | 30 | const Switch: React.FC & { defaultProps: Partial } = props => { 31 | const { prefixCls, checked, color, platform } = props 32 | const classStr = getClassName(props) 33 | let style: any = {} 34 | if (checked) { 35 | style.backgroundColor = color 36 | } 37 | return ( 38 |
39 |
40 | handleChange(e, props)} 44 | className={`${prefixCls}-input`} 45 | /> 46 |
47 | ) 48 | } 49 | 50 | Switch.defaultProps = defaultProps 51 | 52 | export default Switch 53 | -------------------------------------------------------------------------------- /src/components/tab-bar/index.tsx: -------------------------------------------------------------------------------- 1 | import TabBar from './tab-bar' 2 | 3 | export default TabBar 4 | -------------------------------------------------------------------------------- /src/components/tab-bar/interface.tsx: -------------------------------------------------------------------------------- 1 | import { IconProps } from '../icon/icon' 2 | 3 | export interface TabBarProps { 4 | barTintColor?: string 5 | hidden?: boolean 6 | className?: string 7 | prefixCls: string 8 | tabBarPosition: 'top' | 'bottom' 9 | items?: Array 10 | onPress: (key: string) => void 11 | } 12 | 13 | export interface TabBarItemProps { 14 | badge?: number | string 15 | dot?: boolean 16 | icon: React.ReactElement 17 | selectedIcon: React.ReactElement 18 | title: string | React.ReactElement 19 | selectedTitle: string | React.ReactElement 20 | key?: string 21 | content?: React.ReactElement 22 | } 23 | -------------------------------------------------------------------------------- /src/components/tab-bar/style/index.scss: -------------------------------------------------------------------------------- 1 | @import '../../style/index.scss'; 2 | 3 | $tab-bar: 'cp-ui-tab-bar'; 4 | $tabs: 'cp-ui-tabs'; 5 | 6 | .#{$tab-bar} { 7 | height: 100%; 8 | position: fixed; 9 | width: 100%; 10 | top: 0; 11 | left: 0; 12 | 13 | .#{$tabs} { 14 | flex-flow: column; 15 | display: flex; 16 | height: 100%; 17 | 18 | &-content { 19 | flex: 1; 20 | 21 | .#{$tabs}-tabpanel { 22 | width: 100%; 23 | height: 100%; 24 | } 25 | } 26 | 27 | &-tab { 28 | margin: 1px 0 0 0; 29 | } 30 | 31 | &-tab-item-active { 32 | border-bottom: none; 33 | } 34 | } 35 | 36 | &-tab { 37 | flex: 1; 38 | display: flex; 39 | justify-content: center; 40 | align-items: center; 41 | flex-direction: column; 42 | text-align: center; 43 | width: 100%; 44 | 45 | &-icon { 46 | display: flex; 47 | justify-content: center; 48 | } 49 | 50 | &-title { 51 | font-size: 10px; 52 | margin: 2px 0 0 0; 53 | line-height: 14px; 54 | text-align: center; 55 | } 56 | } 57 | 58 | &-content { 59 | display: flex; 60 | flex: 1; 61 | position: relative; 62 | overflow: hidden; 63 | height: 100%; 64 | width: 100%; 65 | 66 | &-inner { 67 | position: absolute; 68 | left: 0; 69 | top: 0; 70 | right: 0; 71 | bottom: 0; 72 | overflow: hidden; 73 | overflow-y: auto; 74 | } 75 | } 76 | 77 | &-hidden { 78 | .#{$tabs} { 79 | &-content { 80 | height: 100%; 81 | } 82 | 83 | &-tab { 84 | display: none; 85 | } 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/components/tab-bar/style/index.tsx: -------------------------------------------------------------------------------- 1 | import '../../style/index' 2 | import './index.scss' 3 | -------------------------------------------------------------------------------- /src/components/tabs/index.tsx: -------------------------------------------------------------------------------- 1 | import Tabs from './tabs' 2 | 3 | export default Tabs 4 | -------------------------------------------------------------------------------- /src/components/tabs/interface.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | /** 3 | * tab 4 | */ 5 | export interface TabProps { 6 | // 每一个key 对应 activeKey,key必传 7 | key: string 8 | // tab的内容 标题 9 | tab?: string | React.ReactNode 10 | // tab对应的内容 11 | content?: React.ReactNode | string 12 | } 13 | 14 | export type TabsTypes = 'card' | 'line' 15 | 16 | export type TabsSizeTypes = 'small' | 'normal' | 'large' 17 | 18 | export type TabsPositionTypes = 'top' | 'bottom' | 'left' | 'right' 19 | 20 | /** 21 | * Tabs 群组 22 | */ 23 | export interface TabsProps { 24 | // 当前激活 tab 面板的 key 25 | activeKey?: string 26 | // type 类型 默认为line 27 | type: TabsTypes 28 | // onChange 切换tab的回调 29 | onChange: (value: string) => void 30 | // size 大小 默认为normal 31 | size: TabsSizeTypes 32 | // tab bar 上额外的元素 可以显示在最右边 33 | tabBarExtraContent?: React.ReactNode 34 | // tabBarGutter tabs 之间的间隙 35 | tabBarGutter?: number 36 | //TabBar 样式 37 | tabTitleStyle?: React.CSSProperties 38 | // className 39 | className?: string 40 | // tabPosition 标签位置 默认为top 41 | tabPosition: TabsPositionTypes 42 | // 前缀 43 | prefixCls: string 44 | // options 将要渲染的源数据 45 | options: Array 46 | // onExtraClick 47 | onExtraClick: (e: React.MouseEvent) => void 48 | //样式 49 | style?: React.CSSProperties 50 | } 51 | -------------------------------------------------------------------------------- /src/components/tabs/style/index.tsx: -------------------------------------------------------------------------------- 1 | import '../../style/index' 2 | import './index.scss' 3 | -------------------------------------------------------------------------------- /src/components/tag/index.tsx: -------------------------------------------------------------------------------- 1 | import Tag from './tag' 2 | 3 | export default Tag 4 | -------------------------------------------------------------------------------- /src/components/tag/interface.tsx: -------------------------------------------------------------------------------- 1 | export type SizeType = 'small' | 'normal' | 'large' 2 | 3 | export type TagCheckedType = 'primary' | 'ticked' 4 | 5 | export interface TagProps { 6 | // size类型 7 | size: SizeType 8 | // onClick 9 | onClick: () => void 10 | // closable 标签是否可以关闭 默认为false 11 | closable: boolean 12 | // color 标签颜色 13 | color?: string 14 | // className 15 | className?: string 16 | // onClose 点击关闭按钮的回调 17 | onClose: () => void 18 | // style 19 | style?: object 20 | 21 | // 标签是否选中 默认为false 22 | checked?: boolean 23 | // onChange 点击的回调 24 | onChange?: (checked: boolean) => void 25 | // disabled 标签是否禁用 默认为false 26 | disabled?: boolean 27 | // type 类型有两种选中类型 28 | type?: TagCheckedType 29 | } 30 | 31 | export interface TagCheckedProps { 32 | // 标签是否选中 默认为false 33 | checked: boolean 34 | // onChange 点击的回调 35 | onChange: (checked: boolean) => void 36 | // disabled 标签是否禁用 默认为false 37 | disabled: boolean 38 | // type 类型有两种选中类型 39 | type: TagCheckedType 40 | } 41 | -------------------------------------------------------------------------------- /src/components/tag/style/index.tsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/10086XIAOZHANG/CP-DESIGN/9971e3f9cf0ae1b311ceb6135cb1ffb812c3640b/src/components/tag/style/index.tsx -------------------------------------------------------------------------------- /src/components/tag/tag.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import ClassNames from 'classnames' 3 | import { TagProps } from './interface' 4 | import Icon from '../icon' 5 | import TagChecked from './tagChecked' 6 | import './style/index.scss' 7 | 8 | const { useState } = React 9 | 10 | const noop = () => {} 11 | 12 | const defaultProps: TagProps = { 13 | size: 'normal', 14 | onClick: noop, 15 | closable: false, 16 | onClose: noop 17 | } 18 | 19 | const prefixCls = 'cp-ui-tag' 20 | 21 | const getClassNames = ({ size, closable, className }: TagProps) => { 22 | return ClassNames(prefixCls, className, { 23 | [`${prefixCls}-${size}`]: size, 24 | [`${prefixCls}-closable`]: closable 25 | }) 26 | } 27 | 28 | const getStyle = (color?: string) => { 29 | let style: any = {} 30 | if (color) { 31 | style.border = 'none' 32 | style.color = '#fff' 33 | style.background = color 34 | } 35 | return style 36 | } 37 | 38 | const handleClose = ({ event, setVisible, onClose }: any) => { 39 | event.stopPropagation() 40 | onClose() 41 | setVisible(false) 42 | } 43 | 44 | const Tag: React.FC & { defaultProps: Partial } = props => { 45 | const [visible, setVisible] = useState(true) 46 | const { 47 | closable, 48 | color, 49 | onClose, 50 | onClick, 51 | checked, 52 | onChange = noop, 53 | disabled = false, 54 | type = 'primary', 55 | style 56 | } = props 57 | const classStr = getClassNames(props) 58 | const wrapperStyle = getStyle(color) 59 | if (checked !== undefined) { 60 | return ( 61 | 62 | {props.children} 63 | 64 | ) 65 | } 66 | return visible ? ( 67 |
68 |
69 | {props.children} 70 | {closable ? ( 71 | handleClose({ event, setVisible, onClose })} /> 72 | ) : null} 73 |
74 |
75 | ) : null 76 | } 77 | 78 | Tag.defaultProps = defaultProps 79 | 80 | export default Tag 81 | -------------------------------------------------------------------------------- /src/components/tag/tagChecked.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import ClassNames from 'classnames' 3 | import { TagCheckedProps } from './interface' 4 | import Tag from './tag' 5 | 6 | const noop = () => {} 7 | 8 | const defaultProps: TagCheckedProps = { 9 | checked: false, 10 | onChange: noop, 11 | disabled: false, 12 | type: 'primary' 13 | } 14 | 15 | const prefixCls = 'cp-ui-tag' 16 | 17 | const getClassNames = ({ type, checked, disabled }: TagCheckedProps) => { 18 | return ClassNames({ 19 | [`${prefixCls}-${type}`]: type, 20 | [`${prefixCls}-checked`]: checked, 21 | [`${prefixCls}-disabled`]: disabled 22 | }) 23 | } 24 | 25 | const handleChange = ({ checked, onChange, disabled }: TagCheckedProps) => { 26 | if (disabled) return 27 | const nextChecked = !checked 28 | onChange(nextChecked) 29 | } 30 | 31 | const TagChecked: React.FC & { 32 | defaultProps: Partial 33 | } = props => { 34 | const classStr = getClassNames(props) 35 | return ( 36 | handleChange(props)}> 37 | {props.children} 38 | 39 | ) 40 | } 41 | 42 | TagChecked.defaultProps = defaultProps 43 | 44 | export default TagChecked 45 | -------------------------------------------------------------------------------- /src/components/toast/index.tsx: -------------------------------------------------------------------------------- 1 | import Toast from './toast' 2 | export default Toast 3 | -------------------------------------------------------------------------------- /src/components/toast/style/index.scss: -------------------------------------------------------------------------------- 1 | @import '../../style/index.scss'; 2 | 3 | $toast: 'cp-ui-toast'; 4 | 5 | .#{$toast} { 6 | position: fixed; 7 | width: 100%; 8 | z-index: 99; 9 | font-size: 14; 10 | text-align: center; 11 | 12 | span { 13 | max-width: 50%; 14 | } 15 | 16 | &-mask { 17 | height: 100%; 18 | display: flex; 19 | justify-content: center; 20 | align-items: center; 21 | left: 0; 22 | top: 0; 23 | transform: translateZ(1px); 24 | } 25 | 26 | &-nomask { 27 | max-width: 50%; 28 | position: fixed; 29 | top: 50%; 30 | left: 50%; 31 | transform: translate(-50%, -50%); 32 | } 33 | 34 | &-notice-content { 35 | .#{$toast}-text { 36 | min-width: 60px; 37 | border-radius: 4px; 38 | color: #fff; 39 | background-color: rgba(0, 0, 0, .7); 40 | line-height: 13px; 41 | padding: 12px 10px; 42 | 43 | &.#{$toast}-text-icon { 44 | border-radius: 6px; 45 | padding: 12px 32px; 46 | 47 | .#{$toast}-text-info { 48 | margin-top: 12px; 49 | } 50 | } 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /src/components/toast/style/index.tsx: -------------------------------------------------------------------------------- 1 | import '../../style/index' 2 | import './index.scss' 3 | -------------------------------------------------------------------------------- /src/components/utils/guid.ts: -------------------------------------------------------------------------------- 1 | let uid = Date.now() 2 | 3 | export const getUid = () => { 4 | uid +=1 5 | return uid 6 | } 7 | 8 | export const getUidString = () => { 9 | return getUid().toString(36) 10 | } -------------------------------------------------------------------------------- /src/components/utils/index.ts: -------------------------------------------------------------------------------- 1 | import { getUid, getUidString } from './guid' 2 | 3 | const omit = (obj: any, arr: string[]) => 4 | Object.keys(obj) 5 | .filter(k => !arr.includes(k)) 6 | .reduce((acc, key) => ((acc[key] = obj[key]), acc), {} as any); 7 | 8 | const compose = (...fns: any) => fns.reduce((f: any, g: any) => (...args: any) => f(g(...args))); 9 | 10 | const getPrefixCls = (prefixCls: string, classStr: string) => { 11 | if (!classStr) return prefixCls 12 | return `${prefixCls}-${classStr}` 13 | } 14 | 15 | export { 16 | omit, 17 | compose, 18 | getPrefixCls, 19 | getUid, 20 | getUidString 21 | } -------------------------------------------------------------------------------- /src/components/utils/type.ts: -------------------------------------------------------------------------------- 1 | export type Omit = Pick>; -------------------------------------------------------------------------------- /stories/combination-listview.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import { withDocs } from 'storybook-readme' 4 | 5 | import ListViewDemo from '../examples/listview' 6 | import ListViewReadme from '../examples/listview/readme.md' 7 | import { withKnobs, text, boolean, number } from '@storybook/addon-knobs' 8 | 9 | storiesOf('Combination 结合', module) 10 | .addDecorator(story =>
{story()}
) 11 | .addDecorator(withKnobs) 12 | .addParameters({ 13 | readme: { 14 | sidebar: ListViewReadme, 15 | codeTheme: 'github' 16 | }, 17 | viewport: { defaultViewport: 'iphone6' } 18 | }) 19 | .add('ListView 长列表', () => { 20 | return 21 | }) 22 | -------------------------------------------------------------------------------- /stories/datashow-accordion.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import { withDocs } from 'storybook-readme' 4 | 5 | import AccordionDemo from '../examples/accordion' 6 | import AccordionReadme from '../examples/accordion/readme.md' 7 | import { withKnobs, text, boolean, number } from '@storybook/addon-knobs' 8 | 9 | storiesOf('Data Display 数据显示', module) 10 | .addDecorator(story =>
{story()}
) 11 | .addDecorator(withKnobs) 12 | .addParameters({ 13 | readme: { 14 | sidebar: AccordionReadme, 15 | codeTheme: 'github' 16 | }, 17 | viewport: { defaultViewport: 'iphone6' } 18 | }) 19 | .add('Accordion 手风琴', () => { 20 | return 21 | }) 22 | -------------------------------------------------------------------------------- /stories/datashow-avatar.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import { withDocs } from 'storybook-readme' 4 | 5 | import AvatarDemo from '../examples/avatar' 6 | import AvatarReadme from '../examples/avatar/readme.md' 7 | import { withKnobs, text, boolean, number } from '@storybook/addon-knobs' 8 | 9 | storiesOf('Data Display 数据显示', module) 10 | .addDecorator(story =>
{story()}
) 11 | .addDecorator(withKnobs) 12 | .addParameters({ 13 | readme: { 14 | sidebar: AvatarReadme, 15 | codeTheme: 'github' 16 | }, 17 | viewport: { defaultViewport: 'iphone6' } 18 | }) 19 | .add('Avatar 头像', () => { 20 | return 21 | }) 22 | -------------------------------------------------------------------------------- /stories/datashow-badge.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import { withDocs } from 'storybook-readme' 4 | 5 | import BadgeDemo from '../examples/badge' 6 | import BadgeReadme from '../examples/badge/readme.md' 7 | import { withKnobs, text, boolean, number } from '@storybook/addon-knobs' 8 | 9 | storiesOf('Data Display 数据显示', module) 10 | .addDecorator(story =>
{story()}
) 11 | .addDecorator(withKnobs) 12 | .addParameters({ 13 | readme: { 14 | sidebar: BadgeReadme, 15 | codeTheme: 'github' 16 | }, 17 | viewport: { defaultViewport: 'iphone6' } 18 | }) 19 | .add('Badge 徽标数', () => { 20 | return 21 | }) 22 | -------------------------------------------------------------------------------- /stories/datashow-card.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import { withDocs } from 'storybook-readme' 4 | 5 | import CardDemo from '../examples/card' 6 | import CardReadme from '../examples/card/readme.md' 7 | import { withKnobs, text, boolean, number } from '@storybook/addon-knobs' 8 | 9 | storiesOf('Data Display 数据显示', module) 10 | .addDecorator(story =>
{story()}
) 11 | .addDecorator(withKnobs) 12 | .addParameters({ 13 | readme: { 14 | sidebar: CardReadme, 15 | codeTheme: 'github' 16 | }, 17 | viewport: { defaultViewport: 'iphone6' } 18 | }) 19 | .add('Card 卡片', () => { 20 | return 21 | }) 22 | -------------------------------------------------------------------------------- /stories/datashow-divider.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import { withDocs } from 'storybook-readme' 4 | 5 | import DividerDemo from '../examples/divider' 6 | import DividerReadme from '../examples/divider/readme.md' 7 | import { withKnobs, text, boolean, number } from '@storybook/addon-knobs' 8 | 9 | storiesOf('Data Display 数据显示', module) 10 | .addDecorator(story =>
{story()}
) 11 | .addDecorator(withKnobs) 12 | .addParameters({ 13 | readme: { 14 | sidebar: DividerReadme, 15 | codeTheme: 'github' 16 | }, 17 | viewport: { defaultViewport: 'iphone6' } 18 | }) 19 | .add('Divider 分割线', () => { 20 | return 21 | }) 22 | -------------------------------------------------------------------------------- /stories/datashow-icon.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import { withDocs } from 'storybook-readme' 4 | 5 | import IconDemo from '../examples/icon' 6 | import IconReadme from '../examples/icon/readme.md' 7 | import { withKnobs, text, boolean, number } from '@storybook/addon-knobs' 8 | 9 | storiesOf('Data Display 数据显示', module) 10 | .addDecorator(story =>
{story()}
) 11 | .addDecorator(withKnobs) 12 | .addParameters({ 13 | readme: { 14 | sidebar: IconReadme, 15 | codeTheme: 'github' 16 | }, 17 | viewport: { defaultViewport: 'iphone6' } 18 | }) 19 | .add('Icon 图标', () => { 20 | return 21 | }) 22 | -------------------------------------------------------------------------------- /stories/datashow-notice-bar.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import { withDocs } from 'storybook-readme' 4 | 5 | import NoticeBarDemo from '../examples/noticeBar' 6 | import NoticeBarReadme from '../examples/noticeBar/readme.md' 7 | import { withKnobs, text, boolean, number } from '@storybook/addon-knobs' 8 | 9 | storiesOf('Data Display 数据显示', module) 10 | .addDecorator(story =>
{story()}
) 11 | .addDecorator(withKnobs) 12 | .addParameters({ 13 | readme: { 14 | sidebar: NoticeBarReadme, 15 | codeTheme: 'github' 16 | }, 17 | viewport: { defaultViewport: 'iphone6' } 18 | }) 19 | .add('NoticeBar 通告栏', () => { 20 | return 21 | }) 22 | -------------------------------------------------------------------------------- /stories/datashow-tags.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import { withDocs } from 'storybook-readme' 4 | 5 | import BadgeDemo from '../examples/tag' 6 | import BadgeReadme from '../examples/tag/readme.md' 7 | import { withKnobs, text, boolean, number } from '@storybook/addon-knobs' 8 | 9 | storiesOf('Data Display 数据显示', module) 10 | .addDecorator(story =>
{story()}
) 11 | .addDecorator(withKnobs) 12 | .addParameters({ 13 | readme: { 14 | sidebar: BadgeReadme, 15 | codeTheme: 'github' 16 | }, 17 | viewport: { defaultViewport: 'iphone6' } 18 | }) 19 | .add('Tag 标签', () => { 20 | return 21 | }) 22 | -------------------------------------------------------------------------------- /stories/feedback-action-sheet.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | 4 | import ActionSheetDemo from '../examples/actionSheet' 5 | import ActionSheetReadme from '../examples/actionSheet/readme.md' 6 | import { withKnobs, text, boolean, number } from '@storybook/addon-knobs' 7 | 8 | // Globablly 9 | 10 | storiesOf('Feedback 反馈', module) 11 | .addDecorator(story =>
{story()}
) 12 | .addDecorator(withKnobs) 13 | .addParameters({ 14 | readme: { 15 | sidebar: ActionSheetReadme, 16 | codeTheme: 'github' 17 | }, 18 | viewport: { defaultViewport: 'iphone6' } 19 | }) 20 | .add('ActionSheet 动作面板', () => { 21 | return 22 | }) 23 | -------------------------------------------------------------------------------- /stories/feedback-modal.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | 4 | import ModalDemo from '../examples/modal' 5 | import ModalReadme from '../examples/modal/readme.md' 6 | import { withKnobs, text, boolean, number } from '@storybook/addon-knobs' 7 | 8 | // Globablly 9 | 10 | storiesOf('Feedback 反馈', module) 11 | .addDecorator(story =>
{story()}
) 12 | .addDecorator(withKnobs) 13 | .addParameters({ 14 | readme: { 15 | sidebar: ModalReadme, 16 | codeTheme: 'github' 17 | }, 18 | viewport: { defaultViewport: 'iphone6' } 19 | }) 20 | .add('Modal 对话框', () => { 21 | return 22 | }) 23 | -------------------------------------------------------------------------------- /stories/feedback-progress.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | 4 | import ProgressDemo from '../examples/progress' 5 | import ProgressReadme from '../examples/progress/readme.md' 6 | import { withKnobs, text, boolean, number } from '@storybook/addon-knobs' 7 | 8 | // Globablly 9 | 10 | storiesOf('Feedback 反馈', module) 11 | .addDecorator(story =>
{story()}
) 12 | .addDecorator(withKnobs) 13 | .addParameters({ 14 | readme: { 15 | sidebar: ProgressReadme, 16 | codeTheme: 'github' 17 | }, 18 | viewport: { defaultViewport: 'iphone6' } 19 | }) 20 | .add('Progress 进度条', () => { 21 | return 22 | }) 23 | -------------------------------------------------------------------------------- /stories/feedback-toast.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | 4 | import ToastDemo from '../examples/toast' 5 | import ToastReadme from '../examples/toast/readme.md' 6 | import { withKnobs, text, boolean, number } from '@storybook/addon-knobs' 7 | 8 | // Globablly 9 | 10 | storiesOf('Feedback 反馈', module) 11 | .addDecorator(story =>
{story()}
) 12 | .addDecorator(withKnobs) 13 | .addParameters({ 14 | readme: { 15 | sidebar: ToastReadme, 16 | codeTheme: 'github' 17 | }, 18 | viewport: { defaultViewport: 'iphone6' } 19 | }) 20 | .add('Toast 轻提示', () => { 21 | return 22 | }) 23 | -------------------------------------------------------------------------------- /stories/general-button.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | 4 | import ButtonDemo from '../examples/button' 5 | import ButtonReadme from '../examples/button/readme.md' 6 | import { withKnobs, text, boolean, number } from '@storybook/addon-knobs' 7 | 8 | // Globablly 9 | 10 | storiesOf('General 通用', module) 11 | .addDecorator(story =>
{story()}
) 12 | .addDecorator(withKnobs) 13 | .addParameters({ 14 | readme: { 15 | sidebar: ButtonReadme, 16 | codeTheme: 'github' 17 | }, 18 | viewport: { defaultViewport: 'iphone6' } 19 | }) 20 | .add('Button 按钮', () => { 21 | return 22 | }) 23 | -------------------------------------------------------------------------------- /stories/general-checkbox.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | 4 | import CheckboxDemo from '../examples/checkbox' 5 | import CheckboxReadme from '../examples/checkbox/readme.md' 6 | import { withKnobs, text, boolean, number } from '@storybook/addon-knobs' 7 | 8 | // Globablly 9 | 10 | storiesOf('General 通用', module) 11 | .addDecorator(story =>
{story()}
) 12 | .addDecorator(withKnobs) 13 | .addParameters({ 14 | readme: { 15 | sidebar: CheckboxReadme, 16 | codeTheme: 'github' 17 | }, 18 | viewport: { defaultViewport: 'iphone6' } 19 | }) 20 | .add('Checkbox 复选框', () => { 21 | return 22 | }) 23 | -------------------------------------------------------------------------------- /stories/general-imagePicker.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | 4 | import ImagePickerDemo from '../examples/imagePicker' 5 | import ImagePickerReadme from '../examples/imagePicker/readme.md' 6 | import { withKnobs, text, boolean, number } from '@storybook/addon-knobs' 7 | 8 | // Globablly 9 | 10 | storiesOf('General 通用', module) 11 | .addDecorator(story =>
{story()}
) 12 | .addDecorator(withKnobs) 13 | .addParameters({ 14 | readme: { 15 | sidebar: ImagePickerReadme, 16 | codeTheme: 'github' 17 | }, 18 | viewport: { defaultViewport: 'iphone6' } 19 | }) 20 | .add('ImagePicker 上传', () => { 21 | return 22 | }) 23 | -------------------------------------------------------------------------------- /stories/general-input.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | 4 | import InputDemo from '../examples/input' 5 | import InputReadme from '../examples/input/readme.md' 6 | import { withKnobs, text, boolean, number } from '@storybook/addon-knobs' 7 | 8 | // Globablly 9 | 10 | storiesOf('General 通用', module) 11 | .addDecorator(story =>
{story()}
) 12 | .addDecorator(withKnobs) 13 | .addParameters({ 14 | readme: { 15 | sidebar: InputReadme, 16 | codeTheme: 'github' 17 | }, 18 | viewport: { defaultViewport: 'iphone6' } 19 | }) 20 | .add('Input 输入框', () => { 21 | return 22 | }) 23 | -------------------------------------------------------------------------------- /stories/general-picker-panel.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | 4 | import PickerPanelDemo from '../examples/pickerPanel' 5 | import PickerPanelReadme from '../examples/pickerPanel/readme.md' 6 | import { withKnobs, text, boolean, number } from '@storybook/addon-knobs' 7 | 8 | // Globablly 9 | 10 | storiesOf('General 通用', module) 11 | .addDecorator(story =>
{story()}
) 12 | .addDecorator(withKnobs) 13 | .addParameters({ 14 | readme: { 15 | sidebar: PickerPanelReadme, 16 | codeTheme: 'github' 17 | }, 18 | viewport: { defaultViewport: 'iphone6' } 19 | }) 20 | .add('PickerPanel 选择器', () => { 21 | return 22 | }) 23 | -------------------------------------------------------------------------------- /stories/general-picker.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | 4 | import PickerDemo from '../examples/picker' 5 | import PickerReadme from '../examples/picker/readme.md' 6 | import { withKnobs, text, boolean, number } from '@storybook/addon-knobs' 7 | 8 | // Globablly 9 | 10 | storiesOf('General 通用', module) 11 | .addDecorator(story =>
{story()}
) 12 | .addDecorator(withKnobs) 13 | .addParameters({ 14 | readme: { 15 | sidebar: PickerReadme, 16 | codeTheme: 'github' 17 | }, 18 | viewport: { defaultViewport: 'iphone5' } 19 | }) 20 | .add('Picker 选择器', () => { 21 | return 22 | }) 23 | -------------------------------------------------------------------------------- /stories/general-radio.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | 4 | import RadioDemo from '../examples/radio' 5 | import RadioReadme from '../examples/radio/readme.md' 6 | import { withKnobs, text, boolean, number } from '@storybook/addon-knobs' 7 | 8 | // Globablly 9 | 10 | storiesOf('General 通用', module) 11 | .addDecorator(story =>
{story()}
) 12 | .addDecorator(withKnobs) 13 | .addParameters({ 14 | readme: { 15 | sidebar: RadioReadme, 16 | codeTheme: 'github' 17 | }, 18 | viewport: { defaultViewport: 'iphone6' } 19 | }) 20 | .add('Radio 单选框', () => { 21 | return 22 | }) 23 | -------------------------------------------------------------------------------- /stories/general-slider.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | 4 | import SliderDemo from '../examples/slider' 5 | import SliderReadme from '../examples/slider/readme.md' 6 | import { withKnobs, text, boolean, number } from '@storybook/addon-knobs' 7 | 8 | // Globablly 9 | 10 | storiesOf('General 通用', module) 11 | .addDecorator(story =>
{story()}
) 12 | .addDecorator(withKnobs) 13 | .addParameters({ 14 | readme: { 15 | sidebar: SliderReadme, 16 | codeTheme: 'github' 17 | }, 18 | viewport: { defaultViewport: 'iphone6' } 19 | }) 20 | .add('Slider 滑动输入条', () => { 21 | return 22 | }) 23 | -------------------------------------------------------------------------------- /stories/general-switch.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | 4 | import SwitchDemo from '../examples/switch' 5 | import SwitchReadme from '../examples/switch/readme.md' 6 | import { withKnobs, text, boolean, number } from '@storybook/addon-knobs' 7 | 8 | // Globablly 9 | 10 | storiesOf('General 通用', module) 11 | .addDecorator(story =>
{story()}
) 12 | .addDecorator(withKnobs) 13 | .addParameters({ 14 | readme: { 15 | sidebar: SwitchReadme, 16 | codeTheme: 'github' 17 | }, 18 | viewport: { defaultViewport: 'iphone6' } 19 | }) 20 | .add('Switch 滑动开关', () => { 21 | return 22 | }) 23 | -------------------------------------------------------------------------------- /stories/gesture-swiipe-action.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import { withDocs } from 'storybook-readme' 4 | 5 | import SwipeActionDemo from '../examples/swipeAction' 6 | import SwipeActionReadme from '../examples/swipeAction/readme.md' 7 | import { withKnobs, text, boolean, number } from '@storybook/addon-knobs' 8 | 9 | storiesOf('Gesture 手势', module) 10 | .addDecorator(story =>
{story()}
) 11 | .addDecorator(withKnobs) 12 | .addParameters({ 13 | readme: { 14 | sidebar: SwipeActionReadme, 15 | codeTheme: 'github' 16 | }, 17 | viewport: { defaultViewport: 'iphone6' } 18 | }) 19 | .add('SwipeAction 滑动操作', () => { 20 | return 21 | }) 22 | -------------------------------------------------------------------------------- /stories/index.scss: -------------------------------------------------------------------------------- 1 | .placeholder { 2 | background-color: #ebebef; 3 | color: #bbb; 4 | text-align: center; 5 | height: 30px; 6 | line-height: 30px; 7 | width: 100%; 8 | } -------------------------------------------------------------------------------- /stories/introduce.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | 4 | import IntroduceDemo from '../examples/introduce' 5 | 6 | storiesOf('OVERVIEW 总览', module).add('Introduce 介绍', () => { 7 | return 8 | }) 9 | -------------------------------------------------------------------------------- /stories/layout-grid.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | 4 | import GridDemo from '../examples/grid' 5 | import AvatarReadme from '../examples/grid/readme.md' 6 | import { withKnobs, text, boolean, number } from '@storybook/addon-knobs' 7 | // Globablly 8 | import './index.scss' 9 | storiesOf('General 通用', module) 10 | .addDecorator(story =>
{story()}
) 11 | .addDecorator(withKnobs) 12 | .addParameters({ 13 | readme: { 14 | sidebar: AvatarReadme, 15 | codeTheme: 'github' 16 | }, 17 | viewport: { defaultViewport: 'iphone6' } 18 | }) 19 | .add('Grid 布局', () => { 20 | return 21 | }) 22 | -------------------------------------------------------------------------------- /stories/navigation-affix.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import { withDocs } from 'storybook-readme' 4 | 5 | import AffixDemo from '../examples/affix' 6 | import AffixReadme from '../examples/affix/readme.md' 7 | import { withKnobs, text, boolean, number } from '@storybook/addon-knobs' 8 | storiesOf('Navigation 导航', module) 9 | .addDecorator(story =>
{story()}
) 10 | .addDecorator(withKnobs) 11 | .addParameters({ 12 | readme: { 13 | sidebar: AffixReadme, 14 | codeTheme: 'github' 15 | }, 16 | viewport: { defaultViewport: 'iphone6' } 17 | }) 18 | .add('Affix 固钉', () => { 19 | return 20 | }) 21 | -------------------------------------------------------------------------------- /stories/navigation-pagination.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import { withDocs } from 'storybook-readme' 4 | 5 | import PaginationDemo from '../examples/pagination' 6 | import PaginationReadme from '../examples/pagination/readme.md' 7 | import { withKnobs, text, boolean, number } from '@storybook/addon-knobs' 8 | storiesOf('Navigation 导航', module) 9 | .addDecorator(story =>
{story()}
) 10 | .addDecorator(withKnobs) 11 | .addParameters({ 12 | readme: { 13 | sidebar: PaginationReadme, 14 | codeTheme: 'github' 15 | }, 16 | viewport: { defaultViewport: 'iphone6' } 17 | }) 18 | .add('Pagination 分页器', () => { 19 | return 20 | }) 21 | -------------------------------------------------------------------------------- /stories/navigation-popover.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import { withDocs } from 'storybook-readme' 4 | 5 | import PopoverDemo from '../examples/popover' 6 | import PopoverReadme from '../examples/popover/readme.md' 7 | import { withKnobs, text, boolean, number } from '@storybook/addon-knobs' 8 | storiesOf('Navigation 导航', module) 9 | .addDecorator(story =>
{story()}
) 10 | .addDecorator(withKnobs) 11 | .addParameters({ 12 | readme: { 13 | sidebar: PopoverReadme, 14 | codeTheme: 'github' 15 | }, 16 | viewport: { defaultViewport: 'iphone6' } 17 | }) 18 | .add('Popover 气泡', () => { 19 | return 20 | }) 21 | -------------------------------------------------------------------------------- /stories/navigation-segmented-control.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import { withDocs } from 'storybook-readme' 4 | 5 | import SegmentedControlDemo from '../examples/segmentedControl' 6 | import SegmentedControlReadme from '../examples/segmentedControl/readme.md' 7 | import { withKnobs, text, boolean, number } from '@storybook/addon-knobs' 8 | storiesOf('Navigation 导航', module) 9 | .addDecorator(story =>
{story()}
) 10 | .addDecorator(withKnobs) 11 | .addParameters({ 12 | readme: { 13 | sidebar: SegmentedControlReadme, 14 | codeTheme: 'github' 15 | }, 16 | viewport: { defaultViewport: 'iphone6' } 17 | }) 18 | .add('SegmentedControl 分段器', () => { 19 | return 20 | }) 21 | -------------------------------------------------------------------------------- /stories/navigation-tabbar.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import { withDocs } from 'storybook-readme' 4 | 5 | import TabBarDemo from '../examples/tabBar' 6 | import TabBarReadme from '../examples/tabBar/readme.md' 7 | import { withKnobs, text, boolean, number } from '@storybook/addon-knobs' 8 | storiesOf('Navigation 导航', module) 9 | .addDecorator(story =>
{story()}
) 10 | .addDecorator(withKnobs) 11 | .addParameters({ 12 | readme: { 13 | sidebar: TabBarReadme, 14 | codeTheme: 'github' 15 | }, 16 | viewport: { defaultViewport: 'iphone6' } 17 | }) 18 | .add('TabBar 标签栏', () => { 19 | return 20 | }) 21 | -------------------------------------------------------------------------------- /stories/navigation-tabs.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import { withDocs } from 'storybook-readme' 4 | 5 | import TabsDemo from '../examples/tabs' 6 | import TabsReadme from '../examples/tabs/readme.md' 7 | import { withKnobs, text, boolean, number } from '@storybook/addon-knobs' 8 | storiesOf('Navigation 导航', module) 9 | .addDecorator(story =>
{story()}
) 10 | .addDecorator(withKnobs) 11 | .addParameters({ 12 | readme: { 13 | sidebar: TabsReadme, 14 | codeTheme: 'github' 15 | }, 16 | viewport: { defaultViewport: 'iphone6' } 17 | }) 18 | .add('Tabs 标签页', () => { 19 | return 20 | }) 21 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "forceConsistentCasingInFileNames": true, 5 | "noImplicitReturns": true, 6 | "moduleResolution": "node", 7 | "experimentalDecorators": true, 8 | "suppressImplicitAnyIndexErrors": true, 9 | "jsx": "react", 10 | "noUnusedParameters": true, 11 | "noUnusedLocals": true, 12 | "target": "es5", 13 | "lib": ["es5", "es6", "es7", "es2017", "dom"], 14 | "emitDecoratorMetadata": true, 15 | "baseUrl": "src", 16 | "allowSyntheticDefaultImports": true, 17 | "paths": { 18 | "@/*": ["*"] 19 | } 20 | }, 21 | "exclude": ["node_modules", "lib", "es"], 22 | "include": ["src", "./externals.d.ts"] 23 | } -------------------------------------------------------------------------------- /tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "allowSyntheticDefaultImports": true 5 | } 6 | } -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint-config-prettier"], 3 | "defaultSeverity": "error", 4 | "rules": { 5 | "adjacent-overload-signatures": true, 6 | "class-name": true, 7 | "eofline": true, 8 | "forin": true, 9 | "interface-over-type-literal": true, 10 | "new-parens": true, 11 | "no-angle-bracket-type-assertion": true, 12 | "no-arg": true, 13 | "no-conditional-assignment": true, 14 | "no-consecutive-blank-lines": true, 15 | "no-construct": true, 16 | "no-duplicate-super": true, 17 | "no-empty": false, 18 | "no-empty-interface": true, 19 | "no-eval": true, 20 | "no-internal-module": true, 21 | "no-invalid-this": false, 22 | "no-string-literal": true, 23 | "no-string-throw": true, 24 | "no-switch-case-fall-through": false, 25 | "no-trailing-whitespace": true, 26 | "no-unsafe-finally": true, 27 | "no-use-before-declare": false, 28 | "no-var-keyword": true, 29 | "no-var-requires": true, 30 | "no-console": [true, "debug", "info", "log", "time", "timeEnd", "trace"], 31 | "no-unused-expression": false, 32 | "radix": true, 33 | "use-isnan": true, 34 | "variable-name": [ 35 | true, 36 | "allow-leading-underscore", 37 | "ban-keywords", 38 | "check-format", 39 | "allow-pascal-case" 40 | ] 41 | } 42 | } 43 | --------------------------------------------------------------------------------