├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .npmignore ├── .prettierignore ├── .prettierrc ├── CHANGELOG.md ├── LICENSE ├── README.md ├── components ├── _util │ ├── getLocale.tsx │ └── version.json ├── accordion │ ├── index.tsx │ ├── index.zh-CN.md │ └── style │ │ └── index.tsx ├── action-sheet │ ├── AndroidContainer.tsx │ ├── index.tsx │ ├── index.zh-CN.md │ └── style │ │ └── index.tsx ├── activity-indicator │ ├── index.tsx │ ├── index.zh-CN.md │ └── style │ │ └── index.tsx ├── badge │ ├── index.tsx │ ├── index.zh-CN.md │ └── style │ │ └── index.tsx ├── button │ ├── PropsType.tsx │ ├── index.tsx │ ├── index.zh-CN.md │ └── style │ │ └── index.tsx ├── card │ ├── CardBody.tsx │ ├── CardFooter.tsx │ ├── CardHeader.tsx │ ├── index.tsx │ ├── index.zh-CN.md │ └── style │ │ └── index.tsx ├── carousel │ ├── index.tsx │ ├── index.zh-CN.md │ └── style │ │ └── index.tsx ├── checkbox │ ├── AgreeItem.tsx │ ├── Checkbox.tsx │ ├── CheckboxItem.tsx │ ├── PropsType.tsx │ ├── index.tsx │ ├── index.zh-CN.md │ └── style │ │ └── index.tsx ├── date-picker-view │ ├── PropsType.tsx │ ├── date-picker-view.tsx │ ├── index.tsx │ ├── index.zh-CN.md │ └── locale │ │ ├── en_US.tsx │ │ ├── es_ES.tsx │ │ ├── ru_RU.tsx │ │ ├── sv_SE.tsx │ │ └── zh_CN.tsx ├── date-picker │ ├── PropsType.tsx │ ├── datepicker │ │ ├── DatePicker.tsx │ │ ├── DatePickerProps.tsx │ │ ├── Popup.tsx │ │ ├── PopupStyles.tsx │ │ ├── index.tsx │ │ └── locale │ │ │ ├── en_US.tsx │ │ │ ├── fa_IR.tsx │ │ │ ├── id_ID.tsx │ │ │ ├── pt_BR.tsx │ │ │ ├── ru_RU.tsx │ │ │ ├── sv_SE.tsx │ │ │ └── zh_CN.tsx │ ├── index.tsx │ ├── index.zh-CN.md │ ├── locale │ │ ├── en_US.tsx │ │ ├── es_ES.tsx │ │ ├── ru_RU.tsx │ │ ├── sv_SE.tsx │ │ └── zh_CN.tsx │ └── utils.tsx ├── drawer │ ├── PropsType.tsx │ ├── index.tsx │ └── index.zh-CN.md ├── flex │ ├── Flex.tsx │ ├── FlexItem.tsx │ ├── PropsType.tsx │ ├── index.tsx │ └── index.zh-CN.md ├── grid │ ├── PropsType.tsx │ ├── index.tsx │ ├── index.zh-CN.md │ └── style │ │ └── index.tsx ├── icon │ ├── index.tsx │ └── index.zh-CN.md ├── image-picker │ ├── CameraRollPicker.tsx │ ├── ImageItem.tsx │ ├── ImageRoll.tsx │ ├── PropsType.tsx │ ├── index.tsx │ ├── index.zh-CN.md │ └── style │ │ └── index.tsx ├── index.tsx ├── input-item │ ├── Input.tsx │ ├── PropsType.tsx │ ├── index.tsx │ ├── index.zh-CN.md │ ├── locale │ │ ├── en_US.tsx │ │ ├── es_ES.tsx │ │ ├── ru_RU.tsx │ │ ├── sv_SE.tsx │ │ └── zh_CN.tsx │ └── style │ │ └── index.tsx ├── list-view │ ├── index.tsx │ ├── index.zh-CN.md │ ├── locale │ │ ├── en_US.tsx │ │ ├── es_ES.tsx │ │ ├── ru_RU.tsx │ │ ├── sv_SE.tsx │ │ └── zh_CN.tsx │ └── style │ │ └── index.tsx ├── list │ ├── ListItem.tsx │ ├── PropsType.tsx │ ├── index.tsx │ ├── index.zh-CN.md │ └── style │ │ └── index.tsx ├── locale-provider │ ├── en_US.tsx │ ├── es_ES.tsx │ ├── index.tsx │ ├── index.zh-CN.md │ ├── ru_RU.tsx │ ├── sv_SE.tsx │ └── zh_CN.tsx ├── modal │ ├── AlertContainer.tsx │ ├── Modal.tsx │ ├── ModalView.tsx │ ├── OperationContainer.tsx │ ├── PromptContainer.tsx │ ├── PropsType.tsx │ ├── alert.tsx │ ├── index.tsx │ ├── index.zh-CN.md │ ├── locale │ │ ├── en_US.tsx │ │ ├── ru_RU.tsx │ │ ├── sv_SE.tsx │ │ └── zh_CN.tsx │ ├── operation.tsx │ ├── prompt.tsx │ └── style │ │ ├── index.tsx │ │ └── prompt.tsx ├── notice-bar │ ├── Marquee.tsx │ ├── PropsType.tsx │ ├── index.tsx │ ├── index.zh-CN.md │ └── style │ │ └── index.tsx ├── pagination │ ├── PropsType.tsx │ ├── index.tsx │ ├── index.zh-CN.md │ ├── locale │ │ ├── en_US.tsx │ │ ├── es_ES.tsx │ │ ├── ru_RU.tsx │ │ ├── sv_SE.tsx │ │ └── zh_CN.tsx │ └── style │ │ └── index.tsx ├── picker-view │ ├── PickerView.tsx │ ├── index.tsx │ └── index.zh-CN.md ├── picker │ ├── MultiPicker.tsx │ ├── MultiPickerMixin.tsx │ ├── MultiPickerProps.tsx │ ├── NativePicker.android.tsx │ ├── NativePicker.ios.tsx │ ├── NativePicker.tsx │ ├── Picker.tsx │ ├── PickerMixin.tsx │ ├── PickerTypes.tsx │ ├── Popup.tsx │ ├── PopupMixin.tsx │ ├── PopupPickerTypes.tsx │ ├── PopupStyles.tsx │ ├── PropsType.tsx │ ├── cascader │ │ ├── Cascader.tsx │ │ ├── CascaderTypes.tsx │ │ ├── Popup.tsx │ │ ├── PopupStyles.tsx │ │ └── index.tsx │ ├── index.tsx │ ├── index.zh-CN.md │ ├── locale │ │ ├── en_US.tsx │ │ ├── es_ES.tsx │ │ ├── ru_RU.tsx │ │ ├── sv_SE.tsx │ │ └── zh_CN.tsx │ └── style │ │ └── index.tsx ├── popover │ ├── index.tsx │ ├── index.zh-CN.md │ └── style │ │ └── index.tsx ├── portal │ ├── README.md │ ├── index.tsx │ ├── portal-consumer.tsx │ ├── portal-host.tsx │ ├── portal-manager.tsx │ └── portal.tsx ├── progress │ ├── index.tsx │ ├── index.zh-CN.md │ └── style │ │ └── index.tsx ├── provider │ └── index.tsx ├── radio │ ├── PropsType.tsx │ ├── Radio.tsx │ ├── RadioItem.tsx │ ├── index.tsx │ ├── index.zh-CN.md │ └── style │ │ └── index.tsx ├── result │ ├── PropsType.tsx │ ├── index.tsx │ ├── index.zh-CN.md │ └── style │ │ └── index.tsx ├── search-bar │ ├── PropsType.tsx │ ├── index.tsx │ ├── index.zh-CN.md │ ├── locale │ │ ├── en_US.tsx │ │ ├── es_ES.tsx │ │ ├── ru_RU.tsx │ │ ├── sv_SE.tsx │ │ └── zh_CN.tsx │ └── style │ │ └── index.tsx ├── segmented-control │ ├── PropsType.tsx │ ├── index.tsx │ ├── index.zh-CN.md │ ├── segmented.android.tsx │ ├── segmented.ios.tsx │ └── style │ │ └── index.tsx ├── slider │ ├── index.tsx │ └── index.zh-CN.md ├── stepper │ ├── InputNumber.tsx │ ├── PropsType.tsx │ ├── index.tsx │ ├── index.zh-CN.md │ └── style │ │ └── index.tsx ├── steps │ ├── StepsItem.tsx │ ├── index.tsx │ ├── index.zh-CN.md │ └── style │ │ └── index.tsx ├── style │ ├── index.tsx │ └── themes │ │ └── default.tsx ├── swipe-action │ ├── index.tsx │ └── index.zh-CN.md ├── switch │ ├── PropsType.tsx │ ├── index.tsx │ └── index.zh-CN.md ├── tab-bar │ ├── PropsType.tsx │ ├── TabBarItem.tsx │ ├── index.tsx │ ├── index.zh-CN.md │ └── style │ │ └── index.tsx ├── tabs │ ├── DefaultTabBar.tsx │ ├── PropsType.tsx │ ├── Tabs.tsx │ ├── index.tsx │ ├── index.zh-CN.md │ └── style │ │ ├── index.tsx │ │ └── tabs.tsx ├── tag │ ├── PropsType.tsx │ ├── index.tsx │ ├── index.zh-CN.md │ └── style │ │ └── index.tsx ├── text │ └── index.tsx ├── textarea-item │ ├── PropsType.tsx │ ├── index.tsx │ ├── index.zh-CN.md │ └── style │ │ └── index.tsx ├── toast │ ├── ToastContainer.tsx │ ├── index.tsx │ ├── index.zh-CN.md │ └── style │ │ └── index.tsx ├── view │ └── index.tsx ├── white-space │ ├── index.tsx │ └── index.zh-CN.md └── wing-blank │ ├── index.tsx │ └── index.zh-CN.md ├── package.json ├── tsconfig.json ├── typings ├── custom.d.ts └── index.d.ts └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | end_of_line = lf 8 | indent_style = space 9 | indent_size = 2 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | lib/ 2 | components/ 3 | example/ 4 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | const eslintrc = { 2 | extends: ['eslint-config-airbnb'], 3 | env: { 4 | browser: true, 5 | node: true, 6 | mocha: true, 7 | jest: true, 8 | es6: true, 9 | }, 10 | parser: 'babel-eslint', 11 | parserOptions: { 12 | ecmaVersion: 6, 13 | ecmaFeatures: { 14 | jsx: true, 15 | experimentalObjectRestSpread: true, 16 | }, 17 | }, 18 | plugins: [ 19 | 'react', 20 | 'babel', 21 | 'jsx-a11y', 22 | ], 23 | rules: { 24 | 'class-methods-use-this': 0, 25 | 'func-names': 0, 26 | 'react/sort-comp': 0, 27 | 'react/prop-types': 0, 28 | 'react/jsx-first-prop-new-line': 0, 29 | 'no-param-reassign': 0, 30 | 'no-return-assign': 0, 31 | 'max-len': 0, 32 | 'react/no-multi-comp': 0, 33 | 'array-callback-return': 0, 34 | 'import/no-unresolved': 0, 35 | 'jsx-a11y/img-has-alt': 0, 36 | 'import/extensions': 0, 37 | 'import/no-extraneous-dependencies': 0, 38 | 'react/no-string-refs': 0, 39 | 'react/jsx-filename-extension': [1, { extensions: ['.js', '.jsx', '.tsx', '.md'] }], 40 | 'react/no-array-index-key': 0, 41 | 'react/no-find-dom-node': 0, 42 | 'react/require-extension': 0, 43 | 'jsx-a11y/anchor-has-content': 0, 44 | 'jsx-a11y/href-no-hash': 0, 45 | 'jsx-a11y/no-static-element-interactions': 0, 46 | 'jsx-a11y/click-events-have-key-events': 0, 47 | 'prefer-destructuring': 0, 48 | 'jsx-a11y/anchor-is-valid': 0, 49 | 'react/jsx-no-comment-textnodes': 0, 50 | 'object-curly-newline': 0, 51 | }, 52 | }; 53 | 54 | if (process.env.RUN_ENV === 'DEMO') { 55 | eslintrc.globals = { 56 | React: true, 57 | ReactDOM: true, 58 | mountNode: true, 59 | AlipayJSBridge: true, 60 | $: true, 61 | dd: true, 62 | process: true, 63 | }; 64 | 65 | Object.assign(eslintrc.rules, { 66 | 'no-console': 0, 67 | 'no-alert': 0, 68 | 'no-plusplus': 0, 69 | 'import/no-webpack-loader-syntax': 0, 70 | 'eol-last': 0, 71 | 'prefer-rest-params': 0, 72 | 'react/no-multi-comp': 0, 73 | }); 74 | } 75 | 76 | module.exports = eslintrc; 77 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .idea/ 3 | .ipr 4 | .iws 5 | *~ 6 | ~* 7 | *.diff 8 | *.patch 9 | *.bak 10 | .DS_Store 11 | Thumbs.db 12 | .project 13 | .*proj 14 | .svn/ 15 | *.swp 16 | *.swo 17 | *.log 18 | node_modules/ 19 | .buildpath 20 | .settings 21 | npm-debug.log 22 | nohup.out 23 | _site 24 | /dist 25 | lib 26 | elasticsearch-* 27 | config/base.yaml 28 | _data 29 | rn-kitchen-sink/ios/build 30 | rn-kitchen-sink/ios/bundle 31 | rn-kitchen-sink/android/bundle 32 | rn-kitchen-sink/android/.gradle 33 | rn-kitchen-sink/android/app/build 34 | rn-kitchen-sink/android/build 35 | rn-kitchen-sink/android/local.properties 36 | rn-kitchen-sink/android/app/src/main/res/drawable* 37 | rn-kitchen-sink/app/*.ipa 38 | rn-kitchen-sink/app/*.apk 39 | xcuserdata 40 | components/**/*.jsx 41 | components/**/*.js 42 | my-release-key.keystore 43 | # yarn.lock 44 | npm-debug.log* 45 | !components/**/__tests__/*.js 46 | !components/**/__mocks__/*.js 47 | coverage 48 | /es/ 49 | package-lock.json 50 | .cdnkey 51 | .jest 52 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | lib/**/demo/*.* 2 | es/**/demo/*.* 3 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | components/ 2 | lib/ 3 | example/ 4 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "singleQuote": true, 4 | "semi": true 5 | } 6 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | - [InputItem](./components/input-item/index.tsx) 2 | - 增加 `itemStyle?: ViewStyle` 属性 3 | - textAlign 增加 'right' 选项 4 | - 把 InputItem clear icon 设置为 x3s 5 | - InputItem clear 增加 textAlign 值不等于 right 才显示的条件 6 | - InputItem ios 下的默认高度设置为 44 7 | - [List](./components/list/index.tsx) 8 | - 增加了 noBorder 属性 9 | - [List.Item](./components/list/ListItem.tsx) 10 | - 增加 `last?: boolean` 属性 11 | - 增加 LineStyle 属性 12 | - 增加 extraStyle 属性 13 | - Extra 默认字体大小调为 16 14 | - [Icon](./components/icon/index.tsx) 15 | - icon size 添加 x3s 选项 16 | - [SearchBar](./components/search-bar/index.tsx) 17 | - 增加 `wrapperStyle?: StyleProp;` 属性 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT LICENSE 2 | 3 | Copyright (c) 2016-present Alipay.com, https://www.alipay.com/ 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | 5 |

6 | 7 | # Ant Design Mobile RN 8 | 9 | Ant Design 移动端设计规范。`@sishuguojixuefu/antd-mobile-rn` 是 Ant Design 的移动规范的 React 实现,服务于蚂蚁及口碑无线业务。 10 | 11 | ## 通知 12 | 13 | 新版本`3.x`已经重构完成并发布,安装升级请查看 [更新日志](https://rn.mobile.ant.design/changelog-cn) 14 | 15 | ## 特性 16 | 17 | - 基于 Ant Design 移动设计规范。 18 | - 规则化的视觉样式配置,适应各类产品风格。 19 | - 基于 React Native 的多平台支持。 20 | - 使用 TypeScript 开发,提供类型定义文件。 21 | 22 | ## 演示 23 | 24 | 25 | 26 | 请先安装 expo app: https://expo.io/tools 27 | 28 | ## 安装 & 使用 29 | 30 | ```bash 31 | npm install @sishuguojixuefu/antd-mobile-rn --save 32 | ``` 33 | 34 | or 35 | 36 | ```bash 37 | yarn add @sishuguojixuefu/antd-mobile-rn 38 | ``` 39 | 40 | ### 链接字体图标 41 | 42 | ```bash 43 | react-native link @ant-design/icons-react-native 44 | ``` 45 | 46 | ### 按需加载 47 | 48 | ```sh 49 | $ yarn add babel-plugin-import -D 50 | ``` 51 | 52 | **babel.config.js:** 53 | 54 | ```js 55 | plugins: [ 56 | ['import', { libraryName: '@sishuguojixuefu/antd-mobile-rn' }], 57 | ], 58 | ``` 59 | 60 | ### 使用 Modal、Toast 61 | 62 | 如果需要使用 `Modal` 以及 `Toast` 还需要在 App 的入口处加上 `Provider`: 63 | 64 | ```js 65 | import React, { Component } from 'react'; 66 | import { Button, Provider, Toast } from '@sishuguojixuefu/antd-mobile-rn'; 67 | 68 | export default class HelloWorldApp extends Component { 69 | render() { 70 | return ( 71 | 72 | 75 | 76 | ); 77 | } 78 | } 79 | ``` 80 | 81 | [介绍](https://github.com/ant-design/ant-design-mobile-rn/blob/master/docs/react/introduce.zh-CN.md#%E5%AE%89%E8%A3%85) 82 | 83 | ## 链接 84 | 85 | - [首页](http://rn.mobile.ant.design) 86 | - [底层 React 模块](http://github.com/react-component) 87 | 88 | ## 欢迎贡献 89 | 90 | 有任何建议或意见您可以进行 [提问](http://github.com/ant-design/ant-design-mobile-rn/issues)。 91 | -------------------------------------------------------------------------------- /components/_util/getLocale.tsx: -------------------------------------------------------------------------------- 1 | export function getComponentLocale( 2 | props: any, 3 | context: any, 4 | componentName: string, 5 | getDefaultLocale: () => any, 6 | ) { 7 | let locale: any = {}; 8 | if (context && context.antLocale && context.antLocale[componentName]) { 9 | locale = context.antLocale[componentName]; 10 | } else { 11 | const defaultLocale = getDefaultLocale(); 12 | // TODO: make default lang of antd be English 13 | // https://github.com/ant-design/ant-design/issues/6334 14 | locale = defaultLocale.default || defaultLocale; 15 | } 16 | 17 | let result = { 18 | ...locale, 19 | }; 20 | if (props.locale) { 21 | result = { 22 | ...result, 23 | ...props.locale, 24 | }; 25 | if (props.locale.lang) { 26 | result.lang = { 27 | ...locale.lang, 28 | ...props.locale.lang, 29 | }; 30 | } 31 | } 32 | return result; 33 | } 34 | 35 | export function getLocaleCode(context: any) { 36 | const localeCode = context.antLocale && context.antLocale.locale; 37 | // Had use LocaleProvide but didn't set locale 38 | if (context.antLocale && context.antLocale.exist && !localeCode) { 39 | return 'zh-cn'; 40 | } 41 | return localeCode; 42 | } 43 | -------------------------------------------------------------------------------- /components/_util/version.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /components/accordion/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Data Display 4 | title: Accordion 5 | subtitle: 手风琴 6 | --- 7 | 8 | 可以折叠/展开的内容区域。 9 | 10 | ### 规则 11 | - 对复杂区域进行分组和隐藏。 12 | - 通常,一次只允许单个内容区域展开;特殊情况,多个内容区域可以同时展开。 13 | 14 | 15 | ## API 16 | 17 | ### Accordion 18 | 19 | | 属性 | 说明 | 类型 | 默认值 | 20 | | ----------------- | --------------------------------------- | ------------------------- | ------ | 21 | | onChange(indexes) | 当section(s)发生变化的时候执行 | (indexes: number[])=>void | - | 22 | | activeSections | 初始化选中`sections` ,留空关闭所有面板 | number[] | [] | 23 | 24 | 更多自定义属性请参考 https://github.com/oblador/react-native-collapsible#properties-1 25 | 26 | 27 | ### Accordion.Panel 28 | 29 | | 属性 | 说明 | 类型 | 默认值 | 30 | | ------ | -------------- | ----------------------- | ------ | 31 | | key | 对应 activeKey | String | 无 | 32 | | header | 面板头内容 | React.Element or String | 无 | 33 | 34 | 注意: 目前暂不支持嵌套使用 35 | -------------------------------------------------------------------------------- /components/accordion/style/index.tsx: -------------------------------------------------------------------------------- 1 | import { StyleSheet, TextStyle, ViewStyle } from 'react-native'; 2 | import { Theme } from '../../style'; 3 | 4 | export interface AccordionStyle { 5 | container: ViewStyle; 6 | header: ViewStyle; 7 | arrow: TextStyle; 8 | headerWrap: ViewStyle; 9 | headerText: TextStyle; 10 | content: ViewStyle; 11 | contentText: TextStyle; 12 | } 13 | 14 | export default (theme: Theme) => 15 | StyleSheet.create({ 16 | container: { 17 | borderTopWidth: StyleSheet.hairlineWidth, 18 | borderTopColor: theme.border_color_base, 19 | }, 20 | header: { 21 | flexDirection: 'row', 22 | alignItems: 'center', 23 | paddingLeft: theme.h_spacing_lg, 24 | paddingRight: 2 * theme.h_spacing_lg, 25 | borderBottomWidth: StyleSheet.hairlineWidth, 26 | borderBottomColor: theme.border_color_base, 27 | }, 28 | arrow: { 29 | color: theme.color_icon_base, 30 | }, 31 | headerWrap: { 32 | flex: 1, 33 | height: theme.list_item_height, 34 | alignItems: 'center', 35 | flexDirection: 'row', 36 | }, 37 | headerText: { 38 | color: theme.color_text_base, 39 | fontSize: theme.font_size_heading, 40 | }, 41 | content: { 42 | paddingVertical: theme.v_spacing_md, 43 | paddingHorizontal: theme.h_spacing_md, 44 | borderBottomWidth: StyleSheet.hairlineWidth, 45 | borderBottomColor: theme.border_color_base, 46 | }, 47 | contentText: { 48 | fontSize: theme.font_size_subhead, 49 | color: theme.color_text_paragraph, 50 | }, 51 | }); 52 | -------------------------------------------------------------------------------- /components/action-sheet/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Feedback 4 | title: ActionSheet 5 | subtitle: 动作面板 6 | --- 7 | 8 | 从底部弹出的模态框,提供和当前场景相关的 2 个以上的操作动作,也支持提供标题和描述。内置固定的展示样式、不支持特别灵活的修改。 9 | 10 | ### 规则 11 | 12 | - 提供清晰的退出按钮。 13 | - 可高亮破坏性操作,e.g. 将『删除』处理成红色文本。 14 | - 不要放置过多内容,避免面板纵向滚动。 15 | 16 | 17 | ## API 18 | 19 | #### static showActionSheetWithOptions(options: Object, callback: Function) 20 | 21 | 显示 action sheet,`options`对象必须包含以下的一个或者多个: 22 | 23 | - options (array of strings) - 按钮标题列表 (required) 24 | - cancelButtonIndex (int) - 按钮列表中取消按钮的索引位置 25 | - destructiveButtonIndex (int) - 按钮列表中破坏性按钮(一般为删除)的索引位置 26 | - title (string) - 顶部标题 27 | - message (string/React.element) - 顶部标题下的简要消息 28 | 29 | #### static showShareActionSheetWithOptions(options: Object, failureCallback: Function, successCallback: Function) 30 | 31 | `React-Native only, react-native@version >= 0.39` 32 | 33 | 显示分享 action sheet,`options`对象必须包含以下的一个或者多个: 34 | 35 | - **options:** 36 | - message(`string`): 顶部标题下的简要消息 37 | - title(`string`): 顶部标题 38 | - url(`string`): 分享的 url `iOS only` 39 | - excludedActivityTypes(`array`): 指定在actionsheet中不显示的活动 `iOS only` 40 | - **Callback**: (`iOS only`, see [react-native/share](https://github.com/facebook/react-native/blob/master/Libraries/Share/Share.js#L80)) 41 | - failureCallback(error): 分享失败调用; 42 | - successCallback(completed, method):分享成功调用; 43 | 44 | #### static close() - (android only) programmatically close. 45 | -------------------------------------------------------------------------------- /components/action-sheet/style/index.tsx: -------------------------------------------------------------------------------- 1 | import { StyleSheet, TextStyle, ViewStyle } from 'react-native'; 2 | import { Theme } from '../../style'; 3 | 4 | export interface ActionSheetStyle { 5 | container: ViewStyle; 6 | wrap: ViewStyle; 7 | content: ViewStyle; 8 | mask: ViewStyle; 9 | title: ViewStyle; 10 | titleText: TextStyle; 11 | message: ViewStyle; 12 | btn: ViewStyle; 13 | cancelBtn: ViewStyle; 14 | cancelBtnMask: ViewStyle; 15 | destructiveBtn: TextStyle; 16 | } 17 | 18 | export default (theme: Theme) => StyleSheet.create({ 19 | container: { 20 | zIndex: theme.action_sheet_zindex, 21 | }, 22 | wrap: { 23 | position: 'absolute', 24 | left: 0, 25 | right: 0, 26 | top: 0, 27 | }, 28 | content: { 29 | position: 'absolute', 30 | left: 0, 31 | right: 0, 32 | bottom: 0, 33 | backgroundColor: theme.fill_base, 34 | }, 35 | mask: { 36 | position: 'absolute', 37 | top: 0, 38 | bottom: 0, 39 | left: 0, 40 | right: 0, 41 | backgroundColor: theme.fill_mask, 42 | }, 43 | title: { 44 | flex: 1, 45 | alignItems: 'center', 46 | // justifyContent: 'center', 47 | marginTop: theme.h_spacing_lg, 48 | marginBottom: theme.h_spacing_lg, 49 | }, 50 | titleText: { 51 | fontWeight: '500', 52 | }, 53 | message: { 54 | flex: 1, 55 | alignItems: 'center', 56 | // justifyContent: 'center', 57 | marginBottom: theme.h_spacing_lg, 58 | }, 59 | btn: { 60 | flex: 1, 61 | alignItems: 'center', 62 | justifyContent: 'center', 63 | height: theme.actionsheet_item_height, 64 | borderStyle: 'solid', 65 | borderTopWidth: 1, 66 | borderTopColor: theme.border_color_base, 67 | backgroundColor: 'white', 68 | }, 69 | cancelBtn: { 70 | marginTop: theme.v_spacing_md, 71 | position: 'relative', 72 | }, 73 | cancelBtnMask: { 74 | position: 'absolute', 75 | top: -theme.v_spacing_md, 76 | left: 0, 77 | right: 0, 78 | height: theme.v_spacing_md, 79 | backgroundColor: theme.fill_grey, 80 | borderStyle: 'solid', 81 | borderTopWidth: 1, 82 | borderTopColor: theme.border_color_base, 83 | }, 84 | destructiveBtn: { 85 | color: theme.brand_error, 86 | fontSize: theme.actionsheet_item_font_size, 87 | }, 88 | }); 89 | -------------------------------------------------------------------------------- /components/activity-indicator/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { ActivityIndicator, Text, View } from 'react-native'; 3 | import { WithTheme, WithThemeStyles } from '../style'; 4 | import ActivityIndicatorStyles, { ActivityIndicatorStyle } from './style/index'; 5 | 6 | export interface ActivityIndicatorNativeProps 7 | extends WithThemeStyles { 8 | styles?: ActivityIndicatorStyle; 9 | color?: string; 10 | animating?: boolean; 11 | toast?: boolean; 12 | size?: 'large' | 'small'; 13 | text?: string; 14 | } 15 | 16 | export default class RNActivityIndicator extends React.Component< 17 | ActivityIndicatorNativeProps, 18 | any 19 | > { 20 | static defaultProps = { 21 | animating: true, 22 | color: 'gray', 23 | size: 'small', 24 | toast: false, 25 | }; 26 | 27 | _renderToast() { 28 | const { color = 'white', size = 'large' } = this.props; 29 | 30 | return ( 31 | 35 | {styles => ( 36 | 37 | 38 | 39 | 40 | {this.props.text && ( 41 | {this.props.text} 42 | )} 43 | 44 | 45 | 46 | )} 47 | 48 | ); 49 | } 50 | 51 | _renderSpinner() { 52 | const { color, size, text } = this.props; 53 | return ( 54 | 58 | {styles => ( 59 | 60 | 61 | {text && {text}} 62 | 63 | )} 64 | 65 | ); 66 | } 67 | 68 | render() { 69 | if (this.props.animating) { 70 | return this.props.toast ? this._renderToast() : this._renderSpinner(); 71 | } 72 | return null; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /components/activity-indicator/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Feedback 4 | title: ActivityIndicator 5 | subtitle: 活动指示器 6 | --- 7 | 8 | 活动指示器。 9 | 表明某个任务正在进行中。 10 | 11 | ### 规则 12 | - 不要让活动指示器静止,用户会以为该任务停滞了。 13 | - 在某些特定场景下,提供有意义的文案,帮助用户明白哪个任务正在进行中,eg:正在上传照片。 14 | - 如果能知道用户的等待时间,可以使用组件 Progress 来替代。 15 | 16 | 17 | ## API 18 | 19 | ```jsx 20 | 21 | 22 | 23 | 24 | 25 | 26 | ``` 27 | 28 | ### ActivityIndicator 29 | 30 | 属性 | 说明 | 类型 | 默认值 31 | ----|-----|------|------ 32 | | animating | 显隐状态 | boolean | true | 33 | | size | spinner大小,可选`small`/`large` | string | small | 34 | | toast | loading样式类型 | boolean | false | 35 | | text | loading文本 | string | - | 36 | | color | spinner颜色 | string | gray | 37 | -------------------------------------------------------------------------------- /components/activity-indicator/style/index.tsx: -------------------------------------------------------------------------------- 1 | import { StyleSheet, TextStyle, ViewStyle } from 'react-native'; 2 | import { Theme } from '../../style'; 3 | 4 | export interface ActivityIndicatorStyle { 5 | container: ViewStyle; 6 | innerContainer: ViewStyle; 7 | wrapper: ViewStyle; 8 | tip: TextStyle; 9 | toast: TextStyle; 10 | spinner: ViewStyle; 11 | } 12 | 13 | export default (theme: Theme) => 14 | StyleSheet.create({ 15 | container: { 16 | position: 'absolute', 17 | top: 0, 18 | left: 0, 19 | bottom: 0, 20 | right: 0, 21 | backgroundColor: 'transparent', 22 | zIndex: theme.toast_zindex, 23 | }, 24 | innerContainer: { 25 | flex: 1, 26 | alignItems: 'center', 27 | justifyContent: 'center', 28 | backgroundColor: 'transparent', 29 | }, 30 | wrapper: { 31 | alignItems: 'center', 32 | justifyContent: 'center', 33 | width: 89, 34 | height: 89, 35 | borderRadius: theme.radius_md, 36 | backgroundColor: theme.toast_fill, 37 | }, 38 | tip: { 39 | color: theme.color_text_base, 40 | fontSize: theme.font_size_base, 41 | marginLeft: theme.h_spacing_md, 42 | }, 43 | toast: { 44 | color: theme.color_text_base_inverse, 45 | fontSize: theme.font_size_base, 46 | marginTop: theme.v_spacing_sm, 47 | }, 48 | spinner: { 49 | flexDirection: 'row', 50 | justifyContent: 'center', 51 | alignItems: 'center', 52 | }, 53 | }); 54 | -------------------------------------------------------------------------------- /components/badge/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { StyleProp, Text, View, ViewStyle } from 'react-native'; 3 | import { WithTheme, WithThemeStyles } from '../style'; 4 | import BadgeStyles, { BadgeStyle } from './style/index'; 5 | 6 | export interface BadgeProps extends WithThemeStyles { 7 | style?: StyleProp; 8 | size?: 'large' | 'small'; 9 | overflowCount?: number; 10 | corner?: boolean; 11 | dot?: boolean; 12 | text?: any; 13 | } 14 | 15 | export default class Badge extends React.Component { 16 | static defaultProps = { 17 | size: 'small', 18 | overflowCount: 99, 19 | dot: false, 20 | corner: false, 21 | }; 22 | 23 | render() { 24 | // tslint:disable:prefer-const 25 | let { 26 | styles, 27 | style, 28 | children, 29 | text, 30 | size, 31 | overflowCount, 32 | dot, 33 | corner, 34 | ...restProps // todo: hot 35 | } = this.props; 36 | return ( 37 | 38 | {s => { 39 | text = 40 | typeof text === 'number' && text > (overflowCount as number) 41 | ? `${overflowCount}+` 42 | : text; 43 | 44 | // dot mode don't need text 45 | if (dot) { 46 | text = ''; 47 | } 48 | // fake styles 49 | const fakeStyles = (s as any) as { [key: string]: ViewStyle }; 50 | const badgeCls = corner ? 'textCorner' : 'textDom'; 51 | const contentDom = !dot ? ( 52 | 56 | {text} 57 | 58 | ) : ( 59 | 63 | ); 64 | 65 | return ( 66 | 67 | 68 | {children} 69 | {text || dot ? contentDom : null} 70 | 71 | 72 | ); 73 | }} 74 | 75 | ); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /components/badge/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Data Display 4 | title: Badge 5 | subtitle: 徽标数 6 | --- 7 | 8 | 图标右上角的红点、数字或者文字。用于告知用户,该区域的状态变化或者待处理任务的数量。 9 | 10 | ### 规则 11 | 12 | - 当用户只需知道大致有内容更新时,应该使用红点型,如:社交中的群消息通知。 13 | - 当用户有必要知晓每条更新时,应该使用数字型。如:社交中的一对一的消息通知。 14 | 15 | ## API 16 | 17 | 属性 | 说明 | 类型 | 默认值 18 | ----|-----|------|------ 19 | size | 大小,可选 `large` `small` | string | `small` 20 | text | 展示的数字或文案,当为数字时候,大于 overflowCount
时显示为 ${overflowCount}+,为 0 时隐藏 | string\|number | - 21 | corner | 置于角落 | boolean | `false` 22 | dot | 不展示数字,只有一个小红点 | boolean | `false` 23 | overflowCount | 展示封顶的数字值 | number | `99` 24 | -------------------------------------------------------------------------------- /components/badge/style/index.tsx: -------------------------------------------------------------------------------- 1 | import { Platform, StyleSheet, TextStyle, ViewStyle } from 'react-native'; 2 | import { Theme } from '../../style'; 3 | 4 | export interface BadgeStyle { 5 | wrap: ViewStyle; 6 | textCornerWrap: ViewStyle; 7 | dot: ViewStyle; 8 | dotSizelarge: ViewStyle; 9 | textDom: ViewStyle; 10 | textCorner: ViewStyle; 11 | textCornerlarge: ViewStyle; 12 | text: TextStyle; 13 | } 14 | 15 | const grid = 4; 16 | 17 | export default (theme: Theme) => 18 | StyleSheet.create({ 19 | wrap: { 20 | flexDirection: 'row', 21 | }, 22 | textCornerWrap: { 23 | overflow: 'hidden', 24 | }, 25 | dot: { 26 | width: 2 * grid, 27 | height: 2 * grid, 28 | borderRadius: grid, 29 | backgroundColor: theme.brand_important, 30 | position: 'absolute', 31 | top: -1 * grid, 32 | right: -1 * grid, 33 | }, 34 | dotSizelarge: { 35 | width: 4 * grid, 36 | height: 4 * grid, 37 | borderRadius: 2 * grid, 38 | }, 39 | textDom: { 40 | paddingVertical: 0.5 * grid, 41 | paddingHorizontal: (Platform.OS === 'ios' ? 1.5 : 2) * grid, 42 | backgroundColor: theme.brand_important, 43 | borderRadius: 4 * theme.radius_sm, 44 | borderStyle: 'solid', 45 | position: 'absolute', 46 | top: -10, 47 | right: -15, 48 | }, 49 | textCorner: { 50 | width: 18 * grid, 51 | backgroundColor: theme.brand_important, 52 | transform: [ 53 | { 54 | rotate: '45deg', 55 | }, 56 | ], 57 | position: 'absolute', 58 | top: 2 * grid, 59 | }, 60 | textCornerlarge: { 61 | width: 26 * grid, 62 | top: 3 * grid, 63 | }, 64 | text: { 65 | color: theme.color_text_base_inverse, 66 | textAlign: 'center', 67 | }, 68 | }); 69 | -------------------------------------------------------------------------------- /components/button/PropsType.tsx: -------------------------------------------------------------------------------- 1 | export interface ButtonPropsType { 2 | type?: 'primary' | 'warning' | 'ghost'; 3 | size?: 'large' | 'small'; 4 | disabled?: boolean; 5 | loading?: boolean; 6 | } 7 | -------------------------------------------------------------------------------- /components/button/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Data Entry 4 | title: Button 5 | subtitle: 按钮 6 | --- 7 | 8 | 点击后会触发一个操作。 9 | 10 | 11 | ## API 12 | 13 | 属性 | 说明 | 类型 | 默认值 14 | ----|-----|------|------ 15 | | type | 按钮类型,可选值为`primary`/`ghost`/`warning`或者不设 | string | - | 16 | | size | 按钮大小,可选值为`large`、`small` | string | `large`| 17 | | activeStyle | 点击反馈的自定义样式 (设为 false 时表示禁止点击反馈) | {}/false | {} | 18 | | activeClassName | 点击反馈的自定义类名 | string | | 19 | | disabled | 设置禁用 | boolean | false | 20 | | onPress | 点击按钮的点击回调函数 | (e: Object): void | 无 | 21 | | style | 自定义样式 | Object | 无 | 22 | | onPressIn | 同 RN TouchableHighlight onPressIn | (e: Object): void | 无 | 23 | | onPressOut | 同 RN TouchableHighlight onPressOut | (e: Object): void | 无 | 24 | | onShowUnderlay | 同 RN TouchableHighlight onShowUnderlay | (e: Object): void | 无 | 25 | | onHideUnderlay | 同 RN TouchableHighlight onHideUnderlay | (e: Object): void | 无 | 26 | -------------------------------------------------------------------------------- /components/card/CardBody.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { StyleProp, View, ViewStyle } from 'react-native'; 3 | import { WithTheme, WithThemeStyles } from '../style'; 4 | import cardStyles, { CardStyle } from './style'; 5 | 6 | export interface CardBodyProps 7 | extends WithThemeStyles> { 8 | style?: StyleProp; 9 | } 10 | 11 | export default class CardBody extends React.Component { 12 | static defaultProps = { 13 | style: {}, 14 | }; 15 | 16 | render() { 17 | const { style, styles, ...restProps } = this.props; 18 | return ( 19 | 20 | {s => } 21 | 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /components/card/CardFooter.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { StyleProp, Text, View, ViewStyle } from 'react-native'; 3 | import { WithTheme, WithThemeStyles } from '../style'; 4 | import CardStyles, { CardStyle } from './style'; 5 | 6 | export interface CardFooterPropsType { 7 | content?: React.ReactNode; 8 | extra?: React.ReactNode; 9 | } 10 | 11 | export interface CardFooterProps 12 | extends CardFooterPropsType, 13 | WithThemeStyles< 14 | Pick 15 | > { 16 | style?: StyleProp; 17 | } 18 | 19 | export default class CardFooter extends React.Component { 20 | static defaultProps = { 21 | style: {}, 22 | }; 23 | 24 | render() { 25 | const { content, extra, styles, style, ...restProps } = this.props; 26 | 27 | return ( 28 | 29 | {s => { 30 | const contentDom = 31 | content !== undefined && React.isValidElement(content) ? ( 32 | {content} 33 | ) : ( 34 | {content} 35 | ); 36 | 37 | const extraDom = 38 | extra !== undefined && React.isValidElement(extra) ? ( 39 | {extra} 40 | ) : ( 41 | {extra} 42 | ); 43 | 44 | return ( 45 | 46 | {contentDom} 47 | {extra ? extraDom : null} 48 | 49 | ); 50 | }} 51 | 52 | ); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /components/card/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { StyleProp, View, ViewStyle } from 'react-native'; 3 | import { WithTheme, WithThemeStyles } from '../style'; 4 | import CardBody from './CardBody'; 5 | import CardFooter from './CardFooter'; 6 | import CardHeader from './CardHeader'; 7 | import CardStyles, { CardStyle } from './style/index'; 8 | 9 | export interface CardNativeProps extends WithThemeStyles { 10 | style?: StyleProp; 11 | full?: boolean; 12 | } 13 | 14 | export default class Card extends React.Component { 15 | static defaultProps = { 16 | style: {}, 17 | full: false, 18 | }; 19 | 20 | static Header = CardHeader; 21 | static Body = CardBody; 22 | static Footer = CardFooter; 23 | 24 | render() { 25 | const { style, styles, full, children, ...restProps } = this.props; 26 | return ( 27 | 28 | {(s) => { 29 | const cardStyle = full ? s.full : {}; 30 | const childDom = React.Children.map(children, child => 31 | React.cloneElement(child as React.ReactElement, { s }), 32 | ); 33 | return ( 34 | 35 | {childDom} 36 | 37 | ); 38 | }} 39 | 40 | ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /components/card/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Data Display 4 | title: Card 5 | subtitle: 卡片 6 | --- 7 | 8 | 用于组织信息和操作,通常也作为详细信息的入口。 9 | 10 | ### 规则 11 | - 形状为矩形。 12 | - 可包含多种类型的元素,eg:图片、文字、按钮等。 13 | 14 | ## API 15 | 16 | ### Card 17 | 18 | 属性 | 说明 | 类型 | 默认值 19 | ----|-----|------|------ 20 | | full | 是否通栏 | boolean | `false` | 21 | 22 | ### Card.Header 23 | 24 | 属性 | 说明 | 类型 | 默认值 25 | ----|-----|------|------ 26 | |title| 卡片标题 | React.Element、String | | 27 | |thumb| 卡片标题图片 | String、React.Element | | 28 | |thumbStyle| 标题图片样式 | Object | {} | 29 | |extra| 卡片标题辅助内容 | React.Element、String | | 30 | 31 | ### Card.Body 32 | 33 | 属性 | 说明 | 类型 | 默认值 34 | ----|-----|------|------ 35 | |无| | | | 36 | 37 | ### Card.Footer 38 | 39 | 属性 | 说明 | 类型 | 默认值 40 | ----|-----|------|------ 41 | |content|尾部内容 | React.Element、String | | 42 | |extra| 尾部辅助内容 | React.Element、String | | 43 | -------------------------------------------------------------------------------- /components/card/style/index.tsx: -------------------------------------------------------------------------------- 1 | import { ImageStyle, StyleSheet, TextStyle, ViewStyle } from 'react-native'; 2 | import { Theme } from '../../style'; 3 | 4 | export interface CardStyle { 5 | card: ViewStyle; 6 | full: ViewStyle; 7 | headerWrap: ViewStyle; 8 | headerTitle: ViewStyle; 9 | headerImage: ImageStyle; 10 | headerContentWrap: ViewStyle; 11 | headerContent: TextStyle; 12 | headerExtraWrap: ViewStyle; 13 | headerExtra: TextStyle; 14 | body: ViewStyle; 15 | footerWrap: ViewStyle; 16 | footerContent: TextStyle; 17 | footerExtra: TextStyle; 18 | } 19 | 20 | export default (theme: Theme) => 21 | StyleSheet.create({ 22 | card: { 23 | borderWidth: theme.border_width_md, 24 | borderColor: theme.border_color_base, 25 | borderRadius: theme.radius_md, 26 | paddingBottom: theme.v_spacing_sm, 27 | flexDirection: 'column', 28 | backgroundColor: theme.fill_base, 29 | }, 30 | full: { 31 | borderRadius: 0, 32 | borderLeftWidth: 0, 33 | borderRightWidth: 0, 34 | }, 35 | headerWrap: { 36 | flexDirection: 'row', 37 | paddingVertical: theme.v_spacing_sm, 38 | paddingRight: theme.h_spacing_lg, 39 | marginLeft: theme.h_spacing_lg, 40 | alignItems: 'center', 41 | }, 42 | headerTitle: { 43 | flex: 1, 44 | flexDirection: 'row', 45 | alignItems: 'center', 46 | }, 47 | headerImage: { 48 | marginRight: theme.h_spacing_sm, 49 | }, 50 | headerContentWrap: { 51 | flex: 1, 52 | }, 53 | headerContent: { 54 | color: theme.color_text_base, 55 | fontSize: theme.font_size_heading, 56 | flex: 1, 57 | }, 58 | headerExtraWrap: { 59 | flex: 1, 60 | }, 61 | headerExtra: { 62 | flex: 1, 63 | fontSize: theme.font_size_heading, 64 | color: theme.color_text_caption, 65 | textAlign: 'right', 66 | }, 67 | body: { 68 | flexGrow: 1, 69 | paddingVertical: theme.v_spacing_md, 70 | minHeight: 48, 71 | borderTopWidth: theme.border_width_md, 72 | borderColor: theme.border_color_base, 73 | }, 74 | footerWrap: { 75 | flexDirection: 'row', 76 | paddingHorizontal: theme.h_spacing_lg, 77 | }, 78 | footerContent: { 79 | flex: 1, 80 | fontSize: theme.font_size_base, 81 | color: theme.color_text_caption, 82 | }, 83 | footerExtra: { 84 | textAlign: 'right', 85 | fontSize: theme.font_size_base, 86 | color: theme.color_text_caption, 87 | }, 88 | }); 89 | -------------------------------------------------------------------------------- /components/carousel/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Data Display 4 | title: Carousel 5 | subtitle: 走马灯 6 | --- 7 | 8 | 走马灯,轮播图 9 | 10 | ## API 11 | 12 | 属性 | 说明 | 类型 | 默认值 13 | ----|-----|------|------ 14 | | selectedIndex | 手动设置当前显示的索引 | number | 0 | 15 | | dots | 是否显示面板指示点 | Boolean | true | 16 | | vertical | 垂直显示 | Boolean | false | 17 | | autoplay | 是否自动切换 | Boolean | false | 18 | | autoplayInterval | 自动切换的时间间隔 | Number | 3000 | 19 | | infinite | 是否循环播放 | Boolean | false | 20 | | afterChange | 切换面板后的回调函数 | (current: number): void | 无 | 21 | | dotStyle | 指示点样式 | Object | 无 | 22 | | dotActiveStyle | 当前激活的指示点样式 | Object | 无 | 23 | | onScrollBeginDrag | 见 react-native scrollView onScrollBeginDrag | (): void | 无 | 24 | | bounces | 见 react-native scrollView bounces | Boolean | true | 25 | | pagination | 自定义 pagination | (props) => React.ReactNode | | 26 | -------------------------------------------------------------------------------- /components/carousel/style/index.tsx: -------------------------------------------------------------------------------- 1 | import { StyleSheet, ViewStyle } from 'react-native'; 2 | import { Theme } from '../../style'; 3 | 4 | export interface CarouselStyle { 5 | pagination: ViewStyle; 6 | paginationX: ViewStyle; 7 | paginationY: ViewStyle; 8 | pointStyle: ViewStyle; 9 | pointActiveStyle: ViewStyle; 10 | spaceStyle: ViewStyle; 11 | } 12 | export default (theme: Theme) => 13 | StyleSheet.create({ 14 | pagination: { 15 | position: 'absolute', 16 | alignItems: 'center', 17 | }, 18 | paginationX: { 19 | bottom: 10, 20 | left: 0, 21 | right: 0, 22 | }, 23 | paginationY: { 24 | right: 10, 25 | top: 0, 26 | bottom: 0, 27 | }, 28 | pointStyle: { 29 | width: 8, 30 | height: 8, 31 | borderRadius: 8, 32 | backgroundColor: theme.color_icon_base, 33 | }, 34 | pointActiveStyle: { 35 | backgroundColor: '#888', 36 | }, 37 | spaceStyle: { 38 | marginHorizontal: theme.h_spacing_sm / 2, 39 | marginVertical: theme.v_spacing_sm / 2, 40 | }, 41 | }); 42 | -------------------------------------------------------------------------------- /components/checkbox/AgreeItem.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { ImageStyle, StyleProp, Text, TouchableWithoutFeedback, View, ViewStyle } from 'react-native'; 3 | import { WithTheme, WithThemeStyles } from '../style'; 4 | import Checkbox from './Checkbox'; 5 | import { CheckboxPropsType } from './PropsType'; 6 | import AgreeItemstyles, { CheckboxStyle } from './style/index'; 7 | 8 | export interface AgreeItemProps 9 | extends CheckboxPropsType, 10 | WithThemeStyles { 11 | checkboxStyle?: StyleProp; 12 | style?: StyleProp; 13 | } 14 | 15 | export default class AgreeItem extends React.Component { 16 | checkbox: Checkbox | null; 17 | 18 | handleClick = () => { 19 | if (this.checkbox) { 20 | this.checkbox.handleClick(); 21 | } 22 | }; 23 | 24 | render() { 25 | const { 26 | style, 27 | checkboxStyle, 28 | children, 29 | disabled, 30 | checked, 31 | defaultChecked, 32 | onChange, 33 | } = this.props; 34 | 35 | return ( 36 | 37 | {styles => { 38 | const contentDom = !children ? null : React.isValidElement( 39 | children, 40 | ) ? ( 41 | children 42 | ) : ( 43 | {children} 44 | ); 45 | 46 | return ( 47 | 48 | 49 | (this.checkbox = ref)} 51 | style={[styles.agreeItemCheckbox, checkboxStyle]} 52 | disabled={disabled} 53 | checked={checked} 54 | defaultChecked={defaultChecked} 55 | onChange={onChange} 56 | /> 57 | {contentDom} 58 | 59 | 60 | ); 61 | }} 62 | 63 | ); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /components/checkbox/CheckboxItem.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { StyleProp, TextStyle, ViewStyle } from 'react-native'; 3 | import List from '../list/index'; 4 | import { WithTheme, WithThemeStyles } from '../style'; 5 | import Checkbox from './Checkbox'; 6 | import { CheckboxItemPropsType } from './PropsType'; 7 | import CheckboxItemStyles, { CheckboxStyle } from './style/index'; 8 | 9 | const ListItem = List.Item; 10 | 11 | export interface CheckboxItemProps 12 | extends CheckboxItemPropsType, 13 | WithThemeStyles { 14 | checkboxStyle?: StyleProp; 15 | style?: StyleProp; 16 | } 17 | 18 | export default class CheckboxItem extends React.Component< 19 | CheckboxItemProps, 20 | any 21 | > { 22 | checkbox: Checkbox | null; 23 | handleClick = () => { 24 | if (this.checkbox) { 25 | this.checkbox.handleClick(); 26 | } 27 | if (this.props.onPress) { 28 | this.props.onPress(); 29 | } 30 | }; 31 | 32 | render() { 33 | const { 34 | style, 35 | checkboxStyle, 36 | defaultChecked, 37 | checked, 38 | disabled, 39 | children, 40 | extra, 41 | onChange, 42 | } = this.props; 43 | 44 | const thumbNode = ( 45 | 46 | {styles => ( 47 | (this.checkbox = ref)} 49 | style={[styles.checkboxItemCheckbox, checkboxStyle]} 50 | defaultChecked={defaultChecked} 51 | checked={checked} 52 | onChange={onChange} 53 | disabled={disabled} 54 | /> 55 | )} 56 | 57 | ); 58 | return ( 59 | 65 | {children} 66 | 67 | ); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /components/checkbox/PropsType.tsx: -------------------------------------------------------------------------------- 1 | export interface OnChangeParams { 2 | target: { 3 | checked: boolean; 4 | }; 5 | } 6 | export interface CheckboxPropsType { 7 | defaultChecked?: boolean; 8 | checked?: boolean; 9 | disabled?: boolean; 10 | onChange?: (params: OnChangeParams) => void; 11 | } 12 | 13 | export interface CheckboxItemPropsType extends CheckboxPropsType { 14 | extra?: React.ReactNode; 15 | prefixCls?: string; 16 | onPress?: (e?: any) => void; 17 | } 18 | -------------------------------------------------------------------------------- /components/checkbox/index.tsx: -------------------------------------------------------------------------------- 1 | import AgreeItem from './AgreeItem'; 2 | import Checkbox from './Checkbox'; 3 | import CheckboxItem from './CheckboxItem'; 4 | 5 | Checkbox.AgreeItem = AgreeItem; 6 | Checkbox.CheckboxItem = CheckboxItem; 7 | 8 | export default Checkbox; 9 | -------------------------------------------------------------------------------- /components/checkbox/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Data Entry 4 | title: Checkbox 5 | subtitle: 复选框 6 | --- 7 | 8 | 复选框 9 | 10 | ## API 11 | 12 | ### Checkbox 13 | 14 | 属性 | 说明 | 类型 | 默认值 15 | ----|-----|------|------ 16 | | defaultChecked | 初始是否选中 | Boolean | 无 | 17 | | checked | 指定当前是否选中 | Boolean | 无 | 18 | | disabled | | Boolean | false | 19 | | onChange | change 事件触发的回调函数 | (e: Object): void | 无 | 20 | 21 | ### Checkbox.CheckboxItem 22 | 23 | 基于`List.Item`对`Checkbox`进行封装,`List.Item`的`thumb`属性固定传入`Checkbox`,其他属性和`List.Item`一致。 24 | 其他 API 和 Checkbox 相同。 25 | 26 | ### Checkbox.AgreeItem 27 | 28 | 用于同意协议这种场景的复选框 29 | -------------------------------------------------------------------------------- /components/checkbox/style/index.tsx: -------------------------------------------------------------------------------- 1 | import { StyleSheet, TextStyle, ViewStyle } from 'react-native'; 2 | import { Theme } from '../../style'; 3 | 4 | export interface CheckboxStyle { 5 | wrapper: ViewStyle; 6 | icon: TextStyle; 7 | iconRight: TextStyle; 8 | agreeItem: ViewStyle; 9 | agreeItemCheckbox: TextStyle; 10 | checkboxItemCheckbox: TextStyle; 11 | } 12 | 13 | export default (theme: Theme) => 14 | StyleSheet.create({ 15 | wrapper: { 16 | flexDirection: 'row', 17 | alignItems: 'center', 18 | }, 19 | icon: { 20 | width: theme.icon_size_sm, 21 | height: theme.icon_size_sm, 22 | }, 23 | iconRight: { 24 | marginLeft: theme.h_spacing_md, 25 | }, 26 | agreeItem: { 27 | flexDirection: 'row', 28 | alignItems: 'center', 29 | }, 30 | agreeItemCheckbox: { 31 | marginLeft: theme.h_spacing_lg, 32 | marginRight: theme.h_spacing_md, 33 | }, 34 | checkboxItemCheckbox: { 35 | marginRight: theme.h_spacing_md, 36 | alignSelf: 'center', 37 | }, 38 | }); 39 | -------------------------------------------------------------------------------- /components/date-picker-view/PropsType.tsx: -------------------------------------------------------------------------------- 1 | import { DatePickerPropsType } from '../date-picker/PropsType'; 2 | 3 | export interface DatePickerProps extends DatePickerPropsType { 4 | onScrollChange?: (newValue: any, vals: any, index: number) => void; 5 | triggerTypes?: string; 6 | styles?: any; 7 | } 8 | -------------------------------------------------------------------------------- /components/date-picker-view/date-picker-view.tsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | import RCDatePicker from '../date-picker/datepicker'; 4 | import { getComponentLocale } from '../_util/getLocale'; 5 | import { DatePickerProps } from './PropsType'; 6 | export default class DatePickerView extends React.Component< 7 | DatePickerProps, 8 | any 9 | > { 10 | static defaultProps = { 11 | mode: 'datetime', 12 | // extra: '请选择', 13 | minuteStep: 1, 14 | use12Hours: false, 15 | }; 16 | 17 | static contextTypes = { 18 | antLocale: PropTypes.object, 19 | }; 20 | 21 | render() { 22 | // tslint:disable-next-line:no-this-assignment 23 | const { props, context } = this; 24 | const locale = getComponentLocale(props, context, 'DatePickerView', () => 25 | require('./locale/zh_CN'), 26 | ); 27 | 28 | // DatePicker use `defaultDate`, maybe because there are PopupDatePicker inside? @yiminghe 29 | // Here Use `date` instead of `defaultDate`, make it controlled fully. 30 | return ( 31 | 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /components/date-picker-view/index.tsx: -------------------------------------------------------------------------------- 1 | import DatePickerView from './date-picker-view'; 2 | 3 | export default DatePickerView; 4 | -------------------------------------------------------------------------------- /components/date-picker-view/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Data Entry 4 | title: DatePickerView 5 | subtitle: 选择器 6 | --- 7 | 8 | DatePickerView 的功能类似于 DatePicker ,但它是直接渲染在区域中,而不是弹出窗口。 9 | 10 | ## API 11 | 12 | 属性 | 说明 | 类型 | 默认值 13 | ----|-----|------|------ 14 | | mode | 日期选择的类型, 可以是日期`date`,时间`time`,日期+时间`datetime`,年`year`,月`month` | String | `date` | 15 | | value | 当前选中时间 | Date | 无 | 16 | | minDate | 最小可选日期 | Date | 2000-1-1 | 17 | | maxDate | 最大可选日期 | Date | 2030-1-1 | 18 | | minuteStep | 分钟数递增步长设置 | Number | 1 | 19 | | locale | 国际化,可覆盖全局`[LocaleProvider](https://mobile.ant.design/components/locale-provider)`的配置 | Object: {DatePickerLocale: {year, month, day, hour, minute, am?, pm?}, okText, dismissText } | - | 20 | | disabled | 是否不可用 | Boolean | false | 21 | | use12Hours | 12小时制 | Boolean | false | 22 | | onChange | 时间发生变化的回调函数 | (date: Object): void | - | 23 | | onValueChange | 每列 picker 改变时的回调 | (vals: any, index: number) => void | - | 24 | -------------------------------------------------------------------------------- /components/date-picker-view/locale/en_US.tsx: -------------------------------------------------------------------------------- 1 | import DatePickerLocale from '../../date-picker/datepicker/locale/en_US'; 2 | 3 | export default DatePickerLocale; 4 | -------------------------------------------------------------------------------- /components/date-picker-view/locale/es_ES.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | calendar: { 3 | // in minutes 4 | timezoneOffset: 1 * 60, 5 | firstDayOfWeek: 0, 6 | minimalDaysInFirstWeek: 1, 7 | }, 8 | year: '', 9 | month: '', 10 | day: '', 11 | hour: '', 12 | minute: '', 13 | }; 14 | -------------------------------------------------------------------------------- /components/date-picker-view/locale/ru_RU.tsx: -------------------------------------------------------------------------------- 1 | import DatePickerLocale from '../../date-picker/datepicker/locale/ru_RU'; 2 | 3 | export default DatePickerLocale; 4 | -------------------------------------------------------------------------------- /components/date-picker-view/locale/sv_SE.tsx: -------------------------------------------------------------------------------- 1 | import DatePickerLocale from '../../date-picker/datepicker/locale/sv_SE'; 2 | 3 | export default DatePickerLocale; 4 | -------------------------------------------------------------------------------- /components/date-picker-view/locale/zh_CN.tsx: -------------------------------------------------------------------------------- 1 | import DatePickerLocale from '../../date-picker/datepicker/locale/zh_CN'; 2 | 3 | export default DatePickerLocale; 4 | -------------------------------------------------------------------------------- /components/date-picker/PropsType.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import AntDatePickerProps from './datepicker/DatePickerProps'; 3 | export interface DatePickerPropsType extends AntDatePickerProps { 4 | value?: Date; 5 | mode?: 'datetime' | 'date' | 'year' | 'month' | 'time'; 6 | minDate?: Date; 7 | maxDate?: Date; 8 | onChange?: (value: Date) => void; 9 | onValueChange?: (vals: any, index: number) => void; 10 | visible?: boolean; 11 | use12Hours?: boolean; 12 | onDismiss?: () => void; 13 | locale?: { 14 | okText: string; 15 | dismissText: string; 16 | extra: string; 17 | DatePickerLocale: { 18 | year: string; 19 | month: string; 20 | day: string; 21 | hour: string; 22 | minute: string; 23 | am?: string; 24 | pm?: string; 25 | }; 26 | }; 27 | minuteStep?: number; 28 | disabled?: boolean; 29 | format?: string | ((value: Date) => string); 30 | extra?: string; 31 | children?: React.ReactNode; 32 | dismissText?: React.ReactNode; 33 | okText?: React.ReactNode; 34 | title?: React.ReactNode; 35 | } 36 | -------------------------------------------------------------------------------- /components/date-picker/datepicker/DatePickerProps.tsx: -------------------------------------------------------------------------------- 1 | import { StyleProp, ViewStyle } from "react-native"; 2 | 3 | interface DatePickerProps { 4 | date?: any; 5 | defaultDate?: any; 6 | minDate?: any; 7 | maxDate?: any; 8 | mode?: string; 9 | disabled?: boolean; 10 | locale?: any; 11 | minuteStep?: number; 12 | formatMonth?: (month: number, date?: any) => any; 13 | formatDay?: (day: number, date?: any) => any; 14 | onDateChange?: (date: any) => void; 15 | onValueChange?: (vals: any, index: number) => void; 16 | itemStyle?: StyleProp; 17 | style?: StyleProp; 18 | onScrollChange?: (date: any, vals: any, index: number) => void; 19 | rootNativeProps?: {}; 20 | use12Hours?: boolean; 21 | } 22 | 23 | export default DatePickerProps; 24 | -------------------------------------------------------------------------------- /components/date-picker/datepicker/Popup.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PopupPicker from '../../picker/Popup'; 3 | import { PopupPickerProps } from '../../picker/PopupPickerTypes'; 4 | import DatePickerProps from './DatePickerProps'; 5 | 6 | export interface PopupDatePickerProps extends PopupPickerProps { 7 | datePicker: React.ReactElement; 8 | onChange?: (date?: any) => void; 9 | date?: any; 10 | } 11 | 12 | class PopupDatePicker extends React.Component { 13 | static defaultProps = { 14 | pickerValueProp: 'date', 15 | pickerValueChangeProp: 'onDateChange', 16 | }; 17 | 18 | onOk = (v: any) => { 19 | const { onChange, onOk } = this.props; 20 | if (onChange) { 21 | onChange(v); 22 | } 23 | if (onOk) { 24 | onOk(v); 25 | } 26 | } 27 | 28 | render() { 29 | return (); 35 | } 36 | } 37 | 38 | export default PopupDatePicker; 39 | -------------------------------------------------------------------------------- /components/date-picker/datepicker/PopupStyles.tsx: -------------------------------------------------------------------------------- 1 | export { default } from '../../picker/PopupStyles'; 2 | -------------------------------------------------------------------------------- /components/date-picker/datepicker/index.tsx: -------------------------------------------------------------------------------- 1 | export { default } from './DatePicker'; 2 | -------------------------------------------------------------------------------- /components/date-picker/datepicker/locale/en_US.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | year: '', 3 | month: '', 4 | day: '', 5 | hour: '', 6 | minute: '', 7 | am: 'AM', 8 | pm: 'PM', 9 | }; 10 | -------------------------------------------------------------------------------- /components/date-picker/datepicker/locale/fa_IR.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | year: 'سال', 3 | month: 'ماه', 4 | day: 'روز', 5 | hour: 'ساعت', 6 | minute: 'دقیقه', 7 | am: 'صبح', 8 | pm: 'بعد از ظهر', 9 | }; 10 | -------------------------------------------------------------------------------- /components/date-picker/datepicker/locale/id_ID.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | year: '', 3 | month: '', 4 | day: '', 5 | hour: '', 6 | minute: '', 7 | am: 'AM', 8 | pm: 'PM', 9 | }; 10 | -------------------------------------------------------------------------------- /components/date-picker/datepicker/locale/pt_BR.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | year: 'Ano', 3 | month: 'Mês', 4 | day: 'Dia', 5 | hour: 'Hora', 6 | minute: 'Minuto', 7 | am: 'AM', 8 | pm: 'PM', 9 | }; 10 | -------------------------------------------------------------------------------- /components/date-picker/datepicker/locale/ru_RU.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | year: '', 3 | month: '', 4 | day: '', 5 | hour: '', 6 | minute: '', 7 | am: 'AM', 8 | pm: 'PM', 9 | }; 10 | -------------------------------------------------------------------------------- /components/date-picker/datepicker/locale/sv_SE.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | year: '', 3 | month: '', 4 | day: '', 5 | hour: '', 6 | minute: '', 7 | am: 'AM', 8 | pm: 'PM', 9 | }; 10 | -------------------------------------------------------------------------------- /components/date-picker/datepicker/locale/zh_CN.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | year: '年', 3 | month: '月', 4 | day: '日', 5 | hour: '时', 6 | minute: '分', 7 | am: '上午', 8 | pm: '下午', 9 | }; 10 | -------------------------------------------------------------------------------- /components/date-picker/index.tsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | import PickerStyles, { PickerStyle } from '../picker/style/index'; 4 | import { WithTheme, WithThemeStyles } from '../style'; 5 | import { getComponentLocale } from '../_util/getLocale'; 6 | import AntDatePicker from './datepicker'; 7 | import PopupDatePicker from './datepicker/Popup'; 8 | import { DatePickerPropsType } from './PropsType'; 9 | import { formatProps } from './utils'; 10 | 11 | export interface DatePickerProps 12 | extends DatePickerPropsType, 13 | WithThemeStyles { 14 | triggerTypes?: string; 15 | } 16 | 17 | export default class DatePicker extends React.Component { 18 | static defaultProps = { 19 | mode: 'datetime', 20 | triggerType: 'onPress', 21 | minuteStep: 1, 22 | }; 23 | static contextTypes = { 24 | antLocale: PropTypes.object, 25 | }; 26 | render() { 27 | const { children, value, itemStyle } = this.props; 28 | const locale = getComponentLocale( 29 | this.props, 30 | (this as any).context, 31 | 'DatePicker', 32 | () => require('./locale/zh_CN'), 33 | ); 34 | 35 | const { okText, dismissText, extra, DatePickerLocale } = locale; 36 | 37 | const dataPicker = ( 38 | 48 | ); 49 | 50 | return ( 51 | 52 | {styles => ( 53 | 61 | {children && 62 | React.isValidElement(children) && 63 | React.cloneElement(children as any, { 64 | extra: value 65 | ? formatProps(this.props, value) 66 | : this.props.extra || extra, 67 | })} 68 | 69 | )} 70 | 71 | ); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /components/date-picker/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Data Entry 4 | title: DatePicker 5 | subtitle: 日期选择 6 | --- 7 | 8 | 用于选择日期或者时间。 9 | 10 | ### 规则 11 | - 最多展示 5 个独立滚轮,每个滚轮表示一个不同的值。 12 | 13 | 14 | ## API 15 | 16 | 属性 | 说明 | 类型 | 默认值 17 | ----|-----|------|------ 18 | | mode | 日期选择的类型, 可以是日期`date`,时间`time`,日期+时间`datetime`,年`year`,月`month` | String | `date` | 19 | | value | 当前选中时间 | Date | 无 | 20 | | minDate | 最小可选日期 | Date | 2000-1-1 | 21 | | maxDate | 最大可选日期 | Date | 2030-1-1 | 22 | | minuteStep | 分钟数递增步长设置 | Number | 1 | 23 | | locale | 国际化,可覆盖全局`[LocaleProvider](https://mobile.ant.design/components/locale-provider)`的配置 | Object: {DatePickerLocale: {year, month, day, hour, minute, am?, pm?}, okText, dismissText } | - | 24 | | disabled | 是否不可用 | Boolean | false | 25 | | onChange | 时间发生变化的回调函数 | (date: Object): void | - | 26 | | onValueChange | 每列 picker 改变时的回调 | (vals: any, index: number) => void | - | 27 | | format | 格式化选中的值 | `(value: Date) => date string` / `format string`(对应 mode 下格式分别为:`YYYY-MM-DD`,`HH:mm`,`YYYY-MM-DD HH:mm`) | - | 28 | | title | 弹框的标题 | string/React.ReactElement | 无 | 29 | | itemStyle | itemStyle | StyleProp; 30 | | - | 31 | | extra | 显示文案 | String | `请选择` | 32 | | onOk | 点击选中时执行的回调 | (val): void | 无 | 33 | | onDismiss | 点击取消时执行的回调 | (): void | 无 | 34 | 35 | 注意:日期字符串在不同浏览器有不同的实现,例如 `new Date('2017-1-1')` 在 Safari 上是 Invalid Date,而在 Chrome 上是能正常解析的。 36 | 37 | 注意:`DatePicker` children 建议是 `List.Item`, 如果不是,需要是自定义组件(组件内需处理 `onClick` / `extra` / `children` 属性,详情请看 [demo](/components/date-picker-cn) 38 | -------------------------------------------------------------------------------- /components/date-picker/locale/en_US.tsx: -------------------------------------------------------------------------------- 1 | import DatePickerLocale from '../datepicker/locale/en_US'; 2 | 3 | export default { 4 | okText: 'OK', 5 | dismissText: 'Cancel', 6 | extra: 'please select', 7 | DatePickerLocale, 8 | }; 9 | -------------------------------------------------------------------------------- /components/date-picker/locale/es_ES.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | okText: 'OK', 3 | dismissText: 'Cancelar', 4 | extra: 'Seleccione', 5 | DatePickerLocale: { 6 | calendar: { 7 | // in minutes 8 | timezoneOffset: 1 * 60, 9 | firstDayOfWeek: 0, 10 | minimalDaysInFirstWeek: 1, 11 | }, 12 | year: '', 13 | month: '', 14 | day: '', 15 | hour: '', 16 | minute: '', 17 | }, 18 | }; 19 | -------------------------------------------------------------------------------- /components/date-picker/locale/ru_RU.tsx: -------------------------------------------------------------------------------- 1 | import DatePickerLocale from '../datepicker/locale/en_US'; 2 | 3 | export default { 4 | okText: 'Ок', 5 | dismissText: 'Отмена', 6 | extra: '', 7 | DatePickerLocale, 8 | }; 9 | -------------------------------------------------------------------------------- /components/date-picker/locale/sv_SE.tsx: -------------------------------------------------------------------------------- 1 | import DatePickerLocale from '../datepicker/locale/en_US'; 2 | 3 | export default { 4 | okText: 'Ok', 5 | dismissText: 'Avbryt', 6 | extra: 'vänligen välj', 7 | DatePickerLocale, 8 | }; 9 | -------------------------------------------------------------------------------- /components/date-picker/locale/zh_CN.tsx: -------------------------------------------------------------------------------- 1 | import DatePickerLocale from '../datepicker/locale/zh_CN'; 2 | 3 | export default { 4 | okText: '确定', 5 | dismissText: '取消', 6 | extra: '请选择', 7 | DatePickerLocale, 8 | }; 9 | -------------------------------------------------------------------------------- /components/date-picker/utils.tsx: -------------------------------------------------------------------------------- 1 | function formatIt(date: Date, form: string) { 2 | const pad = (n: number) => (n < 10 ? `0${n}` : n); 3 | const dateStr = `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad( 4 | date.getDate(), 5 | )}`; 6 | const timeStr = `${pad(date.getHours())}:${pad(date.getMinutes())}`; 7 | if (form === 'YYYY-MM-DD') { 8 | return dateStr; 9 | } 10 | if (form === 'HH:mm') { 11 | return timeStr; 12 | } 13 | return `${dateStr} ${timeStr}`; 14 | } 15 | 16 | export function formatFn(instance: any, value: Date) { 17 | const formatsEnum = { 18 | date: 'YYYY-MM-DD', 19 | time: 'HH:mm', 20 | datetime: 'YYYY-MM-DD HH:mm', 21 | }; 22 | const { format } = instance.props; 23 | const type = typeof format; 24 | if (type === 'string') { 25 | return formatIt(value, format); 26 | } 27 | if (type === 'function') { 28 | return format(value); 29 | } 30 | return formatIt(value, (formatsEnum as any)[instance.props.mode]); 31 | } 32 | 33 | export function formatProps(props: any, value: Date) { 34 | const formatsEnum = { 35 | date: 'YYYY-MM-DD', 36 | time: 'HH:mm', 37 | datetime: 'YYYY-MM-DD HH:mm', 38 | }; 39 | const { format } = props; 40 | const type = typeof format; 41 | if (type === 'string') { 42 | return formatIt(value, format); 43 | } 44 | if (type === 'function') { 45 | return format(value); 46 | } 47 | return formatIt(value, (formatsEnum as any)[props.mode]); 48 | } 49 | -------------------------------------------------------------------------------- /components/drawer/PropsType.tsx: -------------------------------------------------------------------------------- 1 | import React, { CSSProperties } from 'react'; 2 | 3 | export interface DrawerProps { 4 | onOpenChange?: (isOpen: boolean) => void; 5 | sidebar?: React.ReactNode; 6 | open?: boolean; 7 | position?: 'left' | 'right' | 'top' | 'bottom'; 8 | } 9 | 10 | export interface DrawerWebProps extends DrawerProps { 11 | sidebarStyle?: CSSProperties; 12 | contentStyle?: CSSProperties; 13 | overlayStyle?: CSSProperties; 14 | dragHandleStyle?: CSSProperties; 15 | docked?: boolean; 16 | transitions?: boolean; 17 | touch?: boolean; 18 | dragToggleDistance?: number; 19 | prefixCls?: string; 20 | className?: string; 21 | style?: CSSProperties; 22 | } 23 | -------------------------------------------------------------------------------- /components/drawer/index.tsx: -------------------------------------------------------------------------------- 1 | 2 | import DrawerLayout from '@bang88/react-native-drawer-layout'; 3 | import React from 'react'; 4 | import { DrawerProps } from './PropsType'; 5 | 6 | export interface DrawerNativeProps extends DrawerProps { 7 | drawerRef?: (el: DrawerLayout | null) => void; 8 | drawerWidth?: number; 9 | drawerBackgroundColor?: string; 10 | } 11 | export default class Drawer extends React.Component { 12 | static defaultProps = { 13 | position: 'left', 14 | open: false, 15 | drawerWidth: 300, 16 | }; 17 | 18 | drawer: DrawerLayout | null; 19 | 20 | componentDidMount() { 21 | if (this.props.open && this.drawer) { 22 | this.drawer.openDrawer(); 23 | } 24 | } 25 | 26 | componentWillReceiveProps(nextProps: DrawerNativeProps) { 27 | if (nextProps.open !== this.props.open && this.drawer) { 28 | this.drawer[nextProps.open ? 'openDrawer' : 'closeDrawer'](); 29 | } 30 | } 31 | 32 | onOpenChange(isOpen: boolean) { 33 | if (this.props.onOpenChange) { 34 | this.props.onOpenChange(isOpen); 35 | } 36 | } 37 | 38 | render() { 39 | const { 40 | sidebar, 41 | position, 42 | drawerRef, 43 | drawerWidth = 300, 44 | ...restProps 45 | } = this.props; 46 | [ 47 | 'onOpenChange', 48 | 'onDrawerOpen', 49 | 'onDrawerClose', 50 | 'drawerPosition', 51 | 'renderNavigationView', 52 | ].forEach(prop => { 53 | if (restProps.hasOwnProperty(prop)) { 54 | delete (restProps as any)[prop]; 55 | } 56 | }); 57 | // tslint:disable-next-line:variable-name 58 | let _position = (DrawerLayout as any).positions.Left; 59 | if (position === 'right') { 60 | _position = (DrawerLayout as any).positions.Right; 61 | } 62 | return ( 63 | { 65 | if (drawerRef) { 66 | drawerRef(el); 67 | } 68 | this.drawer = el; 69 | }} 70 | renderNavigationView={() => sidebar} 71 | drawerPosition={_position} 72 | onDrawerOpen={() => this.onOpenChange(true)} 73 | onDrawerClose={() => this.onOpenChange(false)} 74 | keyboardDismissMode="on-drag" 75 | drawerWidth={drawerWidth} 76 | {...restProps} 77 | /> 78 | ); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /components/drawer/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Navigation 4 | title: Drawer 5 | subtitle: 抽屉 6 | --- 7 | 8 | 用于在屏幕边缘显示应用导航等内容的面板。 9 | 10 | ### 规则 11 | 12 | - 是 Android 推荐的导航方式,常见于该平台应用。 13 | 14 | ## API 15 | 16 | 属性 | 说明 | 类型 | 默认值 17 | ----|-----|------|------ 18 | | sidebar | 抽屉里的内容 | ReactNode | - | 19 | | onOpenChange | open 状态切换时调用 | (open: bool): void | - | 20 | | open | 开关状态 | Boolean | false | 21 | | position | 抽屉所在位置 | String | 'left', enum{'left', 'right'} | 22 | | drawerWidth | 抽屉宽度 | Number | 300 | 23 | | drawerBackgroundColor | 指定抽屉背景色 | String | - | 24 | | openDrawer | 打开函数 | (): void | - | 25 | | closeDrawer | 关闭函数 | (): void | - | 26 | -------------------------------------------------------------------------------- /components/flex/Flex.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | StyleProp, 4 | TouchableWithoutFeedback, 5 | View, 6 | ViewStyle, 7 | } from 'react-native'; 8 | import { FlexPropsType } from './PropsType'; 9 | 10 | export interface FlexProps extends FlexPropsType { 11 | onPress?: () => void; 12 | onLongPress?: () => void; 13 | onPressIn?: () => void; 14 | onPressOut?: () => void; 15 | style?: StyleProp; 16 | } 17 | 18 | export default class Flex extends React.Component { 19 | static Item: any; 20 | 21 | static defaultProps = { 22 | direction: 'row', 23 | wrap: 'nowrap', 24 | justify: 'start', 25 | align: 'center', 26 | }; 27 | 28 | render() { 29 | const { 30 | style, 31 | direction, 32 | wrap, 33 | justify, 34 | align, 35 | children, 36 | ...restProps 37 | } = this.props; 38 | const transferConst = [justify, align]; 39 | const transferConstStyle = transferConst.map(el => { 40 | let tempTxt; 41 | switch (el) { 42 | case 'start': 43 | tempTxt = 'flex-start'; 44 | break; 45 | case 'end': 46 | tempTxt = 'flex-end'; 47 | break; 48 | case 'between': 49 | tempTxt = 'space-between'; 50 | break; 51 | case 'around': 52 | tempTxt = 'space-around'; 53 | break; 54 | default: 55 | tempTxt = el; 56 | break; 57 | } 58 | 59 | return tempTxt; 60 | }); 61 | const flexStyle: any = { 62 | flexDirection: direction, 63 | flexWrap: wrap, 64 | justifyContent: transferConstStyle[0], 65 | alignItems: transferConstStyle[1], 66 | }; 67 | 68 | const inner = ( 69 | 70 | {children} 71 | 72 | ); 73 | 74 | const shouldWrapInTouchableComponent = 75 | restProps.onPress || 76 | restProps.onLongPress || 77 | restProps.onPressIn || 78 | restProps.onPressOut; 79 | 80 | if (!!shouldWrapInTouchableComponent) { 81 | return ( 82 | 83 | {inner} 84 | 85 | ); 86 | } else { 87 | return inner; 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /components/flex/FlexItem.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | StyleProp, 4 | TouchableWithoutFeedback, 5 | View, 6 | ViewStyle, 7 | } from 'react-native'; 8 | import { FlexItemPropsType } from './PropsType'; 9 | 10 | export interface FlexItemProps extends FlexItemPropsType { 11 | flex?: number; 12 | onPress?: () => void; 13 | onLongPress?: () => void; 14 | onPressIn?: () => void; 15 | onPressOut?: () => void; 16 | style?: StyleProp; 17 | } 18 | 19 | export default class FlexItem extends React.Component { 20 | static defaultProps = { 21 | flex: 1, 22 | }; 23 | render() { 24 | const { style, children, flex, ...restProps } = this.props; 25 | const flexItemStyle = { 26 | flex: flex || 1, 27 | }; 28 | // support other touchablewithoutfeedback props 29 | // TODO support TouchableHighlight 30 | const inner = ( 31 | 32 | {children} 33 | 34 | ); 35 | 36 | const shouldWrapInTouchableComponent = 37 | restProps.onPress || 38 | restProps.onLongPress || 39 | restProps.onPressIn || 40 | restProps.onPressOut; 41 | 42 | if (!!shouldWrapInTouchableComponent) { 43 | return ( 44 | 45 | {inner} 46 | 47 | ); 48 | } else { 49 | return inner; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /components/flex/PropsType.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from 'react'; 2 | 3 | export interface FlexPropsType { 4 | direction?: 'row' | 'row-reverse' | 'column' | 'column-reverse'; 5 | wrap?: 'nowrap' | 'wrap' | 'wrap-reverse'; 6 | justify?: 'start' | 'end' | 'center' | 'between' | 'around'; 7 | align?: 'start' | 'center' | 'end' | 'baseline' | 'stretch'; 8 | children?: ReactNode; 9 | disabled?: boolean; 10 | } 11 | 12 | export interface FlexItemPropsType { 13 | disabled?: boolean; 14 | children?: ReactNode; 15 | } 16 | -------------------------------------------------------------------------------- /components/flex/index.tsx: -------------------------------------------------------------------------------- 1 | import Flex from './Flex'; 2 | import FlexItem from './FlexItem'; 3 | 4 | Flex.Item = FlexItem; 5 | 6 | export default Flex; 7 | -------------------------------------------------------------------------------- /components/flex/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Layout 4 | title: Flex 5 | subtitle: Flex布局 6 | --- 7 | 8 | Flex 是 CSS flex 布局的一个封装。 9 | 10 | ## API 11 | 12 | ### Flex 13 | 14 | 属性 | 说明 | 类型 | 默认值 15 | ----|-----|------|------ 16 | | direction | 项目定位方向,值可以为 `row`,`row-reverse`,`column`,`column-reverse`, RN 仅支持`row`,`column` | String | `row` | 17 | | wrap | 子元素的换行方式,可选`nowrap`,`wrap`,`wrap-reverse`, RN 仅支持`nowrap`,`wrap` | String | `nowrap` | 18 | | justify | 子元素在主轴上的对齐方式,可选`start`,`end`,`center`,`between`,`around` | String | `start` | 19 | | align | 子元素在交叉轴上的对齐方式,可选`start`,`center`,`end`,`baseline`,`stretch` RN仅支持`start`,`end`,`center`,`stretch` | String | `center` | 20 | 21 | ### Flex.Item 22 | 23 | Flex.Item 组件默认加上了样式`flex:1`,保证所有 item 平均分宽度, Flex 容器的 children 不一定是 Flex.Item 24 | -------------------------------------------------------------------------------- /components/grid/PropsType.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface DataItem { 4 | icon?: any; 5 | text?: any; 6 | [key: string]: any; 7 | } 8 | 9 | export interface GridPropsType { 10 | data?: Array; 11 | hasLine?: boolean; 12 | columnNum: number; 13 | isCarousel?: boolean; 14 | carouselMaxRow: number; 15 | onPress?: (dataItem: DataItem | undefined, itemIndex: number) => void; 16 | renderItem?: ( 17 | dataItem: DataItem | undefined, 18 | itemIndex: number, 19 | ) => React.ReactElement; 20 | } 21 | -------------------------------------------------------------------------------- /components/grid/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Data Display 4 | title: Grid 5 | subtitle: 宫格 6 | --- 7 | 8 | 在水平和垂直方向,将布局切分成若干等大的区块。 9 | 10 | ### 规则 11 | - 区块中的内容应该是同类元素,eg:都是图片,或者都是图标+文字。 12 | 13 | ## API 14 | 15 | | 属性 | 说明 | 类型 | 默认值 | 16 | | -------------- | -------------------------------------- | --------------------------------- | ----------- | 17 | | data | 传入的菜单数据 | `Array<{icon, text}>` | [] | 18 | | onPress | 点击每个菜单的回调函数 | (el: Object, index: number): void | - | 19 | | columnNum | 列数 | number | `4` | 20 | | hasLine | 是否有边框 | boolean | `true` | 21 | | isCarousel | 是否跑马灯, | boolean | `false` | 22 | | carouselProps | 跑马灯属性 | CarouselProps | `{}` | 23 | | carouselMaxRow | 如果是跑马灯, 一页跑马灯需要展示的行数 | number | `2` | 24 | | renderItem | 自定义每个 grid 条目的创建函数 | (el, index) => React.Node | - | 25 | | itemStyle | 每个格子自定义样式 | object | {} | 26 | `isCarousel = true` 模式时,还可以传递 [carousel](https://mobile.ant.design/components/carousel) 相关的 API。 27 | -------------------------------------------------------------------------------- /components/grid/style/index.tsx: -------------------------------------------------------------------------------- 1 | import { ImageStyle, StyleSheet, TextStyle, ViewStyle } from 'react-native'; 2 | import { Theme } from '../../style'; 3 | export interface GridStyle { 4 | grayBorderBox: ViewStyle; 5 | icon: ImageStyle; 6 | text: TextStyle; 7 | } 8 | export default (theme: Theme) => 9 | StyleSheet.create({ 10 | grayBorderBox: { 11 | borderColor: theme.border_color_base, 12 | }, 13 | icon: { 14 | width: theme.icon_size_md, 15 | height: theme.icon_size_md, 16 | }, 17 | text: { 18 | fontSize: theme.font_size_caption_sm, 19 | color: theme.color_text_base, 20 | marginTop: theme.v_spacing_md, 21 | }, 22 | }); 23 | -------------------------------------------------------------------------------- /components/icon/index.tsx: -------------------------------------------------------------------------------- 1 | import { IconOutline, OutlineGlyphMapType } from '@ant-design/icons-react-native'; 2 | import React from 'react'; 3 | import { TextProps } from 'react-native'; 4 | import { WithTheme } from '../style'; 5 | export type IconNames = OutlineGlyphMapType; 6 | export interface IconProps extends TextProps { 7 | size?: 'x3s' | 'xxs' | 'xs' | 'sm' | 'md' | 'lg' | number; 8 | color?: string; 9 | name: IconNames; 10 | } 11 | 12 | export default class Icon extends React.Component { 13 | static defaultProps = { 14 | size: 'md', 15 | }; 16 | static displayName = 'Icon'; 17 | render() { 18 | const { size, color, name, ...rest } = this.props; 19 | const sizeMap: { [key: string]: number } = { 20 | x3s: 12, 21 | xxs: 15, 22 | xs: 18, 23 | sm: 21, 24 | md: 22, 25 | lg: 36, 26 | }; 27 | const fontSize = typeof size === 'string' ? sizeMap[size] : size; 28 | 29 | return ( 30 | 31 | {(_, theme) => ( 32 | 38 | )} 39 | 40 | ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /components/icon/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Data Display 4 | title: Icon 5 | subtitle: 图标 6 | --- 7 | 8 | ## 如何使用 9 | 10 | 从`3.0.0` 开始使用 `ant-design-icons` 字体图标不需要单独安装但是需要`link` 11 | 12 | 更多信息请查看https://github.com/ant-design/ant-design-icons/tree/master/packages/icons-react-native 13 | 14 | 安装完成后需要link字体文件 15 | 16 | ```bash 17 | react-native link @ant-design/icons-react-native 18 | ``` 19 | 20 | 使用方式: 21 | 22 | ```jsx 23 | ; 24 | ``` 25 | 26 | > 注: 默认现在Icon使用了 `ant-design-icons` 里面的`outline` 图标 27 | 28 | ## API 29 | 30 | | 属性 | 说明 | 类型 | 默认值 | 31 | | ----- | ------------------- | ---------------------------------- | ------ | 32 | | name | OutlineGlyphMapType | string | 33 | | size | 图标大小 | 'xxs'/'xs'/'sm'/'md'/'lg' / number | `md` | 34 | | color | 图标颜色 | Color | '#000' | 35 | -------------------------------------------------------------------------------- /components/image-picker/ImageItem.tsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Dimensions, Image, ImageStyle, StyleSheet, TouchableOpacity } from 'react-native'; 3 | import Icon from '../icon'; 4 | export type ImageItemProps = { 5 | item?: any; 6 | selected?: boolean; 7 | selectedMarker?: JSX.Element; 8 | imageMargin: number; 9 | containerWidth?: number; 10 | imagesPerRow: number; 11 | onPress?: (...args: any[]) => any; 12 | }; 13 | class ImageItem extends Component { 14 | static defaultProps = { 15 | item: {}, 16 | selected: false, 17 | }; 18 | _imageSize: number; 19 | constructor(props: ImageItemProps) { 20 | super(props); 21 | } 22 | componentWillMount() { 23 | let { width } = Dimensions.get('window'); 24 | const { imageMargin, imagesPerRow, containerWidth } = this.props; 25 | if (typeof containerWidth !== 'undefined') { 26 | width = containerWidth; 27 | } 28 | this._imageSize = (width - (imagesPerRow + 1) * imageMargin) / imagesPerRow; 29 | } 30 | render() { 31 | const { item, selected, selectedMarker, imageMargin } = this.props; 32 | if (!item) { 33 | return null; 34 | } 35 | const marker = selectedMarker ? ( 36 | selectedMarker 37 | ) : ( 38 | 42 | ); 43 | const image = item.node.image; 44 | return ( 45 | this._handleClick(image)} 48 | > 49 | 53 | {selected ? marker : null} 54 | 55 | ); 56 | } 57 | _handleClick(item: any) { 58 | if (this.props.onPress) { 59 | this.props.onPress(item); 60 | } 61 | } 62 | } 63 | const styles = StyleSheet.create<{ 64 | marker: ImageStyle; 65 | }>({ 66 | marker: { 67 | position: 'absolute', 68 | top: 5, 69 | right: 5, 70 | backgroundColor: 'transparent', 71 | }, 72 | }); 73 | 74 | export default ImageItem; 75 | -------------------------------------------------------------------------------- /components/image-picker/ImageRoll.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Modal, StatusBar, StyleSheet, Text, TouchableOpacity, View } from 'react-native'; 3 | import varibles from '../style/themes/default'; 4 | import CameraRollPicker, { CameraRollPickerProps } from './CameraRollPicker'; 5 | 6 | export interface ImageRollProps extends ImageRollTexts { 7 | onCancel: () => void; 8 | onSelected: (imgObj: {}) => void; 9 | cameraPickerProps?: CameraRollPickerProps; 10 | } 11 | 12 | export interface ImageRollTexts { 13 | title?: React.ReactNode; 14 | cancelText?: React.ReactNode; 15 | } 16 | 17 | const styles = StyleSheet.create({ 18 | statusBarBg: { 19 | height: 5 * 4, 20 | }, 21 | naviBar: { 22 | flexDirection: 'row', 23 | justifyContent: 'center', 24 | alignItems: 'center', 25 | borderBottomWidth: 1, 26 | borderBottomColor: '#d9d9d9', 27 | height: 11 * 4, 28 | }, 29 | barTitle: { 30 | flex: 1, 31 | textAlign: 'center', 32 | fontWeight: '500', 33 | marginLeft: 7 * 4, 34 | fontSize: 16, 35 | }, 36 | rightBtn: { 37 | width: 14 * 4, 38 | color: varibles.brand_primary, 39 | fontSize: 16, 40 | }, 41 | }); 42 | 43 | export default class ImageRoll extends React.Component { 44 | static defaultProps = { 45 | title: '图片', 46 | cancelText: '取消', 47 | cameraPickerProps: {}, 48 | }; 49 | onSelected = (images: any[], _: any) => { 50 | this.props.onSelected(images[0]); 51 | this.props.onCancel(); 52 | }; 53 | render() { 54 | const { title, cancelText, cameraPickerProps } = this.props; 55 | 56 | return ( 57 | {}} 61 | transparent={false} 62 | > 63 | 64 | 65 | 66 | 67 | {title} 68 | 69 | {cancelText} 70 | 71 | 72 | 78 | 79 | 80 | ); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /components/image-picker/PropsType.tsx: -------------------------------------------------------------------------------- 1 | // import React from 'react'; 2 | 3 | export interface ImagePickerPropTypes { 4 | styles?: {}; 5 | files?: Array<{}>; 6 | onChange?: (files: Array<{}>, operationType: string, index?: number) => void; 7 | onImageClick?: (index?: number, files?: Array<{}>) => void; 8 | onAddImageClick?: () => void; 9 | onFail?: (msg: string) => void; 10 | selectable?: boolean; 11 | } 12 | -------------------------------------------------------------------------------- /components/image-picker/style/index.tsx: -------------------------------------------------------------------------------- 1 | import { ImageStyle, StyleSheet, TextStyle, ViewStyle } from 'react-native'; 2 | import varibles from '../../style/themes/default'; 3 | 4 | export interface ImagePickerStyle { 5 | container: ViewStyle; 6 | size: ImageStyle; 7 | item: ViewStyle; 8 | image: ImageStyle; 9 | closeWrap: ViewStyle; 10 | closeText: TextStyle; 11 | plusWrap: ViewStyle; 12 | plusWrapNormal: ViewStyle; 13 | plusWrapHighlight: ViewStyle; 14 | plusText: TextStyle; 15 | } 16 | 17 | export default () => 18 | StyleSheet.create({ 19 | container: { 20 | flexWrap: 'wrap', 21 | flexDirection: 'row', 22 | }, 23 | size: { 24 | width: 80, 25 | height: 80, 26 | }, 27 | item: { 28 | marginRight: varibles.h_spacing_sm, 29 | marginBottom: varibles.v_spacing_sm, 30 | overflow: 'hidden', 31 | }, 32 | image: { 33 | overflow: 'hidden', 34 | borderRadius: varibles.radius_sm, 35 | }, 36 | closeWrap: { 37 | width: 16, 38 | height: 16, 39 | backgroundColor: '#999', 40 | borderRadius: 8, 41 | position: 'absolute', 42 | top: 4, 43 | right: 4, 44 | justifyContent: 'center', 45 | alignItems: 'center', 46 | overflow: 'hidden', 47 | }, 48 | closeText: { 49 | color: varibles.color_text_base_inverse, 50 | backgroundColor: 'transparent', 51 | fontSize: 20, 52 | height: 20, 53 | marginTop: -8, 54 | fontWeight: '300', 55 | }, 56 | plusWrap: { 57 | borderRadius: varibles.radius_sm, 58 | borderWidth: 1, 59 | justifyContent: 'center', 60 | alignItems: 'center', 61 | }, 62 | plusWrapNormal: { 63 | backgroundColor: varibles.fill_base, 64 | borderColor: varibles.border_color_base, 65 | }, 66 | plusWrapHighlight: { 67 | backgroundColor: varibles.fill_tap, 68 | borderColor: varibles.border_color_base, 69 | }, 70 | plusText: { 71 | fontSize: 64, 72 | backgroundColor: 'transparent', 73 | fontWeight: '100', 74 | color: varibles.color_text_caption, 75 | }, 76 | }); 77 | -------------------------------------------------------------------------------- /components/index.tsx: -------------------------------------------------------------------------------- 1 | export { default as Accordion } from './accordion/index'; 2 | export { default as ActionSheet } from './action-sheet/index'; 3 | export { default as ActivityIndicator } from './activity-indicator/index'; 4 | export { default as Badge } from './badge/index'; 5 | export { default as Button } from './button/index'; 6 | export { default as Card } from './card/index'; 7 | export { default as Carousel } from './carousel/index'; 8 | export { default as Checkbox } from './checkbox/index'; 9 | export { default as DatePickerView } from './date-picker-view/index'; 10 | export { default as DatePicker } from './date-picker/index'; 11 | export { default as Drawer } from './drawer/index'; 12 | export { default as Flex } from './flex/index'; 13 | export { default as Grid } from './grid/index'; 14 | export { default as Icon } from './icon/index'; 15 | export { default as ImagePicker } from './image-picker/index'; 16 | export { default as InputItem } from './input-item/index'; 17 | export { default as ListView } from './list-view/index'; 18 | export { default as List } from './list/index'; 19 | export { default as Modal } from './modal/index'; 20 | export { default as NoticeBar } from './notice-bar/index'; 21 | export { default as Pagination } from './pagination/index'; 22 | export { default as PickerView } from './picker-view/index'; 23 | export { default as Picker } from './picker/index'; 24 | export { default as Popover } from './popover/index'; 25 | export { default as Portal } from './portal/index'; 26 | export { default as Progress } from './progress/index'; 27 | export { default as Provider } from './provider/index'; 28 | export { default as Radio } from './radio/index'; 29 | export { default as Result } from './result/index'; 30 | export { default as SearchBar } from './search-bar/index'; 31 | export { default as SegmentedControl } from './segmented-control/index'; 32 | export { default as Slider } from './slider/index'; 33 | export { default as Stepper } from './stepper/index'; 34 | export { default as Steps } from './steps/index'; 35 | export { default as SwipeAction } from './swipe-action/index'; 36 | export { default as Switch } from './switch/index'; 37 | export { default as TabBar } from './tab-bar/index'; 38 | export { default as Tabs } from './tabs/index'; 39 | export { default as Tag } from './tag/index'; 40 | export { default as TextareaItem } from './textarea-item/index'; 41 | export { default as Toast } from './toast/index'; 42 | export { default as WhiteSpace } from './white-space/index'; 43 | export { default as WingBlank } from './wing-blank/index'; 44 | -------------------------------------------------------------------------------- /components/input-item/Input.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { TextInput, TextInputProperties } from 'react-native'; 3 | 4 | export interface TextInputProps extends TextInputProperties { 5 | focused?: boolean; 6 | } 7 | 8 | class Input extends React.Component { 9 | inputRef: TextInput | null; 10 | 11 | constructor(props: TextInputProps) { 12 | super(props); 13 | 14 | // todos: remove focused in next major version. 15 | this.state = { 16 | focused: props.focused || false, 17 | }; 18 | } 19 | 20 | componentWillReceiveProps(nextProps: TextInputProps) { 21 | if (nextProps.focused !== this.state.focused) { 22 | this.setState({ 23 | focused: nextProps.focused, 24 | }); 25 | } 26 | } 27 | 28 | componentDidMount() { 29 | if (this.inputRef && (this.props.autoFocus || this.props.focused)) { 30 | this.inputRef.focus(); 31 | } 32 | } 33 | 34 | componentDidUpdate() { 35 | if (this.inputRef && this.props.focused) { 36 | this.inputRef.focus(); 37 | } 38 | } 39 | 40 | focus = () => { 41 | if (this.inputRef) { 42 | this.inputRef.focus(); 43 | } 44 | } 45 | 46 | clear = () => { 47 | if (this.inputRef) { 48 | this.inputRef.clear(); 49 | } 50 | } 51 | 52 | render() { 53 | return ( 54 | ((this.inputRef as any) = el)} 56 | underlineColorAndroid="transparent" 57 | {...this.props} 58 | /> 59 | ); 60 | } 61 | } 62 | 63 | export default Input; 64 | -------------------------------------------------------------------------------- /components/input-item/PropsType.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { KeyboardTypeOptions } from 'react-native'; 3 | export type InputEventHandler = (value?: string) => void; 4 | 5 | export interface InputItemPropsType { 6 | type?: 7 | | 'text' 8 | | 'bankCard' 9 | | 'phone' 10 | | 'password' 11 | | 'number' 12 | | 'digit' | KeyboardTypeOptions; 13 | editable?: boolean; 14 | disabled?: boolean; 15 | name?: string; 16 | value?: string; 17 | defaultValue?: string; 18 | placeholder?: string; 19 | clear?: boolean; 20 | maxLength?: number; 21 | extra?: React.ReactNode; 22 | error?: boolean; 23 | // can not find out where it used 24 | // onErrorPress?: Function; 25 | // size?: 'large' | 'small'; 26 | labelNumber?: number; 27 | labelPosition?: 'left' | 'top'; 28 | textAlign?: 'left' | 'center' | 'right'; 29 | updatePlaceholder?: boolean; 30 | locale?: object; 31 | onChange?: (value: string) => void; 32 | onFocus?: InputEventHandler; 33 | onBlur?: InputEventHandler; 34 | onVirtualKeyboardConfirm?: InputEventHandler; 35 | } 36 | -------------------------------------------------------------------------------- /components/input-item/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Data Entry 4 | title: InputItem 5 | subtitle: 文本输入 6 | --- 7 | 8 | 用于接受单行文本。 9 | 10 | ### 规则 11 | - 支持通过键盘或者剪切板输入文本。 12 | - 通过光标可以在水平方向进行移动。 13 | - 对特定格式的文本进行处理,eg:隐藏密码。 14 | 15 | ## API 16 | 17 | **`InputItem` 必须用 [List](https://mobile.ant.design/components/list) 组件包裹才能正常使用** 18 | 19 | 属性 | 说明 | 类型 | 默认值 20 | ----|-----|------|------ 21 | | type | 可以是银行卡`bankCard`; 手机号`phone`(此时最大长度固定为11,`maxLength`设置无效); 密码`password`; 数字`number`(为了尽量唤起`带小数点`的数字键盘,此类型并不是原生 number,而是``); `digit`(表示原生的 number 类型); 以及其他标准 input type 类型 | String | `text` | 22 | | value | value 值(受控与否参考https://facebook.github.io/react/docs/forms.html) | String | 无 | 23 | | defaultValue | 设置初始默认值 | String | - | 24 | | placeholder | placeholder | String | '' | 25 | | editable | 是否可编辑 | bool | true | 26 | | disabled | 是否禁用 | bool | true | 27 | | clear | 是否带清除功能(仅`editable`为`true`,`disabled`为`false`才生效)。在 Android 中, 处于编辑状态(focus)时 icon 才会出现, 且此组件被`ScrollView`包裹时, 设置`ScrollView`的`keyboardShouldPersistTaps`属性为`handled`或`always`时, icon才会正确响应点击事件 | bool | false | 28 | | maxLength | 最大长度 | number | 无 | 29 | | onChange | change 事件触发的回调函数 | (val: string): void | - | 30 | | onBlur | blur 事件触发的回调函数 | (val: string): void | - | 31 | | onFocus | focus 事件触发的回调函数 | (val: string): void | - | 32 | | error | 报错样式 | bool | false | 33 | | onErrorClick | 点击报错 icon 触发的回调函数 | (e: Object): void | 无 | 34 | | extra | 右边注释 | string or node | '' | 35 | | onExtraClick | extra 点击事件触发的回调函数 | (e: Object): void | 无 | 36 | | onVirtualKeyboardConfirm | 虚拟键盘点击确认时的回调函数 | (val: string): void | 无 | 37 | | labelNumber | 标签的文字个数,可用`2-7`之间的数字 | number | `5` | 38 | | locale | 国际化,可覆盖全局`[LocaleProvider](https://mobile.ant.design/components/locale-provider)`的配置, 当`type`为`money`,可以自定义确认按钮的文案。 | Object: { confirmLabel } | 无 | 39 | | last | 如果是最后一项,则将移除`borderBottom`(默认拥有`borderBottom`) | bool | false | 40 | 41 | > 更多 react-native `InputItem` 属性请参考 react-native TextInput (http://facebook.github.io/react-native/docs/textinput.html) 42 | 43 | > 注意: `InputItem` 当 `type=number` 时不支持输入负号, 你可以利用 `type=text` 来自己实现。 44 | 45 | ## InputItem methods 46 | 47 | 属性 | 说明 | 类型 | 默认值 48 | ----|-----|------|------ 49 | | focus | 使 input 聚焦 | (): void | - | 50 | -------------------------------------------------------------------------------- /components/input-item/locale/en_US.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | confirmLabel: 'Done', 3 | backspaceLabel: 'Backspace', 4 | cancelKeyboardLabel: 'CancelKeyboard', 5 | }; 6 | -------------------------------------------------------------------------------- /components/input-item/locale/es_ES.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | confirmLabel: 'OK', 3 | backspaceLabel: 'Retroceso', 4 | cancelKeyboardLabel: 'Cancelar Teclado', 5 | }; 6 | -------------------------------------------------------------------------------- /components/input-item/locale/ru_RU.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | confirmLabel: 'Ок', 3 | backspaceLabel: 'возврат на одну позицию', 4 | cancelKeyboardLabel: 'Отменить клавиатуру', 5 | }; 6 | -------------------------------------------------------------------------------- /components/input-item/locale/sv_SE.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | confirmLabel: 'Ok', 3 | backspaceLabel: 'Backspace', 4 | cancelKeyboardLabel: 'CancelKeyboard', 5 | }; 6 | -------------------------------------------------------------------------------- /components/input-item/locale/zh_CN.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | confirmLabel: '确定', 3 | backspaceLabel: '退格', 4 | cancelKeyboardLabel: '收起键盘', 5 | }; 6 | -------------------------------------------------------------------------------- /components/input-item/style/index.tsx: -------------------------------------------------------------------------------- 1 | import { StyleSheet, TextStyle, ViewStyle } from 'react-native'; 2 | import { Theme } from '../../style'; 3 | export interface InputItemStyle { 4 | container: ViewStyle; 5 | text: TextStyle; 6 | input: TextStyle; 7 | inputDisabled: TextStyle; 8 | inputErrorColor: TextStyle; 9 | clear: ViewStyle; 10 | extra: TextStyle; 11 | errorIcon: ViewStyle; 12 | } 13 | export default (theme: Theme) => 14 | StyleSheet.create({ 15 | container: { 16 | height: theme.list_item_height + theme.border_width_sm, 17 | borderBottomWidth: StyleSheet.hairlineWidth, 18 | borderBottomColor: theme.border_color_base, 19 | marginLeft: theme.h_spacing_lg, 20 | paddingRight: theme.h_spacing_lg, 21 | marginTop: 0, 22 | marginBottom: 0, 23 | flexDirection: 'row', 24 | alignItems: 'center', 25 | }, 26 | text: { 27 | marginRight: theme.h_spacing_sm, 28 | textAlignVertical: 'center', 29 | fontSize: theme.font_size_heading, 30 | color: theme.color_text_base, 31 | }, 32 | input: { 33 | flex: 1, 34 | // height: theme.list_item_height, 35 | backgroundColor: 'transparent', 36 | fontSize: theme.input_font_size, 37 | color: theme.color_text_base, 38 | }, 39 | inputDisabled: { 40 | backgroundColor: theme.fill_disabled, 41 | color: theme.color_text_disabled, 42 | }, 43 | inputErrorColor: { 44 | color: '#f50', 45 | }, 46 | clear: { 47 | backgroundColor: theme.color_icon_base, 48 | borderRadius: 15, 49 | padding: 2, 50 | }, 51 | extra: { 52 | marginLeft: theme.h_spacing_sm, 53 | fontSize: theme.font_size_subhead, 54 | color: theme.color_text_caption, 55 | }, 56 | errorIcon: { 57 | marginLeft: theme.h_spacing_sm, 58 | width: theme.icon_size_sm, 59 | height: theme.icon_size_sm, 60 | }, 61 | }); 62 | -------------------------------------------------------------------------------- /components/list-view/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Data Display 4 | title: ListView 5 | subtitle: 列表 Experimental 6 | --- 7 | 8 | 更多文档请查看 https://github.com/gameboyVito/react-native-ultimate-listview 9 | -------------------------------------------------------------------------------- /components/list-view/locale/en_US.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | Done: 'Loaded', 3 | Loading: 'Loading', 4 | refreshableTitlePull: 'Pull down refresh', 5 | refreshableTitleRelease: 'Release loading', 6 | refreshableTitleRefreshing: 'Loading...', 7 | noData: 'No data yet', 8 | }; 9 | -------------------------------------------------------------------------------- /components/list-view/locale/es_ES.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | Done: 'Loaded', 3 | Loading: 'Loading', 4 | refreshableTitlePull: 'Pull down refresh', 5 | refreshableTitleRelease: 'Release loading', 6 | refreshableTitleRefreshing: 'Loading...', 7 | noData: 'No data yet', 8 | }; 9 | -------------------------------------------------------------------------------- /components/list-view/locale/ru_RU.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | Done: 'Loaded', 3 | Loading: 'Loading', 4 | refreshableTitlePull: 'Pull down refresh', 5 | refreshableTitleRelease: 'Release loading', 6 | refreshableTitleRefreshing: 'Loading...', 7 | noData: 'No data yet', 8 | }; 9 | -------------------------------------------------------------------------------- /components/list-view/locale/sv_SE.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | Done: 'Loaded', 3 | Loading: 'Loading', 4 | refreshableTitlePull: 'Pull down refresh', 5 | refreshableTitleRelease: 'Release loading', 6 | refreshableTitleRefreshing: 'Loading...', 7 | noData: 'No data yet', 8 | }; 9 | -------------------------------------------------------------------------------- /components/list-view/locale/zh_CN.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | done: '已加载完', 3 | loading: '加载中...', 4 | refreshableTitlePull: '下拉刷新', 5 | refreshableTitleRelease: '释放加载', 6 | refreshableTitleRefreshing: '加载中...', 7 | noData: '暂无数据', 8 | }; 9 | -------------------------------------------------------------------------------- /components/list/PropsType.tsx: -------------------------------------------------------------------------------- 1 | import React, { ReactNode } from 'react'; 2 | import { StyleProp, TextStyle, ViewStyle } from 'react-native'; 3 | // export type ListType = JSX.Element 4 | export interface ListPropsType { 5 | renderHeader?: (() => React.ReactType) | string | JSX.Element; 6 | renderFooter?: (() => React.ReactType) | string | JSX.Element; 7 | children?: false | JSX.Element | JSX.Element[]; 8 | noBorder?: boolean; 9 | } 10 | 11 | export interface ListItemPropsType { 12 | align?: 'top' | 'middle' | 'bottom'; 13 | disabled?: boolean; 14 | multipleLine?: boolean; 15 | children?: ReactNode; 16 | thumb?: ReactNode | null; 17 | extra?: ReactNode; 18 | arrow?: 'horizontal' | 'down' | 'up' | 'empty' | ''; 19 | wrap?: boolean; 20 | activeStyle?: StyleProp; 21 | error?: boolean; 22 | platform?: 'android' | 'ios'; 23 | } 24 | 25 | export interface BriefProps { 26 | children?: ReactNode; 27 | wrap?: boolean; 28 | style?: StyleProp; 29 | } 30 | -------------------------------------------------------------------------------- /components/list/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { StyleProp, Text, View, ViewStyle } from 'react-native'; 3 | import { WithTheme, WithThemeStyles } from '../style'; 4 | import Item from './ListItem'; 5 | import { ListPropsType } from './PropsType'; 6 | import listStyles, { ListStyle } from './style/index'; 7 | 8 | export interface ListProps extends ListPropsType, WithThemeStyles { 9 | style?: StyleProp; 10 | } 11 | 12 | export default class List extends React.Component { 13 | static Item = Item; 14 | 15 | render() { 16 | const { 17 | children, 18 | style, 19 | renderHeader, 20 | renderFooter, 21 | styles, 22 | noBorder, 23 | ...restProps 24 | } = this.props; 25 | 26 | return ( 27 | 28 | {(s) => { 29 | let headerDom: React.ReactElement | null = null; 30 | let footerDom: React.ReactElement | null = null; 31 | 32 | if (renderHeader) { 33 | let content = 34 | typeof renderHeader === 'function' 35 | ? renderHeader() 36 | : renderHeader; 37 | if (typeof content === 'string') { 38 | content = {content}; 39 | } 40 | headerDom = {content}; 41 | } 42 | if (renderFooter) { 43 | let content = 44 | typeof renderFooter === 'function' 45 | ? renderFooter() 46 | : renderFooter; 47 | if (typeof content === 'string') { 48 | content = {content}; 49 | } 50 | footerDom = {content}; 51 | } 52 | 53 | return ( 54 | 55 | {headerDom} 56 | 57 | {children ? children : null} 58 | 59 | 60 | {footerDom} 61 | 62 | ); 63 | }} 64 | 65 | ); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /components/list/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Data Display 4 | title: List 5 | subtitle: 列表 6 | --- 7 | 8 | 单个连续模块垂直排列,显示当前的内容、状态和可进行的操作。eg:联系人列表。 9 | 10 | 当你需要一个 infinite scroll 列表时,请使用 [ListView](https://mobile.ant.design/components/list-view/)。 11 | 12 | ### 规则 13 | - 一般由主要信息、主要操作、次要信息、次要操作组成。 14 | - 主要信息和主要操作放在列表的左边,次要信息和次要操作放在列表的右边。 15 | 16 | ## API 17 | 18 | ### List 19 | 20 | 属性 | 说明 | 类型 | 默认值 21 | ----|-----|------|------ 22 | | renderHeader | list heder | (): void | 无 | 23 | | renderFooter | list footer | (): void | 无 | 24 | 25 | ### List.Item 26 | 27 | 属性 | 说明 | 类型 | 默认值 28 | ----|-----|------|------ 29 | | thumb | 缩略图(当为 string 类型时作为 img src) | String/React.Element | 无 | 30 | | extra | 右边内容 | String/React.Element | 无 | 31 | | arrow | 箭头方向(右,上,下), 可选`horizontal`,`up`,`down`,`empty`,如果是`empty`则存在对应的dom,但是不显示 | String | 无 | 32 | | align | 子元素垂直对齐,可选`top`,`middle`,`bottom` | String | `middle` | 33 | | onPress | 点击事件的回调函数 | (): void | 无 | 34 | | multipleLine | 多行 | Boolean | `false` | 35 | | wrap | 是否换行,默认情况下,文字超长会被隐藏, | Boolean | `false` | 36 | 37 | ### List.Item.Brief 38 | 39 | 辅助说明 40 | -------------------------------------------------------------------------------- /components/locale-provider/en_US.tsx: -------------------------------------------------------------------------------- 1 | import DatePickerView from '../date-picker-view/locale/en_US'; 2 | import DatePicker from '../date-picker/locale/en_US'; 3 | import InputItem from '../input-item/locale/en_US'; 4 | import ListView from '../list-view/locale/en_US'; 5 | import Modal from '../modal/locale/en_US'; 6 | import Pagination from '../pagination/locale/en_US'; 7 | import Picker from '../picker/locale/en_US'; 8 | import SearchBar from '../search-bar/locale/en_US'; 9 | 10 | export default { 11 | locale: 'en', 12 | DatePicker, 13 | DatePickerView, 14 | InputItem, 15 | Modal, 16 | Pagination, 17 | Picker, 18 | SearchBar, 19 | ListView, 20 | }; 21 | -------------------------------------------------------------------------------- /components/locale-provider/es_ES.tsx: -------------------------------------------------------------------------------- 1 | import DatePickerView from '../date-picker-view/locale/es_ES'; 2 | import DatePicker from '../date-picker/locale/es_ES'; 3 | import InputItem from '../input-item/locale/es_ES'; 4 | import ListView from '../list-view/locale/es_ES'; 5 | import Pagination from '../pagination/locale/es_ES'; 6 | import Picker from '../picker/locale/es_ES'; 7 | import SearchBar from '../search-bar/locale/es_ES'; 8 | 9 | export default { 10 | locale: 'es', 11 | DatePicker, 12 | DatePickerView, 13 | InputItem, 14 | Pagination, 15 | Picker, 16 | SearchBar, 17 | ListView, 18 | }; 19 | -------------------------------------------------------------------------------- /components/locale-provider/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | title: Provider 4 | subtitle: 国际化和皮肤配置 5 | type: Other 6 | --- 7 | 8 | 为组件内建文案提供统一的国际化支持。 9 | 10 | ## 使用 11 | 12 | Provider 使用 React 的 [context](https://facebook.github.io/react/docs/context.html) 特性,只需在应用外围包裹一次即可全局生效。 13 | 14 | 15 | ```jsx 16 | import enUS from '@sishuguojixuefu/antd-mobile-rn/lib/locale-provider/en_US'; 17 | 18 | ... 19 | 20 | return ; 21 | ``` 22 | 23 | 我们暂时只提供英语,中文两种语言支持(`默认语言是中文`),所有语言包可以在 [这里](https://github.com/ant-design/ant-design-mobile-rn/blob/master/components/locale-provider/) 找到。 24 | 25 | ### 增加语言包 26 | 27 | 如果你找不到你需要的语言包,欢迎你在 [英文语言包](https://github.com/ant-design/ant-design-mobile-rn/blob/master/components/locale-provider/en_US.tsx) 的基础上创建一个新的语言包,并给我们 Pull Request。 28 | 29 | ### 其他国际化需求 30 | 31 | 本模块仅用于组件的内建文案,若有业务文案的国际化需求,建议使用 [react-intl](https://github.com/yahoo/react-intl),可参考示例:[Intl demo 1](http://github.com/ant-design/intl-example) 和 [Intl demo 2](http://yiminghe.me/learning-react/examples/react-intl.html?locale=en-US)。 32 | 33 | ## API 34 | 35 | | 参数 | 说明 | 类型 | 默认值 | 36 | | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------ | ------ | 37 | | locale | 语言包配置,语言包可到 `@sishuguojixuefu/antd-mobile-rn/lib/locale-provider/` 目录下寻找 | object | - | 38 | | theme | 主题样式配置,可根据需要覆盖部分或者全部变量,具体变量请查看 [theme](https://github.com/ant-design/ant-design-mobile-rn/blob/master/components/style/themes/default.tsx) | object | - | 39 | -------------------------------------------------------------------------------- /components/locale-provider/ru_RU.tsx: -------------------------------------------------------------------------------- 1 | import DatePickerView from '../date-picker-view/locale/ru_RU'; 2 | import DatePicker from '../date-picker/locale/ru_RU'; 3 | import InputItem from '../input-item/locale/ru_RU'; 4 | import ListView from '../list-view/locale/ru_RU'; 5 | import Modal from '../modal/locale/ru_RU'; 6 | import Pagination from '../pagination/locale/ru_RU'; 7 | import Picker from '../picker/locale/ru_RU'; 8 | import SearchBar from '../search-bar/locale/ru_RU'; 9 | 10 | export default { 11 | locale: 'ru', 12 | DatePicker, 13 | DatePickerView, 14 | InputItem, 15 | Modal, 16 | Pagination, 17 | Picker, 18 | SearchBar, 19 | ListView, 20 | }; 21 | -------------------------------------------------------------------------------- /components/locale-provider/sv_SE.tsx: -------------------------------------------------------------------------------- 1 | import DatePickerView from '../date-picker-view/locale/sv_Se'; 2 | import DatePicker from '../date-picker/locale/sv_Se'; 3 | import InputItem from '../input-item/locale/sv_Se'; 4 | import ListView from '../list-view/locale/sv_Se'; 5 | import Modal from '../modal/locale/sv_Se'; 6 | import Pagination from '../pagination/locale/sv_Se'; 7 | import Picker from '../picker/locale/sv_Se'; 8 | import SearchBar from '../search-bar/locale/sv_Se'; 9 | 10 | export default { 11 | locale: 'sv', 12 | DatePicker, 13 | DatePickerView, 14 | InputItem, 15 | Modal, 16 | Pagination, 17 | Picker, 18 | SearchBar, 19 | ListView, 20 | }; 21 | -------------------------------------------------------------------------------- /components/locale-provider/zh_CN.tsx: -------------------------------------------------------------------------------- 1 | import DatePickerView from '../date-picker-view/locale/zh_CN'; 2 | import DatePicker from '../date-picker/locale/zh_CN'; 3 | import InputItem from '../input-item/locale/zh_CN'; 4 | import ListView from '../list-view/locale/zh_CN'; 5 | import Modal from '../modal/locale/zh_CN'; 6 | import Pagination from '../pagination/locale/zh_CN'; 7 | import Picker from '../picker/locale/zh_CN'; 8 | import SearchBar from '../search-bar/locale/zh_CN'; 9 | export default { 10 | locale: 'zh_CN', 11 | DatePicker, 12 | DatePickerView, 13 | InputItem, 14 | Modal, 15 | Pagination, 16 | Picker, 17 | SearchBar, 18 | ListView, 19 | }; 20 | -------------------------------------------------------------------------------- /components/modal/AlertContainer.tsx: -------------------------------------------------------------------------------- 1 | import React, { isValidElement } from 'react'; 2 | import { ScrollView, Text, TextStyle } from 'react-native'; 3 | import Modal from './Modal'; 4 | import { Action } from './PropsType'; 5 | 6 | export interface AlertContainerProps { 7 | title: React.ReactNode; 8 | content: React.ReactNode; 9 | actions: Action[]; 10 | onAnimationEnd?: (visible: boolean) => void; 11 | } 12 | 13 | export default class AlertContainer extends React.Component< 14 | AlertContainerProps, 15 | any 16 | > { 17 | constructor(props: AlertContainerProps) { 18 | super(props); 19 | this.state = { 20 | visible: true, 21 | }; 22 | } 23 | 24 | onClose = () => { 25 | this.setState({ 26 | visible: false, 27 | }); 28 | }; 29 | 30 | render() { 31 | const { title, actions, content, onAnimationEnd } = this.props; 32 | const footer = actions.map(button => { 33 | // tslint:disable-next-line:only-arrow-functions 34 | const orginPress = button.onPress || function() {}; 35 | button.onPress = () => { 36 | const res = orginPress(); 37 | if (res && res.then) { 38 | res.then(() => { 39 | this.onClose(); 40 | }); 41 | } else { 42 | this.onClose(); 43 | } 44 | }; 45 | return button; 46 | }); 47 | 48 | return ( 49 | 60 | 61 | {isValidElement(content) ? content : {content}} 62 | 63 | 64 | ); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /components/modal/OperationContainer.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { TextStyle } from 'react-native'; 3 | import { WithTheme } from '../style'; 4 | import Modal from './Modal'; 5 | import { Action } from './PropsType'; 6 | import modalStyle from './style/index'; 7 | 8 | export interface OperationContainerProps { 9 | actions: Action[]; 10 | onAnimationEnd?: (visible: boolean) => void; 11 | } 12 | 13 | export default class OperationContainer extends React.Component< 14 | OperationContainerProps, 15 | any 16 | > { 17 | constructor(props: OperationContainerProps) { 18 | super(props); 19 | this.state = { 20 | visible: true, 21 | }; 22 | } 23 | 24 | onClose = () => { 25 | this.setState({ 26 | visible: false, 27 | }); 28 | }; 29 | 30 | render() { 31 | const { actions, onAnimationEnd } = this.props; 32 | const footer = actions.map(button => { 33 | // tslint:disable-next-line:only-arrow-functions 34 | const orginPress = button.onPress || function() {}; 35 | button.onPress = () => { 36 | const res = orginPress(); 37 | if (res && (res as any).then) { 38 | (res as any).then(() => { 39 | this.onClose(); 40 | }); 41 | } else { 42 | this.onClose(); 43 | } 44 | }; 45 | return button; 46 | }); 47 | return ( 48 | 49 | {styles => ( 50 | 61 | )} 62 | 63 | ); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /components/modal/PropsType.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { TextStyle } from 'react-native'; 3 | export interface ModalPropsType { 4 | title?: React.ReactNode; 5 | visible: boolean; 6 | maskClosable?: boolean; 7 | closable?: boolean; 8 | footer?: Action[]; 9 | onClose?: () => void; 10 | transparent?: boolean; 11 | popup?: boolean; 12 | animated?: boolean; 13 | locale?: object; 14 | animationType?: any; 15 | onAnimationEnd?: (visible: boolean) => void; 16 | animateAppear?: boolean; 17 | operation?: boolean; 18 | } 19 | 20 | export interface Action { 21 | text: string; 22 | onPress?: () => void | Promise; 23 | style?: T | string; 24 | } 25 | 26 | export type Callback = (valueOrLogin: string, password?: string) => void; 27 | export type CallbackOrActions = Callback | Action[]; 28 | -------------------------------------------------------------------------------- /components/modal/alert.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Portal from '../portal'; 3 | import AlertContainer from './AlertContainer'; 4 | import { Action } from './PropsType'; 5 | 6 | export default function a( 7 | title: React.ReactNode, 8 | content: React.ReactNode, 9 | actions: Action[] = [{ text: '确定' }], 10 | ) { 11 | const key = Portal.add( 12 | { 17 | if (!visible) { 18 | Portal.remove(key); 19 | } 20 | }} 21 | />, 22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /components/modal/index.tsx: -------------------------------------------------------------------------------- 1 | import Modal from './Modal'; 2 | import alert from './alert'; 3 | import prompt from './prompt'; 4 | import operation from './operation'; 5 | 6 | Modal.alert = alert; 7 | Modal.prompt = prompt; 8 | Modal.operation = operation; 9 | 10 | export default Modal; 11 | -------------------------------------------------------------------------------- /components/modal/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Feedback 4 | title: Modal 5 | subtitle: 对话框 6 | --- 7 | 8 | 用作显示系统的重要信息,并请求用户进行操作反馈,eg:删除某个重要内容时,弹出 Modal 进行二次确认。 9 | 10 | ### 规则 11 | - 尽可能少用。Modal 会打断用户操作,只用在重要的时候。 12 | - 标题应该简明,不能超过 1 行;描述内容应该简明、完整,一般不多于 2 行。 13 | - 操作按钮最多到 3 个(竖排),一般为 1-2 个(横排);3 个以上建议使用组件 ActionSheet 来完成。 14 | - 一般将用户最可能点击的按钮,放在右侧。另外,取消按钮应当始终放在左侧。 15 | 16 | ## API 17 | 18 | ### Modal 19 | 20 | 属性 | 说明 | 类型 | 默认值 21 | ----|-----|------|------ 22 | | visible | 对话框是否可见 | Boolean | false | 23 | | closable | 是否显示关闭按钮 | Boolean | false | 24 | | maskClosable | 点击蒙层是否允许关闭 | Boolean | true | 25 | | onClose | 点击 x 或 mask 回调 | (): void | 无 | 26 | | transparent | 是否背景透明 | Boolean | false | 27 | | popup | 是否弹窗模式 | Boolean | false | 28 | | animationType | 可选: 'fade' / 'slide' | String | fade | 29 | | title | 标题 | React.Element | 无 | 30 | | footer | 底部内容 | Array [{text, onPress}] | [] | 31 | 32 | ### Modal.alert(title, message, actions?, platform?) 33 | 34 | 属性 | 说明 | 类型 | 默认值 35 | ----|-----|------|------ 36 | | title | 标题 | String 或 React.Element | 无 | 37 | | message | 提示信息 | String 或 React.Element | 无 | 38 | | actions | 按钮组, [{text, onPress, style}] | Array | 无 | 39 | 40 | `Modal.alert(title, message, actions?, platform?).close()` 可以在外部关闭 Alert 41 | 42 | ### Modal.prompt(title, message, callbackOrActions, type?, defaultValue?, placeholders?, platform?) 43 | 44 | 属性 | 说明 | 类型 | 默认值 45 | ----|-----|------|------ 46 | | title | 标题 | String 或 React.Element | 无 | 47 | | message | 提示信息 | String 或 React.Element | 无 | 48 | | callbackOrActions | 按钮组 [{text, onPress}] 或回调函数 | Array or Function | 无 | 49 | | type | prompt 的样式 | String (`default`, `secure-text`, `login-password`)| `default` | 50 | | defaultValue | 默认值(input 为 password 类型不支持) | String | - | 51 | | placeholders | ['', ''] | String[] | - | 52 | 53 | 54 | `Modal.prompt(title, message, callbackOrActions, type?, defaultValue?, placeholders?, platform?).close()` 可以在外部关闭 prompt` 55 | 56 | ### Modal.operation(actions?, platform?) 57 | 58 | 属性 | 说明 | 类型 | 默认值 59 | ----|-----|------|------ 60 | | actions | 按钮组, [{text, onPress, style}] | Array | 无 | 61 | 62 | `Modal.operation(actions?, platform?).close()` 可以在外部关闭 operation` 63 | -------------------------------------------------------------------------------- /components/modal/locale/en_US.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | okText: 'Ok', 3 | cancelText: 'Cancel', 4 | buttonText: 'Button', 5 | }; 6 | -------------------------------------------------------------------------------- /components/modal/locale/ru_RU.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | okText: 'Ок', 3 | cancelText: 'Отмена', 4 | buttonText: 'Кнопка', 5 | }; 6 | -------------------------------------------------------------------------------- /components/modal/locale/sv_SE.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | okText: 'Ok', 3 | cancelText: 'Avbryt', 4 | buttonText: 'Knapp', 5 | }; 6 | -------------------------------------------------------------------------------- /components/modal/locale/zh_CN.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | okText: '确定', 3 | cancelText: '取消', 4 | buttonText: '按钮', 5 | }; 6 | -------------------------------------------------------------------------------- /components/modal/operation.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Portal from '../portal'; 3 | import OperationContainer from './OperationContainer'; 4 | 5 | export default function a(...args: any[]) { 6 | const actions = args[0] || [{ text: '确定' }]; 7 | 8 | const key = Portal.add( 9 | { 12 | if (!visible) { 13 | Portal.remove(key); 14 | } 15 | }} 16 | />, 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /components/modal/prompt.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { TextStyle } from 'react-native'; 3 | import Portal from '../portal'; 4 | import PromptContainer from './PromptContainer'; 5 | import { CallbackOrActions } from './PropsType'; 6 | 7 | export default function prompt( 8 | title: React.ReactNode, 9 | message: React.ReactNode, 10 | callbackOrActions: CallbackOrActions, 11 | type = 'default', 12 | defaultValue = '', 13 | placeholders = ['', ''], 14 | ) { 15 | if (!callbackOrActions) { 16 | // tslint:disable-next-line:no-console 17 | console.error('Must specify callbackOrActions'); 18 | return; 19 | } 20 | 21 | const key = Portal.add( 22 | { 29 | if (!visible) { 30 | Portal.remove(key); 31 | } 32 | }} 33 | placeholders={placeholders} 34 | />, 35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /components/modal/style/prompt.tsx: -------------------------------------------------------------------------------- 1 | import { StyleSheet, TextStyle, ViewStyle } from 'react-native'; 2 | import { Theme } from '../../style'; 3 | 4 | export interface PromptStyle { 5 | message: TextStyle; 6 | inputGroup: ViewStyle; 7 | inputWrapper: ViewStyle; 8 | input: TextStyle; 9 | inputFirst: ViewStyle; 10 | inputLast: ViewStyle; 11 | } 12 | 13 | export default (variables: Theme) => 14 | StyleSheet.create({ 15 | message: { 16 | marginTop: variables.v_spacing_lg, 17 | color: variables.color_text_caption, 18 | fontSize: variables.font_size_base, 19 | textAlign: 'center', 20 | }, 21 | inputGroup: { 22 | marginTop: variables.v_spacing_md, 23 | flexDirection: 'column', 24 | }, 25 | inputWrapper: { 26 | borderWidth: StyleSheet.hairlineWidth, 27 | borderTopWidth: 0, 28 | borderColor: variables.border_color_base, 29 | }, 30 | input: { 31 | height: 36, 32 | fontSize: variables.font_size_base, 33 | paddingHorizontal: variables.h_spacing_sm, 34 | paddingVertical: 0, 35 | }, 36 | inputFirst: { 37 | borderTopWidth: StyleSheet.hairlineWidth, 38 | borderTopLeftRadius: variables.radius_sm, 39 | borderTopRightRadius: variables.radius_sm, 40 | }, 41 | inputLast: { 42 | borderBottomLeftRadius: variables.radius_sm, 43 | borderBottomRightRadius: variables.radius_sm, 44 | }, 45 | }); 46 | -------------------------------------------------------------------------------- /components/notice-bar/PropsType.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface NoticeBarPropsType { 4 | mode?: 'closable' | 'link'; 5 | onPress?: () => void; 6 | icon?: React.ReactElement; 7 | action?: React.ReactElement; 8 | } 9 | -------------------------------------------------------------------------------- /components/notice-bar/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Data Display 4 | title: NoticeBar 5 | subtitle: 通告栏 6 | --- 7 | 8 | 在导航栏下方,一般用作系统提醒、活动提醒等通知。 9 | 10 | ### 规则 11 | - 需要引起用户关注时使用,重要级别低于 Modal ,高于 Toast。 12 | 13 | ## API 14 | 15 | 属性 | 说明 | 类型 | 默认值 16 | ----|-----|------|------ 17 | | mode | 提示类型,可选 `closable`,`link` | String | '' | 18 | | icon | 在开始位置设置图标 | ReactNode | ``| 19 | | onPress | 点击关闭或者操作区域的回调函数 | (): void | | 20 | | marqueeProps | marquee 参数 | Object | `{loop: false, leading: 500, trailing: 800, fps: 40, style: {}}` | 21 | | action | 用于替换操作 icon 的文案 | ReactElement | | 22 | -------------------------------------------------------------------------------- /components/notice-bar/style/index.tsx: -------------------------------------------------------------------------------- 1 | import { StyleSheet, TextStyle, ViewStyle } from 'react-native'; 2 | import { Theme } from '../../style'; 3 | 4 | export interface NoticeBarStyle { 5 | notice: ViewStyle; 6 | container: ViewStyle; 7 | content: TextStyle; 8 | left6: ViewStyle; 9 | left15: ViewStyle; 10 | actionWrap: ViewStyle; 11 | close: TextStyle; 12 | link: TextStyle; 13 | } 14 | 15 | export default (variables: Theme) => 16 | StyleSheet.create({ 17 | notice: { 18 | backgroundColor: variables.notice_bar_fill, 19 | height: variables.notice_bar_height, 20 | overflow: 'hidden', 21 | flexDirection: 'row', 22 | alignItems: 'center', 23 | }, 24 | container: { 25 | flex: 1, 26 | marginRight: variables.h_spacing_lg, 27 | overflow: 'hidden', 28 | width: 0, // ios bug: width size is wrong (usecase: with react-navigation). 29 | }, 30 | content: { 31 | fontSize: variables.font_size_subhead, 32 | color: variables.brand_warning, 33 | }, 34 | left6: { 35 | marginLeft: variables.h_spacing_sm, 36 | }, 37 | left15: { 38 | marginLeft: variables.h_spacing_lg, 39 | }, 40 | actionWrap: { 41 | marginRight: variables.h_spacing_lg, 42 | }, 43 | close: { 44 | color: variables.brand_warning, 45 | fontSize: 18, 46 | fontWeight: '200', 47 | textAlign: 'left', 48 | }, 49 | link: { 50 | transform: [{ rotate: '225deg' }], 51 | color: variables.brand_warning, 52 | fontSize: variables.font_size_icontext, 53 | fontWeight: '500', 54 | textAlign: 'left', 55 | }, 56 | }); 57 | -------------------------------------------------------------------------------- /components/pagination/PropsType.tsx: -------------------------------------------------------------------------------- 1 | export interface PaginationPropsType { 2 | mode?: 'button' | 'number' | 'pointer'; 3 | simple?: boolean; 4 | current: number; 5 | total: number; 6 | prevText?: string; 7 | nextText?: string; 8 | onPrev?: () => void; 9 | onNext?: () => void; 10 | onChange?: (current: number) => void; 11 | } 12 | export interface PaginationState { 13 | current: number; 14 | } 15 | -------------------------------------------------------------------------------- /components/pagination/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Navigation 4 | title: Pagination 5 | subtitle: 分页器 6 | --- 7 | 8 | 分隔长列表,每次只加载一个页面。 9 | 10 | ### 规则 11 | - 当加载/渲染所有数据将花费很多时间或者流量时使用 12 | 13 | ## API 14 | 15 | 属性 | 说明 | 类型 | 默认值 16 | ----|-----|------|------ 17 | | mode | 形态,可选`button`,`number`,`pointer` | string | `button` | 18 | | current | 当前页号 | number | 1 | 19 | | total | 数据总数 | number | 0 | 20 | | simple | 是否隐藏数值 | boolean | false | 21 | | disabled | 禁用状态 | boolean | false | 22 | | locale | 国际化, 可以覆盖全局`LocaleProvider`的配置 | Object:{prevText, nextText} | 无 | 23 | | onChange | change 事件触发的回调函数 | (e: Object): void | 无 | 24 | -------------------------------------------------------------------------------- /components/pagination/locale/en_US.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | prevText: 'Prev', 3 | nextText: 'Next', 4 | }; 5 | -------------------------------------------------------------------------------- /components/pagination/locale/es_ES.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | prevText: 'Ant', 3 | nextText: 'Sig', 4 | }; 5 | -------------------------------------------------------------------------------- /components/pagination/locale/ru_RU.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | prevText: 'Назад', 3 | nextText: 'Вперёд', 4 | }; 5 | -------------------------------------------------------------------------------- /components/pagination/locale/sv_SE.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | prevText: 'Föreg', 3 | nextText: 'Nästa', 4 | }; 5 | -------------------------------------------------------------------------------- /components/pagination/locale/zh_CN.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | prevText: '上一页', 3 | nextText: '下一页', 4 | }; 5 | -------------------------------------------------------------------------------- /components/pagination/style/index.tsx: -------------------------------------------------------------------------------- 1 | import { StyleSheet, TextStyle, ViewStyle } from 'react-native'; 2 | import { Theme } from '../../style'; 3 | 4 | export interface PaginationStyle { 5 | container: ViewStyle; 6 | numberStyle: ViewStyle; 7 | totalStyle: TextStyle; 8 | activeTextStyle: TextStyle; 9 | indicatorStyle: ViewStyle; 10 | pointStyle: ViewStyle; 11 | pointActiveStyle: ViewStyle; 12 | spaceStyle: ViewStyle; 13 | } 14 | 15 | export default (theme: Theme) => 16 | StyleSheet.create({ 17 | container: { 18 | alignItems: 'center', 19 | justifyContent: 'center', 20 | }, 21 | numberStyle: { 22 | flexDirection: 'row', 23 | justifyContent: 'center', 24 | }, 25 | totalStyle: { 26 | fontSize: 18, 27 | color: theme.color_text_base, 28 | }, 29 | activeTextStyle: { 30 | fontSize: 18, 31 | color: theme.color_link, 32 | }, 33 | indicatorStyle: { 34 | flexDirection: 'row', 35 | }, 36 | pointStyle: { 37 | width: 8, 38 | height: 8, 39 | borderRadius: 8, 40 | backgroundColor: theme.input_color_icon, 41 | }, 42 | pointActiveStyle: { 43 | backgroundColor: '#888', 44 | }, 45 | spaceStyle: { 46 | marginHorizontal: theme.h_spacing_sm / 2, 47 | marginVertical: theme.v_spacing_sm / 2, 48 | }, 49 | }); 50 | -------------------------------------------------------------------------------- /components/picker-view/PickerView.tsx: -------------------------------------------------------------------------------- 1 | 2 | import React from 'react'; 3 | import { StyleProp, ViewStyle } from 'react-native'; 4 | import RMCCascader from '../picker/cascader'; 5 | import MultiPicker from '../picker/MultiPicker'; 6 | import RMCPicker from '../picker/Picker'; 7 | import { PickerData } from '../picker/PropsType'; 8 | 9 | function getDefaultProps() { 10 | return { 11 | cols: 3, 12 | cascade: true, 13 | value: [], 14 | onChange() {}, 15 | }; 16 | } 17 | 18 | export interface PickerViewProps { 19 | cols?: number; 20 | cascade?: boolean; 21 | value?: any[]; 22 | data?: PickerData[] | PickerData[][]; 23 | styles?: any; 24 | onChange?: (value?: any) => void; 25 | onScrollChange?: (value?: any) => void; 26 | indicatorStyle?: StyleProp; 27 | itemStyle?: StyleProp; 28 | } 29 | 30 | export default class PickerView extends React.Component { 31 | static defaultProps = getDefaultProps(); 32 | 33 | getCol = () => { 34 | const { data, indicatorStyle, itemStyle } = this.props; 35 | return (data as PickerData[][]).map((col, index) => { 36 | return ( 37 | 43 | {col.map(item => { 44 | return ( 45 | 46 | {item.label} 47 | 48 | ); 49 | })} 50 | 51 | ); 52 | }); 53 | } 54 | render() { 55 | // tslint:disable-next-line:no-this-assignment 56 | const { props } = this; 57 | let picker; 58 | if (props.cascade) { 59 | picker = ( 60 | 69 | ); 70 | } else { 71 | picker = ( 72 | 78 | {this.getCol()} 79 | 80 | ); 81 | } 82 | return picker; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /components/picker-view/index.tsx: -------------------------------------------------------------------------------- 1 | import PickerView from './PickerView'; 2 | 3 | export default PickerView; 4 | -------------------------------------------------------------------------------- /components/picker-view/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Data Entry 4 | title: PickerView 5 | subtitle: 选择器 6 | --- 7 | 8 | PickerView 的功能类似于 Picker ,但它是直接渲染在区域中,而不是弹出窗口。 9 | 10 | ## API 11 | 12 | 属性 | 说明 | 类型 | 默认值 13 | ----|-----|------|------ 14 | | data | 数据源 | `Array<{value, label}>` / `Array>` | - | 15 | | value | 值, 格式是`[value1, value2, value3]`, 对应数据源的相应级层 value | Array | - | 16 | | cascade | 是否级联 | Boolean| true| 17 | | cols | 列数 | Number | `3` | 18 | | onChange | 选中后的回调,可使用[rc-form](https://github.com/react-component/form) | (val): void | - | 19 | | itemStyle| 每列样式 | Object | - | 20 | | indicatorStyle | indicator 样式 | Object | - | 21 | -------------------------------------------------------------------------------- /components/picker/MultiPicker.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { View } from 'react-native'; 3 | import MultiPickerMixin from './MultiPickerMixin'; 4 | import MultiPickerProps from './MultiPickerProps'; 5 | 6 | export interface MultiPickerProp { 7 | getValue: Function; 8 | } 9 | 10 | const MultiPicker = (props: MultiPickerProp & MultiPickerProps) => { 11 | const { children, style } = props; 12 | const selectedValue = props.getValue(); 13 | const colElements = React.Children.map(children, (col: any, i) => { 14 | return React.cloneElement(col, { 15 | selectedValue: selectedValue[i], 16 | onValueChange: (...args: any[]) => props.onValueChange!(i, ...args), 17 | }); 18 | }); 19 | return {colElements}; 20 | }; 21 | 22 | export default MultiPickerMixin(MultiPicker); 23 | -------------------------------------------------------------------------------- /components/picker/MultiPickerMixin.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import MultiPickerProps from './MultiPickerProps'; 3 | 4 | export default function(ComposedComponent: any) { 5 | return class extends React.Component { 6 | static defaultProps = { 7 | prefixCls: 'rmc-multi-picker', 8 | onValueChange() {}, 9 | }; 10 | 11 | getValue = () => { 12 | const { children, selectedValue } = this.props; 13 | if (selectedValue && selectedValue.length) { 14 | return selectedValue; 15 | } else { 16 | if (!children) { 17 | return []; 18 | } 19 | return React.Children.map(children, (c: any) => { 20 | const cc: any = React.Children.toArray( 21 | c.children || c.props.children, 22 | ); 23 | return cc && cc[0] && cc[0].props.value; 24 | }); 25 | } 26 | }; 27 | 28 | onChange = (i: any, v: any, cb: any) => { 29 | const value = this.getValue().concat(); 30 | value[i] = v; 31 | if (cb) { 32 | cb(value, i); 33 | } 34 | }; 35 | 36 | onValueChange = (i: any, v: any) => { 37 | this.onChange(i, v, this.props.onValueChange); 38 | }; 39 | 40 | onScrollChange = (i: any, v: any) => { 41 | this.onChange(i, v, this.props.onScrollChange); 42 | }; 43 | 44 | render() { 45 | return ( 46 | 52 | ); 53 | } 54 | }; 55 | } 56 | -------------------------------------------------------------------------------- /components/picker/MultiPickerProps.tsx: -------------------------------------------------------------------------------- 1 | import { StyleProp, ViewStyle } from "react-native"; 2 | 3 | export interface PickerCol { 4 | key?: string; 5 | props?: any; 6 | } 7 | 8 | interface MultiPickerProps { 9 | selectedValue?: any[]; 10 | rootNativeProps?: any; 11 | onValueChange?: (v?: any, i?: number) => void; 12 | children?: any; 13 | style?: StyleProp; 14 | onScrollChange?: (v?: any, i?: number) => void; 15 | } 16 | 17 | export default MultiPickerProps; 18 | -------------------------------------------------------------------------------- /components/picker/NativePicker.ios.tsx: -------------------------------------------------------------------------------- 1 | export { Picker as default } from 'react-native'; 2 | -------------------------------------------------------------------------------- /components/picker/NativePicker.tsx: -------------------------------------------------------------------------------- 1 | // hack for ts module resolution 2 | export { default } from './NativePicker.ios'; 3 | -------------------------------------------------------------------------------- /components/picker/Picker.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import NativePicker from './NativePicker'; 3 | import { PickerProps } from './PickerTypes'; 4 | 5 | const Item: any = NativePicker.Item; 6 | 7 | class Picker extends React.Component { 8 | static defaultProps = { 9 | children: [], 10 | }; 11 | 12 | static Item: any = () => {}; 13 | 14 | getValue() { 15 | if ('selectedValue' in this.props) { 16 | return this.props.selectedValue; 17 | } 18 | const children: any = React.Children.toArray(this.props.children); 19 | return children && children[0] && children[0].props.value; 20 | } 21 | 22 | shouldComponentUpdate(nextProps: any) { 23 | return ( 24 | this.props.selectedValue !== nextProps.selectedValue || 25 | this.props.children !== nextProps.children 26 | ); 27 | } 28 | 29 | render() { 30 | const children = React.Children.map(this.props.children, (c: any) => { 31 | return ( 32 | 37 | ); 38 | }); 39 | return {children}; 40 | } 41 | } 42 | 43 | export default Picker; 44 | -------------------------------------------------------------------------------- /components/picker/PickerMixin.tsx: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-console */ 2 | import React from 'react'; 3 | import { PickerProps } from './PickerTypes'; 4 | 5 | type ItemProps = { 6 | value: any; 7 | }; 8 | 9 | const Item = (_props: ItemProps) => null; 10 | 11 | export default function(ComposedComponent: any) { 12 | return class extends React.Component { 13 | static Item = Item; 14 | 15 | select = (value: any, itemHeight: any, scrollTo: any) => { 16 | const children: any = React.Children.toArray(this.props.children); 17 | for (let i = 0, len = children.length; i < len; i++) { 18 | if (children[i].props.value === value) { 19 | this.selectByIndex(i, itemHeight, scrollTo); 20 | return; 21 | } 22 | } 23 | this.selectByIndex(0, itemHeight, scrollTo); 24 | }; 25 | 26 | selectByIndex(index: number, itemHeight: any, zscrollTo: any) { 27 | if ( 28 | index < 0 || 29 | index >= React.Children.count(this.props.children) || 30 | !itemHeight 31 | ) { 32 | return; 33 | } 34 | zscrollTo(index * itemHeight); 35 | } 36 | 37 | computeChildIndex(top: any, itemHeight: any, childrenLength: number) { 38 | const index = Math.round(top / itemHeight); 39 | return Math.min(index, childrenLength - 1); 40 | } 41 | 42 | doScrollingComplete = (top: any, itemHeight: any, fireValueChange: any) => { 43 | const children = React.Children.toArray(this.props.children); 44 | const index = this.computeChildIndex(top, itemHeight, children.length); 45 | const child: any = children[index]; 46 | if (child) { 47 | fireValueChange(child.props.value); 48 | } else if (console.warn) { 49 | console.warn('child not found', children, index); 50 | } 51 | }; 52 | 53 | render() { 54 | return ( 55 | 61 | ); 62 | } 63 | }; 64 | } 65 | -------------------------------------------------------------------------------- /components/picker/PickerTypes.tsx: -------------------------------------------------------------------------------- 1 | import { StyleProp, ViewStyle } from "react-native"; 2 | 3 | export type PickerProps = { 4 | disabled?: boolean; 5 | selectedValue?: any; 6 | onValueChange?: (value: any) => void; 7 | itemStyle?: StyleProp; 8 | indicatorStyle?: StyleProp; 9 | indicatorClassName?: string; 10 | defaultSelectedValue?: any; 11 | style?: StyleProp; 12 | onScrollChange?: (value: any) => void; 13 | noAnimate?: boolean; 14 | }; 15 | -------------------------------------------------------------------------------- /components/picker/Popup.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Text, TouchableHighlight, View } from 'react-native'; 3 | import Modal from '../modal/ModalView'; 4 | import PopupMixin from './PopupMixin'; 5 | 6 | const getModal = (props: any, visible: any, { getContent, hide, onDismiss, onOk }: any) => { 7 | const { styles, title, okText, dismissText } = props; 8 | 9 | const titleEl = 10 | typeof title === 'string' ? ( 11 | {title} 12 | ) : ( 13 | title 14 | ); 15 | const okEl = 16 | typeof okText === 'string' ? ( 17 | {okText} 18 | ) : ( 19 | okText 20 | ); 21 | const dismissEl = 22 | typeof dismissText === 'string' ? ( 23 | {dismissText} 24 | ) : ( 25 | dismissText 26 | ); 27 | 28 | return ( 29 | 35 | 36 | 42 | {dismissEl} 43 | 44 | {titleEl} 45 | 51 | {okEl} 52 | 53 | 54 | {getContent()} 55 | 56 | ); 57 | }; 58 | 59 | export default PopupMixin(getModal, { 60 | actionTextUnderlayColor: '#ddd', 61 | actionTextActiveOpacity: 1, 62 | triggerType: 'onPress', 63 | styles: {}, 64 | WrapComponent: View as any, 65 | }); 66 | -------------------------------------------------------------------------------- /components/picker/PopupPickerTypes.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export type PopupPickerProps = { 4 | picker?: any; 5 | value?: any; 6 | triggerType?: string; 7 | WrapComponent?: any; 8 | dismissText?: string | React.ReactElement; // React.ReactElement only for web 9 | okText?: string | React.ReactElement; // React.ReactElement only for web 10 | title?: string | React.ReactElement; // React.ReactElement only for web 11 | visible?: boolean; 12 | disabled?: boolean; 13 | onOk?: (value?: any) => void; 14 | style?: any; 15 | onVisibleChange?: (visible: boolean) => void; 16 | content?: React.ReactElement | string; 17 | onDismiss?: () => void; 18 | styles?: any; 19 | actionTextUnderlayColor?: string; 20 | actionTextActiveOpacity?: number; 21 | wrapStyle?: React.CSSProperties; 22 | pickerValueProp?: string; 23 | pickerValueChangeProp?: string; 24 | transitionName?: string; 25 | popupTransitionName?: string; 26 | maskTransitionName?: string; 27 | }; 28 | -------------------------------------------------------------------------------- /components/picker/PopupStyles.tsx: -------------------------------------------------------------------------------- 1 | import { StyleSheet } from 'react-native'; 2 | 3 | const textStyle = { 4 | color: '#0ae', 5 | fontSize: 18, 6 | textAlign: 'center', 7 | }; 8 | 9 | const styles = StyleSheet.create({ 10 | modal: { 11 | flexDirection: 'column', 12 | justifyContent: 'flex-end', 13 | }, 14 | header: { 15 | // flex:1, 0.39.0 needs to remove 16 | height: 44, 17 | alignItems: 'center', 18 | flexDirection: 'row', 19 | justifyContent: 'center', 20 | borderBottomWidth: 1, 21 | borderBottomColor: '#e7e7e7', 22 | }, 23 | headerItem: { 24 | height: 44, 25 | alignItems: 'center', 26 | justifyContent: 'center', 27 | flex: 1, 28 | }, 29 | actionText: textStyle, 30 | okText: {}, 31 | dismissText: {}, 32 | title: { 33 | ...textStyle, 34 | color: '#666', 35 | }, 36 | }); 37 | 38 | export default styles; 39 | -------------------------------------------------------------------------------- /components/picker/PropsType.tsx: -------------------------------------------------------------------------------- 1 | import { StyleProp, ViewStyle } from 'react-native'; 2 | import { Omit } from 'utility-types'; 3 | import { CascaderValue } from './cascader/CascaderTypes'; 4 | import { PopupPickerProps } from './PopupPickerTypes'; 5 | export interface PickerData { 6 | value: string | number; 7 | label: string; 8 | children?: PickerData[]; 9 | } 10 | export interface PickerPropsType extends Omit { 11 | data: PickerData[] | PickerData[][]; 12 | cascade?: boolean; 13 | value?: Array; 14 | format?: (values: string[]) => string; 15 | cols?: number; 16 | extra?: string; 17 | onChange?: (date?: CascaderValue) => void; 18 | onPickerChange?: (value: CascaderValue) => void; 19 | itemStyle?: StyleProp; 20 | indicatorStyle?: StyleProp; 21 | } 22 | -------------------------------------------------------------------------------- /components/picker/cascader/CascaderTypes.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { StyleProp, ViewStyle } from 'react-native'; 3 | 4 | export type CascaderOneValue = string | number; 5 | export type CascaderValue = CascaderOneValue[]; 6 | 7 | export interface CascaderDataItem { 8 | label: React.ReactNode; 9 | value: CascaderOneValue; 10 | children?: CascaderDataItem[]; 11 | } 12 | 13 | export interface CascaderProps { 14 | defaultValue?: CascaderValue; 15 | value?: CascaderValue; 16 | onChange?: (value: CascaderValue) => void; 17 | data: CascaderDataItem[]; 18 | cols?: number; 19 | disabled?: boolean; 20 | rootNativeProps?: {}; 21 | pickerItemStyle?: StyleProp; 22 | indicatorStyle?: StyleProp; 23 | style?: StyleProp; 24 | onScrollChange?: (value: CascaderValue) => void; 25 | } 26 | -------------------------------------------------------------------------------- /components/picker/cascader/Popup.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PopupPicker from '../Popup'; 3 | import { PopupPickerProps } from '../PopupPickerTypes'; 4 | import { CascaderProps, CascaderValue } from './CascaderTypes'; 5 | 6 | export interface IPopupCascaderProps extends PopupPickerProps { 7 | cascader: React.ReactElement; 8 | onChange?: (date?: CascaderValue) => void; 9 | } 10 | 11 | class PopupCascader extends React.Component { 12 | static defaultProps = { 13 | pickerValueProp: 'value', 14 | pickerValueChangeProp: 'onChange', 15 | }; 16 | 17 | onOk = (v: any) => { 18 | const { onChange, onOk } = this.props; 19 | if (onChange) { 20 | onChange(v); 21 | } 22 | if (onOk) { 23 | onOk(v); 24 | } 25 | }; 26 | 27 | render() { 28 | return ( 29 | 34 | ); 35 | } 36 | } 37 | 38 | export default PopupCascader; 39 | -------------------------------------------------------------------------------- /components/picker/cascader/PopupStyles.tsx: -------------------------------------------------------------------------------- 1 | export { default } from '../PopupStyles'; 2 | -------------------------------------------------------------------------------- /components/picker/cascader/index.tsx: -------------------------------------------------------------------------------- 1 | export { default } from './Cascader'; 2 | -------------------------------------------------------------------------------- /components/picker/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Data Entry 4 | title: Picker 5 | subtitle: 选择器 6 | --- 7 | 8 | 在一组预设数据中进行选择,e.g. 省市区选择。 9 | 10 | ### 规则 11 | - 尽量使用 Picker 来帮助用户完成输入,避免用户通过键盘直接输入。 12 | - DatePicker 是 Picker 的特定模式。 13 | 14 | ## API 15 | 16 | 属性 | 说明 | 类型 | 默认值 17 | ----|-----|------|------ 18 | | data | 数据源 | `Array<{value, label, children: Array}>` | - | 19 | | value | 值, 格式是`[value1, value2, value3]`, 对应数据源的相应级层value | Array | - | 20 | | format | 格式化选中值的函数 | (labels: string[]): any | `(labels) => { return labels.join(','); } ` | 21 | | cols | 列数 | Number | `3` | 22 | | onChange | 选中后的回调,可使用[rc-form](https://github.com/react-component/form) | (val): void | - | 23 | | onPickerChange | 每列数据选择变化后的回调函数 | (val): void | - | 24 | | onVisibleChange | 当显隐状态变化时回调函数 | (visible: bool): void | - | 25 | | itemStyle | 每列样式 | Object | - | 26 | | indicatorStyle | indicator 样式 | Object | - | 27 | | children| 通常是 `List.Item` | Object | `List.Item` | 28 | | okText | 选中的文案 | String | `确定` | 29 | | dismissText | 取消选中的文案 | String | `取消` | 30 | | onOk | 点击选中时执行的回调 | (val): void | 无 | 31 | | onDismiss | 点击取消时执行的回调 | (): void | 无 | 32 | | title | 大标题 | String | - | 33 | | extra | Picker children 建议是 `List.Item`, 如果不是,需要是自定义组件(组件内需处理`onClick`/`extra`属性) | String | `请选择` | 34 | | disabled | 是否不可用 | Boolean | false | 35 | | cascade | 是否联动 | Boolean | true | 36 | 37 | -------------------------------------------------------------------------------- /components/picker/locale/en_US.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | okText: 'Ok', 3 | dismissText: 'Cancel', 4 | extra: 'please select', 5 | }; 6 | -------------------------------------------------------------------------------- /components/picker/locale/es_ES.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | okText: 'OK', 3 | dismissText: 'Cancelar', 4 | extra: 'Seleccione', 5 | }; 6 | -------------------------------------------------------------------------------- /components/picker/locale/ru_RU.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | okText: 'Ок', 3 | dismissText: 'Отмена', 4 | extra: '', 5 | }; 6 | -------------------------------------------------------------------------------- /components/picker/locale/sv_SE.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | okText: 'Ok', 3 | dismissText: 'Avbryt', 4 | extra: 'vänligen välj', 5 | }; 6 | -------------------------------------------------------------------------------- /components/picker/locale/zh_CN.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | okText: '确定', 3 | dismissText: '取消', 4 | extra: '请选择', 5 | }; 6 | -------------------------------------------------------------------------------- /components/picker/style/index.tsx: -------------------------------------------------------------------------------- 1 | import { StyleSheet, TextStyle, ViewStyle } from 'react-native'; 2 | 3 | export interface PickerStyle { 4 | modal: ViewStyle; 5 | header: ViewStyle; 6 | headerItem: ViewStyle; 7 | actionText: TextStyle; 8 | title: TextStyle; 9 | okText: TextStyle; 10 | dismissText: TextStyle; 11 | } 12 | 13 | export default () => 14 | StyleSheet.create({ 15 | modal: { 16 | flex: 1, 17 | flexDirection: 'column', 18 | justifyContent: 'flex-end', 19 | }, 20 | header: { 21 | flexGrow: 1, 22 | height: 44, 23 | alignItems: 'center', 24 | flexDirection: 'row', 25 | justifyContent: 'center', 26 | borderBottomWidth: 1, 27 | borderBottomColor: '#e7e7e7', 28 | }, 29 | headerItem: { 30 | height: 44, 31 | flex: 1, 32 | alignItems: 'center', 33 | justifyContent: 'center', 34 | }, 35 | actionText: { 36 | color: '#0ae', 37 | fontSize: 18, 38 | textAlign: 'center', 39 | }, 40 | okText: {}, 41 | dismissText: {}, 42 | title: { 43 | color: '#666', 44 | fontSize: 18, 45 | textAlign: 'center', 46 | }, 47 | }); 48 | -------------------------------------------------------------------------------- /components/popover/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Navigation 4 | title: Popover 5 | subtitle: 气泡 6 | --- 7 | 8 | 在点击控件或者某个区域后,浮出一个气泡菜单来做更多的操作。 9 | 如果设置了遮罩层,建议通过点击遮罩层的任一位置,进行退出。 10 | 11 | ## API 12 | 13 | ### Popover 14 | 15 | 属性 | 说明 | 类型 | 默认值 16 | ----|-----|------|------ 17 | | overlay | 弹出层内容 | ReactNode | - | 18 | | placement | 弹出层位置 | 'top | right | bottom | left | auto' | auto | 19 | | onSelect | 选中某选项时的回调函数 | (value: any): void | - | 20 | | triggerStyle | 触发元素外围容器样式 | ViewStyle | - | 21 | | renderOverlayComponent | 自定义弹出层的外围组件,默认是`ScrollView`,示例`(nodes) => {nodes}` | (node: React.ReactNode) => React.ReactNode | - | 22 | 23 | 24 | ### Popover.Item 25 | 26 | 属性 | 说明 | 类型 | 默认值 27 | ----|-----|------|------ 28 | | disabled | 是否禁用 | Boolean | false | 29 | | style | item 样式 | ViewStyle | - | 30 | | value | 可作为选中的条目ID | any | - | 31 | -------------------------------------------------------------------------------- /components/popover/style/index.tsx: -------------------------------------------------------------------------------- 1 | import { StyleSheet, ViewStyle } from 'react-native'; 2 | import { Theme } from '../../style'; 3 | 4 | export interface PopoverStyle { 5 | content: ViewStyle; 6 | arrow: ViewStyle; 7 | background: ViewStyle; 8 | } 9 | 10 | export default (theme: Theme) => 11 | StyleSheet.create({ 12 | content: { 13 | backgroundColor: theme.fill_base, 14 | borderRadius: theme.radius_sm, 15 | padding: 0, 16 | elevation: 3, 17 | }, 18 | arrow: { 19 | borderTopColor: 'transparent', 20 | }, 21 | background: { 22 | backgroundColor: 'transparent', 23 | }, 24 | }); 25 | -------------------------------------------------------------------------------- /components/portal/README.md: -------------------------------------------------------------------------------- 1 | # Portal 2 | 3 | > NOTE: The sources are copy from `react-native-paper` for more informations please move to https://callstack.github.io/react-native-paper/portal.html 4 | -------------------------------------------------------------------------------- /components/portal/index.tsx: -------------------------------------------------------------------------------- 1 | import Portal from './portal'; 2 | export default Portal 3 | -------------------------------------------------------------------------------- /components/portal/portal-consumer.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { PortalMethods } from './portal-host'; 3 | 4 | export type PortalConsumerProps = { 5 | manager: PortalMethods, 6 | children: React.ReactNode, 7 | }; 8 | 9 | export default class PortalConsumer extends React.Component { 10 | 11 | _key: any; 12 | componentDidMount() { 13 | if (!this.props.manager) { 14 | throw new Error( 15 | 'Looks like you forgot to wrap your root component with `Provider` component from `@sishuguojixuefu/antd-mobile-rn`.\n\n', 16 | ); 17 | } 18 | 19 | this._key = this.props.manager.mount(this.props.children); 20 | } 21 | 22 | componentDidUpdate() { 23 | this.props.manager.update(this._key, this.props.children); 24 | } 25 | 26 | componentWillUnmount() { 27 | this.props.manager.unmount(this._key); 28 | } 29 | 30 | render() { 31 | return null; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /components/portal/portal-manager.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { View, StyleSheet } from 'react-native'; 3 | export type State = { 4 | portals: Array<{ 5 | key: number; 6 | children: React.ReactNode; 7 | }>; 8 | }; 9 | export type PortalManagerState = { 10 | portals: any[]; 11 | }; 12 | /** 13 | * Portal host is the component which actually renders all Portals. 14 | */ 15 | export default class PortalManager extends React.PureComponent< 16 | {}, 17 | PortalManagerState 18 | > { 19 | state: State = { 20 | portals: [], 21 | }; 22 | mount = (key: number, children: React.ReactNode) => { 23 | this.setState(state => ({ 24 | portals: [...state.portals, { key, children }], 25 | })); 26 | }; 27 | update = (key: number, children: React.ReactNode) => 28 | this.setState(state => ({ 29 | portals: state.portals.map(item => { 30 | if (item.key === key) { 31 | return { ...item, children }; 32 | } 33 | return item; 34 | }), 35 | })); 36 | unmount = (key: number) => 37 | this.setState(state => ({ 38 | portals: state.portals.filter(item => item.key !== key), 39 | })); 40 | render() { 41 | return this.state.portals.map(({ key, children }, i) => ( 42 | 50 | {children} 51 | 52 | )); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /components/portal/portal.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PortalConsumer from './portal-consumer'; 3 | import PortalHost, { portal, PortalContext } from './portal-host'; 4 | 5 | export type PortalProps = { 6 | /** 7 | * Content of the `Portal`. 8 | */ 9 | children?: React.ReactNode; 10 | }; 11 | 12 | /** 13 | * Portal allows to render a component at a different place in the parent tree. 14 | * You can use it to render content which should appear above other elements, similar to `Modal`. 15 | * It requires a [`Portal.Host`](portal-host.html) component to be rendered somewhere in the parent tree. 16 | * 17 | * ## Usage 18 | * ```js 19 | * import * as React from 'react'; 20 | * import { Portal, Text } from '@sishuguojixuefu/antd-mobile-rn'; 21 | * 22 | * export default class MyComponent extends React.Component { 23 | * render() { 24 | * const { visible } = this.state; 25 | * return ( 26 | * 27 | * This is rendered at a different place 28 | * 29 | * ); 30 | * } 31 | * } 32 | * ``` 33 | */ 34 | class Portal extends React.Component { 35 | static Host = PortalHost; 36 | static add = portal.add; 37 | static remove = portal.remove; 38 | render() { 39 | const { children } = this.props; 40 | 41 | return ( 42 | 43 | {manager => ( 44 | {children} 45 | )} 46 | 47 | ); 48 | } 49 | } 50 | 51 | export default Portal; 52 | -------------------------------------------------------------------------------- /components/progress/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Feedback 4 | title: Progress 5 | subtitle: 进度条 6 | --- 7 | 8 | 表明某个任务的当前进度。 9 | 10 | ### 规则 11 | 12 | - 需要准确告知当前进度,否则应该使用组件 ActivityIndicator。 13 | - 和 NavBar 一起搭配使用时,可以隐藏 Progress 未填充部分的轨道,提升整体感。 14 | 15 | ## API 16 | 17 | 属性 | 说明 | 类型 | 默认值 18 | ----|-----|------|------ 19 | percent | 进度百分比 | number | 0 20 | position | 进度条的位置,fixed 将浮出固定在最顶层,可选: `fixed` `normal` | string | `fixed` 21 | unfilled | 是否显示未填充的轨道 | boolean | true 22 | style | 进度条样式 | object | {} 23 | barStyle | 进度样式 | object | {} 24 | -------------------------------------------------------------------------------- /components/progress/style/index.tsx: -------------------------------------------------------------------------------- 1 | import { StyleSheet, ViewStyle } from 'react-native'; 2 | import { Theme } from '../../style'; 3 | export interface ProgressStyle { 4 | progressOuter: ViewStyle; 5 | progressBar: ViewStyle; 6 | } 7 | export default (theme: Theme) => 8 | StyleSheet.create({ 9 | progressOuter: { 10 | backgroundColor: theme.border_color_base, 11 | flex: 1, 12 | }, 13 | progressBar: { 14 | borderBottomWidth: 4, 15 | borderStyle: 'solid', 16 | borderColor: theme.brand_primary, 17 | }, 18 | }); 19 | -------------------------------------------------------------------------------- /components/provider/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import LocaleProvider, { Locale } from '../locale-provider'; 3 | import Portal from '../portal'; 4 | import { Theme, ThemeProvider } from '../style'; 5 | export interface ProviderProps { 6 | locale?: Partial; 7 | theme?: Partial; 8 | } 9 | export default class Provider extends React.Component { 10 | render() { 11 | return ( 12 | 13 | 14 | {this.props.children} 15 | 16 | 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /components/radio/PropsType.tsx: -------------------------------------------------------------------------------- 1 | export interface RadioPropsType { 2 | defaultChecked?: boolean; 3 | checked?: boolean; 4 | disabled?: boolean; 5 | onChange?: (e: { target: { checked: boolean } }) => void; 6 | name?: string; 7 | wrapLabel?: boolean; 8 | } 9 | 10 | export interface RadioItemPropsType extends RadioPropsType { 11 | radioProps?: object; 12 | onPress?: () => any; 13 | } 14 | -------------------------------------------------------------------------------- /components/radio/RadioItem.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { ImageStyle, StyleProp, Text, View, ViewStyle } from 'react-native'; 3 | import List from '../list/index'; 4 | import { WithTheme, WithThemeStyles } from '../style'; 5 | import { RadioItemPropsType } from './PropsType'; 6 | import Radio from './Radio'; 7 | import RadioItemStyles, { RadioStyle } from './style/index'; 8 | 9 | const ListItem = List.Item; 10 | 11 | export interface RadioItemNativeProps 12 | extends RadioItemPropsType, 13 | WithThemeStyles { 14 | style?: StyleProp; 15 | radioStyle?: StyleProp; 16 | } 17 | 18 | export default class RadioItem extends React.Component< 19 | RadioItemNativeProps, 20 | any 21 | > { 22 | radio: Radio | null; 23 | 24 | handleClick = () => { 25 | if (this.radio) { 26 | this.radio.handleClick(); 27 | } 28 | }; 29 | 30 | render() { 31 | const { 32 | style, 33 | radioStyle, 34 | defaultChecked, 35 | checked, 36 | disabled, 37 | children, 38 | onChange, 39 | } = this.props; 40 | 41 | return ( 42 | 43 | {styles => { 44 | let contentDom: React.ReactElement | null = null; 45 | if (children && React.isValidElement(children)) { 46 | contentDom = {children}; 47 | } else { 48 | const contentStyle = [ 49 | styles.radioItemContent, 50 | disabled ? styles.radioItemContentDisable : {}, 51 | ]; 52 | contentDom = ( 53 | 54 | {this.props.children} 55 | 56 | ); 57 | } 58 | 59 | const radioEl = ( 60 | (this.radio = ref)} 62 | style={radioStyle} 63 | defaultChecked={defaultChecked} 64 | checked={checked} 65 | onChange={onChange} 66 | disabled={disabled} 67 | /> 68 | ); 69 | 70 | return ( 71 | 76 | {contentDom} 77 | 78 | ); 79 | }} 80 | 81 | ); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /components/radio/index.tsx: -------------------------------------------------------------------------------- 1 | import Radio from './Radio'; 2 | import RadioItem from './RadioItem'; 3 | 4 | Radio.RadioItem = RadioItem; 5 | 6 | export default Radio; 7 | -------------------------------------------------------------------------------- /components/radio/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Data Entry 4 | title: Radio 5 | subtitle: 单选框 6 | --- 7 | 8 | 单选框 9 | 10 | ## API 11 | 12 | ### Radio 13 | 14 | 属性 | 说明 | 类型 | 默认值 15 | ----|-----|------|------ 16 | | name | name | String | 无 | 17 | | defaultChecked | 初始是否选中 | Boolean | 无 | 18 | | checked | 指定当前是否选中 | Boolean | 无 | 19 | | disabled | 禁用 | Boolean | false | 20 | | onChange | change 事件触发的回调函数 | (e: Object): void | 无 | 21 | 22 | ### Radio.RadioItem 23 | 24 | 基于`List.Item`对`Radio`进行封装,`List.Item`的`extra`属性固定传入`Radio`,其他属性和`List.Item`一致。 25 | 其他 API 和 Radio 相同。 26 | -------------------------------------------------------------------------------- /components/radio/style/index.tsx: -------------------------------------------------------------------------------- 1 | import { ImageStyle, StyleSheet, TextStyle, ViewStyle } from 'react-native'; 2 | import { Theme } from '../../style'; 3 | 4 | export interface RadioStyle { 5 | wrapper: ViewStyle; 6 | icon: ImageStyle; 7 | radioItem: ViewStyle; 8 | radioItemRadio: ViewStyle; 9 | radioItemContent: TextStyle; 10 | radioItemContentDisable: TextStyle; 11 | } 12 | 13 | export default (theme: Theme) => 14 | StyleSheet.create({ 15 | wrapper: { 16 | flexDirection: 'row', 17 | alignItems: 'center', 18 | }, 19 | icon: { 20 | // width: variables.icon_size_xxs, 21 | // height: variables.icon_size_xxs * 0.8, 22 | }, 23 | radioItem: { 24 | flexDirection: 'row', 25 | alignItems: 'center', 26 | }, 27 | radioItemRadio: { 28 | marginLeft: theme.h_spacing_lg, 29 | marginRight: theme.h_spacing_md, 30 | }, 31 | radioItemContent: { 32 | color: theme.color_text_base, 33 | fontSize: theme.font_size_heading, 34 | }, 35 | radioItemContentDisable: { 36 | color: theme.color_text_disabled, 37 | }, 38 | }); 39 | -------------------------------------------------------------------------------- /components/result/PropsType.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { ImagePropertiesSourceOptions } from 'react-native'; 3 | 4 | export interface ResultPropsType { 5 | imgUrl?: ImagePropertiesSourceOptions; 6 | img?: React.ReactNode; 7 | title?: React.ReactNode; 8 | message?: React.ReactNode; 9 | buttonText?: string; 10 | buttonType?: 'primary' | 'ghost'; 11 | onButtonClick?: (e: any) => void; 12 | } 13 | -------------------------------------------------------------------------------- /components/result/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Combination 4 | title: Result 5 | subtitle: 结果页 6 | --- 7 | 8 | 在整张页面中组织插画、图标、文字等内容,向用户反馈操作结果。 9 | 10 | ### 规则 11 | 12 | - 用作非常重要的操作反馈,如支付成功,无网络状态。 13 | - 个性化且优美的插画,可以提升品牌形象。 14 | - 对于错误类型的结果页,页面中需要提供明确的行动点,eg:重新加载。 15 | 16 | ## API 17 | 18 | 属性 | 说明 | 类型 | 默认值 19 | ----|-----|------|------ 20 | imgUrl | 插图 url | string / Image Source(rn) | - 21 | img | 插图元素 (可以为``/``等), 会覆盖 imgUrl 设置 | ReactNode | - 22 | title | title 文案 | ReactNode | - 23 | message | message 文案 | ReactNode | - 24 | buttonText | 按钮文案 | string | - 25 | buttonType | 请参考 button 的配置 | string | - 26 | onButtonClick | 按钮回调函数 | (e: Object): void | - 27 | -------------------------------------------------------------------------------- /components/result/style/index.tsx: -------------------------------------------------------------------------------- 1 | import { ImageStyle, StyleSheet, TextStyle, ViewStyle } from 'react-native'; 2 | import { Theme } from '../../style'; 3 | 4 | export interface ResultStyle { 5 | result: ViewStyle; 6 | imgWrap: ViewStyle; 7 | img: ImageStyle; 8 | title: ViewStyle; 9 | titleText: TextStyle; 10 | message: ViewStyle; 11 | messageText: TextStyle; 12 | buttonWrap: ViewStyle; 13 | button: ViewStyle; 14 | } 15 | 16 | export default (theme: Theme) => 17 | StyleSheet.create({ 18 | result: { 19 | alignItems: 'center', 20 | paddingVertical: theme.v_spacing_xl, 21 | backgroundColor: theme.fill_base, 22 | borderBottomColor: theme.border_color_base, 23 | }, 24 | imgWrap: { 25 | margin: 0, 26 | }, 27 | img: { 28 | width: 60, 29 | height: 60, 30 | }, 31 | title: { 32 | marginTop: theme.v_spacing_lg, 33 | paddingHorizontal: theme.h_spacing_lg, 34 | }, 35 | titleText: { 36 | fontSize: 21, 37 | color: theme.color_text_base, 38 | }, 39 | message: { 40 | marginTop: theme.v_spacing_lg, 41 | paddingHorizontal: theme.h_spacing_lg, 42 | }, 43 | messageText: { 44 | fontSize: theme.font_size_caption, 45 | color: theme.color_text_caption, 46 | }, 47 | buttonWrap: { 48 | flexDirection: 'row', 49 | marginTop: theme.v_spacing_lg, 50 | paddingHorizontal: theme.h_spacing_lg, 51 | }, 52 | button: { 53 | flex: 1, 54 | }, 55 | }); 56 | -------------------------------------------------------------------------------- /components/search-bar/PropsType.tsx: -------------------------------------------------------------------------------- 1 | function noop() {} 2 | 3 | export interface SearchBarPropsType { 4 | defaultValue?: string; 5 | value?: string; 6 | placeholder?: string; 7 | onSubmit?: (value: string) => void; 8 | onChange?: (value: string) => void; 9 | onFocus?: () => void; 10 | onBlur?: () => void; 11 | onCancel?: (value: string) => void; 12 | showCancelButton?: boolean; 13 | cancelText?: string; 14 | disabled?: boolean; 15 | autoFocus?: boolean; 16 | focused?: boolean; 17 | onClear?: (value: string) => void; 18 | maxLength?: number; 19 | } 20 | 21 | export interface SearchBarState { 22 | value?: string; 23 | focus?: boolean; 24 | focused?: boolean; 25 | } 26 | 27 | export const defaultProps = { 28 | placeholder: '', 29 | onSubmit: noop, 30 | onChange: noop, 31 | onFocus: noop, 32 | onBlur: noop, 33 | onClear: noop, 34 | showCancelButton: false, 35 | disabled: false, 36 | }; 37 | -------------------------------------------------------------------------------- /components/search-bar/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Data Entry 4 | title: SearchBar 5 | subtitle: 搜索栏 6 | --- 7 | 8 | 一般可位于 NavBar 下方,通过『取消按钮』退出激活状态。 9 | 10 | ### 规则 11 | 12 | - 应该在 placeholder 里提供提示文字,提醒用户输入相关内容,比如:双11特卖。 13 | - 在搜索栏下方,可提供有用的标签文案,帮助用户通过点击直接完成输入,比如:列出一些最近搜索的关键词。 14 | 15 | ## API 16 | 17 | 属性 | 说明 | 类型 | 默认值 18 | ----|-----|------|------ 19 | | defaultValue | 搜索框的默认值 | String | | 20 | | value | 搜索框的当前值 | String | | 21 | | placeholder | placeholder | String | | 22 | | onSubmit | submit 事件 (点击键盘的 enter) | (val: string): void | | 23 | | onChange | change 事件的回调 | (val: string): void | | 24 | | onFocus | focus 事件的回调 | (): void | | 25 | | onBlur | blur 事件的回调 | (): void | | 26 | | onCancel | 点击`取消`按钮触发 (不再自动清除输入框的文字) | (val: string): void | | 27 | | showCancelButton | 是否一直显示`取消`按钮 | bool | `false` | 28 | | cancelText | 定制`取消`按钮的文字 | String | `取消` | 29 | | disabled | 设置禁用 | bool | `false` | 30 | 31 | 注:RN 版本更多 API 请参考 [http://facebook.github.io/react-native/docs/textinput.html](http://facebook.github.io/react-native/docs/textinput.html) 32 | -------------------------------------------------------------------------------- /components/search-bar/locale/en_US.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | cancelText: 'Cancel', 3 | }; 4 | -------------------------------------------------------------------------------- /components/search-bar/locale/es_ES.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | cancelText: 'Cancelar', 3 | }; 4 | -------------------------------------------------------------------------------- /components/search-bar/locale/ru_RU.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | cancelText: 'Отмена', 3 | }; 4 | -------------------------------------------------------------------------------- /components/search-bar/locale/sv_SE.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | cancelText: 'Avbryt', 3 | }; 4 | -------------------------------------------------------------------------------- /components/search-bar/locale/zh_CN.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | cancelText: '取消', 3 | }; 4 | -------------------------------------------------------------------------------- /components/search-bar/style/index.tsx: -------------------------------------------------------------------------------- 1 | import { StyleSheet, TextStyle, ViewStyle } from 'react-native'; 2 | import { Theme } from '../../style'; 3 | 4 | export interface SearchBarStyle { 5 | input: TextStyle; 6 | inputWrapper: ViewStyle; 7 | wrapper: ViewStyle; 8 | cancelTextContainer: ViewStyle; 9 | cancelText: TextStyle; 10 | search: TextStyle; 11 | } 12 | 13 | export default (theme: Theme) => 14 | StyleSheet.create({ 15 | inputWrapper: { 16 | flex: 1, 17 | flexDirection: 'row', 18 | }, 19 | input: { 20 | borderRadius: theme.radius_md, 21 | backgroundColor: '#fff', 22 | borderColor: theme.border_color_base, 23 | borderWidth: theme.border_width_sm, 24 | height: theme.search_bar_input_height, 25 | color: theme.color_text_base, 26 | fontSize: theme.font_size_base, 27 | paddingLeft: 28 | theme.h_spacing_lg + 29 | theme.icon_size_xxs + 30 | theme.h_spacing_sm, 31 | paddingRight: 32 | theme.h_spacing_lg + 33 | theme.icon_size_xxs + 34 | theme.h_spacing_sm, 35 | flex: 1, 36 | paddingTop: 0, 37 | paddingBottom: 0, 38 | }, 39 | wrapper: { 40 | backgroundColor: theme.search_bar_fill, 41 | height: theme.search_bar_height, 42 | paddingLeft: theme.h_spacing_md, 43 | paddingRight: theme.h_spacing_md, 44 | flexDirection: 'row', 45 | alignItems: 'center', 46 | }, 47 | cancelTextContainer: { 48 | height: theme.search_bar_input_height, 49 | justifyContent: 'center', 50 | alignItems: 'center', 51 | }, 52 | cancelText: { 53 | fontSize: theme.link_button_font_size, 54 | color: theme.color_link, 55 | paddingLeft: theme.h_spacing_lg, 56 | }, 57 | search: { 58 | color: theme.input_color_icon, 59 | position: 'absolute', 60 | left: theme.h_spacing_md + 8, 61 | top: (theme.search_bar_height - theme.icon_size_xxs) / 2, 62 | fontSize: theme.icon_size_xxs, 63 | }, 64 | }); 65 | -------------------------------------------------------------------------------- /components/segmented-control/PropsType.tsx: -------------------------------------------------------------------------------- 1 | export interface SegmentedControlPropsType { 2 | tintColor?: string; 3 | disabled?: boolean; 4 | selectedIndex?: number; 5 | values?: string[]; 6 | onChange?: (e: any) => void; 7 | onValueChange?: (value: string) => void; 8 | } 9 | -------------------------------------------------------------------------------- /components/segmented-control/index.tsx: -------------------------------------------------------------------------------- 1 | import { Platform } from 'react-native'; 2 | import SegmentedAndroid from './segmented.android'; 3 | import SegmentedIOS from './segmented.ios'; 4 | 5 | export default (Platform.OS === 'ios' ? SegmentedIOS : SegmentedAndroid); 6 | -------------------------------------------------------------------------------- /components/segmented-control/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Navigation 4 | title: SegmentedControl 5 | subtitle: 分段器 6 | --- 7 | 8 | 9 | 由至少 2 个分段控件组成,用作不同视图的显示;是 iOS 的推荐组件。 10 | 11 | ### 规则 12 | - 和 Tabs 功能相似,尽可能避免一个页面中同时出现这两个组件。 13 | - 可以搭配 NavBar 一起使用,用于显示多个视图,分段数一般为 2 个。 14 | - 单独放置一行时,分段数最多为 5 个;文案需要精简,一般 2-4 个字。 15 | - 尽可能保持文案长度一致。 16 | 17 | ## API 18 | 19 | 属性 | 说明 | 类型 | 默认值 20 | ----|-----|------|------ 21 | | style | 自定义样式 | Object | `{}` | 22 | | tintColor | 组件主色调 | String | `#2DB7F5` | 23 | | disabled | 是否启用 | Boolean | false | 24 | | selectedIndex | 选中项在数组中的索引 | Number | 0 | 25 | | values | 选项数组,值是字符串 | array | [] | 26 | | onChange | 回调函数, 其中`e.nativeEvent.selectedSegmentIndex`是选中项索引, `e.nativeEvent.value`是选中的值. | (e): void | function(){} | 27 | | onValueChange | 回调函数 | (val): void | function(){} | 28 | -------------------------------------------------------------------------------- /components/segmented-control/segmented.ios.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { SegmentedControlIOS, StyleProp, ViewStyle } from 'react-native'; 3 | import { SegmentedControlPropsType } from './PropsType'; 4 | import { WithTheme } from '../style'; 5 | 6 | export interface SegmentedControlProps extends SegmentedControlPropsType { 7 | style?: StyleProp; 8 | } 9 | 10 | export default class SegmentedControl extends React.Component< 11 | SegmentedControlProps, 12 | any 13 | > { 14 | static defaultProps = { 15 | selectedIndex: 0, 16 | }; 17 | 18 | render() { 19 | const { tintColor, disabled, selectedIndex, ...restProps } = this.props; 20 | return ( 21 | 22 | {(_, theme) => ( 23 | 29 | )} 30 | 31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /components/segmented-control/style/index.tsx: -------------------------------------------------------------------------------- 1 | import { StyleSheet, TextStyle, ViewStyle } from 'react-native'; 2 | import { Theme } from '../../style'; 3 | 4 | export interface SegmentControlStyle { 5 | segment: ViewStyle; 6 | item: ViewStyle; 7 | itemLeftRadius: ViewStyle; 8 | itemRightRadius: ViewStyle; 9 | itemText: TextStyle; 10 | } 11 | export default (theme: Theme) => 12 | StyleSheet.create({ 13 | segment: { 14 | flexDirection: 'row', 15 | overflow: 'hidden', 16 | borderWidth: StyleSheet.hairlineWidth, 17 | borderColor: theme.brand_primary, 18 | borderRadius: theme.radius_md, 19 | }, 20 | item: { 21 | flex: 1, 22 | paddingVertical: theme.h_spacing_sm, 23 | borderLeftWidth: StyleSheet.hairlineWidth, 24 | borderRightWidth: StyleSheet.hairlineWidth, 25 | borderStyle: 'solid', 26 | alignItems: 'center', 27 | justifyContent: 'center', 28 | }, 29 | itemLeftRadius: { 30 | borderTopLeftRadius: theme.radius_md, 31 | borderBottomLeftRadius: theme.radius_md, 32 | }, 33 | itemRightRadius: { 34 | borderTopRightRadius: theme.radius_md, 35 | borderBottomRightRadius: theme.radius_md, 36 | }, 37 | itemText: { 38 | textAlign: 'center', 39 | fontSize: theme.font_size_caption_sm, 40 | }, 41 | }); 42 | -------------------------------------------------------------------------------- /components/slider/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Slider, View } from 'react-native'; 3 | import { WithTheme } from '../style'; 4 | 5 | export interface SliderProps { 6 | maximumTrackTintColor?: string; 7 | minimumTrackTintColor?: string; 8 | onChange?: (value?: number) => void; 9 | onAfterChange?: (value?: number) => void; 10 | defaultValue?: number; 11 | tipFormatter?: (value?: string) => React.ReactNode; 12 | value?: number; 13 | min?: number; 14 | max?: number; 15 | step?: number; 16 | disabled?: boolean; 17 | } 18 | 19 | export default class SliderAntm extends React.Component { 20 | static defaultProps = { 21 | onChange() {}, 22 | onAfterChange() {}, 23 | defaultValue: 0, 24 | disabled: false, 25 | }; 26 | 27 | render() { 28 | const { 29 | defaultValue, 30 | value, 31 | min, 32 | max, 33 | step, 34 | disabled, 35 | onChange, 36 | onAfterChange, 37 | maximumTrackTintColor, 38 | minimumTrackTintColor, 39 | } = this.props; 40 | return ( 41 | 42 | {(_, theme) => ( 43 | 44 | 59 | 60 | )} 61 | 62 | ); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /components/slider/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Data Entry 4 | title: Slider 5 | subtitle: 滑动输入条 6 | --- 7 | 8 | 允许用户在一个区间中选择特定值,eg:控制屏幕的显示亮度。 9 | 10 | ### 规则 11 | - 默认状态下,左边为最小值,右边为最大值。 12 | - 一般水平放置。 13 | 14 | ## API 15 | 16 | 属性 | 说明 | 类型 | 默认值 17 | ----|-----|------|------ 18 | | min | Number | 0 | 最小值 | 19 | | max | Number | 100 | 最大值 | 20 | | step | Number or null | 1 | 步长,取值必须大于 0,并且可被 (max - min) 整除。当 `marks` 不为空对象时,可以设置 `step` 为 `null`,此时 Slider 的可选值仅有 marks 标出来的部分 | 21 | | value | Number | | 设置当前取值。 | 22 | | defaultValue | Number | 0 | 设置初始取值。| 23 | | disabled | Boolean | false | 值为 `true` 时,滑块为禁用状态 | 24 | | onChange | Function | Noop | 当 Slider 的值发生改变时,会触发 onChange 事件,并把改变后的值作为参数传入 | 25 | | maximumTrackTintColor(`iOS`) | String | `#108ee9`(RN) | 底部背景色 | 26 | | minimumTrackTintColor(`iOS`) | String | `#ddd` (RN) | 当前选中部分的颜色 | 27 | | onAfterChange | Function | Noop | 与 `ontouchend` 触发时机一致,把当前值作为参数传入 | 28 | -------------------------------------------------------------------------------- /components/stepper/PropsType.tsx: -------------------------------------------------------------------------------- 1 | import { StyleProp, TextStyle, ViewStyle } from "react-native"; 2 | 3 | export interface StepPropsType { 4 | min?: number; 5 | max?: number; 6 | step?: number | string; 7 | readOnly?: boolean; 8 | disabled?: boolean; 9 | autoFocus?: boolean; 10 | value?: number; 11 | defaultValue?: number; 12 | onChange?: (value: any) => void; 13 | upStyle?: StyleProp; 14 | downStyle?: StyleProp; 15 | inputStyle?: StyleProp; 16 | name?: string; 17 | } 18 | -------------------------------------------------------------------------------- /components/stepper/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Platform, StyleProp, ViewStyle } from 'react-native'; 3 | import { WithTheme, WithThemeStyles } from '../style'; 4 | import InputNumber from './InputNumber'; 5 | import { StepPropsType } from './PropsType'; 6 | import StepperStyles, { StepperStyle } from './style'; 7 | 8 | export interface StepProps 9 | extends StepPropsType, 10 | WithThemeStyles { 11 | style?: StyleProp; 12 | } 13 | 14 | export default class Stepper extends React.Component { 15 | static defaultProps: StepProps = { 16 | step: 1, 17 | readOnly: false, 18 | disabled: false, 19 | inputStyle: {}, 20 | }; 21 | 22 | render() { 23 | const inputAndroidStyle = 24 | Platform.OS === 'android' 25 | ? { 26 | top: 6, 27 | paddingTop: 0, 28 | height: 26, 29 | } 30 | : {}; 31 | const { inputStyle, ...restProps } = this.props; 32 | const keyboardType = 33 | Platform.OS === 'android' ? 'numeric' : 'numbers-and-punctuation'; 34 | 35 | return ( 36 | 37 | {styles => ( 38 | 44 | )} 45 | 46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /components/stepper/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Data Entry 4 | title: Stepper 5 | subtitle: 步进器 6 | --- 7 | 8 | 用作增加或者减少当前数值。 9 | 10 | ### 规则 11 | - 当想要对数值进行小幅度调整时,可以使用 Stepper,eg:将年化收益从 4.00% 调整到 4.05%。 12 | 13 | ## API 14 | 15 | 属性 | 说明 | 类型 | 默认值 16 | ----|-----|------|------ 17 | | min | 最小值 | Number | -Infinity | 18 | | max | 最大值 | Number | Infinity | 19 | | value | 当前值 | Number | | 20 | | step | 每次改变步数,可以为小数 | Number or String | 1 | 21 | | defaultValue | 初始值 | Number | | 22 | | onChange | 变化时回调函数 | (): void | | 23 | | disabled | 禁用 | Boolean | false | 24 | | readOnly | input 只读 | Boolean | false | 25 | | styles | react native 组件样式 | ReactNative StyleSheet | - | 26 | | inputStyle | react native 显示数字样式 | ReactNative StyleSheet | - | 27 | -------------------------------------------------------------------------------- /components/stepper/style/index.tsx: -------------------------------------------------------------------------------- 1 | import { StyleSheet, TextStyle, ViewStyle } from 'react-native'; 2 | import { Theme } from '../../style'; 3 | export interface StepperStyle { 4 | container: ViewStyle; 5 | input: TextStyle; 6 | stepWrap: ViewStyle; 7 | stepText: TextStyle; 8 | stepDisabled: ViewStyle; 9 | disabledStepTextColor: TextStyle; 10 | highlightStepTextColor: TextStyle; 11 | highlightStepBorderColor: ViewStyle; 12 | } 13 | export default (theme: Theme) => 14 | StyleSheet.create({ 15 | container: { 16 | flex: 1, 17 | flexDirection: 'row', 18 | alignItems: 'center', 19 | justifyContent: 'center', 20 | }, 21 | input: { 22 | flex: 1, 23 | textAlign: 'center', 24 | paddingHorizontal: 8, 25 | fontSize: theme.input_font_size, 26 | color: theme.color_text_base, 27 | }, 28 | stepWrap: { 29 | width: 28, 30 | height: 28, 31 | borderWidth: theme.border_width_md, 32 | borderColor: theme.border_color_base, 33 | borderRadius: theme.radius_md, 34 | backgroundColor: theme.fill_base, 35 | }, 36 | stepText: { 37 | textAlign: 'center', 38 | fontSize: 20, 39 | color: theme.color_text_placeholder, 40 | backgroundColor: 'transparent', 41 | }, 42 | stepDisabled: { 43 | borderColor: theme.color_text_disabled, 44 | backgroundColor: theme.fill_disabled, 45 | }, 46 | disabledStepTextColor: { 47 | color: theme.color_text_disabled, 48 | }, 49 | highlightStepTextColor: { 50 | color: theme.brand_primary, 51 | }, 52 | highlightStepBorderColor: { 53 | borderColor: theme.brand_primary, 54 | }, 55 | }); 56 | -------------------------------------------------------------------------------- /components/steps/index.tsx: -------------------------------------------------------------------------------- 1 | 2 | import React from 'react'; 3 | import { LayoutChangeEvent, View } from 'react-native'; 4 | import { WithTheme, WithThemeStyles } from '../style'; 5 | import StepsItem from './StepsItem'; 6 | import StepsStyles, { StepsStyle } from './style/index'; 7 | 8 | export interface StepsProps extends WithThemeStyles { 9 | direction?: 'vertical' | 'horizontal'; 10 | size?: string; 11 | finishIcon?: string; 12 | children: React.ReactElement[]; 13 | current?: number; 14 | } 15 | 16 | export default class Steps extends React.Component { 17 | static Step: typeof StepsItem; 18 | 19 | static defaultProps = { 20 | direction: '', 21 | }; 22 | 23 | constructor(props: StepsProps) { 24 | super(props); 25 | this.state = { 26 | wrapWidth: 0, 27 | }; 28 | } 29 | 30 | onLayout = (e: LayoutChangeEvent) => { 31 | this.setState({ 32 | wrapWidth: e.nativeEvent.layout.width, 33 | }); 34 | }; 35 | 36 | render() { 37 | const children = this.props.children; 38 | const direction = this.props.direction === 'horizontal' ? 'row' : 'column'; 39 | return ( 40 | 41 | {styles => ( 42 | { 45 | this.onLayout(e); 46 | }} 47 | > 48 | {React.Children.map(children, (ele, idx) => { 49 | let errorTail = -1; 50 | if (idx < children.length - 1) { 51 | const status = children[idx + 1].props.status; 52 | if (status === 'error') { 53 | errorTail = idx; 54 | } 55 | } 56 | return React.cloneElement(ele as any, { 57 | index: idx, 58 | last: idx === (children as any[]).length - 1, 59 | direction: this.props.direction, 60 | current: this.props.current, 61 | width: 62 | (1 / ((children as any[]).length - 1)) * this.state.wrapWidth, 63 | size: this.props.size, 64 | finishIcon: this.props.finishIcon, 65 | errorTail, 66 | styles, 67 | }); 68 | })} 69 | 70 | )} 71 | 72 | ); 73 | } 74 | } 75 | 76 | Steps.Step = StepsItem; 77 | -------------------------------------------------------------------------------- /components/style/index.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-mixed-operators,no-undef,space-infix-ops */ 2 | import deepmerge from 'deepmerge'; 3 | import React, { useContext } from 'react'; 4 | import defaultTheme from './themes/default'; 5 | 6 | export const ThemeContext = React.createContext(defaultTheme); 7 | export type Theme = typeof defaultTheme & { [key: string]: any }; 8 | export type PartialTheme = Partial; 9 | export interface ThemeProviderProps { 10 | value?: PartialTheme; 11 | children?: React.ReactNode; 12 | } 13 | export const ThemeProvider = (props: ThemeProviderProps) => { 14 | const theme = { ...defaultTheme, ...props.value }; 15 | return ( 16 | 17 | {props.children} 18 | 19 | ); 20 | }; 21 | export interface UseThemeContextProps { 22 | theme?: PartialTheme; 23 | } 24 | export const useTheme = (props: UseThemeContextProps = {}) => { 25 | const theme = useContext(ThemeContext); 26 | return { ...theme, ...props.theme }; 27 | }; 28 | 29 | export interface WithThemeProps { 30 | themeStyles: (theme: Theme) => T; 31 | styles?: S; 32 | children: ( 33 | // fix: styles[`${size}RawText`] 34 | styles: T & { [key: string]: any }, 35 | theme: Theme, 36 | ) => React.ReactNode; 37 | } 38 | 39 | /** 40 | * Component can extends this props 41 | */ 42 | export type WithThemeStyles = { styles?: Partial }; 43 | export class WithTheme extends React.Component> { 44 | static defaultProps = { 45 | themeStyles: () => {}, 46 | }; 47 | getStyles = (theme: Theme) => { 48 | const { themeStyles, styles } = this.props; 49 | const defaultThemeStyles = themeStyles(theme); 50 | if (styles) { 51 | // TODO: check these styles has changed 52 | // merge styles from user defined 53 | return deepmerge (defaultThemeStyles, styles); 54 | } 55 | return defaultThemeStyles; 56 | }; 57 | render() { 58 | return ( 59 | 60 | {theme => this.props.children(this.getStyles(theme), theme)} 61 | 62 | ); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /components/swipe-action/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Gesture 4 | title: SwipeAction 5 | subtitle: 滑动操作 6 | --- 7 | 8 | 滑动操作组件。 9 | 10 | ### 定义 11 | 结合手势操作,从屏幕一侧唤出操作。 12 | 13 | ### 规则 14 | 1. 一次只可滑动一行列表 15 | 2. 点击任意按钮之外处或往回滑动该列表可隐藏操作。 16 | 17 | ## API 18 | 19 | ### SwipeAction 20 | 21 | 属性 | 说明 | 类型 | 默认值 22 | ----|-----|------|------ 23 | | style | `swipeout` 样式 | Object | | 24 | | left | 左侧按钮组 | Array | `null` | 25 | | right | 右侧按钮组 | Array | `null` | 26 | | autoClose | 点击按钮后自动隐藏按钮 | Boolean | `function() {}` | 27 | | onOpen | 打开时回调函数 | (): void | `function() {}` | 28 | | disabled | 禁用 `swipeout` | Boolean | `false` | 29 | | onClose | 关闭时回调函数 | (): void | `function() {}` | 30 | 31 | ### Button 32 | 33 | | 参数 | 说明 | 类型 | 默认值 | 34 | |------|------------------|-------------------------|--------| 35 | | text | 按钮文案 | String | `Click` | 36 | | style | 按钮样式 | Object | `` | 37 | | onPress | 按钮点击事件 | (): void | `function() {}` | 38 | -------------------------------------------------------------------------------- /components/switch/PropsType.tsx: -------------------------------------------------------------------------------- 1 | export interface SwitchPropsType { 2 | checked?: boolean; 3 | disabled?: boolean; 4 | onChange?: (checked: boolean) => void; 5 | color?: string; 6 | name?: string; 7 | onPress?: (checked?: boolean) => void; 8 | } 9 | -------------------------------------------------------------------------------- /components/switch/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { StyleProp, Switch, ViewStyle } from 'react-native'; 3 | import { SwitchPropsType } from './PropsType'; 4 | export interface AntmSwitchProps extends SwitchPropsType { 5 | style?: StyleProp; 6 | } 7 | const AntmSwitch = (props: AntmSwitchProps) => { 8 | const { 9 | style, 10 | onChange, 11 | checked = false, 12 | disabled = false, 13 | color = '#4dd865', 14 | } = props; 15 | return ( 16 | 23 | ); 24 | }; 25 | 26 | export default AntmSwitch; 27 | -------------------------------------------------------------------------------- /components/switch/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Data Entry 4 | title: Switch 5 | subtitle: 滑动开关 6 | --- 7 | 8 | 在两个互斥对象进行选择,eg:选择开或关。 9 | 10 | ### 规则 11 | - 只在 List 中使用。 12 | - 避免增加额外的文案来描述当前 Switch 的值。 13 | 14 | ## API 15 | 16 | 属性 | 说明 | 类型 | 默认值 17 | ----|-----|------|------ 18 | | checked | 是否默认选中 | Boolean | false | 19 | | disabled | 是否不可修改 | Boolean | false | 20 | | onChange | change 事件触发的回调函数 | (checked: bool): void | 无 | 21 | | color | 开关打开后的颜色 | String | #4dd865 | 22 | | onPress | click事件触发的回调函数,当switch为disabled时,入参的值始终是默认传入的checked值。 | (checked: bool): void | 无 | 23 | -------------------------------------------------------------------------------- /components/tab-bar/PropsType.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { ImageRequireSource, ImageURISource } from 'react-native'; 3 | 4 | export interface TabBarProps { 5 | barTintColor?: string; 6 | tintColor?: string; 7 | unselectedTintColor?: string; 8 | animated?: boolean; 9 | swipeable?: boolean; 10 | } 11 | export type TabBarIcon = 12 | | ImageURISource 13 | | ImageURISource[] 14 | | ImageRequireSource 15 | | React.ReactNode; 16 | export interface TabBarItemProps { 17 | badge?: string | number; 18 | onPress?: () => void; 19 | selected?: boolean; 20 | icon?: TabBarIcon; 21 | selectedIcon?: TabBarIcon; 22 | title: string; 23 | } 24 | -------------------------------------------------------------------------------- /components/tab-bar/TabBarItem.tsx: -------------------------------------------------------------------------------- 1 | import React, { isValidElement } from 'react'; 2 | import { Image, ImageStyle, StyleProp, Text, TouchableWithoutFeedback, View } from 'react-native'; 3 | import Icon, { IconProps } from '../icon'; 4 | import { TabBarIcon } from './PropsType'; 5 | import TabBarItemStyles from './style'; 6 | 7 | export interface TabBarItemProps { 8 | badge?: string | number; 9 | onPress?: () => void; 10 | selected?: boolean; 11 | icon?: TabBarIcon; 12 | selectedIcon?: TabBarIcon; 13 | title: string; 14 | tintColor?: string; 15 | unselectedTintColor?: string; 16 | iconStyle?: StyleProp; 17 | renderAsOriginal?: boolean; 18 | styles?: ReturnType; 19 | } 20 | export default class TabBarItem extends React.Component { 21 | static defaultProps = { 22 | onPress() {}, 23 | }; 24 | render() { 25 | const { 26 | title, 27 | selected, 28 | tintColor, 29 | unselectedTintColor, 30 | icon, 31 | selectedIcon, 32 | onPress, 33 | badge, 34 | iconStyle, 35 | } = this.props; 36 | const styles = this.props.styles!; 37 | const itemSelectedStyle = selected ? styles.barItemSelected : null; 38 | const badgeDom = badge ? ( 39 | 40 | {badge} 41 | 42 | ) : null; 43 | // icon 44 | const source = 45 | selected && selectedIcon !== undefined 46 | ? selectedIcon 47 | : icon !== undefined 48 | ? icon 49 | : null; 50 | const color = selected ? tintColor : unselectedTintColor; 51 | const isIcon = 52 | source && 53 | (source as any).type && 54 | (source as any).type.displayName === 'Icon'; 55 | return ( 56 | 57 | 58 | 59 | {source === null ? null : isValidElement(source) ? ( 60 | isIcon ? ( 61 | 62 | ) : ( 63 | source 64 | ) 65 | ) : ( 66 | 67 | )} 68 | {badgeDom} 69 | 70 | {title} 71 | 72 | 73 | ); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /components/tab-bar/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Navigation 4 | title: TabBar 5 | subtitle: 标签栏 6 | --- 7 | 8 | 位于 APP 底部,方便用户在不同功能模块之间进行快速切换。 9 | 10 | ### 规则 11 | - 用作 APP 的一级分类,数量控制在 3-5 个之间。 12 | - 即使某个 Tab 不可用,也不要禁用或者移除该 Tab。 13 | - 使用 Badge 进行提示,足不出户也能知道有内容更新。 14 | 15 | ## API 16 | 17 | ### TabBar 18 | 19 | | 属性 | 说明 | 类型 | 默认值 | 20 | | ------------------- | ---------------- | ------ | --------- | 21 | | barTintColor | tabbar 背景色 | String | `white` | 22 | | tintColor | 选中的字体颜色 | String | `#108ee9` | 23 | | unselectedTintColor | 未选中的字体颜色 | String | '#888' | 24 | 25 | ### TabBar.Item 26 | 27 | | 属性 | 说明 | 类型 | 默认值 | 28 | | ------------ | ----------------------------------------------------- | -------------------------------- | ------------------------- | 29 | | badge | 徽标数 | Number \ String | 无 | 30 | | onPress | bar 点击触发,需要自己改变组件 state & selecte={true} | Function | `(){}` | 31 | | selected | 是否选中 | Boolean | false | 32 | | icon | 默认展示图片 | `Image Source | React.ReactNode` | | 33 | | selectedIcon | 选中后的展示图片 | `Image Source | React.ReactNode` | | 34 | | title | 标题文字 | String | | 35 | | key | 唯一标识 | String | 无 | 36 | | iconStyle | icon 样式 | String | { width: 28, height: 28 } | 37 | -------------------------------------------------------------------------------- /components/tab-bar/style/index.tsx: -------------------------------------------------------------------------------- 1 | import { ImageStyle, StyleSheet, TextStyle, ViewStyle } from 'react-native'; 2 | import { Theme } from '../../style'; 3 | 4 | export interface TabBarStyle { 5 | tabbar: ViewStyle; 6 | content: ViewStyle; 7 | tabs: ViewStyle; 8 | barItem: ViewStyle; 9 | barIcon: ImageStyle; 10 | barItemSelected: ViewStyle; 11 | barItemTitle: TextStyle; 12 | contentItem: ViewStyle; 13 | contentItemSelected: ViewStyle; 14 | badge: ViewStyle; 15 | badgeText: TextStyle; 16 | } 17 | 18 | export default (theme: Theme) => 19 | StyleSheet.create({ 20 | tabbar: { 21 | flex: 1, 22 | }, 23 | content: { 24 | flex: 1, 25 | }, 26 | tabs: { 27 | height: theme.tab_bar_height, 28 | borderTopWidth: theme.border_width_md, 29 | borderColor: theme.border_color_base, 30 | borderStyle: 'solid', 31 | flexDirection: 'row', 32 | }, 33 | barItem: { 34 | flex: 1, 35 | alignItems: 'center', 36 | justifyContent: 'center', 37 | }, 38 | barIcon: { 39 | width: 28, 40 | height: 28, 41 | marginTop: 2, 42 | }, 43 | barItemSelected: {}, 44 | barItemTitle: { 45 | fontSize: theme.font_size_icontext, 46 | marginTop: 2, 47 | }, 48 | contentItem: { 49 | position: 'absolute', 50 | top: 0, 51 | left: 0, 52 | right: 0, 53 | bottom: 0, 54 | backgroundColor: 'white', 55 | height: 0, 56 | }, 57 | contentItemSelected: { 58 | height: undefined, 59 | }, 60 | badge: { 61 | minWidth: 20, 62 | height: 20, 63 | borderRadius: 10, 64 | backgroundColor: theme.brand_important, 65 | position: 'absolute', 66 | top: 0, 67 | left: 20, 68 | paddingHorizontal: theme.h_spacing_sm, 69 | }, 70 | badgeText: { 71 | textAlign: 'center', 72 | color: 'white', 73 | }, 74 | }); 75 | -------------------------------------------------------------------------------- /components/tabs/index.tsx: -------------------------------------------------------------------------------- 1 | import { Tabs } from './Tabs'; 2 | 3 | export default Tabs 4 | -------------------------------------------------------------------------------- /components/tabs/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Navigation 4 | title: Tabs 5 | subtitle: 标签页 6 | --- 7 | 8 | 用于让用户在不同的视图中进行切换。 9 | 10 | ### 规则 11 | - 标签数量,一般 2-4 个;其中,标签中的文案需要精简,一般 2-4 个字。 12 | - 在 iOS 端的次级页面中,不建议使用左右滑动来切换 Tab,这个和 iOS 的左滑返回存在冲突,eg:详情页中 Tabs。 13 | 14 | ## API 15 | 16 | ### Tabs 17 | 18 | 属性 | 说明 | 类型 | 默认值 | 必选 19 | ----|-----|------|------|------ 20 | tabs | tab数据 | Models.TabData[] | | true 21 | tabBarPosition | TabBar位置 | 'top' \| 'bottom' | top | false 22 | renderTabBar | 替换TabBar | ((props: TabBarPropsType) => React.ReactNode) \| false | | false 23 | initialPage | 初始化Tab, index or key | number \| string | | false 24 | page | 当前Tab, index or key | number \| string | | false 25 | swipeable | 是否可以滑动内容切换 | boolean | true | false 26 | useOnPan | 使用跟手滚动 | boolean | true | false 27 | prerenderingSiblingsNumber | 预加载两侧Tab数量 | number | 1 | false 28 | animated | 是否开启切换动画 | boolean | true | false 29 | onChange | tab变化时触发 | (tab: Models.TabData, index: number) => void | | false 30 | onTabClick | tab 被点击的回调 | (tab: Models.TabData, index: number) => void | | false 31 | destroyInactiveTab | 销毁超出范围Tab | boolean | false | false 32 | distanceToChangeTab | 滑动切换阈值(宽度比例) | number | 0.3 | false 33 | usePaged | 是否启用分页模式 | boolean | true | false 34 | tabBarUnderlineStyle | tabBar下划线样式 | React.CSSProperties \| any | | false 35 | tabBarBackgroundColor | tabBar背景色 | string | | false 36 | tabBarActiveTextColor | tabBar激活Tab文字颜色 | string | | false 37 | tabBarInactiveTextColor | tabBar非激活Tab文字颜色 | string | | false 38 | tabBarTextStyle | tabBar文字样式 | React.CSSProperties \| any | | false 39 | renderTab | 替换TabBar的Tab | (tab: Models.TabData) => React.ReactNode | | false 40 | renderUnderline | renderUnderline | (style: any) => React.ReactNode | | false 41 | 42 | ### Tabs.DefaultTabBar 43 | 44 | 属性 | 说明 | 类型 | 默认值 | 必选 45 | ----|-----|------|------|------ 46 | goToTab | 跳转Tab | (index: number) => boolean | | true 47 | tabs|tab数据 | Models.TabData[] | | true 48 | activeTab | 当前激活Tab索引 | number | | true 49 | animated | 是否使用动画 | boolean | | true 50 | renderTab | 替换TabBar的Tab | (tab: Models.TabData) => React.ReactNode | | false 51 | page | Tab分页尺寸 | number | 5 | false 52 | onTabClick | tab 被点击的回调 | (tab: Models.TabData, index: number) => void | | false 53 | -------------------------------------------------------------------------------- /components/tabs/style/index.tsx: -------------------------------------------------------------------------------- 1 | import { StyleSheet, TextStyle, ViewStyle } from 'react-native'; 2 | import { Theme } from '../../style'; 3 | export interface TabBarStyle { 4 | container: ViewStyle; 5 | tabs: ViewStyle; 6 | tab: ViewStyle; 7 | underline: ViewStyle; 8 | textStyle: TextStyle; 9 | } 10 | export default (theme: Theme) => 11 | StyleSheet.create({ 12 | container: {}, 13 | tabs: { 14 | flex: 1, 15 | flexDirection: 'row', 16 | backgroundColor: theme.fill_base, 17 | justifyContent: 'space-around', 18 | shadowRadius: 0, 19 | shadowOpacity: 0, 20 | elevation: 0, 21 | }, 22 | tab: { 23 | height: theme.tabs_height, 24 | alignItems: 'center', 25 | justifyContent: 'center', 26 | padding: 0, 27 | flexDirection: 'row', 28 | }, 29 | underline: { 30 | height: 2, 31 | backgroundColor: theme.tabs_color, 32 | }, 33 | textStyle: { 34 | fontSize: 15, 35 | }, 36 | }); 37 | -------------------------------------------------------------------------------- /components/tabs/style/tabs.tsx: -------------------------------------------------------------------------------- 1 | import { StyleSheet, ViewStyle } from 'react-native'; 2 | import { Theme } from '../../style'; 3 | export interface TabsStyle { 4 | container: ViewStyle; 5 | topTabBarSplitLine: ViewStyle; 6 | bottomTabBarSplitLine: ViewStyle; 7 | } 8 | export default (theme: Theme) => 9 | StyleSheet.create({ 10 | container: { 11 | flex: 1, 12 | }, 13 | topTabBarSplitLine: { 14 | borderBottomColor: theme.border_color_base, 15 | borderBottomWidth: 1, 16 | }, 17 | bottomTabBarSplitLine: { 18 | borderTopColor: theme.border_color_base, 19 | borderTopWidth: 1, 20 | }, 21 | }); 22 | -------------------------------------------------------------------------------- /components/tag/PropsType.tsx: -------------------------------------------------------------------------------- 1 | export interface TagPropsType { 2 | disabled?: boolean; 3 | selected?: boolean; 4 | closable?: boolean; 5 | small?: boolean; 6 | onChange?: (selected: boolean) => void; 7 | onClose?: () => void; 8 | afterClose?: () => void; 9 | onLongPress?: () => void; 10 | } 11 | -------------------------------------------------------------------------------- /components/tag/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Data Display 4 | title: Tag 5 | subtitle: 标签 6 | --- 7 | 8 | 进行标记和分类的小标签,用于标记事物的属性和维度,以及进行分类。 9 | 10 | ### 规则 11 | - 标签文字必须显示完全。 12 | 13 | ## API 14 | 15 | 属性 | 说明 | 类型 | 默认值 16 | ----|-----|------|------ 17 | | small | 小号标签 | Boolean | `false` | 18 | | disabled | 是否不可用 | Boolean | `false` | 19 | | closable | 是否关闭(非 disabled small 状态) | Boolean | `false` | 20 | | selected | 是否默认选中 | Boolean | `false` | 21 | | onChange | 切换选中回调函数 | (selected: bool): void | 无 | 22 | | onClose | 点关闭时的回调函数 | (): void | 无 | 23 | | afterClose | 关闭后的回调 | (): void | 无 | 24 | | onLongPress | 长按的回调 | (): void | 无 | -------------------------------------------------------------------------------- /components/text/index.tsx: -------------------------------------------------------------------------------- 1 | export { Text as default } from 'react-native'; 2 | -------------------------------------------------------------------------------- /components/textarea-item/PropsType.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | export type TextAreaEventHandle = (val?: string) => void; 3 | export interface TextAreaItemPropsType { 4 | title?: React.ReactNode; 5 | maxLength?: number; 6 | name?: string; 7 | value?: string; 8 | defaultValue?: string; 9 | placeholder?: string; 10 | clear?: boolean; 11 | rows?: number; 12 | count?: number; 13 | 14 | error?: boolean; 15 | onErrorClick?: () => void; 16 | autoHeight?: boolean; 17 | editable?: boolean; 18 | disabled?: boolean; 19 | labelNumber?: number; 20 | 21 | onChange?: TextAreaEventHandle; 22 | // onBlur?: TextAreaEventHandle; 23 | // onFocus?: TextAreaEventHandle; 24 | } 25 | -------------------------------------------------------------------------------- /components/textarea-item/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Data Entry 4 | title: TextareaItem 5 | subtitle: 多行输入 6 | --- 7 | 8 | 用于接受多行文本。 9 | 10 | ### 规则 11 | - 支持通过键盘或者剪切板输入文本。 12 | - 通过光标可以在垂直或者水平方向进行移动。 13 | 14 | ## API 15 | 16 | 属性 | 说明 | 类型 | 默认值 17 | ----|-----|------|------ 18 | | value | value 值(受控与否参考https://facebook.github.io/react/docs/forms.html) | String | 无 | 19 | | defaultValue | 设置初始默认值 | String | - | 20 | | placeholder | placeholder | String | '' | 21 | | editable | 是否可编辑 | bool | true | 22 | | disabled | 是否禁用 | bool | false | 23 | | clear | 是否带清除功能(仅`editable`为`true`,`disabled`为`false`才生效) | bool | false | 24 | | rows | 显示几行 | number | 1 | 25 | | count | 计数功能,兼具最大长度,默认为0,代表不开启计数功能 | number | - | 26 | | onChange | change 事件触发的回调函数 | (val: string): void | - | 27 | | error | 报错样式 | bool | false | 28 | | onErrorClick | 点击报错 icon 触发的回调 | (): void | 无 | 29 | | autoHeight | 高度自适应, autoHeight 和 rows 请二选一 | bool | false | 30 | | labelNumber | 定宽枚举值:`num * @input-label-width: 34px`,可用`2-7`之间的数字,一般(不能保证全部)能对应显示出相应个数的中文文字(不考虑英文字符) | number | `5` | 31 | | last | 如果是最后一项,则将移除`borderBottom`(默认拥有`borderBottom`) | bool | false | 32 | 33 | > 更多属性请参考 react-native TextInput (http://facebook.github.io/react-native/docs/textinput.html) 34 | 35 | -------------------------------------------------------------------------------- /components/textarea-item/style/index.tsx: -------------------------------------------------------------------------------- 1 | import { StyleSheet, TextStyle, ViewStyle } from 'react-native'; 2 | import { Theme } from '../../style'; 3 | 4 | export interface TextareaItemStyle { 5 | container: ViewStyle; 6 | input: TextStyle; 7 | icon: ViewStyle; 8 | errorIcon: ViewStyle; 9 | count: ViewStyle; 10 | } 11 | 12 | export default (theme: Theme) => 13 | StyleSheet.create({ 14 | container: { 15 | borderBottomWidth: theme.border_width_sm, 16 | borderBottomColor: theme.border_color_base, 17 | }, 18 | input: { 19 | paddingHorizontal: theme.h_spacing_md, 20 | backgroundColor: theme.fill_base, 21 | fontSize: theme.font_size_heading, 22 | lineHeight: Math.round(1.3 * theme.font_size_heading), 23 | textAlignVertical: 'top', 24 | }, 25 | icon: { 26 | position: 'absolute', 27 | top: 8, 28 | width: theme.icon_size_xs, 29 | height: theme.icon_size_xs, 30 | }, 31 | errorIcon: { 32 | position: 'absolute', 33 | right: 18, 34 | top: 12, 35 | }, 36 | count: { 37 | position: 'absolute', 38 | right: theme.h_spacing_md, 39 | bottom: theme.h_spacing_md, 40 | }, 41 | }); 42 | -------------------------------------------------------------------------------- /components/toast/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Portal from '../portal'; 3 | import ToastContainer from './ToastContainer'; 4 | 5 | function notice( 6 | content: string, 7 | type: string, 8 | duration = 2, 9 | onClose: (() => void) | undefined, 10 | mask = true, 11 | ) { 12 | const key = Portal.add( 13 | Portal.remove(key)} 20 | />, 21 | ); 22 | return key; 23 | } 24 | 25 | export default { 26 | SHORT: 3, 27 | LONG: 8, 28 | show(content: string, duration?: number, mask?: boolean) { 29 | return notice(content, 'info', duration, () => {}, mask); 30 | }, 31 | info( 32 | content: string, 33 | duration?: number, 34 | onClose?: () => void, 35 | mask?: boolean, 36 | ) { 37 | return notice(content, 'info', duration, onClose, mask); 38 | }, 39 | success( 40 | content: string, 41 | duration?: number, 42 | onClose?: () => void, 43 | mask?: boolean, 44 | ) { 45 | return notice(content, 'success', duration, onClose, mask); 46 | }, 47 | fail( 48 | content: string, 49 | duration?: number, 50 | onClose?: () => void, 51 | mask?: boolean, 52 | ) { 53 | return notice(content, 'fail', duration, onClose, mask); 54 | }, 55 | offline( 56 | content: string, 57 | duration?: number, 58 | onClose?: () => void, 59 | mask?: boolean, 60 | ) { 61 | return notice(content, 'offline', duration, onClose, mask); 62 | }, 63 | loading( 64 | content: string, 65 | duration?: number, 66 | onClose?: () => void, 67 | mask?: boolean, 68 | ) { 69 | return notice(content, 'loading', duration, onClose, mask); 70 | }, 71 | }; 72 | -------------------------------------------------------------------------------- /components/toast/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Feedback 4 | title: Toast 5 | subtitle: 轻提示 6 | --- 7 | 8 | 一种轻量级反馈/提示,可以用来显示不会打断用户操作的内容,适合用于页面转场、数据交互的等场景中。 9 | 10 | ### 规则 11 | - 一次只显示一个 toast。 12 | - 有 Icon 的 Toast,字数为 4-6 个;没有 Icon 的 Toast,字数不宜超过 14 个。 13 | 14 | ## API 15 | 16 | - `Toast.success(content, duration, onClose, mask)` 17 | - `Toast.fail(content, duration, onClose, mask)` 18 | - `Toast.info(content, duration, onClose, mask)` 19 | - `Toast.loading(content, duration, onClose, mask)` 20 | - `Toast.offline(content, duration, onClose, mask)` 21 | 22 | 组件提供了五个静态方法,参数如下: 23 | 24 | | 属性 | 说明 | 类型 | 默认值 | 25 | | -------- | ------------------------------ | ----------------------- | ------ | 26 | | content | 提示内容 | React.Element or String | 无 | 27 | | duration | 自动关闭的延时,单位秒 | number | 3 | 28 | | onClose | 关闭后回调 | Function | 无 | 29 | | mask | 是否显示透明蒙层,防止触摸穿透 | Boolean | true | 30 | 31 | > **注:** duration = 0 时,onClose 无效,toast 不会消失;隐藏 toast 需要手动调用 hide 32 | 33 | 34 | > 3.0.0 开始移除了 之前的`Toast.hide`方法,`Toast.xxx` 现在返回一个`key`可以使用`Portal.remove(key)`手动关闭提示 35 | 36 | ```js 37 | import { Portal, Toast } from '@sishuguojixuefu/antd-mobile-rn' 38 | const key Toast.loading('messsage') 39 | Portal.remove(key) 40 | ``` 41 | -------------------------------------------------------------------------------- /components/toast/style/index.tsx: -------------------------------------------------------------------------------- 1 | import { StyleSheet, TextStyle, ViewStyle } from 'react-native'; 2 | import { Theme } from '../../style'; 3 | 4 | export interface ToastStyle { 5 | container: ViewStyle; 6 | innerContainer: ViewStyle; 7 | innerWrap: ViewStyle; 8 | iconToast: ViewStyle; 9 | textToast: ViewStyle; 10 | content: TextStyle; 11 | image: TextStyle; 12 | centering: ViewStyle; 13 | } 14 | 15 | export default (theme: Theme) => 16 | StyleSheet.create < ToastStyle > ({ 17 | container: { 18 | position: 'absolute', 19 | top: 0, 20 | left: 0, 21 | bottom: 0, 22 | right: 0, 23 | backgroundColor: 'transparent', 24 | justifyContent: 'center', 25 | alignItems: 'center', 26 | zIndex: theme.toast_zindex, 27 | }, 28 | innerContainer: { 29 | backgroundColor: 'transparent', 30 | }, 31 | innerWrap: { 32 | alignItems: 'center', 33 | backgroundColor: theme.toast_fill, 34 | minWidth: 100, 35 | }, 36 | iconToast: { 37 | borderRadius: theme.radius_lg, 38 | padding: theme.v_spacing_lg, 39 | }, 40 | textToast: { 41 | borderRadius: theme.radius_sm, 42 | paddingVertical: theme.v_spacing_md, 43 | paddingHorizontal: theme.v_spacing_lg, 44 | }, 45 | content: { 46 | color: theme.color_text_base_inverse, 47 | fontSize: theme.font_size_subhead, 48 | }, 49 | image: { 50 | marginBottom: theme.v_spacing_xs, 51 | }, 52 | centering: { 53 | alignItems: 'center', 54 | justifyContent: 'center', 55 | padding: theme.v_spacing_md, 56 | }, 57 | }); 58 | -------------------------------------------------------------------------------- /components/view/index.tsx: -------------------------------------------------------------------------------- 1 | export { View as default } from 'react-native'; 2 | -------------------------------------------------------------------------------- /components/white-space/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { StyleProp, View, ViewStyle } from 'react-native'; 3 | import { WithTheme } from '../style'; 4 | export interface WhiteSpaceProps { 5 | style?: StyleProp; 6 | size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'; 7 | } 8 | class WhiteSpace extends React.Component { 9 | static defaultProps = { 10 | size: 'md', 11 | }; 12 | 13 | render() { 14 | const { size, style } = this.props; 15 | return ( 16 | 17 | {(_, theme) => ( 18 | 19 | )} 20 | 21 | ); 22 | } 23 | } 24 | 25 | export default WhiteSpace; 26 | -------------------------------------------------------------------------------- /components/white-space/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Layout 4 | title: WhiteSpace 5 | subtitle: 上下留白 6 | --- 7 | 8 | 布局控件 9 | 10 | ## API 11 | 12 | 属性 | 说明 | 类型 | 默认值 13 | ----|-----|------|------ 14 | | size | 上下留白的间距,可选`xs`,`sm`,`md`,`lg`,`xl` | string | `md` | 15 | -------------------------------------------------------------------------------- /components/wing-blank/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { StyleProp, View, ViewStyle } from 'react-native'; 3 | import { WithTheme } from '../style'; 4 | 5 | export interface WingBlankProps { 6 | style?: StyleProp; 7 | size?: 'sm' | 'md' | 'lg'; 8 | } 9 | class WingBlank extends React.Component { 10 | static defaultProps = { 11 | size: 'lg', 12 | }; 13 | 14 | render() { 15 | const { size, style, children } = this.props; 16 | return ( 17 | 18 | {(_, theme) => { 19 | const margin = theme[`h_spacing_${size}`]; 20 | return ( 21 | 22 | {children} 23 | 24 | ); 25 | }} 26 | 27 | ); 28 | } 29 | } 30 | 31 | export default WingBlank; 32 | -------------------------------------------------------------------------------- /components/wing-blank/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | category: Components 3 | type: Layout 4 | title: WingBlank 5 | subtitle: 两翼留白 6 | --- 7 | 8 | 布局控件 9 | 10 | ## API 11 | 12 | 属性 | 说明 | 类型 | 默认值 13 | ----|-----|------|------ 14 | | size | 两翼留白的间距,可选`sm`,`md`,`lg` | string | `lg` | 15 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@sishuguojixuefu/antd-mobile-rn", 3 | "version": "3.1.8-beta.11", 4 | "description": "基于蚂蚁金服移动设计规范的 React Native 组件库", 5 | "keywords": [ 6 | "ant", 7 | "design", 8 | "react", 9 | "react-component", 10 | "component", 11 | "components", 12 | "ui", 13 | "framework", 14 | "frontend", 15 | "mobile", 16 | "react native" 17 | ], 18 | "repository": { 19 | "type": "github", 20 | "url": "https://github.com/sishuguojixuefu/antd-mobile-rn" 21 | }, 22 | "files": [ 23 | "lib" 24 | ], 25 | "license": "MIT", 26 | "main": "lib/index.js", 27 | "dependencies": { 28 | "@ant-design/icons-react-native": "^1.0.2", 29 | "@bang88/react-native-drawer-layout": "^2.0.3", 30 | "@bang88/react-native-ultimate-listview": "^3.3.0", 31 | "array-tree-filter": "~2.1.0", 32 | "babel-runtime": "^6.x", 33 | "deepmerge": "^3.0.0", 34 | "normalize-css-color": "^1.0.2", 35 | "react-native-collapsible": "^1.4.0", 36 | "react-native-modal-popover": "^0.0.12", 37 | "react-native-safe-area-view": "^0.11.0", 38 | "react-native-swipeout": "^2.3.6", 39 | "utility-types": "^2.1.0" 40 | }, 41 | "devDependencies": { 42 | "@types/prop-types": "^15.5.7", 43 | "@types/react": "~16.7.13", 44 | "@types/react-native": "^0.57.15", 45 | "babel-eslint": "^7.2.3", 46 | "eslint": "~4.3.0", 47 | "eslint-config-airbnb": "~15.1.0", 48 | "eslint-plugin-babel": "~4.1.1", 49 | "eslint-plugin-import": "~2.7.0", 50 | "eslint-plugin-jsx-a11y": "~6.0.2", 51 | "eslint-plugin-react": "~7.2.0", 52 | "rc-form": "2.2.7", 53 | "typescript": "^3.2.2" 54 | }, 55 | "types": "lib/index.d.ts", 56 | "scripts": { 57 | "build": "tsc -p ./tsconfig.json", 58 | "postversion": "git push --tags && git push && npm publish", 59 | "prepublishOnly": "tsc -p ./tsconfig.json" 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["esnext"], 4 | "strictNullChecks": true, 5 | "moduleResolution": "node", 6 | "jsx": "react", 7 | "noUnusedParameters": true, 8 | "noUnusedLocals": true, 9 | "allowSyntheticDefaultImports": true, 10 | "target": "es5", 11 | "noImplicitAny": true, 12 | "skipLibCheck": true, 13 | "types": ["react", "react-native"], 14 | "esModuleInterop": true, 15 | "declaration": true, 16 | "declarationMap": true, 17 | "sourceMap": true, 18 | "outDir": "lib" 19 | }, 20 | "exclude": ["node_modules", "lib", "es"], 21 | "compileOnSave": false 22 | } 23 | -------------------------------------------------------------------------------- /typings/custom.d.ts: -------------------------------------------------------------------------------- 1 | declare module '@sishuguojixuefu/antd-mobile-rn'; 2 | 3 | declare module 'antd-mobile-demo-data'; 4 | 5 | declare module 'normalize-css-color'; 6 | declare module '@bang88/react-native-ultimate-listview'; 7 | 8 | declare var process: { 9 | env: { 10 | NODE_ENV: string; 11 | DISABLE_ANTD_MOBILE_UPGRADE: string; 12 | }; 13 | }; 14 | -------------------------------------------------------------------------------- /typings/index.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | --------------------------------------------------------------------------------