├── .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 | 固钉不支持sticky
18 |
19 |
26 |
27 | 固钉支持sticky
28 |
29 |
36 |
37 | 固钉底部支持sticky
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 | 固钉不支持sticky
26 |
27 |
34 |
35 | 固钉支持sticky
36 |
37 |
44 |
45 | 固钉底部支持sticky
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 | default
12 |
13 |
14 |
15 |
16 | default disabled
17 |
18 |
19 |
20 |
21 |
22 | primary
23 |
24 |
25 |
26 |
27 |
28 |
29 | primary disabled
30 |
31 |
32 |
33 |
34 |
35 |
36 | warning
37 |
38 |
39 |
40 |
41 |
42 |
43 | warning disabled
44 |
45 |
46 |
47 |
48 |
49 |
50 | loading button
51 |
52 |
53 |
54 |
55 |
56 | with icon
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(Start , 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 | basic
73 |
74 |
75 |
76 |
77 | confirm
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 | text only
35 |
36 |
37 |
38 |
39 | without mask
40 |
41 |
42 |
43 |
44 | Toast.info(customIcon(), 1)}>cumstom icon
45 |
46 |
47 |
48 |
49 | success
50 |
51 |
52 |
53 |
54 | fail
55 |
56 |
57 |
58 |
59 | network failure
60 |
61 |
62 |
63 |
64 | loading
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 =
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 |
37 | {icon}
38 |
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 |
45 |
46 | {
50 | handleChange(onChange, isChecked)
51 | }}
52 | {...rest}
53 | />
54 | {renderIcon(isChecked, color, propsCopy.disabled)}
55 |
56 | {children}
57 |
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 |
--------------------------------------------------------------------------------