├── .editorconfig ├── .gitignore ├── .npmrc ├── LICENSE ├── README.md ├── docs ├── components.md ├── components │ ├── ActivityIndicator.mdx │ ├── Avatar.mdx │ ├── Badge.mdx │ ├── Button.mdx │ ├── CustomTabBar.mdx │ ├── InputNumber.mdx │ ├── List.mdx │ ├── Progress.mdx │ ├── SearchBar.mdx │ ├── Steps.mdx │ ├── TabBar.mdx │ └── Tag.mdx ├── globals.md ├── index.md ├── interfaces │ ├── _actionsheet_.actionsheetprops.md │ ├── _activityindicator_.activityindicatorprops.md │ ├── _avatar_.avatarprops.md │ ├── _badge_.badgeprops.md │ ├── _button_.buttonprops.md │ ├── _calendar_body_interface_.props.md │ ├── _calendar_body_interface_.state.md │ ├── _calendar_controller_interface_.props.md │ ├── _calendar_controller_interface_.state.md │ ├── _calendar_interface_.defaultprops.md │ ├── _calendar_interface_.mutilselectedprops.md │ ├── _calendar_interface_.propsbase.md │ ├── _calendar_interface_.singleselectedprops.md │ ├── _calendar_interface_.state.md │ ├── _calendar_ui_date_list_index_.props.md │ ├── _customtabbar_.customtabbarprops.md │ ├── _floatlayout_.floatlayoutprops.md │ ├── _floatlayout_.floatlayoutprops.onscrolldetail.md │ ├── _form_.formprops.md │ ├── _grid_.griditem.md │ ├── _grid_.gridprops.md │ ├── _icon_.iconprops.md │ ├── _imagepicker_.imagepickerprops.md │ ├── _input_.inputprops.md │ ├── _inputnumber_.inputnumberprops.md │ ├── _list_.listprops.md │ ├── _listheader_.listheaderprops.md │ ├── _listitem_.listitemprops.md │ ├── _loading_.loadingprops.md │ ├── _message_.messageprops.md │ ├── _modal_.modalprops.md │ ├── _progress_.progressprops.md │ ├── _searchbar_.searchbarprops.md │ ├── _statistic_.statisticprops.md │ ├── _steps_.stepsprops.md │ ├── _tabbar_.tabbarprops.md │ ├── _tabs_.tabsprops.md │ ├── _tabspane_.tabspanelprops.md │ ├── _tabspane_.tabspaneprops.md │ ├── _tag_.tagprops.md │ └── _textarea_.textareaprops.md └── modules │ ├── _actionsheet_.md │ ├── _activityindicator_.md │ ├── _avatar_.md │ ├── _badge_.md │ ├── _button_.md │ ├── _calendar_body_index_.md │ ├── _calendar_body_interface_.md │ ├── _calendar_common_constant_.md │ ├── _calendar_common_helper_.md │ ├── _calendar_common_plugins_.md │ ├── _calendar_controller_index_.md │ ├── _calendar_controller_interface_.md │ ├── _calendar_index_.md │ ├── _calendar_interface_.md │ ├── _calendar_ui_date_list_index_.md │ ├── _calendar_ui_day_list_index_.md │ ├── _customtabbar_.md │ ├── _floatlayout_.md │ ├── _form_.md │ ├── _grid_.md │ ├── _icon_.md │ ├── _imagepicker_.md │ ├── _index_.md │ ├── _input_.md │ ├── _inputnumber_.md │ ├── _list_.md │ ├── _listheader_.md │ ├── _listitem_.md │ ├── _loading_.md │ ├── _message_.md │ ├── _modal_.md │ ├── _progress_.md │ ├── _searchbar_.md │ ├── _statistic_.md │ ├── _steps_.md │ ├── _tabbar_.md │ ├── _tabs_.md │ ├── _tabspane_.md │ ├── _tag_.md │ ├── _taro_ui_.md │ ├── _textarea_.md │ └── _utils_.md ├── global.d.ts ├── package.json ├── src ├── ActionSheet.tsx ├── ActivityIndicator.tsx ├── Avatar.tsx ├── Badge.tsx ├── Button.tsx ├── Calendar │ ├── body │ │ └── index.tsx │ ├── common │ │ ├── constant.ts │ │ ├── helper.ts │ │ └── plugins.ts │ ├── controller │ │ └── index.tsx │ ├── index.tsx │ └── ui │ │ ├── date-list │ │ └── index.tsx │ │ └── day-list │ │ └── index.tsx ├── CustomTabBar.tsx ├── FloatLayout.tsx ├── Form.tsx ├── Grid.tsx ├── Icon.tsx ├── ImagePicker.tsx ├── Input.tsx ├── InputNumber.tsx ├── List.tsx ├── ListHeader.tsx ├── ListItem.tsx ├── Loading.tsx ├── Message.tsx ├── Modal.tsx ├── Progress.tsx ├── SearchBar.tsx ├── Statistic.tsx ├── Steps.tsx ├── TabBar.tsx ├── Tabs.tsx ├── TabsPane.tsx ├── Tag.tsx ├── Textarea.tsx ├── TextareaEnhance.tsx ├── index.ts ├── taro-ui.ts └── utils.ts ├── style ├── ActionSheet.scss ├── ActivityIndicator.scss ├── Avatar.scss ├── Badge.scss ├── Button.scss ├── Calendar.scss ├── FloatLayout.scss ├── Grid.scss ├── Icon.scss ├── ImagePicker.scss ├── Input.scss ├── InputNumber.scss ├── List.scss ├── ListHeader.scss ├── ListItem.scss ├── Loading.scss ├── Message.scss ├── Modal.scss ├── Progress.scss ├── SearchBar.scss ├── Statistic.scss ├── Steps.scss ├── TabBar.scss ├── Tabs.scss ├── TabsPane.scss ├── Tag.scss ├── Textarea.scss ├── index.scss ├── mixins.scss └── utils.scss ├── tsconfig.json └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | 14 | [.git/config] 15 | indent_style = tab 16 | 17 | [project.config.json] 18 | insert_final_newline = false 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # Docusaurus 92 | .Docusaurus 93 | website/build 94 | 95 | # vuepress build output 96 | .vuepress/dist 97 | 98 | # Serverless directories 99 | .serverless/ 100 | 101 | # FuseBox cache 102 | .fusebox/ 103 | 104 | # DynamoDB Local files 105 | .dynamodb/ 106 | 107 | # TernJS port file 108 | .tern-port 109 | 110 | # Other 111 | .DS_Store 112 | .temp 113 | website 114 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | # run scripts with root privileges 2 | # @see https://docs.npmjs.com/misc/scripts#user 3 | unsafe-perm=true 4 | 5 | # NPM Taobao registry 6 | registry=https://registry.npm.taobao.org 7 | 8 | # Taobao node binary mirrors 9 | chromedriver_cdnurl=https://npm.taobao.org/mirrors/chromedriver 10 | disturl=https://npm.taobao.org/dist 11 | electron_mirror=https://npm.taobao.org/mirrors/electron 12 | fse_binary_host_mirror=https://npm.taobao.org/mirrors/fsevents 13 | node_inspector_cdnurl=https://npm.taobao.org/mirrors/node-inspector 14 | nodejs_org_mirror=https://npm.taobao.org/mirrors/node 15 | nvm_nodejs_org_mirror=https://npm.taobao.org/mirrors/node 16 | nvm_iojs_org_mirror=https://npm.taobao.org/mirrors/iojs 17 | operadriver_cdnurl=https://npm.taobao.org/mirrors/operadriver 18 | phantomjs_cdnurl=https://npm.taobao.org/mirrors/phantomjs 19 | profiler_binary_host_mirror=http://npm.taobao.org/mirrors/node-inspector/ 20 | puppeteer_download_host=https://npm.taobao.org/mirrors 21 | selenium_cdnurl=http://npm.taobao.org/mirrors/selenium 22 | sass_binary_site=https://npm.taobao.org/mirrors/node-sass 23 | sqlite3_binary_site=http://npm.taobao.org/mirrors/sqlite3 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 tarojsx 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |

Taro3 UI

3 |
4 |
5 | 我们重新(zào)发(lún)明(zi) Taro UI 6 |
7 | 8 |
9 | 10 |
11 | 12 | License 13 | 14 | 15 | npm version 16 | 17 | 18 | npm downloads 19 | 20 | 21 | dependents 22 | 23 | 24 | PRs welcome 25 | 26 |
27 | 28 |
29 | Built with :purple_heart: by 30 | @Colder and 31 | 32 | Contributors 33 | 34 |
35 | :star2: :eyes: :zap: :boom: 36 |
37 |
38 | 39 |
40 | 41 | _当前代码提交频繁, 一些特性时有变化._ 42 | 43 | Taro3 释放了 React 的潜能, 是时候对 Taro UI 进行改进了. 44 | 45 | ## 特性 46 | 47 | - :electric_plug: 一键安装, 使用上尽可能向后兼容. 48 | 49 | - :clapper: 复用 taro-ui 样式, 不改变组件外观. 50 | 51 | - :octopus: 扩展性更强, 许多原本只能传入字符串的地方, 现在可以传入组件了. 52 | 53 | - :mag_right: 完善的 Typescript 类型提示. 54 | 55 | - :gift: 开箱即用, 只需引入组件即可, 无需单独引入样式, 支持 Tree shaking. 56 | 57 | - :telescope: 未来计划引入更多常用的基础组件. 58 | 59 | ## 需求 60 | 61 | - **taro 3+** 62 | - react 16.8+ 63 | 64 | ## 安装 65 | 66 | `npm i @tarojsx/ui` 67 | 68 | ## 使用 69 | 70 | ```tsx 71 | import React from 'react'; 72 | import { Text } from '@tarojs/components'; 73 | import { List, ListHeader, ListItem } from '@tarojsx/ui'; 74 | 75 | export default () => { 76 | return ( 77 | 78 | 79 | 0.2.0}> 80 | 我们重新(zào)发(lún)明(zi)了 Taro UI 81 | 82 | 83 | ); 84 | }; 85 | ``` 86 | 87 | ## 组件 88 | 89 | 源于 Taro UI 90 | 91 | - [ ] Accordion 92 | - [x] ActionSheet 93 | - [ ] 子组件 94 | - [x] ActivityIndicator 95 | - [ ] Article 96 | - [x] [Avatar](./docs/components/Avatar.mdx) 97 | - [x] [Badge](./docs/components/Badge.mdx) 98 | - [x] [Button](./docs/components/Button.mdx) 99 | - [x] Calendar 100 | - [ ] Swipe 操作 101 | - [ ] Card 102 | - [ ] Checkbox 103 | - [ ] Countdown 104 | - [ ] Divider 105 | - [ ] Drawer 106 | - [ ] ~~Fab~~ (已合并入 Button) 107 | - [ ] ~~Flex~~ (使用率不高) 108 | - [x] FloatLayout 109 | - [x] Form 110 | - [x] Grid 111 | - [x] Icon 112 | - [x] ImagePicker 113 | - [ ] Indexes 114 | - [x] Input 115 | - [x] [InputNumber](./docs/components/InputNumber.mdx) 116 | - [x] [List](./docs/components/List.mdx) 117 | - [x] [ListItem](./docs/components/List.mdx) 118 | - [x] Loading 119 | - [ ] Loadmore 120 | - [x] Message 121 | - [ ] Modal 122 | - [ ] NavBar 123 | - [ ] Noticebar 124 | - [ ] Pagination 125 | - [ ] Picker 126 | - [x] [Progress](./docs/components/Progress.mdx) 127 | - [ ] Radio 128 | - [ ] Rate 129 | - [x] [SearchBar](./docs/components/SearchBar.mdx) 130 | - [ ] SegmentedControl 131 | - [ ] Slider 132 | - [x] [Steps](./docs/components/Steps.mdx) 133 | - [ ] SwipeAction 134 | - [ ] Swiper 135 | - [ ] Switch 136 | - [x] [TabBar](./docs/components/TabBar.mdx) 137 | - [x] Tabs 138 | - [ ] Swipe 操作 139 | - [x] TabsPane 140 | - [ ] Swipe 操作 141 | - [x] [Tag](./docs/components/Tag.mdx) 142 | - [x] Textarea 143 | - [ ] Timeline 144 | - [ ] Toast 145 | 146 | 扩展组件 147 | 148 | - [x] [CustomTabBar](./docs/components/CustomTabBar.mdx) 149 | - [x] [ListHeader](./docs/components/List.mdx) 150 | - [x] Statistic 151 | 152 | ## 支持 153 | 154 | 欢迎各种形式的支持. 至少可以给颗星 :star: 155 | 156 | ## License 157 | 158 | [MIT](LICENSE) 159 | -------------------------------------------------------------------------------- /docs/components.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: components 3 | title: 组件说明 4 | --- 5 | 6 | ## 命名 7 | 8 | 取 `taro-ui` 组件名, 去掉 `At` 前缀. 9 | 10 | 如需使用 `taro-ui` 原有的命名规则, 可以 `import { AtButton } from '@tarojsx/ui/dist/taro-ui` 11 | 12 | ## 样式 13 | 14 | 组件自动导入所需的样式, 无需重复导入. 15 | -------------------------------------------------------------------------------- /docs/components/ActivityIndicator.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: ActivityIndicator 活动指示器 3 | --- 4 | 5 | 该组件提供一个加载等待元素,也就是 Loading 组件 6 | 7 | ## 示例 8 | 9 | import { ActivityIndicator } from '@tarojsx/ui'; 10 | import { UI } from '@/ui'; 11 | 12 | ```jsx title="常规" 13 | 14 | ``` 15 | 16 | 17 | 18 | 19 | 20 | ```jsx title="颜色" 21 | 22 | ``` 23 | 24 | 25 | 26 | 27 | 28 | ```jsx title="尺寸" 29 | 30 | ``` 31 | 32 | 33 | 34 | 35 | 36 | ```jsx title="文字" 37 | 38 | ``` 39 | 40 | 41 | 42 | 43 | 44 | ```jsx title="居中" 45 | 46 | ``` 47 | 48 | 49 | 50 | 51 | 52 | ## API 53 | 54 | - [Taro UI 文档 | 活动指示器](https://taro-ui.jd.com/#/docs/activityindicator) 55 | - [``](modules/_activityindicator_.md) 56 | - [`ActivityIndicatorProps`](interfaces/_activityindicator_.activityindicatorprops.md) 57 | -------------------------------------------------------------------------------- /docs/components/Avatar.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Avatar 头像 3 | --- 4 | 5 | 用于展示用户头像 6 | 7 | ## 示例 8 | 9 | import { Avatar } from '@tarojsx/ui'; 10 | import useBaseUrl from '@docusaurus/useBaseUrl'; 11 | import { UI } from '@/ui'; 12 | 13 | ```jsx title="头像" 14 | 15 | ``` 16 | 17 | 18 | 19 | 20 | 21 | ```jsx title="文字" 22 | 23 | ``` 24 | 25 | 26 | 27 | 28 | 29 | ```jsx title="圆形头像" 30 | 31 | ``` 32 | 33 | 34 | 35 | 36 | 37 | ```jsx title="圆形文字" 38 | 39 | ``` 40 | 41 | 42 | 43 | 44 | 45 | ```jsx title="尺寸" 46 | 47 | 48 | 49 | 50 | 51 | ``` 52 | 53 |
54 | 55 | tiny 56 | 57 | 58 | 59 | mini 60 | 61 | 62 | 63 | small 64 | 65 | 66 | 67 | default 68 | 69 | 70 | 71 | large 72 | 73 | 74 |
75 | 76 | ## API 77 | 78 | | 参数 | 说明 | 类型 | 默认值 | 79 | | ---- | ---- | ----------------------------- | ------ | 80 | | size | 尺寸 | `tiny` `mini` `small` `large` | | 81 | 82 | - [Taro UI 文档 | 头像](https://taro-ui.jd.com/#/docs/avatar) 83 | - [``](modules/_avatar_.md) 84 | - [`AvatarProps`](interfaces/_avatar_.avatarprops.md) 85 | -------------------------------------------------------------------------------- /docs/components/Badge.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Badge 徽标 3 | --- 4 | 5 | ## 示例 6 | 7 | import { Badge, Button } from '@tarojsx/ui'; 8 | import { UI } from '@/ui'; 9 | 10 | ```jsx title="数字" 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | ``` 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | ```jsx title="小红点" 34 | 35 | 36 | 37 | ``` 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | ```jsx title="文字" 46 | 47 | 48 | 49 | ``` 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | ## API 58 | 59 | - [Taro UI 文档](https://taro-ui.jd.com/#/docs/badge) 60 | - [``](../modules/_badge_.md) 61 | - [`BadgeProps`](../interfaces/_badge_.badgeprops.md) 62 | -------------------------------------------------------------------------------- /docs/components/Button.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Button 按钮 3 | --- 4 | 5 | ## 示例 6 | 7 | import { Button } from '@tarojsx/ui'; 8 | import { Image } from '@tarojs/components'; 9 | import useBaseUrl from '@docusaurus/useBaseUrl'; 10 | import dayjs from 'dayjs'; 11 | import { UI } from '@/ui'; 12 | 13 | ```jsx title="类型" 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | ``` 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | ```jsx title="尺寸" 46 | 47 | 48 | 49 | ``` 50 | 51 | 52 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | ```jsx title="透明按钮" 62 | 65 | ``` 66 | 67 | 68 | 71 | 72 | 73 | ```jsx title="点击节流" 74 | 75 | ``` 76 | 77 | 78 | {() => { 79 | const [times, setTimes] = React.useState([]); 80 | return ( 81 | <> 82 | 85 | {times.map((time, index) => ( 86 |
{time.format(`ss' SSS''`)}
87 | ))} 88 | 89 | ); 90 | }} 91 |
92 | 93 | ## API 94 | 95 | | 参数 | 说明 | 类型 | 默认值 | 96 | | ------------- | ----------------------------------- | ---------------------------------------------- | ------ | 97 | | type | 类型 | `default` `primary` `secondary` `warn` `error` | | 98 | | size | 尺寸 | `default` `normal` `small` `mini` | | 99 | | clickThrottle | onClick 事件节流时间间隔, 单位: ms. | `boolean` `number` | 500ms | 100 | | transparent | 透明按钮. | `boolean` | | 101 | 102 | - [Taro UI 文档](https://taro-ui.jd.com/#/docs/button) 103 | - [`} 75 | {confirmText && } 76 | 77 | 78 | )} 79 | 80 | 81 | ); 82 | } 83 | 84 | return ( 85 | e.stopPropagation()}> 86 | 87 | {children} 88 | 89 | ); 90 | }; 91 | -------------------------------------------------------------------------------- /src/Progress.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import classNames from 'classnames'; 3 | import { View, Text } from '@tarojs/components'; 4 | 5 | import '../style/Progress.scss'; 6 | 7 | export interface ProgressProps { 8 | className?: string; 9 | style?: React.CSSProperties; 10 | /** 进度 */ 11 | percent?: number; 12 | /** 状态 */ 13 | status?: 'progress' | 'success' | 'error'; 14 | /** 颜色 */ 15 | color?: string; 16 | /** 宽度 */ 17 | strokeWidth?: number; 18 | /** 是否隐藏文字 */ 19 | isHidePercent?: boolean; 20 | /** 过渡动画所需的时间. 默认: 0.3, 单位: 秒, 禁用可提高性能. */ 21 | transitionDuration?: number; 22 | } 23 | 24 | export const Progress: React.FC = (props) => { 25 | const { 26 | className, 27 | style = {}, 28 | percent: initialPercent = 0, 29 | status, 30 | color, 31 | strokeWidth, 32 | isHidePercent, 33 | transitionDuration = 0.3, 34 | } = props; 35 | const percent = Math.min(100, Math.max(0, initialPercent)); 36 | 37 | const rootClass = classNames('at-progress', { [`at-progress--${status}`]: status }, className); 38 | const iconClass = classNames('at-icon', { 39 | 'at-icon-close-circle': status === 'error', 40 | 'at-icon-check-circle': status === 'success', 41 | }); 42 | 43 | const progressStyle: React.CSSProperties = { 44 | width: percent && `${+percent}%`, 45 | height: strokeWidth && `${+strokeWidth}px`, 46 | backgroundColor: color, 47 | }; 48 | progressStyle.transitionDuration = `${transitionDuration ?? 0}s`; 49 | 50 | return ( 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | {!isHidePercent && ( 59 | 60 | {!status || status === 'progress' ? `${percent}%` : } 61 | 62 | )} 63 | 64 | ); 65 | }; 66 | -------------------------------------------------------------------------------- /src/Statistic.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import classNames from 'classnames'; 3 | import { View, Text } from '@tarojs/components'; 4 | 5 | import '../style/Statistic.scss'; 6 | 7 | export interface StatisticProps { 8 | className?: string; 9 | title: React.ReactNode; 10 | value: string | number; 11 | valueStyle?: React.CSSProperties; 12 | prefix?: React.ReactNode; 13 | suffix?: React.ReactNode; 14 | } 15 | 16 | export const Statistic: React.FC = (props) => { 17 | const { className, title, value, valueStyle = {}, prefix, suffix } = props; 18 | 19 | return ( 20 | 21 | {title} 22 | 23 | {!!prefix && {prefix}} 24 | 25 | {value} 26 | 27 | {!!suffix && {suffix}} 28 | 29 | 30 | ); 31 | }; 32 | -------------------------------------------------------------------------------- /src/Steps.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import classNames from 'classnames'; 3 | import { View, Text } from '@tarojs/components'; 4 | import { AtStepsProps } from 'taro-ui/types/steps'; 5 | 6 | import '../style/Steps.scss'; 7 | 8 | export interface StepsProps extends Omit { 9 | style?: React.CSSProperties; 10 | items?: { 11 | title: React.ReactNode; 12 | status?: 'success' | 'error' | string; 13 | icon?: { value: string }; 14 | desc?: React.ReactNode; 15 | }[]; 16 | } 17 | 18 | export const Steps: React.FC = (props) => { 19 | const { className, style = {}, items, current = 0, onChange } = props; 20 | 21 | return ( 22 | 23 | {items?.map((item, i) => ( 24 | onChange?.(i, e as any)} 32 | > 33 | 34 | {i !== 0 && } 35 | {item.status ? ( 36 | 44 | ) : ( 45 | 46 | {item.icon ? ( 47 | 52 | ) : ( 53 | {i + 1} 54 | )} 55 | 56 | )} 57 | {i !== items.length - 1 && } 58 | 59 | {item.title} 60 | {item.desc} 61 | 62 | ))} 63 | 64 | ); 65 | }; 66 | -------------------------------------------------------------------------------- /src/TabsPane.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import classNames from 'classnames'; 3 | import { View } from '@tarojs/components'; 4 | import { AtTabsPaneProps } from 'taro-ui/types/tabs-pane'; 5 | 6 | import '../style/TabsPane.scss'; 7 | 8 | export interface TabsPaneProps extends AtTabsPaneProps { 9 | style?: React.CSSProperties; 10 | } 11 | 12 | export const TabsPane: React.FC = (props) => { 13 | const { className, style = {}, children, tabDirection = 'horizontal', index = 0, current = 0 } = props; 14 | 15 | return ( 16 | 28 | {children} 29 | 30 | ); 31 | }; 32 | -------------------------------------------------------------------------------- /src/Tag.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import classNames from 'classnames'; 3 | import { View, CommonEventFunction } from '@tarojs/components'; 4 | 5 | import '../style/Tag.scss'; 6 | 7 | export interface TagProps { 8 | className?: string; 9 | style?: React.CSSProperties; 10 | type?: 'primary'; 11 | size?: 'small'; 12 | name?: string; 13 | circle?: boolean; 14 | active?: boolean; 15 | disabled?: boolean; 16 | onClick?: CommonEventFunction; 17 | } 18 | 19 | export const Tag: React.FC = (props) => { 20 | const { className, style, children, type, size = 'normal', circle, disabled, active, onClick } = props; 21 | 22 | return ( 23 | 38 | {children} 39 | 40 | ); 41 | }; 42 | -------------------------------------------------------------------------------- /src/Textarea.tsx: -------------------------------------------------------------------------------- 1 | import React, { useMemo } from 'react'; 2 | import Taro from '@tarojs/taro'; 3 | import classNames from 'classnames'; 4 | import { View, CommonEventFunction } from '@tarojs/components'; 5 | import { AtTextareaProps } from 'taro-ui/types/textarea'; 6 | 7 | import { TextareaEnhance, TextareaEnhanceProps } from './TextareaEnhance'; 8 | import '../style/Textarea.scss'; 9 | 10 | export interface TextareaProps 11 | extends Omit, 12 | Pick { 13 | className?: string; 14 | style?: React.CSSProperties; 15 | textareaRef?: React.LegacyRef; 16 | value?: string; 17 | /** 最大输入长度,设置为 -1 的时候不限制最大长度 */ 18 | maxLength?: number; 19 | onChange?: CommonEventFunction; 20 | } 21 | 22 | const ENV = Taro.getEnv(); 23 | 24 | export const Textarea: React.FC = (props) => { 25 | const { 26 | className, 27 | style = {}, 28 | textareaRef, 29 | value = '', 30 | cursorSpacing = 100, 31 | placeholderClass, 32 | count = true, 33 | autoFocus, 34 | textOverflowForbidden = true, 35 | height, 36 | onChange, 37 | ...rest 38 | } = props; 39 | const maxlength = props.maxlength ?? props.maxLength ?? 200; 40 | 41 | const actualMaxLength = useMemo( 42 | () => (textOverflowForbidden ? maxlength : maxlength + 500), 43 | [maxlength, textOverflowForbidden] 44 | ); 45 | const textareaStyle = height ? { height: Taro.pxTransform(Number(height)) } : {}; 46 | const rootCls = classNames( 47 | 'at-textarea', 48 | `at-textarea--${ENV}`, 49 | { 50 | 'at-textarea--error': maxlength < value.length, 51 | }, 52 | className 53 | ); 54 | const placeholderCls = classNames('placeholder', placeholderClass); 55 | 56 | return ( 57 | 58 | 71 | {count && ( 72 | 73 | {value.length}/{maxlength} 74 | 75 | )} 76 | 77 | ); 78 | }; 79 | -------------------------------------------------------------------------------- /src/TextareaEnhance.tsx: -------------------------------------------------------------------------------- 1 | import React, { useRef, useCallback } from 'react'; 2 | import { Textarea } from '@tarojs/components'; 3 | import { TextareaProps } from '@tarojs/components/types/Textarea'; 4 | 5 | export interface TextareaEnhanceProps extends TextareaProps { 6 | /** 7 | * OnBlur/onConfirm 事件也会触发 onChange. 如果 value 与最后一次 onChange 事件相同则跳过. 8 | * 9 | * @default true 10 | */ 11 | mergeChangeEvent?: boolean; 12 | } 13 | 14 | /** 15 | * Textarea 升级版. 16 | * 17 | * - MergeChangeEvent onBlur/onConfirm 事件也会触发 onChange. 18 | * 19 | * 某些输入法(不只是中文), 输入中的文字并没有真正进入 Textarea 中, 只是浮动在上面的输入法自带 UI 控件. 另一些中文输入法会在词语联想过程中提前把拼音输入进输入框内. 这两种情况都会造成 onInput 20 | * 事件不触发或传递错误的值. Textarea 组件的 onBlur/onConfirm 事件中汇报的值永远是正确的最终值. 21 | */ 22 | export const TextareaEnhance: React.FC = (props) => { 23 | const { mergeChangeEvent = true, onInput, onBlur, onConfirm, ...rest } = props; 24 | 25 | /** 上一个输入值 */ 26 | const previousInputValue = useRef(props.value); 27 | 28 | const handleInput = useCallback( 29 | (e) => { 30 | // 记录新值 31 | previousInputValue.current = e.detail.value; 32 | onInput && onInput(e); 33 | }, 34 | [onInput] 35 | ); 36 | 37 | const handleBlur = useCallback( 38 | (e) => { 39 | // 如果丢失焦点时的值与上一个值不同, 先触发 onInput 40 | if (onInput && mergeChangeEvent && e.detail.value !== previousInputValue.current) { 41 | onInput({ ...e, detail: { ...e.detail, keyCode: 0 } }); 42 | } 43 | onBlur && onBlur(e); 44 | }, 45 | [onInput, onBlur, mergeChangeEvent] 46 | ); 47 | 48 | const handleConfirm = useCallback( 49 | (e) => { 50 | // 如果点击"完成"绿按钮时的值与上一个值不同, 先触发 onInput 51 | if (onInput && mergeChangeEvent && e.detail.value !== previousInputValue.current) { 52 | onInput({ ...e, detail: { ...e.detail, keyCode: 0, cursor: 0 } }); 53 | } 54 | onConfirm && onConfirm(e); 55 | }, 56 | [onInput, onConfirm, mergeChangeEvent] 57 | ); 58 | 59 | return