Selaa lähdekoodia

Merge branch main into release

pointhalo 3 vuotta sitten
vanhempi
sitoutus
73ec7e980d
100 muutettua tiedostoa jossa 15877 lisäystä ja 13453 poistoa
  1. 46 0
      .github/workflows/chromatic.yml
  2. 10 1
      README-zh_CN.md
  3. 10 1
      README.md
  4. 1 1
      content/feedback/spin/index-en-US.md
  5. 1 1
      content/feedback/spin/index.md
  6. 2 2
      content/navigation/navigation/index-en-US.md
  7. 4 4
      content/navigation/navigation/index.md
  8. 2 2
      content/show/table/index.md
  9. 21 0
      content/start/changelog/index-en-US.md
  10. 22 0
      content/start/changelog/index.md
  11. 3 3
      content/start/update-to-v2/index-en-US.md
  12. 3 1
      content/start/update-to-v2/index.md
  13. 1 1
      lerna.json
  14. 1 0
      package.json
  15. 3 3
      packages/semi-animation-react/package.json
  16. 1 1
      packages/semi-animation-styled/package.json
  17. 1 1
      packages/semi-animation/package.json
  18. 1 1
      packages/semi-foundation/input/input.scss
  19. 1 1
      packages/semi-foundation/input/variables.scss
  20. 1 1
      packages/semi-foundation/modal/constants.ts
  21. 94 27
      packages/semi-foundation/modal/modal.scss
  22. 6 3
      packages/semi-foundation/modal/modalContentFoundation.ts
  23. 29 30
      packages/semi-foundation/modal/modalFoundation.ts
  24. 1 1
      packages/semi-foundation/modal/rtl.scss
  25. 2 6
      packages/semi-foundation/package.json
  26. 1 1
      packages/semi-foundation/radio/variables.scss
  27. 4 4
      packages/semi-foundation/slider/foundation.ts
  28. 1 11
      packages/semi-foundation/table/bodyFoundation.ts
  29. 0 1
      packages/semi-foundation/table/foundation.ts
  30. 10 1
      packages/semi-foundation/table/rtl.scss
  31. 25 3
      packages/semi-foundation/table/table.scss
  32. 1 0
      packages/semi-foundation/table/variables.scss
  33. 1 1
      packages/semi-icons/package.json
  34. 1 1
      packages/semi-illustrations/package.json
  35. 1 1
      packages/semi-scss-compile/package.json
  36. 1 1
      packages/semi-theme-default/package.json
  37. 1 1
      packages/semi-ui/_base/_story/index.scss
  38. 107 94
      packages/semi-ui/_base/_story/index.stories.js
  39. 10 11
      packages/semi-ui/_portal/_story/portal.stories.js
  40. 2 2
      packages/semi-ui/_test_/utils/table/index.js
  41. 244 221
      packages/semi-ui/anchor/_story/anchor.stories.js
  42. 306 305
      packages/semi-ui/autoComplete/_story/autoComplete.stories.js
  43. 173 152
      packages/semi-ui/avatar/_story/avatar.stories.js
  44. 30 30
      packages/semi-ui/backtop/_story/backtop.stories.js
  45. 81 85
      packages/semi-ui/badge/_story/badge.stories.js
  46. 34 37
      packages/semi-ui/banner/_story/banner.stories.js
  47. 306 272
      packages/semi-ui/breadcrumb/_story/breadcrumb.stories.js
  48. 265 239
      packages/semi-ui/button/_story/button.stories.js
  49. 345 343
      packages/semi-ui/calendar/_story/calendar.stories.js
  50. 514 498
      packages/semi-ui/card/_story/card.stories.js
  51. 4 0
      packages/semi-ui/cascader/_story/CustomTrigger/index.jsx
  52. 557 535
      packages/semi-ui/cascader/_story/cascader.stories.js
  53. 899 764
      packages/semi-ui/checkbox/_story/checkbox.stories.js
  54. 121 116
      packages/semi-ui/collapse/_story/accordion.stories.js
  55. 524 510
      packages/semi-ui/collapsible/_story/collapsible.stories.js
  56. 5 2
      packages/semi-ui/configProvider/_story/RTLDirection/RTLWrapper.tsx
  57. 23 9
      packages/semi-ui/configProvider/_story/configProvider.stories.js
  58. 4 0
      packages/semi-ui/datePicker/_story/BetterRangePicker/index.jsx
  59. 4 0
      packages/semi-ui/datePicker/_story/CustomTrigger/index.jsx
  60. 83 0
      packages/semi-ui/datePicker/_story/DatePickerSlot/index.jsx
  61. 223 164
      packages/semi-ui/datePicker/_story/datePicker.stories.js
  62. 46 45
      packages/semi-ui/descriptions/_story/descriptions.stories.js
  63. 300 304
      packages/semi-ui/dropdown/_story/dropdown.stories.js
  64. 44 40
      packages/semi-ui/empty/_story/empty.stories.js
  65. 442 188
      packages/semi-ui/form/_story/form.stories.js
  66. 283 223
      packages/semi-ui/grid/_story/grid.stories.js
  67. 56 47
      packages/semi-ui/icons/_story/icon.stories.js
  68. 677 507
      packages/semi-ui/input/_story/input.stories.js
  69. 625 539
      packages/semi-ui/inputNumber/_story/inputNumber.stories.js
  70. 265 239
      packages/semi-ui/layout/_story/layout.stories.js
  71. 827 699
      packages/semi-ui/list/_story/list.stories.js
  72. 188 150
      packages/semi-ui/locale/_story/locale.stories.js
  73. 47 62
      packages/semi-ui/modal/Modal.tsx
  74. 15 6
      packages/semi-ui/modal/ModalContent.tsx
  75. 0 43
      packages/semi-ui/modal/ModalTransition.tsx
  76. 1 17
      packages/semi-ui/modal/__test__/modal.test.js
  77. 1 1
      packages/semi-ui/modal/_story/CollapsibleInModal/index.jsx
  78. 201 152
      packages/semi-ui/modal/_story/modal.stories.js
  79. 286 218
      packages/semi-ui/navigation/_story/navigation.stories.js
  80. 195 162
      packages/semi-ui/notification/_story/notification.stories.js
  81. 313 254
      packages/semi-ui/overflowList/_story/overflowList.stories.js
  82. 7 7
      packages/semi-ui/package.json
  83. 124 107
      packages/semi-ui/pagination/_story/pagination.stories.js
  84. 112 79
      packages/semi-ui/popconfirm/_story/popconfirm.stories.js
  85. 523 456
      packages/semi-ui/popover/_story/popover.stories.js
  86. 68 47
      packages/semi-ui/progress/_story/progress.stories.js
  87. 812 634
      packages/semi-ui/radio/_story/radio.stories.js
  88. 83 69
      packages/semi-ui/rating/_story/rating.stories.js
  89. 20 9
      packages/semi-ui/scrollList/_story/scrolllist.stories.js
  90. 2620 2418
      packages/semi-ui/select/_story/select.stories.js
  91. 336 311
      packages/semi-ui/sideSheet/_story/sideSheet.stories.js
  92. 67 58
      packages/semi-ui/skeleton/_story/skeleton.stories.js
  93. 365 246
      packages/semi-ui/slider/_story/slider.stories.js
  94. 3 2
      packages/semi-ui/slider/index.tsx
  95. 242 214
      packages/semi-ui/space/_story/space.stories.js
  96. 76 52
      packages/semi-ui/spin/_story/spin.stories.js
  97. 2 2
      packages/semi-ui/spin/index.tsx
  98. 258 214
      packages/semi-ui/steps/_story/steps.stories.js
  99. 144 108
      packages/semi-ui/switch/_story/switch.stories.js
  100. 25 17
      packages/semi-ui/table/Body/index.tsx

+ 46 - 0
.github/workflows/chromatic.yml

@@ -0,0 +1,46 @@
+# .github/workflows/chromatic.yml
+
+# Workflow name
+name: 'test:chromatic'
+
+# Event for the workflow
+on:
+  pull_request:
+    branches: [ main, release, test-chromatic ]
+    paths:
+      - 'packages/**/*.scss'
+      - '!packages/**/_story/**'
+      - '!packages/**/__test__/**'
+      - '!packages/**/*.stories.[tj]sx?'
+      - '!packages/**/*.story.[tj]sx?'
+      - '!packages/**/*.test.[tj]sx?'
+      - '!packages/**/*.md'
+  push:
+    branches: [ test-chromatic ]
+    paths:
+      - 'packages/**/*.scss'
+      - '!packages/**/*.md'
+
+# List of jobs
+jobs:
+  chromatic-deployment:
+    # Operating System
+    runs-on: ubuntu-latest
+    # Job steps
+    steps:
+      - uses: actions/checkout@v1
+      - uses: actions/setup-node@v2
+        with:
+          node-version: '14'
+      - name: Install dependencies
+        run: npx lerna bootstrap
+      - name: Pre-build libs
+        run: npx lerna run build:lib
+      - name: Publish to Chromatic
+        uses: chromaui/action@v1
+        # Chromatic GitHub Action options
+        with:
+          token: ${{ secrets.GITHUB_TOKEN }}
+          # 👇 Chromatic projectToken, refer to the manage page to obtain it.
+          projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
+          buildScriptName: 'build-storybook'

+ 10 - 1
README-zh_CN.md

@@ -9,7 +9,8 @@
     
 <div align="center">
 
-[![NPM][npm-badge]][npm-url] [![FIGMA][figma-badge]][figma-url] [![LICENSE][license-badge]][license-url] [![CODECOV][codecov-badge]][codecov-url]
+[![NPM][npm-badge]][npm-url] [![FIGMA][figma-badge]][figma-url] [![LICENSE][license-badge]][license-url] 
+[![CODECOV][codecov-badge]][codecov-url] [![Chromatic][chromatic-badge]][chromatic-url]
 
 
 [npm-badge]: https://img.shields.io/npm/v/@douyinfe/semi-ui.svg
@@ -21,6 +22,8 @@
 [license-url]: https://github.com/DouyinFE/semi-design/blob/main/LICENSE
 [codecov-badge]: https://img.shields.io/codecov/c/gh/DouyinFE/semi-design
 [codecov-url]: https://app.codecov.io/gh/DouyinFE/semi-design
+[chromatic-badge]: https://img.shields.io/badge/test-chromatic-f52
+[chromatic-url]: https://www.chromatic.com/
 
 </div>
 
@@ -106,6 +109,12 @@ Semi UI 支持所有主流浏览器。
 
 加入[用户群](https://bytedance.feishu.cn/docs/doccnw93Dujm3UCkHRDTMTm1qwe#).
 
+# 💖 Thanks
+
+<a href="https://www.chromatic.com/"><img src="https://user-images.githubusercontent.com/321738/84662277-e3db4f80-af1b-11ea-88f5-91d67a5e59f6.png" width="153" height="30" alt="Chromatic" /></a>
+
+感谢 [Chromatic](https://www.chromatic.com/) 提供可视化测试平台,帮助我们审查 UI 更改和提供视觉回归测试。
+
 # 🎈 协议
 
 Semi UI 使用 [MIT 协议](LICENSE)

+ 10 - 1
README.md

@@ -9,7 +9,8 @@
     
 <div align="center">
 
-[![NPM][npm-badge]][npm-url] [![FIGMA][figma-badge]][figma-url] [![LICENSE][license-badge]][license-url] [![CODECOV][codecov-badge]][codecov-url]
+[![NPM][npm-badge]][npm-url] [![FIGMA][figma-badge]][figma-url] [![LICENSE][license-badge]][license-url]
+[![CODECOV][codecov-badge]][codecov-url] [![Chromatic][chromatic-badge]][chromatic-url]
 
 
 [npm-badge]: https://img.shields.io/npm/v/@douyinfe/semi-ui.svg
@@ -21,6 +22,8 @@
 [license-url]: https://github.com/DouyinFE/semi-design/blob/main/LICENSE
 [codecov-badge]: https://img.shields.io/codecov/c/gh/DouyinFE/semi-design
 [codecov-url]: https://app.codecov.io/gh/DouyinFE/semi-design
+[chromatic-badge]: https://img.shields.io/badge/test-chromatic-f52
+[chromatic-url]: https://www.chromatic.com/
 
 </div>
 
@@ -104,6 +107,12 @@ See [CONTRIBUTING](CONTRIBUTING-en-US.md) documentation.
 
 Join [User Group](https://bytedance.feishu.cn/docs/doccnw93Dujm3UCkHRDTMTm1qwe#).
 
+# 💖 Thanks
+
+<a href="https://www.chromatic.com/"><img src="https://user-images.githubusercontent.com/321738/84662277-e3db4f80-af1b-11ea-88f5-91d67a5e59f6.png" width="153" height="30" alt="Chromatic" /></a>
+
+Thanks to [Chromatic](https://www.chromatic.com/) for providing the visual testing platform that helps us review UI changes and catch visual regressions.
+
 # 🎈 License
 
 Semi UI is [MIT Licensed](LICENSE)

+ 1 - 1
content/feedback/spin/index-en-US.md

@@ -157,7 +157,7 @@ import { Spin } from '@douyinfe/semi-ui';
 | size             | Size, one of `small`, `middle`, `large`                   | string     | `middle` |
 | spinning         | Toggle whether it is in loading                           | boolean    | true     |
 | style            | Inline style                                              | CSSProperties     | -        |
-| tip              | Description texts when Spin is used as a wrapping element | string     | -        |
+| tip              | Description texts when Spin is used as a wrapping element | ReactNode     | -        |
 | wrapperClassName | Class name of wrapping element                            | string     | -        |
 
 ## Design Tokens

+ 1 - 1
content/feedback/spin/index.md

@@ -132,7 +132,7 @@ import { Spin, Button } from '@douyinfe/semi-ui';
 | size             | 组件大小,可选值为 `small`, `middle`, `large` | string     | `middle` |
 | spinning         | 是否处于加载中的状态                          | boolean    | true     |
 | style            | 内联样式                                      | CSSProperties     | -        |
-| tip              | 当 spin 作为包裹元素时,可以自定义描述文字    | string     | 无       |
+| tip              | 当 spin 作为包裹元素时,可以自定义描述文字    | ReactNode     | 无       |
 | wrapperClassName | 包裹元素的类名                                | string     | 无       |
 
 ## 设计变量

+ 2 - 2
content/navigation/navigation/index-en-US.md

@@ -727,7 +727,7 @@ function NavApp (props = {}) {
 | icon         | Navigation project icon name or component                                                                         | ReactNode                                                            |          |         |
 | indent       | If the icon is empty, keep its space or not. Only effective for first level navigation                            | boolean                                                              | false    |         |
 | itemKey      | Navigation project only key                                                                                       | string                                                               | ""       |         |
-| level        | The nesting level of the current item. When limitIndent is true, it is used to customize the indentation position | number                                                               | 1.27.0   |
+| level        | The nesting level of the current item. When limitIndent is true, it is used to customize the indentation position | number                                                               |          | 1.27.0  |
 | link         | Navigation item href link, when imported, the navigation item will be wrapped with an a tag                       | string                                                               | -        | 1.0.0   |
 | linkOptions  | Parameters transparently passed to the a tag                                                                      | object                                                               | -        | 1.0.0   |
 | text         | Navigation project copy or element                                                                                | string \| ReactNode                                                  | ""       |         |
@@ -771,7 +771,7 @@ function NavApp (props = {}) {
 | children       | Sub element                                                                                                                       | ReactNode                                 |         |         |
 | className      | Outermost style name                                                                                                              | string                                    |         |         |
 | collapseButton | Do you show the bottom "put away the sidebar" button, mode = "vertical" and the child parameter of the Footer component is empty? | boolean\|ReactNode                        | false   |         |
-| collapseText   | Title of the collapse button                                                                                                      | (collapsed?:boolean) => string\|ReactNode |         | 0.35.0  |
+| collapseText   | Title of the collapse button                                                                                                      | (collapsed:boolean) => string\|ReactNode |         | 0.35.0  |
 | style          | Outermost style                                                                                                                   | object                                    |         |         |
 
 ## Design Tokens

+ 4 - 4
content/navigation/navigation/index.md

@@ -528,7 +528,7 @@ class NavApp extends React.Component {
                 defaultOpenKeys={['job']}
                 bodyStyle={{ height: 320 }}
                 items={[
-                    { itemKey: 'user', text: '用户管理', icon: 'user' },
+                    { itemKey: 'user', text: '用户管理', icon: <IconUser /> },
                     {
                         text: '任务平台',
                         icon: <IconSetting />,
@@ -730,7 +730,7 @@ function NavApp (props = {}) {
 | icon        | 导航项目图标                             | ReactNode |      |               |
 | indent      | 如果 icon 为空,是否保留其占位,仅对一级导航生效       | boolean           | false  |               |
 | itemKey     | 导航项目唯一 key                                   | string            | ""     |               |
-| level       | 当前项所在嵌套层级,limitIndent 为 true时,用于自定义缩进位置| number | 1.27.0 |
+| level       | 当前项所在嵌套层级,limitIndent 为 true时,用于自定义缩进位置| number | | 1.27.0 | 
 | link        | 导航项 href 链接,传入时导航项整体会包裹一个 a 标签 | string            | -      | 1.0.0 |
 | linkOptions | 透传给 a 标签的参数                                | object            | -      | 1.0.0 |
 | text        | 导航项目文案或元素                                 | string\|ReactNode | ""     |               |
@@ -774,7 +774,7 @@ function NavApp (props = {}) {
 | children       | 子元素                                                                                   | ReactNode                                 |        |                |
 | className      | 最外层样式名                                                                             | string                                    |        |                |
 | collapseButton | 是否展示底部“收起侧边栏”按钮,mode="vertical" 且 Footer 组件的 children 参数为空才有效果 | boolean\|ReactNode                        | false  |                |
-| collapseText   | “收起”按钮的文案                                                                         | (collapsed?:boolean) => string\|ReactNode |        | 0.35.0 |
+| collapseText   | “收起”按钮的文案                                                                         | (collapsed:boolean) => string\|ReactNode |        | 0.35.0 |
 | style          | 最外层样式                                                                               | CSSProperties                                    |        |                |
 
 ## 设计变量
@@ -788,4 +788,4 @@ function NavApp (props = {}) {
 ## FAQ
 
 -   **导航动画丢失?**  
-    在使用函数式组件时,应该用 useState 或者 useMemo 包裹一下 items,原因是 items 直接传一个数组会触发组件重新渲染。
+    在使用函数式组件时,应该用 useState 或者 useMemo 包裹一下 items,原因是 items 直接传一个数组会触发组件重新渲染。

+ 2 - 2
content/show/table/index.md

@@ -821,8 +821,8 @@ render(CustomDropdownItem);
 
 > 注意:
 >
-> -   自 0.27.0版本后,展开按钮会默认与第一列文案渲染在同一个单元格内,你可以通过往Table传入 hideExpandedColumn={false} 将展开按钮单独作为一列渲染。
-> -   请务必为每行数据提供一个与其他行值不同的 "key",或者使用 rowKey 参数指定一个作为主键的属性名。
+> - 自 0.27.0版本后,展开按钮会默认与第一列文案渲染在同一个单元格内,你可以通过往Table传入 `hideExpandedColumn={false}` 将展开按钮单独作为一列渲染。
+> - 请务必为每行数据提供一个与其他行值不同的 `key`,或者使用 rowKey 参数指定一个作为主键的属性名。
 
 #### 一般可展开行
 

+ 21 - 0
content/start/changelog/index-en-US.md

@@ -16,6 +16,27 @@ Version:Major.Minor.Patch
 
 ---
 
+#### 🎉 2.0.8 (2021-11-11)
+- 【Fix】
+  - Fix Modal afterClose not work in some scenario.
+
+#### 🎉 2.0.7 (2021-11-10)
+- 【Fix】
+  - semi-icons add dependencies `classnames` [#231](https://github.com/DouyinFE/semi-design/issues/231)
+- 【Style】
+  - Table Fixed the problem of table misalignment when there is a fixed column/header scenario, all columns are not set to width [#247](https://github.com/DouyinFE/semi-design/issues/247)
+
+
+#### 🎉 2.0.6 (2021-11-10)
+- 【Style】
+  - Table removed scrollbar column when there is a fixed column/header scenario by using the `overflow-y` to simulate the scrollbar [#164](https://github.com/DouyinFE/semi-design/issues/164)
+
+#### 🎉 2.0.5 (2021-11-09)
+- 【Style】
+   - Fixed the border style issue when the Input component is hover [#204](https://github.com/DouyinFE/semi-design/issues/204)
+- 【Perf】
+   - Modal uses CSS animation to optimize the animation effect when opening and closing [#236](https://github.com/DouyinFE/semi-design/issues/236)
+
 #### 🎉 2.0.4 (2021-11-08)
 - 【Fix】
    - Fixed Cascader single selection, the problem that the `defaultValue` is disabled when the node is selected will be filtered [#183](https://github.com/DouyinFE/semi-design/issues/183)

+ 22 - 0
content/start/changelog/index.md

@@ -15,6 +15,28 @@ Semi 版本号遵循**Semver**规范(主版本号-次版本号-修订版本号
 
 ---
 
+#### 🎉 2.0.8 (2021-11-11)
+- 【Fix】
+  - 修复 Modal afterClose 部分场景失效
+
+#### 🎉 2.0.7 (2021-11-10)
+- 【Fix】
+  - 修复 Icon 包缺少 classnames 依赖问题 [#231](https://github.com/DouyinFE/semi-design/issues/231)
+- 【Style】
+  - Table 修复了固定列/表头场景,所有列均不设置宽度时表格对不齐问题 [#247](https://github.com/DouyinFE/semi-design/issues/247)
+
+
+#### 🎉 2.0.6 (2021-11-10)
+- 【Style】
+  - Table 移除固定列/固定表头时在表头插入的滚动轴列,使用 overflow-y 方案模拟滚动轴 [#164](https://github.com/DouyinFE/semi-design/issues/164)
+
+
+#### 🎉 2.0.5 (2021-11-09)
+- 【Style】
+  - 修复 Input 组件 hover 时 border 样式问题 [#204](https://github.com/DouyinFE/semi-design/issues/204)
+- 【Perf】
+  - Modal 使用 CSS 动画,优化打开和关闭时的动画效果 [#236](https://github.com/DouyinFE/semi-design/issues/236)
+
 #### 🎉 2.0.4 (2021-11-08)
 - 【Fix】
   - 修复 Cascader 单选时,defaultValue 为 disabled 节点时选中会被过滤的问题 [#183](https://github.com/DouyinFE/semi-design/issues/183)

+ 3 - 3
content/start/update-to-v2/index-en-US.md

@@ -75,9 +75,9 @@ import en_GB from '@douyinfe/semi-ui/lib/es/locale/source/en_GB'
 - Tooltip no longer supports the `disabled` attribute, and components that rely on Tooltip (such as Popover, Dropdown, etc.) transparently transmitted to Tooltip `disabled` will become invalid
 - Table
   - API that no longer responds when componentDidUpdate
-    - DefaultExpandAllRows, please replace with expandAllRows
-    - Default ExpandRowKeys, please replace with expandRowKeys
-    - Default ExpandAllGroupRows, please replace with expandAllGroupRows
+    - defaultExpandAllRows, please replace with expandAllRows
+    - defaultExpandRowKeys, please replace with expandRowKeys
+    - defaultExpandAllGroupRows, please replace with expandAllGroupRows
 
 ### 🎨 Style incompatibility
 

+ 3 - 1
content/start/update-to-v2/index.md

@@ -66,7 +66,9 @@ import en_GB from '@douyinfe/semi-ui/lib/es/locale/source/en_GB'
   - 自定义 svg 不再支持插件方式配置 srcSvgPaths
   - Button icon 属性不再支持通过 string 传递内置 icon 或 iconType
   - Dropdown 删除 iconType 属性,统一为 icon 属性
-  - Navigation icon 不再支持通过 string 方式传入,需要传入 ReactNode
+  - Navigation 
+    - Nav.item组件, Nav.Sub组件 props.icon 不再支持通过 string 方式传入,需要传入 ReactNode 
+    - Nav 组件props.items 中的 icon也不再支持通过 string 方式传入,需要传入 ReactNode  
   - Notification icon 不再支持通过 string 方式传入,请统一使用 ReactNode
 - AutoComplete 正式废弃 onChangeWithObject 属性
 - Cascader triggerRender 的入参移除 onInputChange

+ 1 - 1
lerna.json

@@ -1,5 +1,5 @@
 {
     "useWorkspaces": true,
     "npmClient": "yarn",
-    "version": "2.0.4"
+    "version": "2.0.8"
 }

+ 1 - 0
package.json

@@ -136,6 +136,7 @@
     "babel-plugin-transform-require-context": "^0.1.1",
     "babel-runtime": "^6.26.0",
     "case-sensitive-paths-webpack-plugin": "^2.4.0",
+    "chromatic": "^6.0.6",
     "crypto": "^1.0.1",
     "css-loader": "^3.6.0",
     "enzyme": "^3.11.0",

+ 3 - 3
packages/semi-animation-react/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@douyinfe/semi-animation-react",
-  "version": "2.0.4",
+  "version": "2.0.8",
   "description": "motion library for semi-ui-react",
   "keywords": [
     "motion",
@@ -26,8 +26,8 @@
   },
   "dependencies": {
     "@babel/runtime-corejs3": "^7.15.4",
-    "@douyinfe/semi-animation": "2.0.4",
-    "@douyinfe/semi-animation-styled": "2.0.4",
+    "@douyinfe/semi-animation": "2.0.8",
+    "@douyinfe/semi-animation-styled": "2.0.8",
     "classnames": "^2.2.6"
   },
   "peerDependencies": {

+ 1 - 1
packages/semi-animation-styled/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@douyinfe/semi-animation-styled",
-  "version": "2.0.4",
+  "version": "2.0.8",
   "description": "semi styled animation",
   "keywords": [
     "semi",

+ 1 - 1
packages/semi-animation/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@douyinfe/semi-animation",
-  "version": "2.0.4",
+  "version": "2.0.8",
   "description": "animation base library for semi-ui",
   "keywords": [
     "animation",

+ 1 - 1
packages/semi-foundation/input/input.scss

@@ -60,7 +60,7 @@ $module: #{$prefix}-input;
 
     &:hover {
         background-color: $color-input_default-bg-hover;
-        border: $color-input_default-border-hover;
+        border-color: $color-input_default-border-hover;
     }
 
     // &:active {

+ 1 - 1
packages/semi-foundation/input/variables.scss

@@ -4,7 +4,7 @@ $color-input_default-bg-default: var(--semi-color-fill-0); // 输入框背景颜
 $color-input_default-text-default: var(--semi-color-text-0); // 输入框文本颜色 - 默认
 
 $color-input_default-bg-hover: var(--semi-color-fill-1); // 输入框背景颜色 - 悬浮
-$color-input_default-border-hover: $color-input_default-bg-hover; // 输入框描边颜色 - 悬浮
+$color-input_default-border-hover: transparent·; // 输入框描边颜色 - 悬浮
 
 $color-input_default-bg-active: var(--semi-color-fill-2); // 输入框背景颜色 - 按下
 $color-input_default-border-active: $color-input_default-bg-active; // 输入框描边颜色 - 按下

+ 1 - 1
packages/semi-foundation/modal/constants.ts

@@ -14,4 +14,4 @@ const strings = {
 export {
     cssClasses,
     strings
-};
+};

+ 94 - 27
packages/semi-foundation/modal/modal.scss

@@ -8,7 +8,7 @@ $module: #{$prefix}-modal;
     position: relative;
     // width: 600px;
     margin: $spacing-modal-marginY $spacing-modal-marginX;
-
+    
     &-mask {
         position: fixed;
         top: $spacing-modal_mask-top;
@@ -19,18 +19,18 @@ $module: #{$prefix}-modal;
         height: 100%;
         // filter: alpha(opacity=50);
         z-index: $z-modal-mask;
-
+        
         &-hidden {
             display: none;
         }
     }
-
+    
     &-icon-wrapper {
         display: inline-flex;
         margin-right: $spacing-modal_icon_wrapper-marginRight;
         width: $width-icon-extra-large;
     }
-
+    
     &-wrap {
         position: fixed;
         overflow: auto;
@@ -42,7 +42,7 @@ $module: #{$prefix}-modal;
         -webkit-overflow-scrolling: touch;
         outline: 0;
     }
-
+    
     &-title {
         display: inline-flex;
         align-items: flex-start;
@@ -50,7 +50,7 @@ $module: #{$prefix}-modal;
         width: $width-modal_title;
         margin: $spacing-modal_title-margin;
     }
-
+    
     &-content {
         position: relative;
         display: flex;
@@ -66,17 +66,17 @@ $module: #{$prefix}-modal;
         overflow: hidden;
         @include shadow-elevated;
     }
-
+    
     &-content-fullScreen {
         border-radius: $radius-modal_content_fullscreen;
         border: none;
     }
-
+    
     // &-close {
     // position: absolute;
     // right: 15px;
     // }
-
+    
     &-header {
         display: flex;
         align-items: flex-start;
@@ -87,24 +87,24 @@ $module: #{$prefix}-modal;
         color: $color-modal_main-text;
         border-bottom: $width-modal_header-border solid $color-modal_header-border;
     }
-
+    
     &-body-wrapper {
         display: flex;
         align-items: flex-start;
         margin: $spacing-modal_body_wrapper-marginY $spacing-modal_body_wrapper-marginX;
     }
-
+    
     &-body {
         flex: 1 1 auto;
         // padding: $spacing-loose;
         margin: $spacing-modal_body-margin;
         padding: $spacing-modal_body-padding;
     }
-
+    
     &-withIcon {
         margin-left: $spacing-modal_content_withicon-marginLeft;
     }
-
+    
     &-footer {
         // padding: $spacing-loose;
         margin: $spacing-modal_footer-marginY $spacing-modal_footer-marginX;
@@ -112,62 +112,62 @@ $module: #{$prefix}-modal;
         text-align: right;
         border-radius: $radius-modal_footer;
         border-top: $width-modal_footer-border solid $color-modal_footer-border;
-
+        
         .#{$prefix}-button {
             margin-left: $spacing-modal_footer_button-marginLeft;
             margin-right: 0;
         }
     }
-
+    
     &-confirm {
         .#{$module}-header {
             margin-bottom: $spacing-modal_confirm_header-marginBottom;
         }
-
+        
         // &-content-withIcon {
         // margin-left: 36px;
         // }
-
+        
         &-icon-wrapper {
             display: inline-flex;
             margin-right: $spacing-modal_confirm_icon_wrapper-marginRight;
             width: $width-icon-extra-large;
         }
-
+        
         &-icon {
             display: inline-flex;
             color: $color-modal_primary-icon;
         }
     }
-
+    
     &-info-icon {
         color: $color-modal_info-icon;
     }
-
+    
     &-success-icon {
         color: $color-modal_success-icon;
     }
-
+    
     &-error-icon {
         color: $color-modal_danger-icon;
     }
-
+    
     &-warning-icon {
         color: $color-modal_warning-icon;
     }
-
+    
     &-small {
         width: $width-modal_small;
     }
-
+    
     &-medium {
         width: $width-modal_medium;
     }
-
+    
     &-large {
         width: $width-modal_large;
     }
-
+    
     &-full-width {
         width: $width-modal_full_width;
     }
@@ -193,8 +193,75 @@ $module: #{$prefix}-modal;
     }
 }
 
-.#{$module}-hidden {
+.#{$module}-displayNone {
     display: none;
 }
 
+.#{$module}-content-animate-hide {
+    animation: 90ms #{$module}-content-keyframe-hide ease forwards;
+}
+
+.#{$module}-content-animate-show {
+    animation: 120ms #{$module}-content-keyframe-show cubic-bezier(0, 0, 0.26, 1.38) forwards;
+}
+
+.#{$module}-mask-animate-hide {
+    animation: 90ms #{$module}-mask-keyframe-hide ease forwards;
+}
+
+.#{$module}-mask-animate-show {
+    animation: 90ms #{$module}-mask-keyframe-show ease forwards;
+}
+
+
+@keyframes #{$module}-content-keyframe-show {
+    
+    0% {
+        opacity: 0;
+        transform: scale(0.7);
+    }
+    
+    100% {
+        opacity: 1;
+        transform: scale(1);
+    }
+}
+
+@keyframes #{$module}-content-keyframe-hide {
+    
+    0% {
+        opacity: 1;
+        transform: scale(1);
+    }
+    
+    100% {
+        opacity: 0;
+        transform: scale(0.7);
+    }
+}
+
+
+@keyframes #{$module}-mask-keyframe-show {
+    
+    0% {
+        opacity: 0;
+    }
+    
+    100% {
+        opacity: 1;
+    }
+}
+
+@keyframes #{$module}-mask-keyframe-hide {
+    
+    0% {
+        opacity: 1;
+    }
+    
+    100% {
+        opacity: 0;
+    }
+}
+
+
 @import "./rtl.scss";

+ 6 - 3
packages/semi-foundation/modal/modalContentFoundation.ts

@@ -2,17 +2,20 @@ import BaseFoundation, { DefaultAdapter } from '../base/foundation';
 import KeyCode from '../utils/keyCode';
 import { ModalProps } from '../modal/modalFoundation';
 
-export interface ModalContentProps extends ModalProps{
+export interface ModalContentProps extends ModalProps {
     onClose: (e: any) => void;
     getContainerContext: () => any;
     isFullScreen?: boolean;
+    contentClassName?: string,
+    maskClassName?: string;
+    onAnimationEnd?: () => void;
 }
 
-export interface ModalContentState{
+export interface ModalContentState {
     dialogMouseDown: boolean;
 }
 
-export interface ModalContentAdapter extends DefaultAdapter<ModalContentProps, ModalContentState>{
+export interface ModalContentAdapter extends DefaultAdapter<ModalContentProps, ModalContentState> {
     notifyClose: (e: any) => void;
     notifyDialogMouseDown: () => void;
     notifyDialogMouseUp: () => void;

+ 29 - 30
packages/semi-foundation/modal/modalFoundation.ts

@@ -1,17 +1,16 @@
-import { get } from 'lodash-es';
 import BaseFoundation, { DefaultAdapter } from '../base/foundation';
 import { Motion } from '../utils/type';
 
 export type OKType = 'primary' | 'secondary' | 'tertiary' | 'warning' | 'danger';
 export type Size = 'small' | 'medium' | 'large' | 'full-width';
 
-export interface ModalAdapter extends DefaultAdapter<ModalProps, ModalState>{
+export interface ModalAdapter extends DefaultAdapter<ModalProps, ModalState> {
     disabledBodyScroll: () => void;
     enabledBodyScroll: () => void;
     notifyCancel: (e: any) => void;
     notifyOk: (e: any) => void;
     notifyClose: () => void;
-    toggleHidden: (hidden: boolean) => void;
+    toggleHidden: (hidden: boolean, callback?: (hidden: boolean) => void) => void;
     notifyFullScreen: (isFullScreen: boolean) => void;
     getProps: () => ModalProps;
 }
@@ -95,33 +94,33 @@ export default class ModalFoundation extends BaseFoundation<ModalAdapter> {
     }
 
 
-    toggleHidden = (hidden: boolean) => {
-        this._adapter.toggleHidden(hidden);
+    toggleHidden = (hidden: boolean, callback?: (hidden: boolean) => void) => {
+        this._adapter.toggleHidden(hidden, callback);
     };
 
-    // eslint-disable-next-line max-len
-    mergeMotionProp = (motion: Motion, prop: string, cb: () => void) => {
-        const mergedMotion = typeof (motion) === 'undefined' || motion ? {
-            ...(motion as { [key: string]: (() => void) | boolean }),
-            [prop]: (...args: any) => {
-                const curr = get(motion, prop);
-                if (typeof curr === 'function') {
-                    curr(...args);
-                }
-                cb();
-            }
-        } : false;
-        return mergedMotion;
-    };
-
-    getMergedMotion() {
-        let { motion } = this._adapter.getProps();
-        const { keepDOM } = this._adapter.getProps();
-        motion = this.mergeMotionProp(motion, 'didLeave', this.afterClose.bind(this));
-        if (!keepDOM) {
-            return motion;
-        }
-        const mergedMotion = this.mergeMotionProp(motion, 'didLeave', this.toggleHidden.bind(this, true));
-        return mergedMotion;
-    }
+    // // eslint-disable-next-line max-len
+    // mergeMotionProp = (motion: Motion, prop: string, cb: () => void) => {
+    //     const mergedMotion = typeof (motion) === 'undefined' || motion ? {
+    //         ...(motion as { [key: string]: (() => void) | boolean }),
+    //         [prop]: (...args: any) => {
+    //             const curr = get(motion, prop);
+    //             if (typeof curr === 'function') {
+    //                 curr(...args);
+    //             }
+    //             cb();
+    //         }
+    //     } : false;
+    //     return mergedMotion;
+    // };
+    //
+    // getMergedMotion() {
+    //     let { motion } = this._adapter.getProps();
+    //     const { keepDOM } = this._adapter.getProps();
+    //     motion = this.mergeMotionProp(motion, 'didLeave', this.afterClose.bind(this));
+    //     if (!keepDOM) {
+    //         return motion;
+    //     }
+    //     const mergedMotion = this.mergeMotionProp(motion, 'didLeave', this.toggleHidden.bind(this, true));
+    //     return mergedMotion;
+    // }
 }

+ 1 - 1
packages/semi-foundation/modal/rtl.scss

@@ -12,7 +12,7 @@ $module: #{$prefix}-modal;
             margin-right: 0;
             margin-left: $spacing-modal_confirm_icon_wrapper-marginRight;
         }
-        
+
     }
 
     &-withIcon {

+ 2 - 6
packages/semi-foundation/package.json

@@ -1,18 +1,14 @@
 {
     "name": "@douyinfe/semi-foundation",
-    "version": "2.0.4",
+    "version": "2.0.8",
     "description": "",
-    "files": [
-        "lib",
-        "README.md"
-    ],
     "scripts": {
         "build:lib": "node ./scripts/compileLib.js",
         "prepublishOnly": "npm run build:lib"
     },
     "dependencies": {
         "@babel/runtime-corejs3": "^7.15.4",
-        "@douyinfe/semi-animation": "2.0.4",
+        "@douyinfe/semi-animation": "2.0.8",
         "async-validator": "^3.5.0",
         "classnames": "^2.2.6",
         "date-fns": "^2.9.0",

+ 1 - 1
packages/semi-foundation/radio/variables.scss

@@ -48,7 +48,7 @@ $width-radio_hover-border: $border-thickness-control; // 描边宽度 - 悬浮
 $width-radio_disabled-border: $border-thickness-control; // 描边宽度 - 禁用态
 $width-radio_innder-border: $border-thickness-control; // 描边宽度 - 禁用态
 
-$height-radio_inner_min: $spacing-base-loose; // 单选按钮高度
+$height-radio_inner_min: 20px; // 单选按钮高度
 $width-radio_inner: $width-icon-medium; // 单选按钮宽度
 $spacing-radio_addon-paddingLeft: $spacing-tight; //单选标题到单选按钮左侧边距
 $spacing-radio_addon-marginLeft: $width-radio_inner; //单选标题左侧整体外边距

+ 4 - 4
packages/semi-foundation/slider/foundation.ts

@@ -79,7 +79,7 @@ export interface SliderAdapter extends DefaultAdapter<SliderProps, SliderState>{
     getMinHandleEl: () => { current: HTMLElement };
     getMaxHandleEl: () => { current: HTMLElement };
     onHandleDown: (e: any) => any;
-    onHandleMove: (mousePos: number, isMin: boolean, stateChangeCallback?: () => void) => boolean | void;
+    onHandleMove: (mousePos: number, isMin: boolean, stateChangeCallback?: () => void, clickTrack?: boolean) => boolean | void;
     setEventDefault: (e: any) => void;
     setStateVal: (state: keyof SliderState, value: any) => void;
     onHandleEnter: (position: SliderState['focusPos']) => void;
@@ -568,7 +568,7 @@ export default class SliderFoundation extends BaseFoundation<SliderAdapter> {
         const mousePos = this.handleMousePos(e.pageX, e.pageY);
         const position = vertical ? mousePos.y : mousePos.x;
         const isMin = this.checkWhichHandle(position);
-        this.setHandlePos(position, isMin);
+        this.setHandlePos(position, isMin, true);
     };
 
     /**
@@ -576,8 +576,8 @@ export default class SliderFoundation extends BaseFoundation<SliderAdapter> {
      *
      * @memberof SliderFoundation
      */
-    setHandlePos = (position: number, isMin: boolean) => {
-        this._adapter.onHandleMove(position, isMin, () => this._adapter.onHandleUpAfter());
+    setHandlePos = (position: number, isMin: boolean, clickTrack = false) => {
+        this._adapter.onHandleMove(position, isMin, () => this._adapter.onHandleUpAfter(), clickTrack);
     };
 
     /**

+ 1 - 11
packages/semi-foundation/table/bodyFoundation.ts

@@ -15,15 +15,6 @@ export default class TableBodyFoundation<P = Record<string, any>, S = Record<str
     init() {
         this.initVirtualizedData();
         this.initExpandBtnShouldInRow();
-
-        /**
-         * Use ResizeObserver to monitor changes in the size of the body content area, and notify Table to recalculate if it changes. columns #1219
-         * (Only monitor the scroll.y scene, other scenes are not monitored, because the header of the scroll.y scene is a separate table, and a scrollbar column will be inserted)
-         */
-        const { scroll } = this.getProps(); // TODO check: this._adapter.getProps -> this.getProps
-        if (get(scroll, 'y')) {
-            this.observeBodyResize();
-        }
     }
 
     destroy() {
@@ -120,9 +111,8 @@ export default class TableBodyFoundation<P = Record<string, any>, S = Record<str
     /**
      * Use ResizeObserver to monitor changes in the size of the body content area, and notify Table to recalculate if it changes. columns #1219
      * (Only monitor the scroll.y scene, other scenes are not monitored, because the header of the scroll.y scene is a separate table, and a scrollbar column will be inserted)
-     * @param {any} bodyDOM
      */
-    observeBodyResize(bodyDOM?: any) {
+    observeBodyResize(bodyDOM: any) {
         const { scroll } = this.getProps(); // TODO check: this._adapter.getProps -> this.getProps
         if (get(scroll, 'y')) {
             return this._adapter.observeBodyResize(bodyDOM);

+ 0 - 1
packages/semi-foundation/table/foundation.ts

@@ -107,7 +107,6 @@ class TableFoundation<RecordType> extends BaseFoundation<TableAdapter<RecordType
         cachedColumns: BaseColumnProps<RecordType>[], 
         rowSelectionUpdate: boolean, 
         hideExpandedColumn: boolean,
-        scrollbarColumnUpdate: boolean | string | number,
         bodyHasScrollBar: boolean,
     ) => BaseColumnProps<RecordType>[];
     memoizedFilterColumns: (columns: BaseColumnProps<RecordType>[], ignoreKeys?: string[]) => BaseColumnProps<RecordType>[];

+ 10 - 1
packages/semi-foundation/table/rtl.scss

@@ -112,6 +112,7 @@ $module: #{$prefix}-table;
         &-bordered {
             .#{$module}-container {
                 border-left: 0;
+                border-right: $border-table;
             }
 
             .#{$module}-thead > .#{$module}-row > .#{$module}-row-head,
@@ -121,9 +122,17 @@ $module: #{$prefix}-table;
             }
 
             .#{$module}-placeholder {
-                border-left: $width-table_base_border $border-table_base-borderStyle $color-table-border-default;
+                border-left: $border-table;
                 border-right: 0;
             }
+
+            .#{$module}-header {
+
+                &::-webkit-scrollbar {
+                    border-right: 0;
+                    border-left: $border-table;
+                }
+            }
         }
 
         &-fixed {

+ 25 - 3
packages/semi-foundation/table/table.scss

@@ -54,6 +54,12 @@ $module: #{$prefix}-table;
 
     &-header {
         overflow: hidden;
+
+        &::-webkit-scrollbar {
+            background-color: transparent;
+            border-bottom: $border-table_head-bottom;
+        }
+        scrollbar-base-color: transparent;
     }
 
     &-body {
@@ -83,7 +89,7 @@ $module: #{$prefix}-table;
                 color: $color-table_th-text-default;
                 font-weight: $font-weight-bold;
                 text-align: left;
-                border-bottom: #{$width-table_header_border} #{$border-table_base-borderStyle} $color-table_th-border-default;
+                border-bottom: $border-table_head-bottom;
                 padding-left: $spacing-table_row_head-paddingX;
                 padding-right: $spacing-table_row_head-paddingX;
                 padding-top: $spacing-table_row_head-paddingY;
@@ -420,11 +426,18 @@ $module: #{$prefix}-table;
         }
 
         .#{$module}-container {
-            border: #{$width-table_base_border} #{$border-table_base-borderStyle} $color-table-border-default;
+            border: $border-table;
             border-right: 0;
             border-bottom: 0;
         }
 
+        .#{$module}-header {
+
+            &::-webkit-scrollbar {
+                border-right: $border-table;
+            }
+        }
+
         .#{$module}-footer {
             border-left: $border-table;
             border-right: $border-table;
@@ -444,7 +457,7 @@ $module: #{$prefix}-table;
         }
 
         .#{$module}-placeholder {
-            border-right: $width-table_base_border $border-table_base-borderStyle $color-table-border-default;
+            border-right: $border-table;
         }
     }
 
@@ -462,6 +475,7 @@ $module: #{$prefix}-table;
 
     &-fixed {
         table-layout: fixed;
+        min-width: 100%;
 
         & > .#{$module}-tbody {
             & > .#{$module}-row-expand > .#{$module}-row-cell > .#{$module}-expand-inner,
@@ -478,6 +492,14 @@ $module: #{$prefix}-table;
                 align-items: center;
             }
         }
+
+        // when header is fixed, table should use `table-layout: fixed` to avoid align bug
+        &-header {
+
+            table {
+                table-layout: fixed;
+            }
+        }
     }
 
     &-scroll {

+ 1 - 0
packages/semi-foundation/table/variables.scss

@@ -80,4 +80,5 @@ $border-table_base-borderStyle: solid; // 表格描边样式
 $shadow-table_left: -3px 0 0 0 $color-table_shadow-bg-default; // 表格滚动阴影 - 左侧
 $shadow-table_right: 3px 0 0 0 $color-table_shadow-bg-default; // 表格滚动阴影 - 右侧
 $border-table: #{$width-table_base_border} #{$border-table_base-borderStyle} $color-table-border-default; // 表格默认描边
+$border-table_head-bottom: #{$width-table_header_border} #{$border-table_base-borderStyle} $color-table_th-border-default; // 表头单元格描边 - 底部
 $border-table_resizer: $width-table_resizer_border solid $color-table_resizer-bg-default; // 表格拉伸标识描边

+ 1 - 1
packages/semi-icons/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@douyinfe/semi-icons",
-  "version": "2.0.4",
+  "version": "2.0.8",
   "description": "semi icons",
   "keywords": [
     "semi",

+ 1 - 1
packages/semi-illustrations/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@douyinfe/semi-illustrations",
-  "version": "2.0.4",
+  "version": "2.0.8",
   "description": "semi illustrations",
   "keywords": [
     "semi",

+ 1 - 1
packages/semi-scss-compile/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@douyinfe/semi-scss-compile",
-  "version": "2.0.4",
+  "version": "2.0.8",
   "description": "compile semi scss to css",
   "author": "[email protected]",
   "license": "MIT",

+ 1 - 1
packages/semi-theme-default/package.json

@@ -1,6 +1,6 @@
 {
     "name": "@douyinfe/semi-theme-default",
-    "version": "2.0.4",
+    "version": "2.0.8",
     "description": "semi-theme-default",
     "keywords": [
         "semi-theme",

+ 1 - 1
packages/semi-ui/_base/_story/index.scss

@@ -11,4 +11,4 @@ body {
     #root {
         padding: 20px;
     }
-}
+}

+ 107 - 94
packages/semi-ui/_base/_story/index.stories.js

@@ -1,105 +1,118 @@
 import React, { useMemo } from 'react';
-import { storiesOf } from '@storybook/react';
 import { Button, Typography, Card, Tooltip, Tag, Avatar, Rating, Nav, Layout } from '../../index';
 import { IconHelpCircle, IconUser, IconStar, IconSetting } from '@douyinfe/semi-icons';
 import './index.scss';
 
-const stories = storiesOf('All', module);
+export default {
+  title: 'Base',
+};
 
-stories.add('test always dark/light', () => {
-    function Demo() {
-        const { Text } = Typography;
-        const { Header, Footer, Sider, Content } = Layout;
+export {
+  TestAlwaysDarkLight
+};
 
-        const switchMode = () => {
-            const body = document.body;
-            if (body.hasAttribute('theme-mode')) {
-                body.removeAttribute('theme-mode');
-                // 通知官网更新当前模式,下同
-                // window.setMode("light");
-            } else {
-                body.setAttribute('theme-mode', 'dark');
-                // window.setMode("dark");
-            }
-        };
-        const opts = {
-            content: 'Hi, Bytedance dance dance',
-            duration: 3,
-        };
+const TestAlwaysDarkLight = () => {
+  function Demo() {
+    const { Text } = Typography;
+    const { Header, Footer, Sider, Content } = Layout;
 
-        const blocks = title => (
-            <Layout>
-                <Header style={{ height: 60 }}>Header</Header>
-                <Layout style={{ height: 'calc(100vh - 260px)' }}>
-                    <Sider style={{ background: 'var(--semi-color-white)' }}>
-                        <div class="semi-always-light">
-                            <Nav
-                                style={{ background: 'var(--semi-color-white)' }}
-                                // bodyStyle={{ height: '100%' }}
-                                items={[
-                                    { itemKey: 'user', text: '用户管理', icon: <IconUser /> },
-                                    { itemKey: 'union', text: '公会中心', icon: <IconStar /> },
-                                    {
-                                        text: '任务平台',
-                                        icon: <IconSetting />,
-                                        itemKey: 'job',
-                                        items: ['任务管理', '用户任务查询'],
-                                    },
-                                ]}
-                                onSelect={data => console.log('trigger onSelect: ', data)}
-                                onClick={data => console.log('trigger onClick: ', data)}
-                            />
-                        </div>
-                    </Sider>
-                    <Content>
-                      <Card
-                          title={`Semi Design ${title}`}
-                          style={{ maxWidth: 360, marginRight: 12 }}
-                          headerExtraContent={<Text link>更多</Text>}
-                      >
-                          Semi Design 是由互娱社区前端团队与 UED
-                          团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的
-                          Web 应用。
-                          <Tooltip content={'hi bytedance'}>
-                              <IconHelpCircle />
-                          </Tooltip>
-                      </Card>
-                      <div>
-                          <div>
-                              <Avatar style={{ margin: 4 }}>AS</Avatar>
-                              <Avatar color="red" style={{ margin: 4 }}>
-                                  BM
-                              </Avatar>
-                              <Avatar color="light-blue" style={{ margin: 4 }}>
-                                  TJ
-                              </Avatar>
-                              <Avatar style={{ color: '#f56a00', backgroundColor: '#fde3cf', margin: 4 }}>
-                                  ZL
-                              </Avatar>
-                              <Avatar style={{ backgroundColor: '#87d068', margin: 4 }}>YZ</Avatar>
-                          </div>
-                          <Tag> default tag </Tag>
-                          <Rating defaultValue={5} />
-                      </div>
-                    </Content>
-                </Layout>
-                <Footer style={{ height: 200, background: 'var(--semi-color-black)', color: 'var(--semi-color-white)' }}>Footer</Footer>
-            </Layout>
-        );
+    const switchMode = () => {
+      const body = document.body;
+      if (body.hasAttribute('theme-mode')) {
+        body.removeAttribute('theme-mode');
+        // 通知官网更新当前模式,下同
+        // window.setMode("light");
+      } else {
+        body.setAttribute('theme-mode', 'dark');
+        // window.setMode("dark");
+      }
+    };
+    const opts = {
+      content: 'Hi, Bytedance dance dance',
+      duration: 3,
+    };
 
-        return (
-            <div className="container">
-                <div>
-                    <Button onClick={switchMode}>Switch Mode</Button>
-                </div>
-                <div>
-                    <div>{blocks('default')}</div>
-                    {/* <div id="semi-always-dark">{blocks('always dark')}</div>
-                    <div id="semi-always-light">{blocks('always light')}</div> */}
-                </div>
+    const blocks = title => (
+      <Layout>
+        <Header style={{ height: 60 }}>Header</Header>
+        <Layout style={{ height: 'calc(100vh - 260px)' }}>
+          <Sider style={{ background: 'var(--semi-color-white)' }}>
+            <div class="semi-always-light">
+              <Nav
+                style={{ background: 'var(--semi-color-white)' }}
+                // bodyStyle={{ height: '100%' }}
+                items={[
+                  { itemKey: 'user', text: '用户管理', icon: <IconUser /> },
+                  { itemKey: 'union', text: '公会中心', icon: <IconStar /> },
+                  {
+                    text: '任务平台',
+                    icon: <IconSetting />,
+                    itemKey: 'job',
+                    items: ['任务管理', '用户任务查询'],
+                  },
+                ]}
+                onSelect={data => console.log('trigger onSelect: ', data)}
+                onClick={data => console.log('trigger onClick: ', data)}
+              />
+            </div>
+          </Sider>
+          <Content>
+            <Card
+              title={`Semi Design ${title}`}
+              style={{ maxWidth: 360, marginRight: 12 }}
+              headerExtraContent={<Text link>更多</Text>}
+            >
+              Semi Design 是由互娱社区前端团队与 UED
+              团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的
+              Web 应用。
+              <Tooltip content={'hi bytedance'}>
+                <IconHelpCircle />
+              </Tooltip>
+            </Card>
+            <div>
+              <div>
+                <Avatar style={{ margin: 4 }}>AS</Avatar>
+                <Avatar color="red" style={{ margin: 4 }}>
+                  BM
+                </Avatar>
+                <Avatar color="light-blue" style={{ margin: 4 }}>
+                  TJ
+                </Avatar>
+                <Avatar style={{ color: '#f56a00', backgroundColor: '#fde3cf', margin: 4 }}>
+                  ZL
+                </Avatar>
+                <Avatar style={{ backgroundColor: '#87d068', margin: 4 }}>YZ</Avatar>
+              </div>
+              <Tag> default tag </Tag>
+              <Rating defaultValue={5} />
             </div>
-        );
-    }
+          </Content>
+        </Layout>
+        <Footer
+          style={{
+            height: 200,
+            background: 'var(--semi-color-black)',
+            color: 'var(--semi-color-white)',
+          }}
+        >
+          Footer
+        </Footer>
+      </Layout>
+    );
+
+    return (
+      <div className="container">
+        <div>
+          <Button onClick={switchMode}>Switch Mode</Button>
+        </div>
+        <div>
+          <div>{blocks('default')}</div>
+          {/* <div id="semi-always-dark">{blocks('always dark')}</div>
+                    <div id="semi-always-light">{blocks('always light')}</div> */}
+        </div>
+      </div>
+    );
+  }
 
-    return <Demo />;
-});
+  return <Demo />;
+};

+ 10 - 11
packages/semi-ui/_portal/_story/portal.stories.js

@@ -1,18 +1,17 @@
 import React from 'react';
-import { storiesOf } from '@storybook/react';
-// import { withKnobs, text, boolean } from '@storybook/addon-knobs';
-import withPropsCombinations from 'react-storybook-addon-props-combinations';
 
 import Portal from '../index';
 
-const stories = storiesOf('Portal', module);
+export default {
+  title: 'Portal',
+}
 
-// stories.addDecorator(withKnobs);;
+export {
+  Basic
+}
 
-stories.add('Portal', () => (
-    <div>
-        <Portal>
-            123
-        </Portal>
+const Basic = () => (
+  <div>
+    <Portal>123</Portal>
   </div>
-));
+);

+ 2 - 2
packages/semi-ui/_test_/utils/table/index.js

@@ -11,7 +11,7 @@ function getRandomNumber(end = 100, start = 0) {
 function getData(total = 25) {
     const _data = [];
     for (let i = 0; i < total; i++) {
-        let age = 40 + (Math.random() > 0.5 ? 1 : -1) * Math.ceil(i / 3);
+        let age = (i * 1000) % 149;
         let name = `Edward King ${i}`;
         _data.push({
             key: String(i),
@@ -171,7 +171,7 @@ function getNestColumns() {
 function getNestData(total = 25) {
     const data = [];
     for (let i = 0; i < total; i++) {
-        let age = 40 + (Math.random() > 0.5 ? 1 : -1) * (i % 9);
+        let age = (i * 1000) % 149;
         let name = `Edward King ${i}`;
         data.push({
             key: String(i),

+ 244 - 221
packages/semi-ui/anchor/_story/anchor.stories.js

@@ -1,243 +1,266 @@
 import React from 'react';
 import { Anchor } from '../../index';
-import { storiesOf } from '@storybook/react';
 
-const stories = storiesOf('Anchor', module);
+export default {
+  title: 'Anchor',
+}
 
 const getContainer = () => {
-    const node = document.getElementById('box');
-    return node;
+  const node = document.getElementById('box');
+  return node;
 };
 
 const Link = Anchor.Link;
 
-stories.add('不同大小', () => (
-    <div>
-        <div>小号尺寸</div>
-        <Anchor size={'small'}>
-            <Link href="#welcome" title="welcome" />
-            <Link href="#api" title="api too much to show" />
-            <Link href="#contact" title="contact" />
-        </Anchor>
-        <br />
-        <div>默认</div>
-        <Anchor>
-            <Link href="#welcome" title="welcome" />
-            <Link href="#api" title="api too much to show" />
-            <Link href="#contact" title="contact" />
-        </Anchor>
-    </div>
-));
+export const Size = () => (
+  <div>
+    <div>小号尺寸</div>
+    <Anchor size={'small'}>
+      <Link href="#welcome" title="welcome" />
+      <Link href="#api" title="api too much to show" />
+      <Link href="#contact" title="contact" />
+    </Anchor>
+    <br />
+    <div>默认</div>
+    <Anchor>
+      <Link href="#welcome" title="welcome" />
+      <Link href="#api" title="api too much to show" />
+      <Link href="#contact" title="contact" />
+    </Anchor>
+  </div>
+);
 
-stories.add('不同主题', () => (
-    <div>
-        <div>点击锚点查看效果</div>
-        <br />
-        <Anchor railTheme={'primary'}>
-            <Link href="#组件" title="组件" />
-            <Link href="#设计语言" title="设计语言" />
-            <Link href="#物料平台" title="物料平台" />
-            <Link href="#主题商店" title="主题商店" />
-        </Anchor>
-        <br />
-        <Anchor railTheme={'tertiary'}>
-            <Link href="#组件" title="组件" />
-            <Link href="#设计语言" title="设计语言" />
-            <Link href="#物料平台" title="物料平台" />
-            <Link href="#主题商店" title="主题商店" />
-        </Anchor>
-        <br />
-        <Anchor railTheme={'muted'}>
-            <Link href="#组件" title="组件" />
-            <Link href="#设计语言" title="设计语言" />
-            <Link href="#物料平台" title="物料平台" />
-            <Link href="#主题商店" title="主题商店" />
-        </Anchor>
-    </div>
-));
+export const Theme = () => (
+  <div>
+    <div>点击锚点查看效果</div>
+    <br />
+    <Anchor railTheme={'primary'}>
+      <Link href="#组件" title="组件" />
+      <Link href="#设计语言" title="设计语言" />
+      <Link href="#物料平台" title="物料平台" />
+      <Link href="#主题商店" title="主题商店" />
+    </Anchor>
+    <br />
+    <Anchor railTheme={'tertiary'}>
+      <Link href="#组件" title="组件" />
+      <Link href="#设计语言" title="设计语言" />
+      <Link href="#物料平台" title="物料平台" />
+      <Link href="#主题商店" title="主题商店" />
+    </Anchor>
+    <br />
+    <Anchor railTheme={'muted'}>
+      <Link href="#组件" title="组件" />
+      <Link href="#设计语言" title="设计语言" />
+      <Link href="#物料平台" title="物料平台" />
+      <Link href="#主题商店" title="主题商店" />
+    </Anchor>
+  </div>
+);
 
-stories.add('动态展示', () => (
-    <div>
-        <div>Anchor 设置 autoCollapse 可以动态展示下一级锚点。</div>
-        <br />
-        <div>点击 1.Semi Design 查看效果</div>
-        <Anchor autoCollapse={true}>
-            <Link href="#Semi Design" title="1. Semi Design">
-                <Link href="#组件" title="1.1 组件">
-                    <Link href="#头像" title="1.1.1 Avatar" />
-                    <Link href="#按钮" title="1.1.2 Button" />
-                    <Link href="#图标" title="1.1.3 Icon" />
-                </Link>
-                <Link href="#物料" title="1.2 物料" />
-                <Link href="#主题商店" title="1.3 主题商店" />
-            </Link>
-            <Link href="#设计语言" title="2. 设计语言" />
-        </Anchor>
-        <br />
-        <div>默认不进行动态折叠</div>
-        <Anchor autoCollapse={false}>
-            <Link href="#Semi Design" title="1. Semi Design">
-                <Link href="#组件" title="1.1 组件">
-                    <Link href="#头像" title="1.1.1 Avatar" />
-                    <Link href="#按钮" title="1.1.2 Button" />
-                    <Link href="#图标" title="1.1.3 Icon" />
-                </Link>
-                <Link href="#物料" title="1.2 物料" />
-                <Link href="#主题商店" title="1.3 主题商店" />
-            </Link>
-            <Link href="#设计语言" title="2. 设计语言" />
-        </Anchor>
-    </div>
-));
+export const autoCollapse = () => (
+  <div>
+    <div>Anchor 设置 autoCollapse 可以动态展示下一级锚点。</div>
+    <br />
+    <div>点击 1.Semi Design 查看效果</div>
+    <Anchor autoCollapse={true}>
+      <Link href="#Semi Design" title="1. Semi Design">
+        <Link href="#组件" title="1.1 组件">
+          <Link href="#头像" title="1.1.1 Avatar" />
+          <Link href="#按钮" title="1.1.2 Button" />
+          <Link href="#图标" title="1.1.3 Icon" />
+        </Link>
+        <Link href="#物料" title="1.2 物料" />
+        <Link href="#主题商店" title="1.3 主题商店" />
+      </Link>
+      <Link href="#设计语言" title="2. 设计语言" />
+    </Anchor>
+    <br />
+    <div>默认不进行动态折叠</div>
+    <Anchor autoCollapse={false}>
+      <Link href="#Semi Design" title="1. Semi Design">
+        <Link href="#组件" title="1.1 组件">
+          <Link href="#头像" title="1.1.1 Avatar" />
+          <Link href="#按钮" title="1.1.2 Button" />
+          <Link href="#图标" title="1.1.3 Icon" />
+        </Link>
+        <Link href="#物料" title="1.2 物料" />
+        <Link href="#主题商店" title="1.3 主题商店" />
+      </Link>
+      <Link href="#设计语言" title="2. 设计语言" />
+    </Anchor>
+  </div>
+);
 
-stories.add('工具提示', () => (
-    <div>
-        <div>工具提示可以在 Link 超出最大宽度时显示 Link 的文字内容</div>
-        <br />
-        <Anchor showTooltip={true}>
-            <Link href="#组件" title="组件" />
-            <Link href="#设计语言" title="设计语言" />
-            <Link href="#物料平台" title="物料平台" />
-            <Link href="#主题商店" title="主题商店" />
-            <Link href="#显示工具提示" title="工具提示是一个有用的工具,它可以在文字缩略时展示全部内容。" />
-        </Anchor>
-        <br />
-        <div>position可以设置工具提示的位置</div>
-        <Anchor showTooltip={true} position={'right'}>
-            <Link href="#组件" title="组件" />
-            <Link href="#设计语言" title="设计语言" />
-            <Link href="#物料平台" title="物料平台" />
-            <Link href="#主题商店" title="主题商店" />
-            <Link href="#工具提示位置" title="工具提示是一个有用的工具,它可以在文字缩略时展示全部内容。" />
-        </Anchor>
-    </div>
-));
+export const showTooltip = () => (
+  <div>
+    <div>工具提示可以在 Link 超出最大宽度时显示 Link 的文字内容</div>
+    <br />
+    <Anchor showTooltip={true}>
+      <Link href="#组件" title="组件" />
+      <Link href="#设计语言" title="设计语言" />
+      <Link href="#物料平台" title="物料平台" />
+      <Link href="#主题商店" title="主题商店" />
+      <Link
+        href="#显示工具提示"
+        title="工具提示是一个有用的工具,它可以在文字缩略时展示全部内容。"
+      />
+    </Anchor>
+    <br />
+    <div>position可以设置工具提示的位置</div>
+    <Anchor showTooltip={true} position={'right'}>
+      <Link href="#组件" title="组件" />
+      <Link href="#设计语言" title="设计语言" />
+      <Link href="#物料平台" title="物料平台" />
+      <Link href="#主题商店" title="主题商店" />
+      <Link
+        href="#工具提示位置"
+        title="工具提示是一个有用的工具,它可以在文字缩略时展示全部内容。"
+      />
+    </Anchor>
+  </div>
+);
 
-stories.add('max-height', () => (
-    <div>
-        <div>设置 maxHeight 可以控制 Anchor 的高度,滚动显示 Anchor 内容</div>
-        <br />
-        <Anchor maxHeight={'100px'}>
-            <Link href="#组件" title="组件" />
-            <Link href="#设计语言" title="设计语言" />
-            <Link href="#物料平台" title="物料平台" />
-            <Link href="#主题商店" title="主题商店" />
-            <Link href="#显示工具提示" title="工具提示是一个有用的工具,它可以在文字缩略时展示全部内容。" />
-        </Anchor>
-    </div>
-));
+export const MaxHeight = () => (
+  <div>
+    <div>设置 maxHeight 可以控制 Anchor 的高度,滚动显示 Anchor 内容</div>
+    <br />
+    <Anchor maxHeight={'100px'}>
+      <Link href="#组件" title="组件" />
+      <Link href="#设计语言" title="设计语言" />
+      <Link href="#物料平台" title="物料平台" />
+      <Link href="#主题商店" title="主题商店" />
+      <Link
+        href="#显示工具提示"
+        title="工具提示是一个有用的工具,它可以在文字缩略时展示全部内容。"
+      />
+    </Anchor>
+  </div>
+);
 
-stories.add('定位方式', () => (
-    <div>
-        <Anchor style={{ position: 'absolute', right: 0 }} scrollMotion={false} getContainer={getContainer}>
-            <Link href="#welcome" title="welcome" />
-            <Link href="#api" title="api too much to show">
-                <Link href="#docs" title="docs">
-                    <Link href="#doc1" title="doc1" />
-                    <Link href="#doc2" title="doc2" />
-                </Link>
-            </Link>
-            <Link href="#contact" title="contact" />
-        </Anchor>
+export const StylePosition = () => (
+  <div>
+    <Anchor
+      style={{ position: 'absolute', right: 0 }}
+      scrollMotion={false}
+      getContainer={getContainer}
+    >
+      <Link href="#welcome" title="welcome" />
+      <Link href="#api" title="api too much to show">
+        <Link href="#docs" title="docs">
+          <Link href="#doc1" title="doc1" />
+          <Link href="#doc2" title="doc2" />
+        </Link>
+      </Link>
+      <Link href="#contact" title="contact" />
+    </Anchor>
 
-        <div>设置style对象可以改变 Anchor 组件的定位方式,右边就是个 fixed 的 Anchor</div>
-        <div id="box" style={{ height: '500px', overflow: 'scroll' }}>
-            <h1 id="welcome" style={{ height: '300px' }}>
-                Welcome
-            </h1>
-            <h1 id="api" style={{ height: '300px' }}>
-                API
-            </h1>
-            <h2 id="docs" style={{ height: '200px' }}>
-                Docs
-            </h2>
-            <h3 id="doc1" style={{ height: '100px' }}>
-                Doc1
-            </h3>
-            <h3 id="doc2" style={{ height: '100px' }}>
-                Doc2
-            </h3>
-            <h1 id="contact" style={{ height: '300px' }}>
-                Contact me
-            </h1>
-        </div>
+    <div>设置style对象可以改变 Anchor 组件的定位方式,右边就是个 fixed 的 Anchor</div>
+    <div id="box" style={{ height: '500px', overflow: 'scroll' }}>
+      <h1 id="welcome" style={{ height: '300px' }}>
+        Welcome
+      </h1>
+      <h1 id="api" style={{ height: '300px' }}>
+        API
+      </h1>
+      <h2 id="docs" style={{ height: '200px' }}>
+        Docs
+      </h2>
+      <h3 id="doc1" style={{ height: '100px' }}>
+        Doc1
+      </h3>
+      <h3 id="doc2" style={{ height: '100px' }}>
+        Doc2
+      </h3>
+      <h1 id="contact" style={{ height: '300px' }}>
+        Contact me
+      </h1>
     </div>
-));
+  </div>
+);
 
-stories.add('targetOffset', () => (
-    <div>
-        <Anchor style={{ position: 'absolute', right: 0, top: 100 }} targetOffset={100} scrollMotion={true} getContainer={getContainer}>
-            <Link href="#welcome" title="welcome" />
-            <Link href="#api" title="api too much to show">
-                <Link href="#docs" title="docs">
-                    <Link href="#doc1" title="doc1" />
-                    <Link href="#doc2" title="doc2" />
-                </Link>
-            </Link>
-            <Link href="#contact" title="contact" />
-        </Anchor>
+export const TargetOffset = () => (
+  <div>
+    <Anchor
+      style={{ position: 'absolute', right: 0, top: 100 }}
+      targetOffset={100}
+      scrollMotion={true}
+      getContainer={getContainer}
+    >
+      <Link href="#welcome" title="welcome" />
+      <Link href="#api" title="api too much to show">
+        <Link href="#docs" title="docs">
+          <Link href="#doc1" title="doc1" />
+          <Link href="#doc2" title="doc2" />
+        </Link>
+      </Link>
+      <Link href="#contact" title="contact" />
+    </Anchor>
 
-        <div id="box" style={{ height: '500px', overflow: 'scroll', border: '1px solid #eee' }}>
-            <div style={{ position: 'fixed', border: '1px solid red', height: 100, width: '100%' }}>这是 fixed 的一段话</div>
-            <h1 style={{ height: '300px' }}>
-                whatever
-            </h1>
-            <h1 id="welcome" style={{ height: '300px' }}>
-                Welcome
-            </h1>
-            <h1 id="api" style={{ height: '300px' }}>
-                API
-            </h1>
-            <h2 id="docs" style={{ height: '200px' }}>
-                Docs
-            </h2>
-            <h3 id="doc1" style={{ height: '100px' }}>
-                Doc1
-            </h3>
-            <h3 id="doc2" style={{ height: '100px' }}>
-                Doc2
-            </h3>
-            <h1 id="contact" style={{ height: '300px' }}>
-                Contact me
-            </h1>
-        </div>
+    <div id="box" style={{ height: '500px', overflow: 'scroll', border: '1px solid #eee' }}>
+      <div style={{ position: 'fixed', border: '1px solid red', height: 100, width: '100%' }}>
+        这是 fixed 的一段话
+      </div>
+      <h1 style={{ height: '300px' }}>whatever</h1>
+      <h1 id="welcome" style={{ height: '300px' }}>
+        Welcome
+      </h1>
+      <h1 id="api" style={{ height: '300px' }}>
+        API
+      </h1>
+      <h2 id="docs" style={{ height: '200px' }}>
+        Docs
+      </h2>
+      <h3 id="doc1" style={{ height: '100px' }}>
+        Doc1
+      </h3>
+      <h3 id="doc2" style={{ height: '100px' }}>
+        Doc2
+      </h3>
+      <h1 id="contact" style={{ height: '300px' }}>
+        Contact me
+      </h1>
     </div>
-));
+  </div>
+);
 
-stories.add('fix container scroll bug #1158', () => (
-    <div style={{ height: '120vh' }}>
-        <div style={{ width: 500, height: 500, position: 'relative', overflowY: 'scroll' }}>
-            <Anchor style={{ position: 'absolute', right: 0 }} scrollMotion={true} getContainer={getContainer}>
-                <Link href="#welcome" title="welcome" />
-                <Link href="#api" title="api too much to show">
-                    <Link href="#docs" title="docs">
-                        <Link href="#doc1" title="doc1" />
-                        <Link href="#doc2" title="doc2" />
-                    </Link>
-                </Link>
-                <Link href="#contact" title="contact" />
-            </Anchor>
+export const FixContainerScrollBug1158 = () => (
+  <div style={{ height: '120vh' }}>
+    <div style={{ width: 500, height: 500, position: 'relative', overflowY: 'scroll' }}>
+      <Anchor
+        style={{ position: 'absolute', right: 0 }}
+        scrollMotion={true}
+        getContainer={getContainer}
+      >
+        <Link href="#welcome" title="welcome" />
+        <Link href="#api" title="api too much to show">
+          <Link href="#docs" title="docs">
+            <Link href="#doc1" title="doc1" />
+            <Link href="#doc2" title="doc2" />
+          </Link>
+        </Link>
+        <Link href="#contact" title="contact" />
+      </Anchor>
 
-            <div id="box" style={{ height: 700, overflowY: 'scroll' }}>
-                <h1 id="welcome" style={{ height: '300px' }}>
-                    Welcome
-                </h1>
-                <h1 id="api" style={{ height: '300px' }}>
-                    API
-                </h1>
-                <h2 id="docs" style={{ height: '200px' }}>
-                    Docs
-                </h2>
-                <h3 id="doc1" style={{ height: '100px' }}>
-                    Doc1
-                </h3>
-                <h3 id="doc2" style={{ height: '100px' }}>
-                    Doc2
-                </h3>
-                <h1 id="contact" style={{ height: '300px' }}>
-                    Contact me
-                </h1>
-            </div>
-        </div>
+      <div id="box" style={{ height: 700, overflowY: 'scroll' }}>
+        <h1 id="welcome" style={{ height: '300px' }}>
+          Welcome
+        </h1>
+        <h1 id="api" style={{ height: '300px' }}>
+          API
+        </h1>
+        <h2 id="docs" style={{ height: '200px' }}>
+          Docs
+        </h2>
+        <h3 id="doc1" style={{ height: '100px' }}>
+          Doc1
+        </h3>
+        <h3 id="doc2" style={{ height: '100px' }}>
+          Doc2
+        </h3>
+        <h1 id="contact" style={{ height: '300px' }}>
+          Contact me
+        </h1>
+      </div>
     </div>
-));
+  </div>
+);

+ 306 - 305
packages/semi-ui/autoComplete/_story/autoComplete.stories.js

@@ -1,348 +1,349 @@
-import React, { Component, useState, useDebugValue } from 'react';
-import { storiesOf } from '@storybook/react'; // import { withKnobs, text, boolean } from '@storybook/addon-knobs';
+import React, { Component, useState } from 'react';
 
-import withPropsCombinations from 'react-storybook-addon-props-combinations';
-import { Button, TextArea, Icon } from '../../index';
 import CustomTrigger from './CustomTrigger';
 import AutoComplete from '../index';
-import { result } from 'lodash';
 import { IconSearch } from '@douyinfe/semi-icons';
-const stories = storiesOf('AutoComplete', module); // stories.addDecorator(withKnobs);;
+
+export default {
+  title: 'AutoComplete',
+  parameters: {
+    chromatic: { disableSnapshot: true },
+  },
+}
 
 const props = {
-    onBlur: (v, e) => {
-        console.log('onBlur');
-        console.log(v, e);
-    },
-    onFocus: (v, e) => {
-        console.log('onFocus');
-        console.log(v, e);
-    },
+  onBlur: (v, e) => {
+    console.log('onBlur');
+    console.log(v, e);
+  },
+  onFocus: (v, e) => {
+    console.log('onFocus');
+    console.log(v, e);
+  },
 };
 
 class Demo extends React.Component {
-    constructor() {
-        super();
-        this.state = {
-            data: [],
-            data2: ['mike', 'tony', 'steve'],
-        };
-        this.acref = React.createRef();
+  constructor() {
+    super();
+    this.state = {
+      data: [],
+      data2: ['mike', 'tony', 'steve'],
+    };
+    this.acref = React.createRef();
+  }
+
+  handleSearch(value) {
+    // let data =  !value ? [] : [value, value + value, value + value + value];
+    let result; // if (!value || value.indexOf('@') >= 0) {
+    //     result = [];
+    // } else {
+
+    if (value) {
+      result = ['gmail.com', '163.com', 'qq.com'].map(domain => `${value}@${domain}`);
+    } else {
+      result = [];
+    } // }
+
+    this.setState({
+      data: result,
+    });
+  }
+
+  handleSearch2(value) {
+    // let data2 =  !value ? [] : [value, value + value, value + value + value];
+    let result;
+
+    if (!value || value.indexOf('@') >= 0) {
+      result = [];
+    } else {
+      result = ['gmail.com', '163.com', 'qq.com'].map(domain => `${value}@${domain}`);
     }
 
-    handleSearch(value) {
-        // let data =  !value ? [] : [value, value + value, value + value + value];
-        let result; // if (!value || value.indexOf('@') >= 0) {
-        //     result = [];
-        // } else {
-
-        if (value) {
-            result = ['gmail.com', '163.com', 'qq.com'].map(domain => `${value}@${domain}`);
-        } else {
-            result = [];
-        } // }
-
-        this.setState({
-            data: result,
-        });
-    }
+    this.setState({
+      data2: result,
+    });
+  }
+
+  render() {
+    const { data, data2 } = this.state;
+    return (
+      <div>
+        <AutoComplete
+          placeholder="fe"
+          className="test-ac"
+          prefix={<IconSearch />}
+          showClear
+          data={data}
+          style={{
+            width: 300,
+          }}
+          onSearch={this.handleSearch.bind(this)}
+          onSelect={v => console.log(v)}
+          {...props}
+          ref={this.acref}
+        />
+      </div>
+    );
+  }
+}
 
-    handleSearch2(value) {
-        // let data2 =  !value ? [] : [value, value + value, value + value + value];
-        let result;
+export const BasicUsage = () => <Demo />;
 
-        if (!value || value.indexOf('@') >= 0) {
-            result = [];
-        } else {
-            result = ['gmail.com', '163.com', 'qq.com'].map(domain => `${value}@${domain}`);
-        }
+class CustomOptionDemo extends Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      data: [],
+      data2: [],
+    };
+  }
 
-        this.setState({
-            data2: result,
-        });
-    }
+  search = value => {
+    let result;
 
-    render() {
-        const { data, data2 } = this.state;
-        return (
-            <div>
-                <AutoComplete
-                    placeholder="fe"
-                    className="test-ac"
-                    prefix={<IconSearch />}
-                    showClear
-                    data={data}
-                    style={{
-                        width: 300,
-                    }}
-                    onSearch={this.handleSearch.bind(this)}
-                    onSelect={v => console.log(v)}
-                    {...props}
-                    ref={this.acref}
-                />
-            </div>
-        );
+    if (!value) {
+      result = [];
+    } else {
+      result = ['gmail.com', '163.com', 'qq.com'].map(domain => `${value}@${domain}`);
     }
-}
-
-stories.add('基本使用', () => <Demo />);
 
-class CustomOptionDemo extends Component {
-    constructor(props) {
-        super(props);
-        this.state = {
-            data: [],
-            data2: [],
+    this.setState({
+      data: result,
+    });
+  };
+  renderOption = item => {
+    return (
+      <>
+        <span
+          style={{
+            color: 'pink',
+          }}
+        >
+          邮箱
+        </span>
+        : <span>{item}</span>
+      </>
+    );
+  };
+  search2 = value => {
+    let result;
+
+    if (!value) {
+      result = [];
+    } else {
+      result = ['gmail.com', '163.com', 'qq.com'].map(domain => {
+        return {
+          email: `${value}@${domain}`,
+          time: new Date().valueOf(),
+          value: `${value}@${domain}`,
         };
+      });
     }
 
-    search = value => {
-        let result;
-
-        if (!value) {
-            result = [];
-        } else {
-            result = ['gmail.com', '163.com', 'qq.com'].map(domain => `${value}@${domain}`);
-        }
-
-        this.setState({
-            data: result,
-        });
-    };
-    renderOption = item => {
-        return (
-            <>
-                <span
-                    style={{
-                        color: 'pink',
-                    }}
-                >
-                    邮箱
-                </span>
-                : <span>{item}</span>
-            </>
-        );
-    };
-    search2 = value => {
-        let result;
-
-        if (!value) {
-            result = [];
-        } else {
-            result = ['gmail.com', '163.com', 'qq.com'].map(domain => {
-                return {
-                    email: `${value}@${domain}`,
-                    time: new Date().valueOf(),
-                    value: `${value}@${domain}`,
-                };
-            });
-        }
-
-        this.setState({
-            data2: result,
-        });
-    };
-    renderObjectOption = item => {
-        return (
-            <div>
-                <span
-                    style={{
-                        color: 'pink',
-                    }}
-                >
-                    邮箱
-                </span>
-                : <span>{item.email}</span>
-                <span>time</span>: <span>{item.time}</span>
-            </div>
-        );
-    };
-
-    render() {
-        return (
-            <>
-                <AutoComplete
-                    showClear
-                    data={this.state.data}
-                    renderItem={this.renderOption}
-                    style={{
-                        width: '250px',
-                    }}
-                    optionLabelProp="value"
-                    onSearch={this.search}
-                ></AutoComplete>
-                <br />
-                <br />
-                <AutoComplete
-                    onChangeWithObject
-                    style={{
-                        width: '250px',
-                    }}
-                    renderItem={this.renderObjectOption}
-                    renderSelectedItem={node => node.email}
-                    data={this.state.data2}
-                    onSearch={this.search2}
-                />
-            </>
-        );
-    }
+    this.setState({
+      data2: result,
+    });
+  };
+  renderObjectOption = item => {
+    return (
+      <div>
+        <span
+          style={{
+            color: 'pink',
+          }}
+        >
+          邮箱
+        </span>
+        : <span>{item.email}</span>
+        <span>time</span>: <span>{item.time}</span>
+      </div>
+    );
+  };
+
+  render() {
+    return (
+      <>
+        <AutoComplete
+          showClear
+          data={this.state.data}
+          renderItem={this.renderOption}
+          style={{
+            width: '250px',
+          }}
+          optionLabelProp="value"
+          onSearch={this.search}
+        ></AutoComplete>
+        <br />
+        <br />
+        <AutoComplete
+          onChangeWithObject
+          style={{
+            width: '250px',
+          }}
+          renderItem={this.renderObjectOption}
+          renderSelectedItem={node => node.email}
+          data={this.state.data2}
+          onSearch={this.search2}
+        />
+      </>
+    );
+  }
 }
 
-stories.add('自定义选项内容', () => <CustomOptionDemo />);
+export const RenderItem = () => <CustomOptionDemo />;
 
 class WithDefaultValue extends React.Component {
-    constructor() {
-        super();
-        this.state = {
-            data: ['[email protected]', '[email protected]', '[email protected]'],
-        };
-        this.onSearch = this.onSearch.bind(this);
-    }
-    onSearch(value) {
-        let result;
-
-        if (!value) {
-            result = [];
-        } else {
-            result = ['gmail.com', '163.com', 'qq.com'].map(domain => `${value}@${domain}`);
-        }
-
-        this.setState({
-            data: result,
-        });
+  constructor() {
+    super();
+    this.state = {
+      data: ['[email protected]', '[email protected]', '[email protected]'],
+    };
+    this.onSearch = this.onSearch.bind(this);
+  }
+  onSearch(value) {
+    let result;
+
+    if (!value) {
+      result = [];
+    } else {
+      result = ['gmail.com', '163.com', 'qq.com'].map(domain => `${value}@${domain}`);
     }
 
-    render() {
-        let { data } = this.state;
-        return (
-            <>
-                {/* <AutoComplete
+    this.setState({
+      data: result,
+    });
+  }
+
+  render() {
+    let { data } = this.state;
+    return (
+      <>
+        {/* <AutoComplete
            defaultValue='[email protected]'
            data={data}
            onSearch={this.onSearch}
         /> */}
 
-                <AutoComplete defaultValue="semi" data={data} onSearch={this.onSearch} />
-            </>
-        );
-    }
+        <AutoComplete defaultValue="semi" data={data} onSearch={this.onSearch} />
+      </>
+    );
+  }
 }
 
-stories.add('defaultValue', () => <WithDefaultValue />);
+export const DefaultValue = () => <WithDefaultValue />;
 
 class ControlledMode extends React.Component {
-    constructor() {
-        super();
-        this.state = {
-            data: [],
-            dataObject: [],
-            value: '',
-        };
-        this.onSearch = this.onSearch.bind(this);
-        this.onChange = this.onChange.bind(this);
-    }
-
-    onSearch(value) {
-        let result, resultObject;
-
-        if (!value) {
-            result = [];
-            resultObject = [];
-        } else {
-            result = ['gmail.com', '163.com', 'qq.com'].map(domain => `${value}@${domain}`);
-            resultObject = ['gmail.com', '163.com', 'qq.com'].map(domain => ({
-                label: `${value}@${domain}`,
-                value: `${value}@${domain}`,
-            }));
-        }
-
-        this.setState({
-            data: result,
-            dataObject: resultObject,
-        });
-    }
-
-    onChange(value) {
-        this.setState({
-            value: value,
-        });
+  constructor() {
+    super();
+    this.state = {
+      data: [],
+      dataObject: [],
+      value: '',
+    };
+    this.onSearch = this.onSearch.bind(this);
+    this.onChange = this.onChange.bind(this);
+  }
+
+  onSearch(value) {
+    let result, resultObject;
+
+    if (!value) {
+      result = [];
+      resultObject = [];
+    } else {
+      result = ['gmail.com', '163.com', 'qq.com'].map(domain => `${value}@${domain}`);
+      resultObject = ['gmail.com', '163.com', 'qq.com'].map(domain => ({
+        label: `${value}@${domain}`,
+        value: `${value}@${domain}`,
+      }));
     }
 
-    render() {
-        let { data, value, dataObject } = this.state;
-        return (
-            <>
-                <AutoComplete
-                    showClear
-                    value={value}
-                    data={data}
-                    onChange={this.onChange}
-                    onSearch={this.onSearch}
-                    style={{
-                        width: 200,
-                    }}
-                />
-                <br />
-                <AutoComplete
-                    showClear
-                    value={value}
-                    data={dataObject}
-                    onChange={this.onChange}
-                    onSearch={this.onSearch}
-                    style={{
-                        width: 200,
-                    }}
-                />
-                <br />
-                <AutoComplete
-                    defaultValue={'hello semi'}
-                    showClear
-                    value={value}
-                    data={dataObject}
-                    onChange={this.onChange}
-                    onSearch={this.onSearch}
-                    style={{
-                        width: 200,
-                    }}
-                />
-            </>
-        );
-    }
+    this.setState({
+      data: result,
+      dataObject: resultObject,
+    });
+  }
+
+  onChange(value) {
+    this.setState({
+      value: value,
+    });
+  }
+
+  render() {
+    let { data, value, dataObject } = this.state;
+    return (
+      <>
+        <AutoComplete
+          showClear
+          value={value}
+          data={data}
+          onChange={this.onChange}
+          onSearch={this.onSearch}
+          style={{
+            width: 200,
+          }}
+        />
+        <br />
+        <AutoComplete
+          showClear
+          value={value}
+          data={dataObject}
+          onChange={this.onChange}
+          onSearch={this.onSearch}
+          style={{
+            width: 200,
+          }}
+        />
+        <br />
+        <AutoComplete
+          defaultValue={'hello semi'}
+          showClear
+          value={value}
+          data={dataObject}
+          onChange={this.onChange}
+          onSearch={this.onSearch}
+          style={{
+            width: 200,
+          }}
+        />
+      </>
+    );
+  }
 }
 
-const EmptyContent = () => {
-    let [data, setData] = useState([]);
-    const [loading, setLoading] = useState(false);
-
-    const fetchData = v => {
-        setLoading(true);
-        setTimeout(() => {
-            if (!v) {
-                setData([]);
-                setLoading(false);
-                return;
-            }
-
-            setData(() => {
-                const res = Array.from(Array(5)).map(c => Math.random());
-                return res;
-            });
-            setLoading(false);
-        }, 1000);
-    };
-
-    return <AutoComplete loading={loading} data={data} emptyContent={'空数据'} onSearch={fetchData} />;
+export const EmptyContent = () => {
+  let [data, setData] = useState([]);
+  const [loading, setLoading] = useState(false);
+
+  const fetchData = v => {
+    setLoading(true);
+    setTimeout(() => {
+      if (!v) {
+        setData([]);
+        setLoading(false);
+        return;
+      }
+
+      setData(() => {
+        const res = Array.from(Array(5)).map(c => Math.random());
+        return res;
+      });
+      setLoading(false);
+    }, 1000);
+  };
+
+  return (
+    <AutoComplete loading={loading} data={data} emptyContent={'空数据'} onSearch={fetchData} />
+  );
 };
 
-const AutoFocus = () => {
-    return <AutoComplete autoFocus />;
+export const AutoFocus = () => {
+  return <AutoComplete autoFocus />;
 };
 
-stories.add('value受控', () => <ControlledMode />);
-stories.add('远程搜索', () => <Demo />);
-stories.add(`CustomTrigger`, () => <CustomTrigger />);
-stories.add(`Disabled`, () => {
-    return <AutoComplete disabled />;
-});
-stories.add('emptyContent配合远程搜索数据展示', () => <EmptyContent />);
-stories.add('autofocus', () => <AutoFocus />);
+export const ControlledValue = () => <ControlledMode />;
+
+export const CustomTriggerDemo = () => <CustomTrigger />;
+
+export const Disabled = () => <AutoComplete disabled />;

+ 173 - 152
packages/semi-ui/avatar/_story/avatar.stories.js

@@ -1,170 +1,191 @@
 import React from 'react';
-import { storiesOf } from '@storybook/react';
-// import { withKnobs, text, boolean } from '@storybook/addon-knobs';
-import withPropsCombinations from 'react-storybook-addon-props-combinations';
-
 import Avatar from '../index';
 import Popover from '../../popover/index';
 import AvatarGroup from '../avatarGroup';
 
-const stories = storiesOf('Avatar', module);
-
-// stories.addDecorator(withKnobs);;
+export default {
+  title: 'Avatar',
+}
 
-stories.add('avatar', () => (
+export const Basic = () => (
+  <div>
     <div>
-        <div>
-            <Avatar>U</Avatar>
-            <Avatar size="large">U</Avatar>
-            <Avatar size="extra-small" >U</Avatar>
-            <Avatar size="small">U</Avatar>
-            <Avatar size="default">U</Avatar>
-            <Avatar size="extra-large">U</Avatar>
-        </div>
-        <div>
-            <Avatar shape="square" >U</Avatar>
-            <Avatar shape="square" size="large">U</Avatar>
-            <Avatar shape="square" size="extra-small">U</Avatar>
-            <Avatar shape="square" size="small">U</Avatar>
-            <Avatar shape="square" size="default">U</Avatar>
-            <Avatar shape="square" size="extra-large">U</Avatar>
-        </div>
+      <Avatar>U</Avatar>
+      <Avatar size="large">U</Avatar>
+      <Avatar size="extra-small">U</Avatar>
+      <Avatar size="small">U</Avatar>
+      <Avatar size="default">U</Avatar>
+      <Avatar size="extra-large">U</Avatar>
     </div>
-));
-
-stories.add('custom avatar', () => (
     <div>
-        <Avatar>U</Avatar>
-        <Avatar color='red'>U</Avatar>
-        <Avatar color='red' size="default">DF</Avatar>
-        <Avatar src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" />
-        <Avatar size="default" src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" />
-        <Avatar size="small" src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" />
-        <Avatar style={{ color: '#f56a00', backgroundColor: '#fde3cf' }}>U</Avatar>
-        <Avatar style={{ backgroundColor: '#87d068' }} >YZ</Avatar>
+      <Avatar shape="square">U</Avatar>
+      <Avatar shape="square" size="large">
+        U
+      </Avatar>
+      <Avatar shape="square" size="extra-small">
+        U
+      </Avatar>
+      <Avatar shape="square" size="small">
+        U
+      </Avatar>
+      <Avatar shape="square" size="default">
+        U
+      </Avatar>
+      <Avatar shape="square" size="extra-large">
+        U
+      </Avatar>
     </div>
-));
+  </div>
+);
 
-stories.add('avatar group', () => (
-    <div>
-        <p>medium</p>
-        <AvatarGroup>
-            <Avatar color='red'>LL</Avatar>
-            <Avatar >CX</Avatar>
-            <Avatar size="default">CX</Avatar>
-            <Avatar color='amber'>RM</Avatar>
-            <Avatar style={{ color: '#f56a00', backgroundColor: '#fde3cf' }}>ZL</Avatar>
-            <Avatar style={{ backgroundColor: '#87d068' }} >YZ</Avatar>
-        </AvatarGroup>
-        <p>default</p>
-        <AvatarGroup size="default">
-            <Avatar color='red'>LL</Avatar>
-            <Avatar >CX</Avatar>
-            <Avatar size="default">CX</Avatar>
-            <Avatar color='amber'>RM</Avatar>
-            <Avatar style={{ color: '#f56a00', backgroundColor: '#fde3cf' }}>ZL</Avatar>
-            <Avatar style={{ backgroundColor: '#87d068' }} >YZ</Avatar>
-        </AvatarGroup>
-        <p>small</p>
-        <AvatarGroup size="small">
-            <Avatar color='red'>LL</Avatar>
-            <Avatar >CX</Avatar>
-            <Avatar size="default">CX</Avatar>
-            <Avatar color='amber'>RM</Avatar>
-            <Avatar style={{ color: '#f56a00', backgroundColor: '#fde3cf' }}>ZL</Avatar>
-            <Avatar style={{ backgroundColor: '#87d068' }} >YZ</Avatar>
-        </AvatarGroup>
-    </div>
-));
+export const CustomAvatar = () => (
+  <div>
+    <Avatar>U</Avatar>
+    <Avatar color="red">U</Avatar>
+    <Avatar color="red" size="default">
+      DF
+    </Avatar>
+    <Avatar src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" />
+    <Avatar size="default" src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" />
+    <Avatar size="small" src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" />
+    <Avatar style={{ color: '#f56a00', backgroundColor: '#fde3cf' }}>U</Avatar>
+    <Avatar style={{ backgroundColor: '#87d068' }}>YZ</Avatar>
+  </div>
+);
 
-stories.add('avatar group 头像覆盖方式', () => (
-    <div>
-        <div>overlapFrom=start</div>
-        <AvatarGroup overlapFrom={'start'}>
-            <Avatar color='red'>LL</Avatar>
-            <Avatar >CX</Avatar>
-            <Avatar color='amber'>RM</Avatar>
-            <Avatar style={{ color: '#f56a00', backgroundColor: '#fde3cf' }}>ZL</Avatar>
-            <Avatar style={{ backgroundColor: '#87d068' }} >YZ</Avatar>
-        </AvatarGroup><br /><br />
-        <div>overlapFrom=end</div>
-        <AvatarGroup overlapFrom={'end'}>
-            <Avatar color='red'>LL</Avatar>
-            <Avatar >CX</Avatar>
-            <Avatar color='amber'>RM</Avatar>
-            <Avatar style={{ color: '#f56a00', backgroundColor: '#fde3cf' }}>ZL</Avatar>
-            <Avatar style={{ backgroundColor: '#87d068' }} >YZ</Avatar>
-        </AvatarGroup><br /><br />
-    </div>
-));
+export const GroupSize = () => (
+  <div>
+    <p>medium</p>
+    <AvatarGroup>
+      <Avatar color="red">LL</Avatar>
+      <Avatar>CX</Avatar>
+      <Avatar size="default">CX</Avatar>
+      <Avatar color="amber">RM</Avatar>
+      <Avatar style={{ color: '#f56a00', backgroundColor: '#fde3cf' }}>ZL</Avatar>
+      <Avatar style={{ backgroundColor: '#87d068' }}>YZ</Avatar>
+    </AvatarGroup>
+    <p>default</p>
+    <AvatarGroup size="default">
+      <Avatar color="red">LL</Avatar>
+      <Avatar>CX</Avatar>
+      <Avatar size="default">CX</Avatar>
+      <Avatar color="amber">RM</Avatar>
+      <Avatar style={{ color: '#f56a00', backgroundColor: '#fde3cf' }}>ZL</Avatar>
+      <Avatar style={{ backgroundColor: '#87d068' }}>YZ</Avatar>
+    </AvatarGroup>
+    <p>small</p>
+    <AvatarGroup size="small">
+      <Avatar color="red">LL</Avatar>
+      <Avatar>CX</Avatar>
+      <Avatar size="default">CX</Avatar>
+      <Avatar color="amber">RM</Avatar>
+      <Avatar style={{ color: '#f56a00', backgroundColor: '#fde3cf' }}>ZL</Avatar>
+      <Avatar style={{ backgroundColor: '#87d068' }}>YZ</Avatar>
+    </AvatarGroup>
+  </div>
+);
 
-stories.add('avatar group 最大显示头像数', () => (
-    <div>
-        <div>maxCount=3</div>
-        <AvatarGroup maxCount={3}>
-            <Avatar color='red'>LL</Avatar>
-            <Avatar >CX</Avatar>
-            <Avatar color='amber'>RM</Avatar>
-            <Avatar style={{ color: '#f56a00', backgroundColor: '#fde3cf' }}>ZL</Avatar>
-            <Avatar style={{ backgroundColor: '#87d068' }} >YZ</Avatar>
-        </AvatarGroup><br /><br />
-    </div>
-));
+export const OverlapFromDemo = () => (
+  <div>
+    <div>overlapFrom=start</div>
+    <AvatarGroup overlapFrom={'start'}>
+      <Avatar color="red">LL</Avatar>
+      <Avatar>CX</Avatar>
+      <Avatar color="amber">RM</Avatar>
+      <Avatar style={{ color: '#f56a00', backgroundColor: '#fde3cf' }}>ZL</Avatar>
+      <Avatar style={{ backgroundColor: '#87d068' }}>YZ</Avatar>
+    </AvatarGroup>
+    <br />
+    <br />
+    <div>overlapFrom=end</div>
+    <AvatarGroup overlapFrom={'end'}>
+      <Avatar color="red">LL</Avatar>
+      <Avatar>CX</Avatar>
+      <Avatar color="amber">RM</Avatar>
+      <Avatar style={{ color: '#f56a00', backgroundColor: '#fde3cf' }}>ZL</Avatar>
+      <Avatar style={{ backgroundColor: '#87d068' }}>YZ</Avatar>
+    </AvatarGroup>
+    <br />
+    <br />
+  </div>
+);
+
+export const MaxCountDemo = () => (
+  <div>
+    <div>maxCount=3</div>
+    <AvatarGroup maxCount={3}>
+      <Avatar color="red">LL</Avatar>
+      <Avatar>CX</Avatar>
+      <Avatar color="amber">RM</Avatar>
+      <Avatar style={{ color: '#f56a00', backgroundColor: '#fde3cf' }}>ZL</Avatar>
+      <Avatar style={{ backgroundColor: '#87d068' }}>YZ</Avatar>
+    </AvatarGroup>
+    <br />
+    <br />
+  </div>
+);
 
 const renderMore = (restNumber, restAvatars) => {
-    const content = (
-        restAvatars.map((avatar, index) => {
-            return (
-                <div style={{ paddingBottom: '12px' }}>
-                    {React.cloneElement(avatar, { size: 'extra-small' })}
-                    <span style={{ marginLeft: 8, fontSize: 14 }}>这是段文字描述</span>
-                </div>
-            );
-        })
-    );
+  const content = restAvatars.map((avatar, index) => {
     return (
-        <Popover content={content} autoAdjustOverflow={false} position={'bottomRight'} style={{ padding: '12px 8px', paddingBottom: 0 }}>
-            <Avatar>
-                {`+${restNumber}`}
-            </Avatar>
-        </Popover>
-    )
-}
+      <div style={{ paddingBottom: '12px' }}>
+        {React.cloneElement(avatar, { size: 'extra-small' })}
+        <span style={{ marginLeft: 8, fontSize: 14 }}>这是段文字描述</span>
+      </div>
+    );
+  });
+  return (
+    <Popover
+      content={content}
+      autoAdjustOverflow={false}
+      position={'bottomRight'}
+      style={{ padding: '12px 8px', paddingBottom: 0 }}
+    >
+      <Avatar>{`+${restNumber}`}</Avatar>
+    </Popover>
+  );
+};
 
-stories.add('avatar group 自定义渲染 more 标签', () => (
-    <div>
-        <AvatarGroup maxCount={3} renderMore={renderMore}>
-            <Avatar color='red'>LL</Avatar>
-            <Avatar >CX</Avatar>
-            <Avatar color='amber'>RM</Avatar>
-            <Avatar style={{ color: '#f56a00', backgroundColor: '#fde3cf' }}>ZL</Avatar>
-            <Avatar style={{ backgroundColor: '#87d068' }} >YZ</Avatar>
-        </AvatarGroup><br /><br />
-    </div>
-));
+export const RenderMoreDemo = () => (
+  <div>
+    <AvatarGroup maxCount={3} renderMore={renderMore}>
+      <Avatar color="red">LL</Avatar>
+      <Avatar>CX</Avatar>
+      <Avatar color="amber">RM</Avatar>
+      <Avatar style={{ color: '#f56a00', backgroundColor: '#fde3cf' }}>ZL</Avatar>
+      <Avatar style={{ backgroundColor: '#87d068' }}>YZ</Avatar>
+    </AvatarGroup>
+    <br />
+    <br />
+  </div>
+);
 
-stories.add('avatar extra-extra-small overlap', () => (
-    <div>
-        <AvatarGroup size="extra-extra-small" overlapFrom={'start'}>
-            <Avatar color='red'>LL</Avatar>
-            <Avatar >CX</Avatar>
-            <Avatar color='amber'>RM</Avatar>
-            <Avatar style={{ color: '#f56a00', backgroundColor: '#fde3cf' }}>ZL</Avatar>
-            <Avatar style={{ backgroundColor: '#87d068' }} >YZ</Avatar>
-        </AvatarGroup><br/><br/>
-        <AvatarGroup size="extra-extra-small" overlapFrom={'end'}>
-            <Avatar color='red'>LL</Avatar>
-            <Avatar >CX</Avatar>
-            <Avatar color='amber'>RM</Avatar>
-            <Avatar style={{ color: '#f56a00', backgroundColor: '#fde3cf' }}>ZL</Avatar>
-            <Avatar style={{ backgroundColor: '#87d068' }} >YZ</Avatar>
-        </AvatarGroup><br/><br/>
-        <AvatarGroup size="extra-extra-small" maxCount={3}>
-            <Avatar color='red'>LL</Avatar>
-            <Avatar >CX</Avatar>
-            <Avatar color='amber'>RM</Avatar>
-            <Avatar style={{ color: '#f56a00', backgroundColor: '#fde3cf' }}>ZL</Avatar>
-            <Avatar style={{ backgroundColor: '#87d068' }} >YZ</Avatar>
-        </AvatarGroup>
-    </div>
-));
+export const ExtraExtraSmallOverlap = () => (
+  <div>
+    <AvatarGroup size="extra-extra-small" overlapFrom={'start'}>
+      <Avatar color="red">LL</Avatar>
+      <Avatar>CX</Avatar>
+      <Avatar color="amber">RM</Avatar>
+      <Avatar style={{ color: '#f56a00', backgroundColor: '#fde3cf' }}>ZL</Avatar>
+      <Avatar style={{ backgroundColor: '#87d068' }}>YZ</Avatar>
+    </AvatarGroup>
+    <br />
+    <br />
+    <AvatarGroup size="extra-extra-small" overlapFrom={'end'}>
+      <Avatar color="red">LL</Avatar>
+      <Avatar>CX</Avatar>
+      <Avatar color="amber">RM</Avatar>
+      <Avatar style={{ color: '#f56a00', backgroundColor: '#fde3cf' }}>ZL</Avatar>
+      <Avatar style={{ backgroundColor: '#87d068' }}>YZ</Avatar>
+    </AvatarGroup>
+    <br />
+    <br />
+    <AvatarGroup size="extra-extra-small" maxCount={3}>
+      <Avatar color="red">LL</Avatar>
+      <Avatar>CX</Avatar>
+      <Avatar color="amber">RM</Avatar>
+      <Avatar style={{ color: '#f56a00', backgroundColor: '#fde3cf' }}>ZL</Avatar>
+      <Avatar style={{ backgroundColor: '#87d068' }}>YZ</Avatar>
+    </AvatarGroup>
+  </div>
+);

+ 30 - 30
packages/semi-ui/backtop/_story/backtop.stories.js

@@ -1,37 +1,37 @@
 import React from 'react';
-import { storiesOf } from '@storybook/react'; // import { withKnobs, text, boolean } from '@storybook/addon-knobs';
 
-import withPropsCombinations from 'react-storybook-addon-props-combinations';
 import BackTop from '../index';
-import Icon from '../../icons';
 import { IconArrowUp } from '@douyinfe/semi-icons';
 
-const stories = storiesOf('BackTop', module); // stories.addDecorator(withKnobs);;
+export default {
+  title: 'BackTop',
+}
 
-stories.add('BackTop', () => (
-    <div>
-        <div style={{height: 1600, width: 300, background: 'grey'}}></div>
-        <BackTop visibilityHeight={-1} />
+export const Default = () => (
+  <div>
+    <div style={{ height: 1600, width: 300, background: 'grey' }}></div>
+    <BackTop visibilityHeight={-1} />
   </div>
-));
-stories.add('custom BackTop', () => (
-    <div>
-        <div
-            style={{
-                height: 1600,
-                width: 300,
-                background: 'grey',
-            }}
-        ></div>
-        <BackTop
-            style={{
-                height: 40,
-                width: 40,
-                backgroundColor: '#ddd',
-                paddingTop: 12,
-            }}
-        >
-            <IconArrowUp />
-        </BackTop>
-    </div>
-));
+);
+
+export const Custom = () => (
+  <div>
+    <div
+      style={{
+        height: 1600,
+        width: 300,
+        background: 'grey',
+      }}
+    ></div>
+    <BackTop
+      style={{
+        height: 40,
+        width: 40,
+        backgroundColor: '#ddd',
+        paddingTop: 12,
+      }}
+    >
+      <IconArrowUp />
+    </BackTop>
+  </div>
+);

+ 81 - 85
packages/semi-ui/badge/_story/badge.stories.js

@@ -1,95 +1,91 @@
 import React from 'react';
-import { storiesOf } from '@storybook/react';
-// import { withKnobs, text, boolean } from '@storybook/addon-knobs';
-
 import Badge from '../index';
-import Icon from '../../icons';
-
-const stories = storiesOf('Badge', module);
-
 
+export default {
+  title: 'Badge',
+}
 
 const style = {
-    width: '42px',
-    height: '42px',
-    borderRadius: '4px',
-    background: '#eee',
-    display: 'inline-block',
-    verticalAlign: 'middle',
+  width: '42px',
+  height: '42px',
+  borderRadius: '4px',
+  background: '#eee',
+  display: 'inline-block',
+  verticalAlign: 'middle',
 };
 
-stories.add('Badge default', () => (
-    <div>
-        <Badge count={5}>
-            <a style={style}></a>
-        </Badge>
-        <Badge dot>
-            <a style={style}></a>
-        </Badge>
-        <Badge count={5} />
-        <Badge dot />
-    </div>
-));
+export const Default = () => (
+  <div>
+    <Badge count={5}>
+      <a style={style}></a>
+    </Badge>
+    <Badge dot>
+      <a style={style}></a>
+    </Badge>
+    <Badge count={5} />
+    <Badge dot />
+  </div>
+);
 
-stories.add('Badge maxCount', () => (
-    <div>
-        <Badge count={99} >
-            <a style={style}></a>
-        </Badge>
-        <Badge count={100} >
-            <a style={style}></a>
-        </Badge>
-        <Badge count={99} overflowCount={10} >
-            <a style={style}></a>
-        </Badge>
-        <Badge count={1000} overflowCount={999} >
-            <a style={style}></a>
-        </Badge>
-    </div>
-));
+export const MaxCount = () => (
+  <div>
+    <Badge count={99}>
+      <a style={style}></a>
+    </Badge>
+    <Badge count={100}>
+      <a style={style}></a>
+    </Badge>
+    <Badge count={99} overflowCount={10}>
+      <a style={style}></a>
+    </Badge>
+    <Badge count={1000} overflowCount={999}>
+      <a style={style}></a>
+    </Badge>
+  </div>
+);
 
-stories.add('Badge type', () => (
-    <div>
-        <Badge count={5} type='primary' >
-            <a style={style}></a>
-        </Badge>
-        <Badge count={5} type='secondary' >
-            <a style={style}></a>
-        </Badge>
-        <Badge count={5} type='tertiary' >
-            <a style={style}></a>
-        </Badge>
-        <Badge count={5} type='warning' >
-            <a style={style}></a>
-        </Badge>
-        <Badge count={5} type='danger' >
-            <a style={style}></a>
-        </Badge>
-        <Badge dot type='primary' >
-            <a style={style}></a>
-        </Badge>
-    </div>
-));
+export const Type = () => (
+  <div>
+    <Badge count={5} type="primary">
+      <a style={style}></a>
+    </Badge>
+    <Badge count={5} type="secondary">
+      <a style={style}></a>
+    </Badge>
+    <Badge count={5} type="tertiary">
+      <a style={style}></a>
+    </Badge>
+    <Badge count={5} type="warning">
+      <a style={style}></a>
+    </Badge>
+    <Badge count={5} type="danger">
+      <a style={style}></a>
+    </Badge>
+    <Badge dot type="primary">
+      <a style={style}></a>
+    </Badge>
+  </div>
+);
 
-stories.add('Badge theme', () => (
-    <div>
-        <Badge count={5} theme='solid' >
-            <a style={style}></a>
-        </Badge>
-        <Badge count={5} theme='light' >
-            <a style={style}></a>
-        </Badge>
-        <Badge count={5} theme='inverted' >
-            <a style={style}></a>
-        </Badge>
-        <Badge dot theme='solid' >
-            <a style={style}></a>
-        </Badge>
-        <Badge dot theme='light' >
-            <a style={style}></a>
-        </Badge>
-        <Badge dot theme='inverted' >
-            <a style={style}></a>
-        </Badge>
-    </div>
-));
+export const Theme = () => (
+  <div>
+    <Badge count={5} theme="solid">
+      <a style={style}></a>
+    </Badge>
+    <Badge count={5} theme="light">
+      <a style={style}></a>
+    </Badge>
+    <Badge count={5} theme="inverted">
+      <a style={style}></a>
+    </Badge>
+    <Badge dot theme="solid">
+      <a style={style}></a>
+    </Badge>
+    <Badge dot theme="light">
+      <a style={style}></a>
+    </Badge>
+    <Badge dot theme="inverted">
+      <a style={style}></a>
+    </Badge>
+  </div>
+);

+ 34 - 37
packages/semi-ui/banner/_story/banner.stories.js

@@ -1,48 +1,45 @@
 import React from 'react';
-import { storiesOf } from '@storybook/react';
-// import { withKnobs, text, boolean } from '@storybook/addon-knobs';
-import withPropsCombinations from 'react-storybook-addon-props-combinations';
 
 import Banner from '../index';
-
 import Button from '@douyinfe/semi-ui/button/index';
 
-const stories = storiesOf('Banner', module);
-
-// stories.addDecorator(withKnobs);;
+export default {
+  title: 'Banner',
+}
 
-stories.add('basic banner', () => (
-    <>
-        <Banner description="A pre-released version is available" />
-        <br />
-        <Banner
-            onClick={e => console.log('clicking banner!!!!', e.target)}
-            onClose={e => {
-                e.stopPropagation();
-            }}
-            description="A pre-released version is available A pre-released version is availableA pre-released version is availableA pre-released version is availableA pre-released version is availableA pre-released version is availableA pre-released version is available"
-        >
-            <Button onClick={e => e.stopPropagation()}>test</Button>
-        </Banner>
-    </>
-));
 
-stories.add('in container', () => (
+export const Default = () => (
+  <>
+    <Banner description="A pre-released version is available" />
+    <br />
     <Banner
-        onClick={e => console.log('clicking banner!!!!', e.target)}
-        onClose={e => {
-            e.stopPropagation();
-        }}
-        fullMode={false}
-        title="标题"
-        description="A pre-released version is available"
+      onClick={e => console.log('clicking banner!!!!', e.target)}
+      onClose={e => {
+        e.stopPropagation();
+      }}
+      description="A pre-released version is available A pre-released version is availableA pre-released version is availableA pre-released version is availableA pre-released version is availableA pre-released version is availableA pre-released version is available"
     >
-        <Button onClick={e => e.stopPropagation()}>test</Button>
+      <Button onClick={e => e.stopPropagation()}>test</Button>
     </Banner>
-));
+  </>
+);
 
-stories.add('in container and bordered', () => (
-    <Banner title="标题" bordered description="A pre-released version is available">
-        <Button onClick={e => e.stopPropagation()}>test</Button>
-    </Banner>
-));
+export const InContainer = () => (
+  <Banner
+    onClick={e => console.log('clicking banner!!!!', e.target)}
+    onClose={e => {
+      e.stopPropagation();
+    }}
+    fullMode={false}
+    title="标题"
+    description="A pre-released version is available"
+  >
+    <Button onClick={e => e.stopPropagation()}>test</Button>
+  </Banner>
+);
+
+export const InContainerAndBordered = () => (
+  <Banner title="标题" bordered description="A pre-released version is available">
+    <Button onClick={e => e.stopPropagation()}>test</Button>
+  </Banner>
+);

+ 306 - 272
packages/semi-ui/breadcrumb/_story/breadcrumb.stories.js

@@ -1,283 +1,317 @@
 /* argus-disable unPkgSensitiveInfo */
 import React from 'react';
-import { storiesOf } from '@storybook/react';
 import Breadcrumb from '../index';
 import Popover from '../../popover';
-import { IconMore, IconArrowRight, IconHome, IconArticle, IconChevronRight, IconArticle } from '@douyinfe/semi-icons';
+import {
+  IconMore,
+  IconArrowRight,
+  IconHome,
+  IconArticle,
+  IconChevronRight,
+} from '@douyinfe/semi-icons';
 
-const stories = storiesOf('Breadcrumb', module);
-stories.add('regular breadcrumb', () => (
-    <div>
-        <Breadcrumb
-            routes={[
-                {
-                    path: '/home',
-                    name: 'home',
-                },
-                'breadcrumb',
-                'default',
-            ]}
-            onClick={item => console.log(item)}
-        />
-        <Breadcrumb
-            routes={[
-                {
-                    path: '/home',
-                    icon: <IconHome />,
-                    href: '#',
-                },
-                {
-                    path: '/breadcrumb',
-                    name: 'breadcrumb',
-                    icon: <IconChevronRight />,
-                },
-                'icon',
-            ]}
-            onClick={item => console.log(item)}
-        />
-        <Breadcrumb
-            routes={[
-                {
-                    path: '/home',
-                    name: 'home',
-                },
-                'breadcrumb',
-                'separator',
-                'string',
-            ]}
-            onClick={item => console.log(item)}
-            separator={'>'}
-        />
-        <Breadcrumb
-            routes={[
-                {
-                    path: '/home',
-                    name: 'home',
-                },
-                'breadcrumb',
-                'separator',
-                'with icon',
-            ]}
-            onClick={item => console.log(item)}
-            separator={<IconArrowRight size={'small'} />}
-        />
-        <Breadcrumb routes={['首页', '当这个页面标题很长时需要省略', '详情页']} onClick={item => console.log(item)} />
-        <Breadcrumb
-            routes={['首页', '当层级很多的时候', '又一层很长需要省略的时候', '再一层', '上上一层', '上一层', '详情页']}
-            onClick={item => console.log(item)}
-        />
-    </div>
-));
-stories.add('compact breadcrumb', () => (
-    <div>
-        <Breadcrumb
-            routes={[
-                {
-                    path: '/home',
-                    name: 'home',
-                },
-                'breadcrumb',
-                'compact',
-            ]}
-            onClick={item => console.log(item)}
-            compact={true}
-        />
-        <Breadcrumb
-            routes={[
-                {
-                    path: '/home',
-                    icon: <IconHome />,
-                },
-                {
-                    path: '/breadcrumb',
-                    name: 'breadcrumb',
-                    icon: <IconChevronRight />,
-                },
-                'icon',
-            ]}
-            onClick={item => console.log(item)}
-            compact={true}
-        />
-        <Breadcrumb
-            routes={[
-                {
-                    path: '/home',
-                    name: 'home',
-                },
-                'breadcrumb',
-                'separator',
-                'string',
-            ]}
-            onClick={item => console.log(item)}
-            separator={'>'}
-            compact={true}
-        />
-        <Breadcrumb
-            routes={[
-                {
-                    path: '/home',
-                    name: 'home',
-                },
-                'breadcrumb',
-                'separator',
-                'icon',
-            ]}
-            onClick={item => console.log(item)}
-            separator={<IconArrowRight size={'small'} />}
-            compact={true}
-        />
-        <Breadcrumb
-            routes={['首页', '当这个页面标题很长时需要省略', '详情页']}
-            onClick={item => console.log(item)}
-            compact={true}
-        />
-        <Breadcrumb
-            routes={['首页', '当层级很多的时候', '又一层很长需要省略的时候', '再一层', '上上一层', '上一层', '详情页']}
-            onClick={item => console.log(item)}
-            compact={true}
-        />
-    </div>
-));
-stories.add('breadcrumbitem', () => (
-    <div>
-        <Breadcrumb onClick={item => console.log(item)}>
-            <Breadcrumb.Item onClick={item => console.log('child', item)}>home</Breadcrumb.Item>
-            <Breadcrumb.Item href="#">breadcrumb</Breadcrumb.Item>
-            <Breadcrumb.Item>default</Breadcrumb.Item>
-        </Breadcrumb>
-        <Breadcrumb onClick={item => console.log(item)}>
-            <Breadcrumb.Item icon={<IconHome />}></Breadcrumb.Item>
-            <Breadcrumb.Item>breadcrumb</Breadcrumb.Item>
-            <Breadcrumb.Item>default</Breadcrumb.Item>
-        </Breadcrumb>
-        <Breadcrumb separator={'>'} onClick={item => console.log(item)}>
-            <Breadcrumb.Item>home</Breadcrumb.Item>
-            <Breadcrumb.Item href="#">breadcrumb</Breadcrumb.Item>
-            <Breadcrumb.Item>separator</Breadcrumb.Item>
-        </Breadcrumb>
-        <Breadcrumb compact={true} onClick={item => console.log(item)}>
-            <Breadcrumb.Item>home</Breadcrumb.Item>
-            <Breadcrumb.Item>breadcrumb</Breadcrumb.Item>
-            <Breadcrumb.Item>compact</Breadcrumb.Item>
-        </Breadcrumb>
-        <Breadcrumb onClick={item => console.log(item)}>
-            <Breadcrumb.Item>首页</Breadcrumb.Item>
-            <Breadcrumb.Item>当这个页面标题很长时需要省略</Breadcrumb.Item>
-            <Breadcrumb.Item>详情页</Breadcrumb.Item>
-        </Breadcrumb>
-        <Breadcrumb onClick={item => console.log(item)}>
-            <Breadcrumb.Item>首页</Breadcrumb.Item>
-            <Breadcrumb.Item>当层级很多的时候</Breadcrumb.Item>
-            <Breadcrumb.Item>又一层很长需要省略的时候</Breadcrumb.Item>
-            <Breadcrumb.Item>再一层</Breadcrumb.Item>
-            <Breadcrumb.Item>上上一层</Breadcrumb.Item>
-            <Breadcrumb.Item>上一层</Breadcrumb.Item>
-            <Breadcrumb.Item>详情页</Breadcrumb.Item>
-        </Breadcrumb>
-        <Breadcrumb></Breadcrumb>
-    </div>
-));
-stories.add('test', () => (
-    <div>
-        <Breadcrumb onClick={item => console.log(item)}>
-            <Breadcrumb.Item onClick={item => console.log('child', item)}>home jump</Breadcrumb.Item>
-            <Breadcrumb.Item href="#">breadcrumb</Breadcrumb.Item>
-            <Breadcrumb.Item>
-                <h1>default</h1>
-            </Breadcrumb.Item>
-        </Breadcrumb>
-        <Breadcrumb>
-            <Breadcrumb.Item icon={<IconHome />}></Breadcrumb.Item>
-            <Breadcrumb.Item icon={<IconArticle />}>
-                <h5>breadcrumb</h5>
-            </Breadcrumb.Item>
-            <Breadcrumb.Item>with icon</Breadcrumb.Item>
-        </Breadcrumb>
-    </div>
-));
-const serpator = '-'; // 用于拼接 restItem 数组项的分隔符
+export default {
+  title: 'Breadcrumb',
+}
+
+export const Default = () => (
+  <div>
+    <Breadcrumb
+      routes={[
+        {
+          path: '/home',
+          name: 'home',
+        },
+        'breadcrumb',
+        'default',
+      ]}
+      onClick={item => console.log(item)}
+    />
+    <Breadcrumb
+      routes={[
+        {
+          path: '/home',
+          icon: <IconHome />,
+          href: '#',
+        },
+        {
+          path: '/breadcrumb',
+          name: 'breadcrumb',
+          icon: <IconChevronRight />,
+        },
+        'icon',
+      ]}
+      onClick={item => console.log(item)}
+    />
+    <Breadcrumb
+      routes={[
+        {
+          path: '/home',
+          name: 'home',
+        },
+        'breadcrumb',
+        'separator',
+        'string',
+      ]}
+      onClick={item => console.log(item)}
+      separator={'>'}
+    />
+    <Breadcrumb
+      routes={[
+        {
+          path: '/home',
+          name: 'home',
+        },
+        'breadcrumb',
+        'separator',
+        'with icon',
+      ]}
+      onClick={item => console.log(item)}
+      separator={<IconArrowRight size={'small'} />}
+    />
+    <Breadcrumb
+      routes={['首页', '当这个页面标题很长时需要省略', '详情页']}
+      onClick={item => console.log(item)}
+    />
+    <Breadcrumb
+      routes={[
+        '首页',
+        '当层级很多的时候',
+        '又一层很长需要省略的时候',
+        '再一层',
+        '上上一层',
+        '上一层',
+        '详情页',
+      ]}
+      onClick={item => console.log(item)}
+    />
+  </div>
+);
+
+export const Compact = () => (
+  <div>
+    <Breadcrumb
+      routes={[
+        {
+          path: '/home',
+          name: 'home',
+        },
+        'breadcrumb',
+        'compact',
+      ]}
+      onClick={item => console.log(item)}
+      compact={true}
+    />
+    <Breadcrumb
+      routes={[
+        {
+          path: '/home',
+          icon: <IconHome />,
+        },
+        {
+          path: '/breadcrumb',
+          name: 'breadcrumb',
+          icon: <IconChevronRight />,
+        },
+        'icon',
+      ]}
+      onClick={item => console.log(item)}
+      compact={true}
+    />
+    <Breadcrumb
+      routes={[
+        {
+          path: '/home',
+          name: 'home',
+        },
+        'breadcrumb',
+        'separator',
+        'string',
+      ]}
+      onClick={item => console.log(item)}
+      separator={'>'}
+      compact={true}
+    />
+    <Breadcrumb
+      routes={[
+        {
+          path: '/home',
+          name: 'home',
+        },
+        'breadcrumb',
+        'separator',
+        'icon',
+      ]}
+      onClick={item => console.log(item)}
+      separator={<IconArrowRight size={'small'} />}
+      compact={true}
+    />
+    <Breadcrumb
+      routes={['首页', '当这个页面标题很长时需要省略', '详情页']}
+      onClick={item => console.log(item)}
+      compact={true}
+    />
+    <Breadcrumb
+      routes={[
+        '首页',
+        '当层级很多的时候',
+        '又一层很长需要省略的时候',
+        '再一层',
+        '上上一层',
+        '上一层',
+        '详情页',
+      ]}
+      onClick={item => console.log(item)}
+      compact={true}
+    />
+  </div>
+);
+
+export const BreadcrumbItemJSX = () => (
+  <div>
+    <Breadcrumb onClick={item => console.log(item)}>
+      <Breadcrumb.Item onClick={item => console.log('child', item)}>home</Breadcrumb.Item>
+      <Breadcrumb.Item href="#">breadcrumb</Breadcrumb.Item>
+      <Breadcrumb.Item>default</Breadcrumb.Item>
+    </Breadcrumb>
+    <Breadcrumb onClick={item => console.log(item)}>
+      <Breadcrumb.Item icon={<IconHome />}></Breadcrumb.Item>
+      <Breadcrumb.Item>breadcrumb</Breadcrumb.Item>
+      <Breadcrumb.Item>default</Breadcrumb.Item>
+    </Breadcrumb>
+    <Breadcrumb separator={'>'} onClick={item => console.log(item)}>
+      <Breadcrumb.Item>home</Breadcrumb.Item>
+      <Breadcrumb.Item href="#">breadcrumb</Breadcrumb.Item>
+      <Breadcrumb.Item>separator</Breadcrumb.Item>
+    </Breadcrumb>
+    <Breadcrumb compact={true} onClick={item => console.log(item)}>
+      <Breadcrumb.Item>home</Breadcrumb.Item>
+      <Breadcrumb.Item>breadcrumb</Breadcrumb.Item>
+      <Breadcrumb.Item>compact</Breadcrumb.Item>
+    </Breadcrumb>
+    <Breadcrumb onClick={item => console.log(item)}>
+      <Breadcrumb.Item>首页</Breadcrumb.Item>
+      <Breadcrumb.Item>当这个页面标题很长时需要省略</Breadcrumb.Item>
+      <Breadcrumb.Item>详情页</Breadcrumb.Item>
+    </Breadcrumb>
+    <Breadcrumb onClick={item => console.log(item)}>
+      <Breadcrumb.Item>首页</Breadcrumb.Item>
+      <Breadcrumb.Item>当层级很多的时候</Breadcrumb.Item>
+      <Breadcrumb.Item>又一层很长需要省略的时候</Breadcrumb.Item>
+      <Breadcrumb.Item>再一层</Breadcrumb.Item>
+      <Breadcrumb.Item>上上一层</Breadcrumb.Item>
+      <Breadcrumb.Item>上一层</Breadcrumb.Item>
+      <Breadcrumb.Item>详情页</Breadcrumb.Item>
+    </Breadcrumb>
+    <Breadcrumb></Breadcrumb>
+  </div>
+);
+
+export const Test = () => (
+  <div>
+    <Breadcrumb onClick={item => console.log(item)}>
+      <Breadcrumb.Item onClick={item => console.log('child', item)}>home jump</Breadcrumb.Item>
+      <Breadcrumb.Item href="#">breadcrumb</Breadcrumb.Item>
+      <Breadcrumb.Item>
+        <h1>default</h1>
+      </Breadcrumb.Item>
+    </Breadcrumb>
+    <Breadcrumb>
+      <Breadcrumb.Item icon={<IconHome />}></Breadcrumb.Item>
+      <Breadcrumb.Item icon={<IconArticle />}>
+        <h5>breadcrumb</h5>
+      </Breadcrumb.Item>
+      <Breadcrumb.Item>with icon</Breadcrumb.Item>
+    </Breadcrumb>
+  </div>
+);
+
+const separator = '-'; // 用于拼接 restItem 数组项的分隔符
 
 const renderMore = restItem => {
-    const content = (
-        <>
-            {restItem.map((item, idx) => (
-                <React.Fragment key={`restItem-${idx}`}>
-                    {item}
-                    {idx !== restItem.length - 1 && (
-                        <span
-                            style={{
-                                color: 'var(--semi-color-text-2)',
-                                marginRight: '6px',
-                            }}
-                        >
-                            {serpator}
-                        </span>
-                    )}
-                </React.Fragment>
-            ))}
-        </>
-    );
-    return (
-        <Popover
-            content={content}
-            style={{
-                padding: 12,
-            }}
-            showArrow
-        >
-            <IconMore />
-        </Popover>
-    );
+  const content = (
+    <>
+      {restItem.map((item, idx) => (
+        <React.Fragment key={`restItem-${idx}`}>
+          {item}
+          {idx !== restItem.length - 1 && (
+            <span
+              style={{
+                color: 'var(--semi-color-text-2)',
+                marginRight: '6px',
+              }}
+            >
+              {separator}
+            </span>
+          )}
+        </React.Fragment>
+      ))}
+    </>
+  );
+  return (
+    <Popover
+      content={content}
+      style={{
+        padding: 12,
+      }}
+      showArrow
+    >
+      <IconMore />
+    </Popover>
+  );
 };
 
-stories.add('renderMore', () => (
-    <div
-        style={{
-            margin: '100px',
-        }}
+export const RenderMore = () => (
+  <div
+    style={{
+      margin: '100px',
+    }}
+  >
+    <Breadcrumb
+      renderMore={restItem => renderMore(restItem)}
+      onClick={(item, e) => console.log(item, e)}
     >
-        <Breadcrumb renderMore={restItem => renderMore(restItem)} onClick={(item, e) => console.log(item, e)}>
-            <Breadcrumb.Item>首页</Breadcrumb.Item>
-            <Breadcrumb.Item>当层级很多的时候</Breadcrumb.Item>
-            <Breadcrumb.Item>又一层</Breadcrumb.Item>
-            <Breadcrumb.Item>再一层</Breadcrumb.Item>
-            <Breadcrumb.Item>上上一层</Breadcrumb.Item>
-            <Breadcrumb.Item>上一层</Breadcrumb.Item>
-            <Breadcrumb.Item>详情页</Breadcrumb.Item>
-        </Breadcrumb>
-        <br />
-        <br />
-        <div>
-            <Breadcrumb
-                renderMore={restItem => renderMore(restItem)}
-                onClick={(item, e) => console.log(item, e)}
-                routes={[
-                    {
-                        path: '/',
-                        href: '/',
-                        icon: <IconHome />,
-                    },
-                    {
-                        path: '/breadcrumb',
-                        href: '/components/breadcrumb',
-                        name: 'breadcrumb',
-                        icon: <IconArticle />,
-                    },
-                    {
-                        path: '/breadcrumb',
-                        href: '/components/breadcrumb',
-                        name: 'breadcrumb',
-                        icon: <IconArticle />,
-                    },
-                    {
-                        path: '/breadcrumb',
-                        href: '/components/breadcrumb',
-                        name: 'breadcrumb',
-                        icon: <IconArticle />,
-                    },
-                    'with icon',
-                ]}
-            />
-        </div>
+      <Breadcrumb.Item>首页</Breadcrumb.Item>
+      <Breadcrumb.Item>当层级很多的时候</Breadcrumb.Item>
+      <Breadcrumb.Item>又一层</Breadcrumb.Item>
+      <Breadcrumb.Item>再一层</Breadcrumb.Item>
+      <Breadcrumb.Item>上上一层</Breadcrumb.Item>
+      <Breadcrumb.Item>上一层</Breadcrumb.Item>
+      <Breadcrumb.Item>详情页</Breadcrumb.Item>
+    </Breadcrumb>
+    <br />
+    <br />
+    <div>
+      <Breadcrumb
+        renderMore={restItem => renderMore(restItem)}
+        onClick={(item, e) => console.log(item, e)}
+        routes={[
+          {
+            path: '/',
+            href: '/',
+            icon: <IconHome />,
+          },
+          {
+            path: '/breadcrumb',
+            href: '/components/breadcrumb',
+            name: 'breadcrumb',
+            icon: <IconArticle />,
+          },
+          {
+            path: '/breadcrumb',
+            href: '/components/breadcrumb',
+            name: 'breadcrumb',
+            icon: <IconArticle />,
+          },
+          {
+            path: '/breadcrumb',
+            href: '/components/breadcrumb',
+            name: 'breadcrumb',
+            icon: <IconArticle />,
+          },
+          'with icon',
+        ]}
+      />
     </div>
-));
+  </div>
+);

+ 265 - 239
packages/semi-ui/button/_story/button.stories.js

@@ -1,5 +1,4 @@
 import React, { useState } from 'react';
-import { storiesOf } from '@storybook/react'; // import { withKnobs, text, boolean } from '@storybook/addon-knobs';
 
 import withPropsCombinations from 'react-storybook-addon-props-combinations';
 import { strings, numbers, cssClasses } from '@douyinfe/semi-foundation/button/constants';
@@ -8,247 +7,274 @@ import ButtonGroup from '../buttonGroup';
 import SplitButtonGroup from '../splitButtonGroup';
 import Dropdown from '../../dropdown';
 import { Tooltip, Switch } from '@douyinfe/semi-ui';
-import { IconTick, IconEdit, IconTwitter, IconUser,IconCopy,IconSearch,IconPlay } from '@douyinfe/semi-icons';
+import {
+  IconTick,
+  IconEdit,
+  IconTwitter,
+  IconUser,
+  IconCopy,
+  IconSearch,
+  IconPlay,
+} from '@douyinfe/semi-icons';
 import Collapse from '../../collapse';
 
-const stories = storiesOf('Button', module); // stories.addDecorator(withKnobs);;
-
-stories.add('button', () => <Button type="primary">UI semi</Button>);
-stories.add('danger', () => <Button type="danger">hello button</Button>);
-stories.add('warning', () => <Button type="warning">hello button</Button>);
-stories.add('with icon', () => (
-    <>
-        <Button icon={<IconTick />}>hello button</Button>
-        <br />
-        <Button icon={<IconEdit />} noHorizontalPadding={false} ghost={false}>
-            Edit me
-        </Button>
-        <Button icon={<IconUser />} />
-    </>
-));
-stories.add(
-    'combination show',
-    withPropsCombinations(
-        Button,
-        {
-            disabled: [false, true],
-            children: ['hello button'],
-            size: strings.sizes,
-            type: strings.btnTypes,
-            theme: strings.themes, // block: [false, true],
-            // ghost: [false, true],
-            // light: [false, true],
-        },
-        {
-            showSource: false,
-        }
-    )
+export default {
+  title: 'Button',
+}
+
+export const Primary = () => <Button type="primary">UI semi</Button>;
+
+export const Danger = () => <Button type="danger">hello button</Button>;
+
+export const Warning = () => <Button type="warning">hello button</Button>;
+
+export const WithIcon = () => (
+  <>
+    <Button icon={<IconTick />}>hello button</Button>
+    <br />
+    <Button icon={<IconEdit />} noHorizontalPadding={false} ghost={false}>
+      Edit me
+    </Button>
+    <Button icon={<IconUser />} />
+  </>
 );
-stories.add('button group', () => (
-    <div>
-        <ButtonGroup disabled>
-            <Button>复制</Button>
-            <Button type="primary">查找</Button>
-            <Button type="danger">粘贴</Button>
-        </ButtonGroup>
-        <br />
-        <ButtonGroup>
-            <Button icon={<IconCopy />} theme={'solid'} />
-            <Button icon={<IconSearch />} theme={'solid'} />
-            <Button icon={<IconPlay />} theme={'solid'} />
-        </ButtonGroup>
-        <br />
-
-        <ButtonGroup size={'large'}>
-            <Button icon={<IconCopy />} theme={'solid'} />
-            <Button icon={<IconSearch />} theme={'solid'} />
-            <Button icon={<IconPlay />} theme={'solid'} />
-        </ButtonGroup>
-        <br />
-
-        <ButtonGroup size={'small'}>
-            <Button icon={<IconCopy />} theme={'solid'} />
-            <Button icon={<IconSearch />} theme={'solid'} />
-            <Button icon={<IconPlay />} theme={'solid'} />
-        </ButtonGroup>
-        <br />
-
-        <ButtonGroup>
-            <Button icon={<IconCopy />} theme={'solid'}>
-                拷贝
-            </Button>
-            <Button icon={<IconSearch />} theme={'solid'}>
-                搜索
-            </Button>
-            <Button icon={<IconPlay />} theme={'solid'}>
-                播放
-            </Button>
-        </ButtonGroup>
-        <br />
-
-        <ButtonGroup size={'large'}>
-            <Button icon={<IconCopy />} theme={'solid'}>
-                拷贝
-            </Button>
-            <Button icon={<IconSearch />} theme={'solid'}>
-                搜索
-            </Button>
-            <Button icon={<IconPlay />} theme={'solid'}>
-                播放
-            </Button>
-        </ButtonGroup>
-        <br />
-
-        <ButtonGroup size={'small'}>
-            <Button icon={<IconCopy />} theme={'solid'}>
-                拷贝
-            </Button>
-            <Button icon={<IconSearch />} theme={'solid'}>
-                搜索
-            </Button>
-            <Button icon={<IconPlay />} theme={'solid'}>
-                播放
-            </Button>
-        </ButtonGroup>
-        <br />
-    </div>
-));
-stories.add('button loading', () => {
-    function LoadingDemo() {
-        const [loading, setLoading] = useState(false);
-        return (
-            <div
-                style={{
-                    maxWidth: 400,
-                    maxHeight: 300,
-                    padding: 50,
-                }}
-            >
-                <div>
-                    <Switch checked={loading} onChange={loading => setLoading(loading)} />
-                </div>
-                <Button loading={loading}>保存</Button>
-                <Button loading={loading} type="danger" theme="solid">
-                    删除
-                </Button>
-                <Button loading={loading} type="danger" theme="solid" disabled>
-                    删除
-                </Button>
-                <Button loading={loading} type="danger" theme="solid" block>
-                    删除
-                </Button>
-                <Tooltip content={loading ? '正在保存' : '保存'}>
-                    <Button loading={loading}>保存</Button>
-                </Tooltip>
-                <Button icon={<IconEdit />} loading={loading} />
-                <Tooltip content={loading ? '载入中' : '编辑'}>
-                    <Button icon={<IconEdit />} loading={loading} />
-                </Tooltip>
-                <Tooltip content={loading ? '载入中' : '编辑'}>
-                    <Button icon={<IconEdit />} loading={loading} theme="solid" />
-                </Tooltip>
-                <Tooltip content={loading ? '载入中' : '编辑'}>
-                    <Button icon={<IconEdit />} loading={loading} theme="solid" type="danger" />
-                </Tooltip>
-                <Tooltip content={loading ? '载入中' : '编辑'}>
-                    <Button icon={<IconEdit />} loading={loading} theme="solid" type="warning" disabled />
-                </Tooltip>
-            </div>
-        );
-    }
-
-    return <LoadingDemo />;
-});
+
+export const CombinationShow = withPropsCombinations(
+  Button,
+  {
+    disabled: [false, true],
+    children: ['hello button'],
+    size: strings.sizes,
+    type: strings.btnTypes,
+    theme: strings.themes, // block: [false, true],
+    // ghost: [false, true],
+    // light: [false, true],
+  },
+  {
+    showSource: false,
+  }
+);
+
+export const ButtonGroupDemo = () => (
+  <div>
+    <ButtonGroup disabled>
+      <Button>复制</Button>
+      <Button type="primary">查找</Button>
+      <Button type="danger">粘贴</Button>
+    </ButtonGroup>
+    <br />
+    <ButtonGroup>
+      <Button icon={<IconCopy />} theme={'solid'} />
+      <Button icon={<IconSearch />} theme={'solid'} />
+      <Button icon={<IconPlay />} theme={'solid'} />
+    </ButtonGroup>
+    <br />
+
+    <ButtonGroup size={'large'}>
+      <Button icon={<IconCopy />} theme={'solid'} />
+      <Button icon={<IconSearch />} theme={'solid'} />
+      <Button icon={<IconPlay />} theme={'solid'} />
+    </ButtonGroup>
+    <br />
+
+    <ButtonGroup size={'small'}>
+      <Button icon={<IconCopy />} theme={'solid'} />
+      <Button icon={<IconSearch />} theme={'solid'} />
+      <Button icon={<IconPlay />} theme={'solid'} />
+    </ButtonGroup>
+    <br />
+
+    <ButtonGroup>
+      <Button icon={<IconCopy />} theme={'solid'}>
+        拷贝
+      </Button>
+      <Button icon={<IconSearch />} theme={'solid'}>
+        搜索
+      </Button>
+      <Button icon={<IconPlay />} theme={'solid'}>
+        播放
+      </Button>
+    </ButtonGroup>
+    <br />
+
+    <ButtonGroup size={'large'}>
+      <Button icon={<IconCopy />} theme={'solid'}>
+        拷贝
+      </Button>
+      <Button icon={<IconSearch />} theme={'solid'}>
+        搜索
+      </Button>
+      <Button icon={<IconPlay />} theme={'solid'}>
+        播放
+      </Button>
+    </ButtonGroup>
+    <br />
+
+    <ButtonGroup size={'small'}>
+      <Button icon={<IconCopy />} theme={'solid'}>
+        拷贝
+      </Button>
+      <Button icon={<IconSearch />} theme={'solid'}>
+        搜索
+      </Button>
+      <Button icon={<IconPlay />} theme={'solid'}>
+        播放
+      </Button>
+    </ButtonGroup>
+    <br />
+  </div>
+);
+
+export function Loading() {
+    const [loading, setLoading] = useState(false);
+    return (
+      <div
+        style={{
+          maxWidth: 400,
+          maxHeight: 300,
+          padding: 50,
+        }}
+      >
+        <div>
+          <Switch checked={loading} onChange={loading => setLoading(loading)} />
+        </div>
+        <Button loading={loading}>保存</Button>
+        <Button loading={loading} type="danger" theme="solid">
+          删除
+        </Button>
+        <Button loading={loading} type="danger" theme="solid" disabled>
+          删除
+        </Button>
+        <Button loading={loading} type="danger" theme="solid" block>
+          删除
+        </Button>
+        <Tooltip content={loading ? '正在保存' : '保存'}>
+          <Button loading={loading}>保存</Button>
+        </Tooltip>
+        <Button icon={<IconEdit />} loading={loading} />
+        <Tooltip content={loading ? '载入中' : '编辑'}>
+          <Button icon={<IconEdit />} loading={loading} />
+        </Tooltip>
+        <Tooltip content={loading ? '载入中' : '编辑'}>
+          <Button icon={<IconEdit />} loading={loading} theme="solid" />
+        </Tooltip>
+        <Tooltip content={loading ? '载入中' : '编辑'}>
+          <Button icon={<IconEdit />} loading={loading} theme="solid" type="danger" />
+        </Tooltip>
+        <Tooltip content={loading ? '载入中' : '编辑'}>
+          <Button icon={<IconEdit />} loading={loading} theme="solid" type="warning" disabled />
+        </Tooltip>
+      </div>
+    );
+};
+
 const menu = [
-    {
-        node: 'title',
-        name: '标题一',
-    },
-    {
-        node: 'item',
-        name: '编辑项目',
-        onClick: () => console.log('编辑项目点击'),
-    },
-    {
-        node: 'item',
-        name: '重置项目',
-        type: 'secondary',
-    },
-    {
-        node: 'divider',
-    },
-    {
-        node: 'item',
-        name: '从项目创建模版',
-        type: 'tertiary',
-    },
-    {
-        node: 'item',
-        name: '复制项目',
-        type: 'warning',
-    },
-    {
-        node: 'divider',
-    },
-    {
-        node: 'item',
-        name: '删除项目',
-        type: 'danger',
-    },
+  {
+    node: 'title',
+    name: '标题一',
+  },
+  {
+    node: 'item',
+    name: '编辑项目',
+    onClick: () => console.log('编辑项目点击'),
+  },
+  {
+    node: 'item',
+    name: '重置项目',
+    type: 'secondary',
+  },
+  {
+    node: 'divider',
+  },
+  {
+    node: 'item',
+    name: '从项目创建模版',
+    type: 'tertiary',
+  },
+  {
+    node: 'item',
+    name: '复制项目',
+    type: 'warning',
+  },
+  {
+    node: 'divider',
+  },
+  {
+    node: 'item',
+    name: '删除项目',
+    type: 'danger',
+  },
 ];
 const content = '批量通过';
-stories.add('split button', () => (
-    <>
-        <p>基础</p>
-        <SplitButtonGroup>
-            <Button theme="solid" type="primary">
-                前面
-            </Button>
-            <Button theme="solid" type="primary">
-                后面
-            </Button>
-        </SplitButtonGroup>
-        <br />
-        <SplitButtonGroup>
-            <Button theme="solid" type="primary">
-                One
-            </Button>
-        </SplitButtonGroup>
-        <br />
-        <SplitButtonGroup>
-            <Button size="small" theme="solid" type="primary">
-                前面
-            </Button>
-            <Button size="small" theme="solid" type="primary">
-                中间
-            </Button>
-            <Button size="small" theme="solid" type="primary">
-                后面
-            </Button>
-            <Dropdown trigger="click" menu={menu} position="bottomRight">
-                <Button size="small" theme="solid" type="primary" icon={<IconTwitter />}></Button>
-            </Dropdown>
-        </SplitButtonGroup>
-    </>
-));
-
-stories.add('button stopPropagation when disabled', () => (
-    <>
-        <Collapse>
-            <Collapse.Panel header={<>title<Button>按钮</Button></>} itemKey="1">
-                <p>Hi, bytedance dance dance. This is the docsite of Semi UI. </p>
-            </Collapse.Panel>
-            <Collapse.Panel header={<>title<Button disabled>按钮</Button></>} itemKey="2">
-                <p>Hi, bytedance dance dance. This is the docsite of Semi UI. </p>
-            </Collapse.Panel>
-        </Collapse>
-        <div onClick={() => console.log('div')}>
-            <span>正常冒泡</span>
-            <Button onClick={() => console.log('button')}>按钮</Button>
-        </div>
-        <div onClick={() => console.log('div')}>
-            <span>禁用 Button 后,阻止冒泡</span>
-            <Button disabled onClick={() => console.log('button')}>按钮</Button>
-        </div>
-    </>
-));
+
+export const SplitButton = () => (
+  <>
+    <p>基础</p>
+    <SplitButtonGroup>
+      <Button theme="solid" type="primary">
+        前面
+      </Button>
+      <Button theme="solid" type="primary">
+        后面
+      </Button>
+    </SplitButtonGroup>
+    <br />
+    <SplitButtonGroup>
+      <Button theme="solid" type="primary">
+        One
+      </Button>
+    </SplitButtonGroup>
+    <br />
+    <SplitButtonGroup>
+      <Button size="small" theme="solid" type="primary">
+        前面
+      </Button>
+      <Button size="small" theme="solid" type="primary">
+        中间
+      </Button>
+      <Button size="small" theme="solid" type="primary">
+        后面
+      </Button>
+      <Dropdown trigger="click" menu={menu} position="bottomRight">
+        <Button size="small" theme="solid" type="primary" icon={<IconTwitter />}></Button>
+      </Dropdown>
+    </SplitButtonGroup>
+  </>
+);
+
+export const StopPropagationWhenDisabled = () => (
+  <>
+    <Collapse>
+      <Collapse.Panel
+        header={
+          <>
+            title<Button>按钮</Button>
+          </>
+        }
+        itemKey="1"
+      >
+        <p>Hi, bytedance dance dance. This is the docsite of Semi UI. </p>
+      </Collapse.Panel>
+      <Collapse.Panel
+        header={
+          <>
+            title<Button disabled>按钮</Button>
+          </>
+        }
+        itemKey="2"
+      >
+        <p>Hi, bytedance dance dance. This is the docsite of Semi UI. </p>
+      </Collapse.Panel>
+    </Collapse>
+    <div onClick={() => console.log('div')}>
+      <span>正常冒泡</span>
+      <Button onClick={() => console.log('button')}>按钮</Button>
+    </div>
+    <div onClick={() => console.log('div')}>
+      <span>禁用 Button 后,阻止冒泡</span>
+      <Button disabled onClick={() => console.log('button')}>
+        按钮
+      </Button>
+    </div>
+  </>
+);

+ 345 - 343
packages/semi-ui/calendar/_story/calendar.stories.js

@@ -1,6 +1,4 @@
 import React, { useState } from 'react';
-import { storiesOf } from '@storybook/react';
-import withPropsCombinations from 'react-storybook-addon-props-combinations';
 
 import Calendar from '../index';
 import { Button, RadioGroup, Radio, LocaleProvider, Select } from '@douyinfe/semi-ui';
@@ -18,386 +16,390 @@ import th_TH from '@douyinfe/semi-ui/locale/source/th_TH';
 import tr_TR from '@douyinfe/semi-ui/locale/source/tr_TR';
 import pt_BR from '@douyinfe/semi-ui/locale/source/pt_BR';
 
-const stories = storiesOf('Calendar', module);
 const { Option } = Select;
 
-// stories.addDecorator(withKnobs);;
+export default {
+  title: 'Calendar',
+}
 
 const time = new Date();
 let id = 0;
 const language = {
-    'zh_CN': zh_CN,
-    'en_GB': en_GB,
-    'ko_KR': ko_KR,
-    'ja_JP': ja_JP,
-    'ar': ar,
-    'vi_VN': vi_VN,
-    'ru_RU': ru_RU,
-    'id_ID': id_ID,
-    'ms_MY': ms_MY,
-    'th_TH': th_TH,
-    'tr_TR': tr_TR,
-    'pt_BR': pt_BR,
+  zh_CN: zh_CN,
+  en_GB: en_GB,
+  ko_KR: ko_KR,
+  ja_JP: ja_JP,
+  ar: ar,
+  vi_VN: vi_VN,
+  ru_RU: ru_RU,
+  id_ID: id_ID,
+  ms_MY: ms_MY,
+  th_TH: th_TH,
+  tr_TR: tr_TR,
+  pt_BR: pt_BR,
 };
 
 const events = [
-    {
-        allDay: true,
-        children: (<div style={{ backgroundColor: 'blue', height: '100%' }}>today-allDay</div>)
-    },
-    {
-        start: time,
-        children: (<div style={{ backgroundColor: 'indigo', height: '100px' }}>today-now</div>)
-    },
-    {
-        allDay: true,
-        children: (<div style={{ backgroundColor: 'green', height: '100%' }}>today-allDay2</div>)
-    }, {
-        allDay: true,
-        children: (<div style={{ backgroundColor: 'blue', height: '100%' }}>today-allDay3</div>)
-    }, {
-        allDay: true,
-        children: (<div style={{ backgroundColor: 'green', height: '100%' }}>today-allDay4</div>)
-    },
+  {
+    allDay: true,
+    children: <div style={{ backgroundColor: 'blue', height: '100%' }}>today-allDay</div>,
+  },
+  {
+    start: time,
+    children: <div style={{ backgroundColor: 'indigo', height: '100px' }}>today-now</div>,
+  },
+  {
+    allDay: true,
+    children: <div style={{ backgroundColor: 'green', height: '100%' }}>today-allDay2</div>,
+  },
+  {
+    allDay: true,
+    children: <div style={{ backgroundColor: 'blue', height: '100%' }}>today-allDay3</div>,
+  },
+  {
+    allDay: true,
+    children: <div style={{ backgroundColor: 'green', height: '100%' }}>today-allDay4</div>,
+  },
 ];
 
 const weeklyEvents = [
-    {
-        allDay: true,
-        start: new Date(2019, 6, 15, 8, 0, 0),
-        children: (<div style={{ backgroundColor: 'blue', height: '100%' }}>7-15-AllDayA</div>)
-    },
-    {
-        start: new Date(2019, 6, 16, 8, 32, 0),
-        children: (<div style={{ backgroundColor: 'indigo', height: '100%' }}>7-16 8:32 here is a very long content just to see if the content will collapse or not not sure if this is long enough aaaaaaaaaaa</div>)
-    },
-    {
-        start: new Date(2019, 6, 16, 14, 30, 0),
-        end: new Date(2019, 6, 16, 20, 0, 0),
-        children: (<div style={{ backgroundColor: 'indigo', height: '100%' }}>7-16 14:30-20:00</div>)
-    },
-    {
-        start: new Date(2019, 6, 18, 14, 45, 0),
-        end: new Date(2019, 6, 19, 6, 18, 0),
-        children: (<div style={{ backgroundColor: 'indigo', height: '100%' }}>7-18 14:45 ~ 7-19 6:18</div>)
-    },
-    // {
-    //     start: new Date(2019, 6, 18, 8, 0, 0),
-    //     end: new Date(2019, 6, 20, 6, 0, 0),
-    //     children: (<div style={{backgroundColor: 'indigo', height: '100%'}}>AllDayB</div>)
-    // },
-    // {
-    //     start: new Date(2019, 6, 15, 9, 0, 0),
-    //     end: new Date(2019, 6, 16, 23, 0, 0),
-    //     children: (<div style={{backgroundColor: 'LightSkyBlue', height: '100%'}}>AllDayC</div>)
-    // },
-    // {
-    //     start: new Date(2019, 6, 14, 6, 0, 0),
-    //     end: new Date(2019, 6, 18, 6, 0, 0),
-    //     children: (<div style={{backgroundColor: 'YellowGreen', height: '100%'}}>AllDayD</div>)
-    // },
-    // {
-    //     start: new Date(2019, 6, 12, 20, 0, 0),
-    //     end: new Date(2019, 6, 16, 14, 0, 0),
-    //     children: (<div style={{backgroundColor: 'pink', height: '100%'}}>AllDayE</div>)
-    // },
-    // {
-    //     start: new Date(2019, 6, 19, 10, 0, 0),
-    //     end: new Date(2019, 6, 20, 16, 0, 0),
-    //     children: (<div style={{backgroundColor: 'red', height: '100%'}}>AllDayF</div>)
-    // },
-    // {
-    //     start: new Date(2019, 6, 11, 10, 0, 0),
-    //     end: new Date(2019, 6, 25, 8, 0, 0),
-    //     children: (<div style={{backgroundColor: 'green', height: '100%'}}>AllDayG</div>)
-    // },
-]
+  {
+    allDay: true,
+    start: new Date(2019, 6, 15, 8, 0, 0),
+    children: <div style={{ backgroundColor: 'blue', height: '100%' }}>7-15-AllDayA</div>,
+  },
+  {
+    start: new Date(2019, 6, 16, 8, 32, 0),
+    children: (
+      <div style={{ backgroundColor: 'indigo', height: '100%' }}>
+        7-16 8:32 here is a very long content just to see if the content will collapse or not not
+        sure if this is long enough aaaaaaaaaaa
+      </div>
+    ),
+  },
+  {
+    start: new Date(2019, 6, 16, 14, 30, 0),
+    end: new Date(2019, 6, 16, 20, 0, 0),
+    children: <div style={{ backgroundColor: 'indigo', height: '100%' }}>7-16 14:30-20:00</div>,
+  },
+  {
+    start: new Date(2019, 6, 18, 14, 45, 0),
+    end: new Date(2019, 6, 19, 6, 18, 0),
+    children: (
+      <div style={{ backgroundColor: 'indigo', height: '100%' }}>7-18 14:45 ~ 7-19 6:18</div>
+    ),
+  },
+];
 // const events = [];
 const date = new Date(2019, 6, 18, 8, 0, 0);
 
 const dailyEventStyle = {
-    borderRadius: '3px',
-    boxSizing: 'border-box',
-    border: 'var(--semi-color-primary) 1px solid',
-    padding: '10px',
-    backgroundColor: 'var(--semi-color-primary-light-default)',
-    height: '100%',
-    overflow: 'hidden'
+  borderRadius: '3px',
+  boxSizing: 'border-box',
+  border: 'var(--semi-color-primary) 1px solid',
+  padding: '10px',
+  backgroundColor: 'var(--semi-color-primary-light-default)',
+  height: '100%',
+  overflow: 'hidden',
 };
 const allDayStyle = {
-    borderRadius: '3px',
-    boxSizing: 'border-box',
-    border: 'var(--semi-color-bg-1) 1px solid',
-    marginRight: '12px',
-    padding: '2px 4px',
-    backgroundColor: 'var(--semi-color-primary-light-active)',
-    height: '100%',
-    overflow: 'hidden'
+  borderRadius: '3px',
+  boxSizing: 'border-box',
+  border: 'var(--semi-color-bg-1) 1px solid',
+  marginRight: '12px',
+  padding: '2px 4px',
+  backgroundColor: 'var(--semi-color-primary-light-active)',
+  height: '100%',
+  overflow: 'hidden',
 };
 
 const weeklyEvents2 = [
-    {
-        allDay: true,
-        start: new Date(2019, 6, 22, 8, 0, 0),
-        children: (<div style={{ backgroundColor: 'blue', height: '100%' }}>7-22-allDay</div>)
-    },
-    {
-        start: new Date(2019, 6, 23, 8, 32, 0),
-        children: (<div style={{ backgroundColor: 'indigo', height: '100%' }}>7-23 8:32</div>)
-    },
-    {
-        start: new Date(2019, 6, 23, 14, 30, 0),
-        end: new Date(2019, 6, 23, 20, 0, 0),
-        children: (<div style={{ backgroundColor: 'indigo', height: '100%' }}>7-23 14:30-20:00</div>)
-    },
-    {
-        start: new Date(2019, 6, 25, 14, 45, 0),
-        end: new Date(2019, 6, 26, 6, 18, 0),
-        children: (<div style={{ backgroundColor: 'indigo', height: '100%' }}>7-25 14:45 ~ 7-26 6:18</div>)
-    },
-    {
-        start: new Date(2019, 6, 25, 8, 0, 0),
-        end: new Date(2019, 6, 27, 6, 0, 0),
-        children: (<div style={{ backgroundColor: 'indigo', height: '100%' }}>7-25 8:00 ~ 7-27 6:00</div>)
-    },
-    {
-        start: new Date(2019, 6, 22, 9, 0, 0),
-        end: new Date(2019, 6, 23, 23, 0, 0),
-        children: (<div style={{ backgroundColor: 'LightSkyBlue', height: '100%' }}>7-22 9:00 ~ 7-23 23:00</div>)
-    },
-    {
-        start: new Date(2019, 6, 21, 6, 0, 0),
-        end: new Date(2019, 6, 25, 6, 0, 0),
-        children: (<div style={{ backgroundColor: 'YellowGreen', height: '100%' }}>7-21 6:00 ~ 7-25 6:00</div>)
-    },
-    {
-        start: new Date(2019, 6, 19, 20, 0, 0),
-        end: new Date(2019, 6, 23, 14, 0, 0),
-        children: (<div style={{ backgroundColor: 'pink', height: '100%' }}>7-19 20:00 ~ 7-23 14:00</div>)
-    },
-    {
-        start: new Date(2019, 6, 26, 10, 0, 0),
-        end: new Date(2019, 6, 27, 16, 0, 0),
-        children: (<div style={{ backgroundColor: 'red', height: '100%' }}>7-26 10:00 ~ 7-27 16:00</div>)
-    },
-    {
-        start: new Date(2019, 6, 18, 10, 0, 0),
-        end: new Date(2019, 6, 30, 8, 0, 0),
-        children: (<div style={{ backgroundColor: 'green', height: '100%' }}>7-18 10:00 ~ 7-30 8:00</div>)
-    },
-]
-
-stories.add('dayCalendar', () => {
-    return (
-        <div>
-            <Calendar
-                mode='day'
-                events={events}
-            // displayValue={new Date(2019, 6, 16, 8, 0, 0)}
-            ></Calendar>
-        </div>
-    );
-});
+  {
+    allDay: true,
+    start: new Date(2019, 6, 22, 8, 0, 0),
+    children: <div style={{ backgroundColor: 'blue', height: '100%' }}>7-22-allDay</div>,
+  },
+  {
+    start: new Date(2019, 6, 23, 8, 32, 0),
+    children: <div style={{ backgroundColor: 'indigo', height: '100%' }}>7-23 8:32</div>,
+  },
+  {
+    start: new Date(2019, 6, 23, 14, 30, 0),
+    end: new Date(2019, 6, 23, 20, 0, 0),
+    children: <div style={{ backgroundColor: 'indigo', height: '100%' }}>7-23 14:30-20:00</div>,
+  },
+  {
+    start: new Date(2019, 6, 25, 14, 45, 0),
+    end: new Date(2019, 6, 26, 6, 18, 0),
+    children: (
+      <div style={{ backgroundColor: 'indigo', height: '100%' }}>7-25 14:45 ~ 7-26 6:18</div>
+    ),
+  },
+  {
+    start: new Date(2019, 6, 25, 8, 0, 0),
+    end: new Date(2019, 6, 27, 6, 0, 0),
+    children: (
+      <div style={{ backgroundColor: 'indigo', height: '100%' }}>7-25 8:00 ~ 7-27 6:00</div>
+    ),
+  },
+  {
+    start: new Date(2019, 6, 22, 9, 0, 0),
+    end: new Date(2019, 6, 23, 23, 0, 0),
+    children: (
+      <div style={{ backgroundColor: 'LightSkyBlue', height: '100%' }}>7-22 9:00 ~ 7-23 23:00</div>
+    ),
+  },
+  {
+    start: new Date(2019, 6, 21, 6, 0, 0),
+    end: new Date(2019, 6, 25, 6, 0, 0),
+    children: (
+      <div style={{ backgroundColor: 'YellowGreen', height: '100%' }}>7-21 6:00 ~ 7-25 6:00</div>
+    ),
+  },
+  {
+    start: new Date(2019, 6, 19, 20, 0, 0),
+    end: new Date(2019, 6, 23, 14, 0, 0),
+    children: (
+      <div style={{ backgroundColor: 'pink', height: '100%' }}>7-19 20:00 ~ 7-23 14:00</div>
+    ),
+  },
+  {
+    start: new Date(2019, 6, 26, 10, 0, 0),
+    end: new Date(2019, 6, 27, 16, 0, 0),
+    children: <div style={{ backgroundColor: 'red', height: '100%' }}>7-26 10:00 ~ 7-27 16:00</div>,
+  },
+  {
+    start: new Date(2019, 6, 18, 10, 0, 0),
+    end: new Date(2019, 6, 30, 8, 0, 0),
+    children: (
+      <div style={{ backgroundColor: 'green', height: '100%' }}>7-18 10:00 ~ 7-30 8:00</div>
+    ),
+  },
+];
 
-stories.add('weekCalendar', () => {
-    return (
-        <div>
-            <Calendar
-                displayValue={date}
-                events={weeklyEvents}
-            ></Calendar>
-        </div>
-    );
-});
+export const DayCalendar = () => {
+  return (
+    <div>
+      <Calendar
+        mode="day"
+        events={events}
+        // displayValue={new Date(2019, 6, 16, 8, 0, 0)}
+      ></Calendar>
+    </div>
+  );
+};
 
-stories.add('this week calendar', () => {
-    return (
-        <div>
-            <Calendar
-                events={weeklyEvents2}
-                displayValue={new Date(2019, 6, 22, 8, 0, 0)}
-            ></Calendar>
-        </div>
-    );
-});
+DayCalendar.parameters = {
+  chromatic: { disableSnapshot: true },
+}
 
-stories.add('month calendar', () => {
-    return (
-        <Calendar
-            events={[...weeklyEvents2, ...weeklyEvents]}
-            mode='month'
-        ></Calendar>
-    );
-});
+export const WeekCalendar = () => {
+  return (
+    <div>
+      <Calendar displayValue={date} events={weeklyEvents}></Calendar>
+    </div>
+  );
+};
 
-const AddDemo = () => {
-    const [event, setEvent] = useState([]);
-    const [mode, setMode] = useState('day');
+export const ThisWeekCalendar = () => {
+  return (
+    <div>
+      <Calendar events={weeklyEvents2} displayValue={new Date(2019, 6, 22, 8, 0, 0)}></Calendar>
+    </div>
+  );
+};
 
-    const addEvent = () => {
-        let newEvent = {
-            allDay: true,
-            start: new Date(),
-            key: `${id}`,
-            children: (<div style={allDayStyle}>today-{id}</div>)
-        };
-        id++;
-        setEvent([...event, newEvent]);
-    }
+export const MonthCalendar = () => {
+  return <Calendar events={[...weeklyEvents2, ...weeklyEvents]} mode="month"></Calendar>;
+};
 
-    const removeEvent = () => {
-        let newEvents = [...event];
-        newEvents.pop();
-        setEvent([...newEvents]);
-    }
-    return (
-        <>
-            <Button onClick={addEvent}>add</Button>
-            <Button onClick={removeEvent}>remove</Button>
-            <RadioGroup onChange={(e) => setMode(e.target.value)} value={mode}>
-                <Radio value={'day'}>日视图</Radio>
-                <Radio value={'week'}>周视图</Radio>
-                <Radio value={'month'}>月视图</Radio>
-            </RadioGroup>
-            <Calendar
-                events={event}
-                mode={mode}
-            />
-        </>
-    );
+MonthCalendar.parameters = {
+  chromatic: { disableSnapshot: true },
 }
 
-stories.add('add event to calendar', () => <AddDemo />);
+const AddEventToCalendar = () => {
+  const [event, setEvent] = useState([]);
+  const [mode, setMode] = useState('day');
+
+  const addEvent = () => {
+    let newEvent = {
+      allDay: true,
+      start: new Date(),
+      key: `${id}`,
+      children: <div style={allDayStyle}>today-{id}</div>,
+    };
+    id++;
+    setEvent([...event, newEvent]);
+  };
 
+  const removeEvent = () => {
+    let newEvents = [...event];
+    newEvents.pop();
+    setEvent([...newEvents]);
+  };
+  return (
+    <>
+      <Button onClick={addEvent}>add</Button>
+      <Button onClick={removeEvent}>remove</Button>
+      <RadioGroup onChange={e => setMode(e.target.value)} value={mode}>
+        <Radio value={'day'}>日视图</Radio>
+        <Radio value={'week'}>周视图</Radio>
+        <Radio value={'month'}>月视图</Radio>
+      </RadioGroup>
+      <Calendar events={event} mode={mode} />
+    </>
+  );
+};
 
-const UpdateDemo = () => {
-    const [event, setEvent] = useState([]);
-    const [mode, setMode] = useState('day');
-    const [updateId, setId] = useState(id);
+export const UpdateEvent = () => {
+  const [event, setEvent] = useState([]);
+  const [mode, setMode] = useState('day');
+  const [updateId, setId] = useState(id);
 
-    const addEvent = () => {
-        let key = `${id}`;
-        let newEvent = {
-            allDay: true,
-            start: new Date(),
-            key,
-            children: (<div style={allDayStyle} onClick={() => {
-                console.log(key);
-                setId(key);
-            }}>today-{key}</div>),
+  const addEvent = () => {
+    let key = `${id}`;
+    let newEvent = {
+      allDay: true,
+      start: new Date(),
+      key,
+      children: (
+        <div
+          style={allDayStyle}
+          onClick={() => {
+            console.log(key);
+            setId(key);
+          }}
+        >
+          today-{key}
+        </div>
+      ),
+    };
+    id++;
+    setEvent([...event, newEvent]);
+  };
 
-        };
-        id++;
-        setEvent([...event, newEvent]);
-    }
+  const updateEvent = () => {
+    let ind = event.findIndex(item => {
+      return item.key === updateId;
+    });
+    let newArr = [...event];
+    newArr[ind].key = `${Math.random()}`;
+    newArr[ind].children = <div style={allDayStyle}>today-{Math.random(0, 1)}</div>;
+    setEvent(newArr);
+  };
 
-    const updateEvent = () => {
-        let ind = event.findIndex(item => {
-            return item.key === updateId;
-        });
-        let newArr = [...event];
-        newArr[ind].key = `${Math.random()}`
-        newArr[ind].children = (<div style={allDayStyle}>today-{Math.random(0, 1)}</div>)
-        setEvent(newArr);
-    }
+  return (
+    <>
+      <Button onClick={addEvent}>add</Button>
+      <Button onClick={updateEvent}>update</Button>
+      <RadioGroup onChange={e => setMode(e.target.value)} value={mode}>
+        <Radio value={'day'}>日视图</Radio>
+        <Radio value={'week'}>周视图</Radio>
+        <Radio value={'month'}>月视图</Radio>
+      </RadioGroup>
+      <Calendar events={event} mode={mode} />
+    </>
+  );
+};
 
-    return (
-        <>
-            <Button onClick={addEvent}>add</Button>
-            <Button onClick={updateEvent}>update</Button>
-            <RadioGroup onChange={(e) => setMode(e.target.value)} value={mode}>
-                <Radio value={'day'}>日视图</Radio>
-                <Radio value={'week'}>周视图</Radio>
-                <Radio value={'month'}>月视图</Radio>
-            </RadioGroup>
-            <Calendar
-                events={event}
-                mode={mode}
-            />
-        </>
-    );
+UpdateEvent.parameters = {
+  chromatic: { disableSnapshot: true },
 }
 
-stories.add('update event', () => <UpdateDemo />);
+export const DateGridRenderWeek = () => {
+  return (
+    <div>
+      <Calendar
+        displayValue={date}
+        events={weeklyEvents}
+        dateGridRender={(dateString, date) => {
+          if (dateString === new Date(2019, 6, 16).toString()) {
+            return (
+              <div style={{ backgroundColor: 'red', height: '100%', width: '100%' }}>123test</div>
+            );
+          }
+          return null;
+        }}
+      ></Calendar>
+    </div>
+  );
+};
 
-stories.add('dateGridRender - week', () => {
-    return (
-        <div>
-            <Calendar
-                displayValue={date}
-                events={weeklyEvents}
-                dateGridRender={(dateString, date) => {
-                    if (dateString === new Date(2019, 6, 16).toString()) {
-                        return <div style={{ backgroundColor: 'red', height: '100%', width: '100%' }}>123test</div>
-                    }
-                    return null;
-                }}
-            ></Calendar>
-        </div>
-    );
-});
+export const DateGridRenderMonth = () => {
+  return (
+    <div>
+      <Calendar
+        mode="month"
+        displayValue={date}
+        events={weeklyEvents}
+        dateGridRender={(dateString, date) => {
+          console.log(dateString);
+          if (dateString === new Date(2019, 6, 16).toString()) {
+            return (
+              <div style={{ backgroundColor: 'red', height: '100%', width: '100%' }}>123test</div>
+            );
+          }
+          return null;
+        }}
+      ></Calendar>
+    </div>
+  );
+};
 
-stories.add('dateGridRender - month', () => {
-    return (
-        <div>
-            <Calendar
-                mode='month'
-                displayValue={date}
-                events={weeklyEvents}
-                dateGridRender={(dateString, date) => {
-                    console.log(dateString)
-                    if (dateString === new Date(2019, 6, 16).toString()) {
-                        return <div style={{ backgroundColor: 'red', height: '100%', width: '100%' }}>123test</div>
-                    }
-                    return null;
-                }}
-            ></Calendar>
-        </div>
-    );
-});
+export const RangeCalenderMonth = () => {
+  return (
+    <div>
+      <Calendar
+        mode={'range'}
+        range={[new Date(2019, 6, 22), new Date(2019, 6, 25)]}
+        events={weeklyEvents2}
+        displayValue={new Date(2019, 6, 22)}
+      />
+    </div>
+  );
+};
 
-stories.add('rangecalender - month', () => {
-    return (
-        <div>
-            <Calendar
-                mode={'range'}
-                range={[new Date(2019, 6, 22), new Date(2019, 6, 25)]}
-                events={weeklyEvents2}
-                displayValue={new Date(2019, 6, 22)}
-            />
-        </div>
-    );
-});
+export const WithLocaleProvider = () => {
+  const [locale, setLocale] = useState(zh_CN);
+  const onLanguageChange = code => {
+    setLocale(language[code]);
+  };
 
-stories.add('locale provider', () => {
-    const [locale, setLocale] = useState(zh_CN);
-    const onLanguageChange = (code) => {
-        setLocale(language[code]);
-    };
+  return (
+    <LocaleProvider>
+      <div style={{ borderBottom: '1px solid var(--semi-color-border)', paddingBottom: 20 }}>
+        <Select
+          onChange={onLanguageChange}
+          insetLabel="切换语言"
+          style={{ width: 250 }}
+          defaultValue="zh_CN"
+        >
+          <Option value="zh_CN">中文</Option>
+          <Option value="en_GB">英语(英)</Option>
+          <Option value="ja_JP">日语</Option>
+          <Option value="ko_KR">韩语</Option>
+          <Option value="ar">阿拉伯语</Option>
+          <Option value="vi_VN">越南语</Option>
+          <Option value="ru_RU">俄罗斯语</Option>
+          <Option value="id_ID">印尼语</Option>
+          <Option value="ms_MY">马来语</Option>
+          <Option value="th_TH">泰语</Option>
+          <Option value="tr_TR">土耳其语</Option>
+          <Option value="pt_BR">葡萄牙语(巴西)</Option>
+        </Select>
+      </div>
+      <LocaleProvider locale={locale}>
+        <Calendar mode="day" />
+        <br />
+        <Calendar mode="week" />
+        <br />
+        <Calendar mode="month" />
+        <br />
+      </LocaleProvider>
+    </LocaleProvider>
+  );
+};
 
-    return (
-        <LocaleProvider>
-            <div style={{ borderBottom: '1px solid var(--semi-color-border)', paddingBottom: 20 }}>
-                <Select onChange={onLanguageChange} insetLabel='切换语言' style={{width: 250}} defaultValue='zh_CN'>
-                    <Option value='zh_CN'>中文</Option>
-                    <Option value='en_GB'>英语(英)</Option>
-                    <Option value='ja_JP'>日语</Option>
-                    <Option value='ko_KR'>韩语</Option>
-                    <Option value='ar'>阿拉伯语</Option>
-                    <Option value='vi_VN'>越南语</Option>
-                    <Option value='ru_RU'>俄罗斯语</Option>
-                    <Option value='id_ID'>印尼语</Option>
-                    <Option value='ms_MY'>马来语</Option>
-                    <Option value='th_TH'>泰语</Option>
-                    <Option value='tr_TR'>土耳其语</Option>
-                    <Option value='pt_BR'>葡萄牙语(巴西)</Option>
-                </Select>
-            </div>
-            <LocaleProvider locale={locale}>
-                <Calendar mode='day' /><br />
-                <Calendar mode='week' /><br />
-                <Calendar mode='month' /><br />
-            </LocaleProvider>
-        </LocaleProvider>
-    );
-});
+WithLocaleProvider.parameters = {
+  chromatic: { disableSnapshot: true }
+}

+ 514 - 498
packages/semi-ui/card/_story/card.stories.js

@@ -1,539 +1,555 @@
 import React, { useState } from 'react';
-import { storiesOf } from '@storybook/react';
 import {
-    Space,
-    Button,
-    Avatar,
-    Typography,
-    Row,
-    Tabs,
-    TabPane,
-    Col,
-    Skeleton,
-    Switch,
-    Rating,
+  Space,
+  Button,
+  Avatar,
+  Typography,
+  Row,
+  Tabs,
+  TabPane,
+  Col,
+  Skeleton,
+  Switch,
+  Rating,
 } from '@douyinfe/semi-ui/';
 import Card from '../index';
 import CardGroup from '../cardGroup';
-import { IconChevronRight, IconLikeThumb, IconLikeHeart, IconEdit, IconWrench } from '@douyinfe/semi-icons';
+import {
+  IconChevronRight,
+  IconLikeThumb,
+  IconLikeHeart,
+  IconEdit,
+  IconWrench,
+} from '@douyinfe/semi-icons';
 
-const stories = storiesOf('Card', module);
 const { Text } = Typography;
 const { Meta } = Card;
-stories.add('default', () => (
-    <Space wrap>
-        <Card
-            title="基础卡片"
-            style={{
-                width: 360,
-            }}
-            headerExtraContent={<Text link={{}}>更多</Text>}
-        >
-            Semi Design 是由互娱社区前端团队与 UED
-            团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的
-            Web 应用。
-        </Card>
-        <Card
-            title="titleisstringtitleisstringtitleisstringtitleisstringtitleisstring"
-            style={{
-                width: 360,
-            }}
-            headerExtraContent={<Text link={{}}>更多</Text>}
-        >
-            Semi Design 是由互娱社区前端团队与 UED
-            团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的
-            Web 应用。
-        </Card>
-        <Card
-            title="标题为字符串标题特别长标题特别长标题特别长标题特别长标题特别长"
-            style={{
-                width: 360,
-            }}
-            headerExtraContent={<Text link={{}}>更多</Text>}
-        >
-            Semi Design 是由互娱社区前端团队与 UED
-            团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的
-            Web 应用。
-        </Card>
-        <Card
-            title={<div>标题为node标题特别长标题特别长标题特别长标题特别长标题特别长</div>}
-            style={{
-                width: 360,
-            }}
-            headerExtraContent={<Text link={{}}>更多</Text>}
-        >
-            Semi Design 是由互娱社区前端团队与 UED
-            团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的
-            Web 应用。
-        </Card>
-        <Card
-            header={<div>头部内容为node头部内容特别长头部内容特别长头部内容特别长头部内容特别长头部内容特别长</div>}
-            style={{
-                width: 360,
-            }}
-            headerExtraContent={<Text link={{}}>更多</Text>}
-        >
-            Semi Design 是由互娱社区前端团队与 UED
-            团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的
-            Web 应用。
-        </Card>
-        <Card
-            header={<div>headerheaderheaderheaderheaderheaderheaderheaderheaderheader</div>}
-            style={{
-                width: 360,
-            }}
-            headerExtraContent={<Text link={{}}>更多</Text>}
-        >
-            Semi Design 是由互娱社区前端团队与 UED
-            团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的
-            Web 应用。
-        </Card>
-    </Space>
-));
 
-function SimpleDemo() {
-    return (
-        <Space align="start" vertical spacing="medium">
-            <Card
-                style={{
-                    width: 360,
-                }}
-            >
-                Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统。
-            </Card>
-            <Card
-                style={{
-                    width: 360,
-                }}
-                bodyStyle={{
-                    display: 'flex',
-                    alignItems: 'center',
-                    justifyContent: 'space-between',
-                }}
-            >
-                <Meta
-                    title="Semi Doc"
-                    avatar={
-                        <Avatar
-                            size="default"
-                            src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/card-meta-avatar-docs-demo.jpg"
-                        />
-                    }
-                />
-                <Text link={{}}>
-                    <IconChevronRight />
-                </Text>
-            </Card>
-        </Space>
-    );
+export default {
+  title: 'Card',
 }
 
-stories.add('simple ', () => <SimpleDemo />);
-stories.add('cover ', () => (
+export const Default = () => (
+  <Space wrap>
     <Card
-        style={{
-            width: 360,
-        }}
-        cover={
-            <img
-                alt="example"
-                src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/card-cover-docs-demo.jpeg"
-            />
-        }
+      title="基础卡片"
+      style={{
+        width: 360,
+      }}
+      headerExtraContent={<Text link={{}}>更多</Text>}
     >
-        <Meta title="卡片封面" />
+      Semi Design 是由互娱社区前端团队与 UED
+      团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的
+      Web 应用。
     </Card>
-));
-stories.add('bordered', () => (
-    <div
-        style={{
-            display: 'inline-block',
-            padding: 20,
-            backgroundColor: 'var(--semi-color-fill-0)',
-        }}
+    <Card
+      title="titleisstringtitleisstringtitleisstringtitleisstringtitleisstring"
+      style={{
+        width: 360,
+      }}
+      headerExtraContent={<Text link={{}}>更多</Text>}
     >
-        <Card
-            style={{
-                width: 360,
-            }}
-            bordered={false}
-            title="Semi Design"
-        >
-            基于 Semi Design 的中后台设计案例聚合分享平台,海量案例和模板代码助力体验 & 效率提升。
-        </Card>
-    </div>
-));
-stories.add('headerLine / footerLine', () => (
+      Semi Design 是由互娱社区前端团队与 UED
+      团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的
+      Web 应用。
+    </Card>
     <Card
-        style={{
-            width: 360,
-        }}
-        title="Semi Design"
-        headerLine={true}
-        footerLine={false}
-        footer="footer"
+      title="标题为字符串标题特别长标题特别长标题特别长标题特别长标题特别长"
+      style={{
+        width: 360,
+      }}
+      headerExtraContent={<Text link={{}}>更多</Text>}
     >
-        基于 Semi Design 的中后台设计案例聚合分享平台,海量案例和模板代码助力体验 & 效率提升。
+      Semi Design 是由互娱社区前端团队与 UED
+      团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的
+      Web 应用。
     </Card>
-));
-stories.add('shadows', () => (
-    <Space>
-        <Card
-            style={{
-                width: 360,
-            }}
-            title="没有设置shadows"
-        >
-            基于 Semi Design 的中后台设计案例聚合分享平台,海量案例和模板代码助力体验 & 效率提升。
-        </Card>
-        <Card
-            style={{
-                width: 360,
-            }}
-            title="shadows为hover"
-            shadows="hover"
-        >
-            基于 Semi Design 的中后台设计案例聚合分享平台,海量案例和模板代码助力体验 & 效率提升。
-        </Card>
-        <Card
-            style={{
-                width: 360,
-            }}
-            title="shadows为always"
-            shadows="always"
-        >
-            基于 Semi Design 的中后台设计案例聚合分享平台,海量案例和模板代码助力体验 & 效率提升。
-        </Card>
-    </Space>
-));
-stories.add('Card.Meta', () => (
     <Card
+      title={<div>标题为node标题特别长标题特别长标题特别长标题特别长标题特别长</div>}
+      style={{
+        width: 360,
+      }}
+      headerExtraContent={<Text link={{}}>更多</Text>}
+    >
+      Semi Design 是由互娱社区前端团队与 UED
+      团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的
+      Web 应用。
+    </Card>
+    <Card
+      header={
+        <div>
+          头部内容为node头部内容特别长头部内容特别长头部内容特别长头部内容特别长头部内容特别长
+        </div>
+      }
+      style={{
+        width: 360,
+      }}
+      headerExtraContent={<Text link={{}}>更多</Text>}
+    >
+      Semi Design 是由互娱社区前端团队与 UED
+      团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的
+      Web 应用。
+    </Card>
+    <Card
+      header={<div>headerheaderheaderheaderheaderheaderheaderheaderheaderheader</div>}
+      style={{
+        width: 360,
+      }}
+      headerExtraContent={<Text link={{}}>更多</Text>}
+    >
+      Semi Design 是由互娱社区前端团队与 UED
+      团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的
+      Web 应用。
+    </Card>
+  </Space>
+);
+
+export function Simple() {
+  return (
+    <Space align="start" vertical spacing="medium">
+      <Card
         style={{
-            width: 360,
+          width: 360,
         }}
-        title={
-            <Meta
-                title="Semi Doc"
-                description="全面、易用、优质"
-                avatar={
-                    <Avatar
-                        size="default"
-                        src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/card-meta-avatar-docs-demo.jpg"
-                    />
-                }
-            />
-        }
-        headerExtraContent={<Text link={{}}>More</Text>}
-        cover={
-            <img
-                alt="example"
-                src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/card-cover-docs-demo.jpeg"
-            />
-        }
-        footerLine={true}
-        footerStyle={{
-            display: 'flex',
-            justifyContent: 'flex-end',
+      >
+        Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统。
+      </Card>
+      <Card
+        style={{
+          width: 360,
         }}
-        footer={
-            <Space>
-                <Button theme="borderless" type="primary">
-                    精选案例
-                </Button>
-                <Button theme="solid" type="primary">
-                    开始使用
-                </Button>
-            </Space>
-        }
+        bodyStyle={{
+          display: 'flex',
+          alignItems: 'center',
+          justifyContent: 'space-between',
+        }}
+      >
+        <Meta
+          title="Semi Doc"
+          avatar={
+            <Avatar
+              size="default"
+              src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/card-meta-avatar-docs-demo.jpg"
+            />
+          }
+        />
+        <Text link={{}}>
+          <IconChevronRight />
+        </Text>
+      </Card>
+    </Space>
+  );
+}
+
+export const Cover = () => (
+  <Card
+    style={{
+      width: 360,
+    }}
+    cover={
+      <img
+        alt="example"
+        src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/card-cover-docs-demo.jpeg"
+      />
+    }
+  >
+    <Meta title="卡片封面" />
+  </Card>
+);
+
+export const Bordered = () => (
+  <div
+    style={{
+      display: 'inline-block',
+      padding: 20,
+      backgroundColor: 'var(--semi-color-fill-0)',
+    }}
+  >
+    <Card
+      style={{
+        width: 360,
+      }}
+      bordered={false}
+      title="Semi Design"
     >
-        Semi Design 是由互娱社区前端团队与 UED
-        团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的
-        Web 应用。
+      基于 Semi Design 的中后台设计案例聚合分享平台,海量案例和模板代码助力体验 & 效率提升。
     </Card>
-));
-stories.add('inner', () => (
+  </div>
+);
+
+export const HeaderLineFooterLine = () => (
+  <Card
+    style={{
+      width: 360,
+    }}
+    title="Semi Design"
+    headerLine={true}
+    footerLine={false}
+    footer="footer"
+  >
+    基于 Semi Design 的中后台设计案例聚合分享平台,海量案例和模板代码助力体验 & 效率提升。
+  </Card>
+);
+
+export const Shadows = () => (
+  <Space>
     <Card
-        title="Card title"
-        style={{
-            width: 360,
-        }}
+      style={{
+        width: 360,
+      }}
+      title="没有设置shadows"
     >
-        <Card
-            title="Inner Card title"
-            style={{
-                marginBottom: 20,
-            }}
-            headerExtraContent={<Text link={{}}>More</Text>}
-        >
-            Inner Card content
+      基于 Semi Design 的中后台设计案例聚合分享平台,海量案例和模板代码助力体验 & 效率提升。
+    </Card>
+    <Card
+      style={{
+        width: 360,
+      }}
+      title="shadows为hover"
+      shadows="hover"
+    >
+      基于 Semi Design 的中后台设计案例聚合分享平台,海量案例和模板代码助力体验 & 效率提升。
+    </Card>
+    <Card
+      style={{
+        width: 360,
+      }}
+      title="shadows为always"
+      shadows="always"
+    >
+      基于 Semi Design 的中后台设计案例聚合分享平台,海量案例和模板代码助力体验 & 效率提升。
+    </Card>
+  </Space>
+);
+
+export const MetaDemo = () => (
+  <Card
+    style={{
+      width: 360,
+    }}
+    title={
+      <Meta
+        title="Semi Doc"
+        description="全面、易用、优质"
+        avatar={
+          <Avatar
+            size="default"
+            src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/card-meta-avatar-docs-demo.jpg"
+          />
+        }
+      />
+    }
+    headerExtraContent={<Text link={{}}>More</Text>}
+    cover={
+      <img
+        alt="example"
+        src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/card-cover-docs-demo.jpeg"
+      />
+    }
+    footerLine={true}
+    footerStyle={{
+      display: 'flex',
+      justifyContent: 'flex-end',
+    }}
+    footer={
+      <Space>
+        <Button theme="borderless" type="primary">
+          精选案例
+        </Button>
+        <Button theme="solid" type="primary">
+          开始使用
+        </Button>
+      </Space>
+    }
+  >
+    Semi Design 是由互娱社区前端团队与 UED
+    团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的
+    Web 应用。
+  </Card>
+);
+
+export const Inner = () => (
+  <Card
+    title="Card title"
+    style={{
+      width: 360,
+    }}
+  >
+    <Card
+      title="Inner Card title"
+      style={{
+        marginBottom: 20,
+      }}
+      headerExtraContent={<Text link={{}}>More</Text>}
+    >
+      Inner Card content
+    </Card>
+    <Card title="Inner Card title" headerExtraContent={<Text link={{}}>More</Text>}>
+      Inner Card content
+    </Card>
+  </Card>
+);
+
+export const Grid = () => (
+  <div
+    style={{
+      backgroundColor: 'var(--semi-color-fill-0)',
+      padding: 20,
+    }}
+  >
+    <Row gutter={[16, 16]}>
+      <Col span={8}>
+        <Card title="Card Title" bordered={false}>
+          Card Content
         </Card>
-        <Card title="Inner Card title" headerExtraContent={<Text link={{}}>More</Text>}>
-            Inner Card content
+      </Col>
+      <Col span={8}>
+        <Card title="Card Title" bordered={false}>
+          Card Content
         </Card>
-    </Card>
-));
-stories.add('grid', () => (
-    <div
+      </Col>
+      <Col span={8}>
+        <Card title="Card Title" bordered={false}>
+          Card Content
+        </Card>
+      </Col>
+    </Row>
+    <Row gutter={[16, 16]}>
+      <Col span={16}>
+        <Card title="Card Title" bordered={false}>
+          Card Content
+        </Card>
+      </Col>
+      <Col span={8}>
+        <Card title="Card Title" bordered={false}>
+          Card Content
+        </Card>
+      </Col>
+    </Row>
+  </div>
+);
+
+export function Loading() {
+  const [loading, setLoading] = useState(true);
+  const { Meta } = Card;
+  const { Title, Paragraph, Image } = Skeleton;
+  return (
+    <Space vertical align="start" spacing="medium">
+      <Switch onChange={v => setLoading(!v)} />
+      <Card
         style={{
-            backgroundColor: 'var(--semi-color-fill-0)',
-            padding: 20,
+          width: 360,
         }}
-    >
-        <Row gutter={[16, 16]}>
-            <Col span={8}>
-                <Card title="Card Title" bordered={false}>
-                    Card Content
-                </Card>
-            </Col>
-            <Col span={8}>
-                <Card title="Card Title" bordered={false}>
-                    Card Content
-                </Card>
-            </Col>
-            <Col span={8}>
-                <Card title="Card Title" bordered={false}>
-                    Card Content
-                </Card>
-            </Col>
-        </Row>
-        <Row gutter={[16, 16]}>
-            <Col span={16}>
-                <Card title="Card Title" bordered={false}>
-                    Card Content
-                </Card>
-            </Col>
-            <Col span={8}>
-                <Card title="Card Title" bordered={false}>
-                    Card Content
-                </Card>
-            </Col>
-        </Row>
-    </div>
-));
-
-function LoadingDemo() {
-    const [loading, setLoading] = useState(true);
-    const { Meta } = Card;
-    const { Title, Paragraph, Image } = Skeleton;
-    return (
-        <Space vertical align="start" spacing="medium">
-            <Switch onChange={v => setLoading(!v)} />
-            <Card
+        loading={loading}
+      >
+        <Meta title="Semi Doc" description="全面、易用、优质" />
+      </Card>
+      <Card
+        style={{
+          width: 360,
+        }}
+        title={
+          <Meta
+            title={
+              <Skeleton
                 style={{
-                    width: 360,
+                  width: 80,
                 }}
+                placeholder={<Title />}
                 loading={loading}
-            >
-                <Meta title="Semi Doc" description="全面、易用、优质" />
-            </Card>
-            <Card
+              >
+                <Typography.Title heading={5}>Semi Doc</Typography.Title>
+              </Skeleton>
+            }
+            description={
+              <Skeleton
                 style={{
-                    width: 360,
+                  width: 150,
+                  marginTop: 12,
                 }}
-                title={
-                    <Meta
-                        title={
-                            <Skeleton
-                                style={{
-                                    width: 80,
-                                }}
-                                placeholder={<Title />}
-                                loading={loading}
-                            >
-                                <Typography.Title heading={5}>Semi Doc</Typography.Title>
-                            </Skeleton>
-                        }
-                        description={
-                            <Skeleton
-                                style={{
-                                    width: 150,
-                                    marginTop: 12,
-                                }}
-                                placeholder={<Paragraph rows={1} />}
-                                loading={loading}
-                            >
-                                <Typography.Text>全面、易用、优质</Typography.Text>
-                            </Skeleton>
-                        }
-                        avatar={
-                            <Skeleton placeholder={<Skeleton.Avatar />} loading={loading}>
-                                <Avatar
-                                    size="default"
-                                    src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/card-meta-avatar-docs-demo.jpg"
-                                />
-                            </Skeleton>
-                        }
-                    />
-                }
-                headerExtraContent={
-                    <Skeleton
-                        style={{
-                            width: 50,
-                        }}
-                        placeholder={<Paragraph rows={1} />}
-                        loading={loading}
-                    >
-                        <Typography.Text link={{}}>More</Typography.Text>
-                    </Skeleton>
-                }
-                cover={
-                    <Skeleton
-                        style={{
-                            width: '100%',
-                            height: 110,
-                        }}
-                        placeholder={<Image />}
-                        loading={loading}
-                    >
-                        <img
-                            alt="example"
-                            src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/card-cover-docs-demo.jpeg"
-                        />
-                    </Skeleton>
-                }
-            ></Card>
-        </Space>
-    );
-}
-
-stories.add('loading', () => <LoadingDemo />);
-stories.add('tabs', () => (
-    <Card title="Card title">
-        <Tabs
-            type="line"
-            style={{
-                marginTop: -20,
-                marginBottom: -20,
-            }}
-        >
-            <TabPane tab="Tab 1" itemKey="1">
-                <p>content1</p>
-                <p>content1</p>
-                <p>content1</p>
-            </TabPane>
-            <TabPane tab="Tab 2" itemKey="2">
-                <p>content2</p>
-                <p>content2</p>
-                <p>content2</p>
-            </TabPane>
-        </Tabs>
-    </Card>
-));
-stories.add('actions', () => (
-    <Space align="start">
-        <Card
-            style={{
-                width: 360,
-            }}
-            title={
-                <Meta
-                    title="Semi Doc"
-                    description="全面、易用、优质"
-                    avatar={
-                        <Avatar
-                            size="default"
-                            src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/card-meta-avatar-docs-demo.jpg"
-                        />
-                    }
+                placeholder={<Paragraph rows={1} />}
+                loading={loading}
+              >
+                <Typography.Text>全面、易用、优质</Typography.Text>
+              </Skeleton>
+            }
+            avatar={
+              <Skeleton placeholder={<Skeleton.Avatar />} loading={loading}>
+                <Avatar
+                  size="default"
+                  src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/card-meta-avatar-docs-demo.jpg"
                 />
+              </Skeleton>
             }
-            actions={[<Rating defaultValue={4} />]}
-            headerLine={false}
-            footerLine={false}
-            footerStyle={{
-                display: 'flex',
-                justifyContent: 'flex-end',
+          />
+        }
+        headerExtraContent={
+          <Skeleton
+            style={{
+              width: 50,
             }}
-            footer={
-                <Space>
-                    <Button theme="solid" type="primary">
-                        打分
-                    </Button>
-                </Space>
-            }
-        >
-            Semi Design 是由互娱社区前端团队与 UED
-            团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的
-            Web 应用。
-        </Card>
-        <Card
+            placeholder={<Paragraph rows={1} />}
+            loading={loading}
+          >
+            <Typography.Text link={{}}>More</Typography.Text>
+          </Skeleton>
+        }
+        cover={
+          <Skeleton
             style={{
-                width: 360,
+              width: '100%',
+              height: 110,
             }}
-            title={
-                <Meta
-                    title="Semi Doc"
-                    description="全面、易用、优质"
-                    avatar={
-                        <Avatar
-                            size="default"
-                            src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/card-meta-avatar-docs-demo.jpg"
-                        />
-                    }
-                />
-            }
-            actions={[
-                <IconLikeThumb />,
-                <IconLikeHeart />,
-                <IconEdit />,
-                <IconWrench />,
-            ]}
-            headerLine={false}
-        >
-            Semi Design 是由互娱社区前端团队与 UED
-            团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的
-            Web 应用。
-        </Card>
+            placeholder={<Image />}
+            loading={loading}
+          >
+            <img
+              alt="example"
+              src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/card-cover-docs-demo.jpeg"
+            />
+          </Skeleton>
+        }
+      ></Card>
     </Space>
-));
-stories.add('CardGroup', () => (
-    <CardGroup spacing={12}>
-        {new Array(3).fill(null).map((v, idx) => (
-            <Card
-                key={idx}
-                style={{
-                    width: 300,
-                }}
-                title={
-                    <Meta
-                        title="Semi Doc"
-                        description="全面、易用、优质"
-                        avatar={
-                            <Avatar
-                                size="default"
-                                src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/card-meta-avatar-docs-demo.jpg"
-                            />
-                        }
-                    />
-                }
-                headerExtraContent={<Text link>More</Text>}
-                cover={
-                    <img
-                        alt="example"
-                        src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/card-cover-docs-demo.jpeg"
-                    />
-                }
-            >
-                Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统。
-            </Card>
-        ))}
-    </CardGroup>
-));
-stories.add('CardGroup-grid', () => (
-    <CardGroup type="grid">
-        {new Array(7).fill(null).map((v, idx) => (
-            <Card
-                key={idx}
-                shadows="hover"
-                title="Card title"
-                headerLine={false}
-                style={{
-                    width: 260,
-                }}
-                headerExtraContent={<Text link>More</Text>}
-            >
-                <Text>Card content</Text>
-            </Card>
-        ))}
-    </CardGroup>
-));
+  );
+}
+
+
+export const WithTabs = () => (
+  <Card title="Card title">
+    <Tabs
+      type="line"
+      style={{
+        marginTop: -20,
+        marginBottom: -20,
+      }}
+    >
+      <TabPane tab="Tab 1" itemKey="1">
+        <p>content1</p>
+        <p>content1</p>
+        <p>content1</p>
+      </TabPane>
+      <TabPane tab="Tab 2" itemKey="2">
+        <p>content2</p>
+        <p>content2</p>
+        <p>content2</p>
+      </TabPane>
+    </Tabs>
+  </Card>
+);
+
+export const Actions = () => (
+  <Space align="start">
+    <Card
+      style={{
+        width: 360,
+      }}
+      title={
+        <Meta
+          title="Semi Doc"
+          description="全面、易用、优质"
+          avatar={
+            <Avatar
+              size="default"
+              src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/card-meta-avatar-docs-demo.jpg"
+            />
+          }
+        />
+      }
+      actions={[<Rating defaultValue={4} />]}
+      headerLine={false}
+      footerLine={false}
+      footerStyle={{
+        display: 'flex',
+        justifyContent: 'flex-end',
+      }}
+      footer={
+        <Space>
+          <Button theme="solid" type="primary">
+            打分
+          </Button>
+        </Space>
+      }
+    >
+      Semi Design 是由互娱社区前端团队与 UED
+      团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的
+      Web 应用。
+    </Card>
+    <Card
+      style={{
+        width: 360,
+      }}
+      title={
+        <Meta
+          title="Semi Doc"
+          description="全面、易用、优质"
+          avatar={
+            <Avatar
+              size="default"
+              src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/card-meta-avatar-docs-demo.jpg"
+            />
+          }
+        />
+      }
+      actions={[<IconLikeThumb />, <IconLikeHeart />, <IconEdit />, <IconWrench />]}
+      headerLine={false}
+    >
+      Semi Design 是由互娱社区前端团队与 UED
+      团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的
+      Web 应用。
+    </Card>
+  </Space>
+);
+
+export const CardGroupDemo = () => (
+  <CardGroup spacing={12}>
+    {new Array(3).fill(null).map((v, idx) => (
+      <Card
+        key={idx}
+        style={{
+          width: 300,
+        }}
+        title={
+          <Meta
+            title="Semi Doc"
+            description="全面、易用、优质"
+            avatar={
+              <Avatar
+                size="default"
+                src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/card-meta-avatar-docs-demo.jpg"
+              />
+            }
+          />
+        }
+        headerExtraContent={<Text link>More</Text>}
+        cover={
+          <img
+            alt="example"
+            src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/card-cover-docs-demo.jpeg"
+          />
+        }
+      >
+        Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统。
+      </Card>
+    ))}
+  </CardGroup>
+);
+
+export const CardGroupGrid = () => (
+  <CardGroup type="grid">
+    {new Array(7).fill(null).map((v, idx) => (
+      <Card
+        key={idx}
+        shadows="hover"
+        title="Card title"
+        headerLine={false}
+        style={{
+          width: 260,
+        }}
+        headerExtraContent={<Text link>More</Text>}
+      >
+        <Text>Card content</Text>
+      </Card>
+    ))}
+  </CardGroup>
+);

+ 4 - 0
packages/semi-ui/cascader/_story/CustomTrigger/index.jsx

@@ -1,6 +1,10 @@
 import React from 'react';
 import { AutoComplete, Icon, Button, Cascader } from '@douyinfe/semi-ui';
 
+Demo.parameters = {
+    chromatic: { disableSnapshot: false },
+}
+
 export default function Demo() {
     const treeData = [
         {

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 557 - 535
packages/semi-ui/cascader/_story/cascader.stories.js


+ 899 - 764
packages/semi-ui/checkbox/_story/checkbox.stories.js

@@ -1,808 +1,943 @@
-import React, {useCallback, useMemo, useState} from 'react';
-import {storiesOf} from '@storybook/react'; // import { withKnobs, text, boolean } from '@storybook/addon-knobs';
+import React, { useCallback, useMemo, useState } from 'react';
 import Button from '../../button';
 import Popover from '../../popover';
 import Checkbox from '../index';
 import CheckboxGroup from '../checkboxGroup';
-import {Col, Input, Row} from '../../index';
-import {IconClose} from '@douyinfe/semi-icons';
+import { Col, Input, Row } from '../../index';
+import { IconClose } from '@douyinfe/semi-icons';
 
-const stories = storiesOf('Checkbox', module); // stories.addDecorator(withKnobs);;
+export default {
+  title: 'Checkbox',
+}
 
-stories.add('checkbox default', () => {
-    return (
-        <div>
-            <Checkbox onChange={e => console.log(e)} value={1} onChange={v => console.log(v)}>
-                hello
-            </Checkbox>
-            <br/>
-            <Checkbox checked>这是一个受控的checked=true的checkbox,没有配onChange</Checkbox>
-            <br/>
-            <Checkbox defaultChecked>这是一个不受控的defaultChecked=true的checkbox</Checkbox>
-            <br/>
-            <Checkbox disabled>这是一个受控的disabled=true的checkbox</Checkbox>
-            <br/>
-            <Checkbox checked disabled>
-                既checked又disabled
-            </Checkbox>
-            <br/>
-            <Checkbox indeterminate>indeterminate</Checkbox>
-        </div>
-    );
-});
-stories.add('checkbox without text', () => {
-    return (
-        <div>
-            <Checkbox onChange={e => console.log(e)}/>
-        </div>
-    );
-});
+export const CheckboxDefault = () => {
+  return (
+    <div>
+      <Checkbox onChange={e => console.log(e)} value={1} onChange={v => console.log(v)}>
+        hello
+      </Checkbox>
+      <br />
+      <Checkbox checked>这是一个受控的checked=true的checkbox,没有配onChange</Checkbox>
+      <br />
+      <Checkbox defaultChecked>这是一个不受控的defaultChecked=true的checkbox</Checkbox>
+      <br />
+      <Checkbox disabled>这是一个受控的disabled=true的checkbox</Checkbox>
+      <br />
+      <Checkbox checked disabled>
+        既checked又disabled
+      </Checkbox>
+      <br />
+      <Checkbox indeterminate>indeterminate</Checkbox>
+    </div>
+  );
+};
+
+export const CheckboxWithoutText = () => {
+  return (
+    <div>
+      <Checkbox onChange={e => console.log(e)} />
+    </div>
+  );
+};
 
 class CheckboxControl extends React.Component {
-    state = {
-        checked: true,
-        disabled: false,
-    };
-    toggleChecked = () => {
-        this.setState({
-            checked: !this.state.checked,
-        });
-    };
-    toggleDisable = () => {
-        this.setState({
-            disabled: !this.state.disabled,
-        });
-    };
-    onChange = e => {
-        console.log('checked = ', e.target.checked);
-        this.setState({
-            checked: e.target.checked,
-        });
-    };
+  state = {
+    checked: true,
+    disabled: false,
+  };
+  toggleChecked = () => {
+    this.setState({
+      checked: !this.state.checked,
+    });
+  };
+  toggleDisable = () => {
+    this.setState({
+      disabled: !this.state.disabled,
+    });
+  };
+  onChange = e => {
+    console.log('checked = ', e.target.checked);
+    this.setState({
+      checked: e.target.checked,
+    });
+  };
 
-    render() {
-        const label = `${this.state.checked ? 'Checked' : 'Unchecked'}-${this.state.disabled ? 'Disabled' : 'Enabled'}`;
-        return (
-            <div>
-                <p
-                    style={{
-                        marginBottom: '20px',
-                    }}
-                >
-                    <Checkbox checked={this.state.checked} disabled={this.state.disabled} onChange={this.onChange}>
-                        {label}
-                    </Checkbox>
-                </p>
-                <p>
-                    <Button type="primary" size="small" onClick={this.toggleChecked}>
-                        {!this.state.checked ? 'Check' : 'Uncheck'}
-                    </Button>
-                    <Button
-                        style={{
-                            marginLeft: '10px',
-                        }}
-                        type="primary"
-                        size="small"
-                        onClick={this.toggleDisable}
-                    >
-                        {!this.state.disabled ? 'Disable' : 'Enable'}
-                    </Button>
-                </p>
-            </div>
-        );
-    }
+  render() {
+    const label = `${this.state.checked ? 'Checked' : 'Unchecked'}-${
+      this.state.disabled ? 'Disabled' : 'Enabled'
+    }`;
+    return (
+      <div>
+        <p
+          style={{
+            marginBottom: '20px',
+          }}
+        >
+          <Checkbox
+            checked={this.state.checked}
+            disabled={this.state.disabled}
+            onChange={this.onChange}
+          >
+            {label}
+          </Checkbox>
+        </p>
+        <p>
+          <Button type="primary" size="small" onClick={this.toggleChecked}>
+            {!this.state.checked ? 'Check' : 'Uncheck'}
+          </Button>
+          <Button
+            style={{
+              marginLeft: '10px',
+            }}
+            type="primary"
+            size="small"
+            onClick={this.toggleDisable}
+          >
+            {!this.state.disabled ? 'Disable' : 'Enable'}
+          </Button>
+        </p>
+      </div>
+    );
+  }
 }
 
-stories.add('checkbox controlled disabled & checked', () => <CheckboxControl/>);
+export const CheckboxControlledDisabledChecked = () => <CheckboxControl />;
 
-class GroupDemo extends React.Component {
-    constructor() {
-        super();
-        this.state = {
-            value: [],
-        };
-        this.onChange = this.onChange.bind(this);
-    }
-
-    onChange(value) {
-        console.log(value);
-        this.setState({
-            value: value,
-        });
-    }
+CheckboxControlledDisabledChecked.story = {
+  name: 'checkbox controlled disabled & checked',
+};
 
-    render() {
-        let {value} = this.state;
-        return (
-            <>
-                水平Group
-                <Checkbox.Group direction="horizontal" onChange={v => console.log(v)}>
-                    <Checkbox value="dy">抖音</Checkbox>
-                    <Checkbox value="hotsoon">火山</Checkbox>
-                    <Checkbox value="toutiao">今日头条</Checkbox>
-                    <Checkbox value="xigua">西瓜视频</Checkbox>
-                </Checkbox.Group>
-                <br/>
-                <br/>
-                垂直Group
-                <Checkbox.Group onChange={v => console.log(v)}>
-                    <Checkbox value="dy">抖音</Checkbox>
-                    <Checkbox value="hotsoon">火山</Checkbox>
-                    <Checkbox value="toutiao">今日头条</Checkbox>
-                    <Checkbox value="xigua">西瓜视频</Checkbox>
-                </Checkbox.Group>
-                <br/>
-                <br/>
-                默认Group
-                <Checkbox.Group direction="horizontal" defaultValue={['xigua']} onChange={console.log}>
-                    <Checkbox value="dy">抖音</Checkbox>
-                    <Checkbox value="hotsoon">火山</Checkbox>
-                    <Checkbox value="toutiao">今日头条</Checkbox>
-                    <Checkbox value="xigua">西瓜视频</Checkbox>
-                </Checkbox.Group>
-                <br/>
-                <br/>
-                受控Group
-                <Checkbox.Group direction="horizontal" value={value} onChange={console.log}>
-                    <Checkbox value="dy">抖音</Checkbox>
-                    <Checkbox value="hotsoon">火山</Checkbox>
-                    <Checkbox value="toutiao">今日头条</Checkbox>
-                    <Checkbox value="xigua">西瓜视频</Checkbox>
-                </Checkbox.Group>
-                <br/>
-                <br/>
-                受控Group+onChange
-                <Checkbox.Group direction="horizontal" value={value} onChange={this.onChange}>
-                    <Checkbox value="dy">抖音</Checkbox>
-                    <Checkbox value="hotsoon">火山</Checkbox>
-                    <Checkbox value="toutiao">今日头条</Checkbox>
-                    <Checkbox value="xigua">西瓜视频</Checkbox>
-                </Checkbox.Group>
-                <br/>
-                <br/>
-                disabled
-                <Checkbox.Group disabled>
-                    <Checkbox value="dy">抖音</Checkbox>
-                    <Checkbox value="hotsoon">火山</Checkbox>
-                    <Checkbox value="toutiao">今日头条</Checkbox>
-                    <Checkbox value="xigua">西瓜视频</Checkbox>
-                </Checkbox.Group>
-            </>
-        );
-    }
-}
+class GroupDemo extends React.Component {
+  constructor() {
+    super();
+    this.state = {
+      value: [],
+    };
+    this.onChange = this.onChange.bind(this);
+  }
 
-stories.add('checkbox group', () => <GroupDemo/>);
-stories.add('checkbox group with options ', () => {
-    function onChange(checkedValues) {
-        console.log('checked = ', checkedValues);
-    }
+  onChange(value) {
+    console.log(value);
+    this.setState({
+      value: value,
+    });
+  }
 
-    const plainOptions = ['green', 'red', 'pink'];
-    const options = [
-        {
-            label: 'green',
-            value: 'green',
-        },
-        {
-            label: 'red',
-            value: 'red',
-        },
-        {
-            label: 'pink',
-            value: 'pink',
-            disabled: true,
-        },
-    ];
-    const optionsWithDisabled = [
-        {
-            label: 'green',
-            value: 'green',
-        },
-        {
-            label: 'red',
-            value: 'red',
-        },
-        {
-            label: 'pink',
-            value: 'pink',
-            disabled: false,
-        },
-    ];
-    return (
-        <div>
-            default
-            <CheckboxGroup options={plainOptions} defaultValue={['green']} onChange={onChange}/>
-            <br/>
-            <br/>
-            受控
-            <CheckboxGroup options={plainOptions} value={['green']} onChange={onChange}/>
-            <br/>
-            最后一个disabled
-            <br/>
-            <CheckboxGroup options={options} defaultValue={['red']} onChange={onChange}/>
-            <br/>
-            全体disabled, 优先父级disabled,次选子级disabled
-            <br/>
-            <CheckboxGroup options={optionsWithDisabled} disabled defaultValue={['green']} onChange={onChange}/>
-        </div>
-    );
-});
-stories.add('checkboxGroup-直接后代是其他类型Node', () => {
-    return (
-        <CheckboxGroup>
-            <div className="test">
-                <Checkbox value="green" extra="苹果">
-                    green
-                </Checkbox>
-                <Checkbox value="red" extra="梨">
-                    red
-                </Checkbox>
-                <Checkbox value="pink" extra="橙子">
-                    pink
-                </Checkbox>
-            </div>
-        </CheckboxGroup>
-    );
-});
-stories.add('checkbox 主文本+副文本', () => {
-    let options = [
-        {
-            label: 'green',
-            value: 'green',
-            extra: '苹果',
-        },
-        {
-            label: 'red',
-            value: 'red',
-            extra: '梨',
-        },
-        {
-            label: 'pink',
-            value: 'pink',
-            disabled: true,
-            extra: '橙子',
-        },
-    ];
-    return (
-        <div>
-            checkbox
-            <Checkbox
-                onChange={e => console.log(e)}
-                extra="我是副文本,这是辅助的文本,辅助文本会更长一些,甚至还可能换行"
-            >
-                我是主文本
-            </Checkbox>
-            <Checkbox
-                style={{
-                    width: 200,
-                }}
-                onChange={e => console.log(e)}
-                extra="我是副文本,这是辅助的文本,辅助文本会更长一些,甚至还可能换行"
-            >
-                我是主文本
-            </Checkbox>
-            <br/>
-            <br/>
-            checkboxGroup
-            <CheckboxGroup>
-                <Checkbox value="green" extra="苹果">
-                    green
-                </Checkbox>
-                <Checkbox value="red" extra="梨">
-                    red
-                </Checkbox>
-                <Checkbox value="pink" extra="橙子">
-                    pink
-                </Checkbox>
-            </CheckboxGroup>
-            <br/>
-            <br/>
-            checkboxGroup with options
-            <CheckboxGroup options={options}></CheckboxGroup>
-        </div>
-    );
-});
-stories.add('checkbox + grid', () => {
+  render() {
+    let { value } = this.state;
     return (
-        <Checkbox.Group
-            style={{
-                width: '100%',
-            }}
-            onChange={v => console.log(v)}
-        >
-            <Row>
-                <Col span={8}>
-                    <Checkbox value="A">
-                        无限长的一串字The Storybook webapp UI can be customised with this addon. It can be used to
-                        change the header, show/hide various UI elements and to enable full-screen mode by default.
-                    </Checkbox>
-                </Col>
-                <Col span={8}>
-                    <Checkbox value="B">B</Checkbox>
-                </Col>
-                <Col span={8}>
-                    <Checkbox value="C">C</Checkbox>
-                </Col>
-                <Col span={8}>
-                    <Checkbox value="D">D</Checkbox>
-                </Col>
-                <Col span={8}>
-                    <Checkbox value="E">E</Checkbox>
-                </Col>
-            </Row>
+      <>
+        水平Group
+        <Checkbox.Group direction="horizontal" onChange={v => console.log(v)}>
+          <Checkbox value="dy">抖音</Checkbox>
+          <Checkbox value="hotsoon">火山</Checkbox>
+          <Checkbox value="toutiao">今日头条</Checkbox>
+          <Checkbox value="xigua">西瓜视频</Checkbox>
+        </Checkbox.Group>
+        <br />
+        <br />
+        垂直Group
+        <Checkbox.Group onChange={v => console.log(v)}>
+          <Checkbox value="dy">抖音</Checkbox>
+          <Checkbox value="hotsoon">火山</Checkbox>
+          <Checkbox value="toutiao">今日头条</Checkbox>
+          <Checkbox value="xigua">西瓜视频</Checkbox>
+        </Checkbox.Group>
+        <br />
+        <br />
+        默认Group
+        <Checkbox.Group direction="horizontal" defaultValue={['xigua']} onChange={console.log}>
+          <Checkbox value="dy">抖音</Checkbox>
+          <Checkbox value="hotsoon">火山</Checkbox>
+          <Checkbox value="toutiao">今日头条</Checkbox>
+          <Checkbox value="xigua">西瓜视频</Checkbox>
+        </Checkbox.Group>
+        <br />
+        <br />
+        受控Group
+        <Checkbox.Group direction="horizontal" value={value} onChange={console.log}>
+          <Checkbox value="dy">抖音</Checkbox>
+          <Checkbox value="hotsoon">火山</Checkbox>
+          <Checkbox value="toutiao">今日头条</Checkbox>
+          <Checkbox value="xigua">西瓜视频</Checkbox>
+        </Checkbox.Group>
+        <br />
+        <br />
+        受控Group+onChange
+        <Checkbox.Group direction="horizontal" value={value} onChange={this.onChange}>
+          <Checkbox value="dy">抖音</Checkbox>
+          <Checkbox value="hotsoon">火山</Checkbox>
+          <Checkbox value="toutiao">今日头条</Checkbox>
+          <Checkbox value="xigua">西瓜视频</Checkbox>
         </Checkbox.Group>
+        <br />
+        <br />
+        disabled
+        <Checkbox.Group disabled>
+          <Checkbox value="dy">抖音</Checkbox>
+          <Checkbox value="hotsoon">火山</Checkbox>
+          <Checkbox value="toutiao">今日头条</Checkbox>
+          <Checkbox value="xigua">西瓜视频</Checkbox>
+        </Checkbox.Group>
+      </>
     );
-});
+  }
+}
 
+export const CheckboxGroupDemo = () => <GroupDemo />;
 
-const IndeterminateDemo = () => {
-    const options = ['yellow', 'green', 'red'];
-    const defaultCheckedColors = ['yellow', 'red'];
+export const CheckboxGroupWithOptions = () => {
+  function onChange(checkedValues) {
+    console.log('checked = ', checkedValues);
+  }
 
-    const [checkedList, setCheckList] = useState(defaultCheckedColors);
-    const [indeterminate, setIndeterminate] = useState(true);
-    const [checkAll, setCheckAll] = useState(false);
+  const plainOptions = ['green', 'red', 'pink'];
+  const options = [
+    {
+      label: 'green',
+      value: 'green',
+    },
+    {
+      label: 'red',
+      value: 'red',
+    },
+    {
+      label: 'pink',
+      value: 'pink',
+      disabled: true,
+    },
+  ];
+  const optionsWithDisabled = [
+    {
+      label: 'green',
+      value: 'green',
+    },
+    {
+      label: 'red',
+      value: 'red',
+    },
+    {
+      label: 'pink',
+      value: 'pink',
+      disabled: false,
+    },
+  ];
+  return (
+    <div>
+      default
+      <CheckboxGroup options={plainOptions} defaultValue={['green']} onChange={onChange} />
+      <br />
+      <br />
+      受控
+      <CheckboxGroup options={plainOptions} value={['green']} onChange={onChange} />
+      <br />
+      最后一个disabled
+      <br />
+      <CheckboxGroup options={options} defaultValue={['red']} onChange={onChange} />
+      <br />
+      全体disabled, 优先父级disabled,次选子级disabled
+      <br />
+      <CheckboxGroup
+        options={optionsWithDisabled}
+        disabled
+        defaultValue={['green']}
+        onChange={onChange}
+      />
+    </div>
+  );
+};
 
-    const onCheckListChange = checkedList => {
-        setCheckList([...checkedList]);
-        setIndeterminate(!!checkedList.length && checkedList.length < options.length);
-        setCheckAll(checkedList.length === options.length)
-    };
+export const CheckboxGroupWithOtherTypeChild = () => {
+  return (
+    <CheckboxGroup>
+      <div className="test">
+        <Checkbox value="green" extra="苹果">
+          green
+        </Checkbox>
+        <Checkbox value="red" extra="梨">
+          red
+        </Checkbox>
+        <Checkbox value="pink" extra="橙子">
+          pink
+        </Checkbox>
+      </div>
+    </CheckboxGroup>
+  );
+};
 
-    const onCheckAllChange = e => {
-        setCheckList([...(e.target.checked ? options : [])]);
-        setIndeterminate(false);
-        setCheckAll(e.target.checked)
-    };
+CheckboxGroupWithOtherTypeChild.story = {
+  name: 'checkboxGroup-直接后代是其他类型Node',
+};
 
+export const CheckboxExtra = () => {
+  let options = [
+    {
+      label: 'green',
+      value: 'green',
+      extra: '苹果',
+    },
+    {
+      label: 'red',
+      value: 'red',
+      extra: '梨',
+    },
+    {
+      label: 'pink',
+      value: 'pink',
+      disabled: true,
+      extra: '橙子',
+    },
+  ];
+  return (
+    <div>
+      checkbox
+      <Checkbox
+        onChange={e => console.log(e)}
+        extra="我是副文本,这是辅助的文本,辅助文本会更长一些,甚至还可能换行"
+      >
+        我是主文本
+      </Checkbox>
+      <Checkbox
+        style={{
+          width: 200,
+        }}
+        onChange={e => console.log(e)}
+        extra="我是副文本,这是辅助的文本,辅助文本会更长一些,甚至还可能换行"
+      >
+        我是主文本
+      </Checkbox>
+      <br />
+      <br />
+      checkboxGroup
+      <CheckboxGroup>
+        <Checkbox value="green" extra="苹果">
+          green
+        </Checkbox>
+        <Checkbox value="red" extra="梨">
+          red
+        </Checkbox>
+        <Checkbox value="pink" extra="橙子">
+          pink
+        </Checkbox>
+      </CheckboxGroup>
+      <br />
+      <br />
+      checkboxGroup with options
+      <CheckboxGroup options={options}></CheckboxGroup>
+    </div>
+  );
+};
 
-    return
-    return (
-        <div>
-            <div
-                style={{
-                    borderBottom: '1px solid #E9E9E9',
-                }}
-            >
-                <Checkbox
-                    indeterminate={indeterminate}
-                    onChange={onCheckAllChange}
-                    checked={state.checkAll}
-                >
-                    Check all
-                </Checkbox>
-            </div>
-            <br/>
-            <CheckboxGroup options={options} value={checkedList} onChange={onCheckListChange}/>
-        </div>
-    );
-}
+export const CheckboxGrid = () => {
+  return (
+    <Checkbox.Group
+      style={{
+        width: '100%',
+      }}
+      onChange={v => console.log(v)}
+    >
+      <Row>
+        <Col span={8}>
+          <Checkbox value="A">
+            无限长的一串字The Storybook webapp UI can be customised with this addon. It can be used
+            to change the header, show/hide various UI elements and to enable full-screen mode by
+            default.
+          </Checkbox>
+        </Col>
+        <Col span={8}>
+          <Checkbox value="B">B</Checkbox>
+        </Col>
+        <Col span={8}>
+          <Checkbox value="C">C</Checkbox>
+        </Col>
+        <Col span={8}>
+          <Checkbox value="D">D</Checkbox>
+        </Col>
+        <Col span={8}>
+          <Checkbox value="E">E</Checkbox>
+        </Col>
+      </Row>
+    </Checkbox.Group>
+  );
+};
 
+CheckboxGrid.story = {
+  name: 'checkbox + grid',
+};
 
-stories.add('checkbox inderterminate联动', () => <IndeterminateDemo/>);
-stories.add('checkbox render in div', () => (
-    <>
-        <div
-            onClick={(...args) => {
-                console.log('clicked checkbox outer: ', ...args);
-            }}
-        >
-            <Checkbox
-                onChange={(...args) => {
-                    console.log('clicked checkbox: ', ...args);
-                }}
-            />
-        </div>
-    </>
-));
-stories.add(`checkbox in popover`, () => (
+export const IndeterminateDemo = () => {
+  const options = ['yellow', 'green', 'red'];
+  const defaultCheckedColors = ['yellow', 'red'];
+
+  const [checkedList, setCheckList] = useState(defaultCheckedColors);
+  const [indeterminate, setIndeterminate] = useState(true);
+  const [checkAll, setCheckAll] = useState(false);
+
+  const onCheckListChange = checkedList => {
+    setCheckList([...checkedList]);
+    setIndeterminate(!!checkedList.length && checkedList.length < options.length);
+    setCheckAll(checkedList.length === options.length);
+  };
+
+  const onCheckAllChange = e => {
+    setCheckList([...(e.target.checked ? options : [])]);
+    setIndeterminate(false);
+    setCheckAll(e.target.checked);
+  };
+
+  return (
     <div>
-        <Popover
-            content={
-                <div>
-                    <Checkbox>选项一</Checkbox>
-                    <Checkbox defaultChecked>选项二</Checkbox>
-                    <Checkbox>选项三</Checkbox>
-                </div>
-            }
-        >
-            <Button>click me</Button>
-        </Popover>
+      <div
+        style={{
+          borderBottom: '1px solid #E9E9E9',
+        }}
+      >
+        <Checkbox indeterminate={indeterminate} onChange={onCheckAllChange} checked={checkAll}>
+          Check all
+        </Checkbox>
+      </div>
+      <br />
+      <CheckboxGroup options={options} value={checkedList} onChange={onCheckListChange} />
     </div>
-));
+  );
+};
+
+export const CheckboxRenderInDiv = () => (
+  <>
+    <div
+      onClick={(...args) => {
+        console.log('clicked checkbox outer: ', ...args);
+      }}
+    >
+      <Checkbox
+        onChange={(...args) => {
+          console.log('clicked checkbox: ', ...args);
+        }}
+      />
+    </div>
+  </>
+);
+
+export const CheckboxInPopover = () => (
+  <div>
+    <Popover
+      content={
+        <div>
+          <Checkbox>选项一</Checkbox>
+          <Checkbox defaultChecked>选项二</Checkbox>
+          <Checkbox>选项三</Checkbox>
+        </div>
+      }
+    >
+      <Button>click me</Button>
+    </Popover>
+  </div>
+)
 
 const SwitchCheckedFromTrue2Undefined = () => {
-    const [props, setProps] = useState();
-    const [flag, setFlag] = useState(0);
-
-    const change = () => {
-        if (flag === 0) {
-            setFlag(1);
-            setProps({checked: true});
-        } else {
-            setFlag(0);
-            setProps({checked: false});
-        }
-    };
+  const [props, setProps] = useState();
+  const [flag, setFlag] = useState(0);
 
-    return <>
-        <Checkbox {...props} >123</Checkbox>
-        <Button onClick={() => change()}>switch</Button>
+  const change = () => {
+    if (flag === 0) {
+      setFlag(1);
+      setProps({ checked: true });
+    } else {
+      setFlag(0);
+      setProps({ checked: false });
+    }
+  };
+
+  return (
+    <>
+      <Checkbox {...props}>123</Checkbox>
+      <Button onClick={() => change()}>switch</Button>
     </>
+  );
 };
 
-stories.add('checkbox switch checked: true => undefined', () => <SwitchCheckedFromTrue2Undefined/>);
+export const CheckboxSwitchCheckedTrueUndefined = () => <SwitchCheckedFromTrue2Undefined />;
+
+CheckboxSwitchCheckedTrueUndefined.story = {
+  name: 'checkbox switch checked: true => undefined',
+};
 
 const TransformSelect = props => {
-    const {onChange, value, options = [], defaultValue = [], placeholder} = props;
-    const [currentValue, setCurrentValue] = useState([]);
-    const [inputValue, setInputValue] = useState(''); // 变化
-
-    const onSelectChange = useCallback(() => {
-        setCurrentValue(currentValue);
-        onChange && onChange(currentValue);
-    }, []); // 选择某一个
-
-    const removeValue = useCallback(
-        currentIndex => {
-            currentValue.splice(currentIndex, 1);
-            onSelectChange([...currentValue]);
-        },
-        [currentValue]
-    ); // 选择所有
-
-    const selectAllValue = useCallback(() => {
-        const value = options.map(option => option.value);
-        onSelectChange(value);
-    }, [options]);
-    const viewsOptions = useMemo(() => {
-        if (inputValue) {
-            const newOptions = options.filter(option => option.label.indexOf(inputValue) !== -1);
-            return newOptions;
-        }
-
-        return options;
-    }, [options, inputValue]);
-    return (
+  const { onChange, value, options = [], defaultValue = [], placeholder } = props;
+  const [currentValue, setCurrentValue] = useState([]);
+  const [inputValue, setInputValue] = useState(''); // 变化
+
+  const onSelectChange = useCallback(() => {
+    setCurrentValue(currentValue);
+    onChange && onChange(currentValue);
+  }, []); // 选择某一个
+
+  const removeValue = useCallback(
+    currentIndex => {
+      currentValue.splice(currentIndex, 1);
+      onSelectChange([...currentValue]);
+    },
+    [currentValue]
+  ); // 选择所有
+
+  const selectAllValue = useCallback(() => {
+    const value = options.map(option => option.value);
+    onSelectChange(value);
+  }, [options]);
+  const viewsOptions = useMemo(() => {
+    if (inputValue) {
+      const newOptions = options.filter(option => option.label.indexOf(inputValue) !== -1);
+      return newOptions;
+    }
+
+    return options;
+  }, [options, inputValue]);
+  return (
+    <div>
+      <div>
         <div>
-            <div>
-                <div>
-                    <Input
-                        value={inputValue}
-                        prefix="search"
-                        clearable
-                        onChange={value => setInputValue(value)}
-                        placeholder={placeholder}
-                    />
-                </div>
-                <div>
-                    <span>{`共 ${options.length} 项`}</span>
-                    <Button type="tertiary" size="small" theme="borderless" onClick={() => selectAllValue()}>
-                        全选
-                    </Button>
-                </div>
-                <div>
-                    <CheckboxGroup
-                        options={viewsOptions}
-                        value={currentValue}
-                        onChange={onSelectChange}
-                        direction="vertical"
-                    />
-                </div>
-            </div>
-            <div>
-                <div>
-                    <span>{`已选 ${currentValue.length} 项`}</span>
-                    <Button type="tertiary" size="small" theme="borderless" onClick={() => onSelectChange([])}>
-                        清空
-                    </Button>
-                </div>
-                <div>
-                    {currentValue.length > 0 ? (
-                        currentValue.map((value, idx) => {
-                            // 不存在不需要展示
-                            const option = options.find(option => option.value === value);
-                            return (
-                                <div key={option.key ? option.key : idx}>
-                                    <span>{option.label}</span>
-                                    <span onClick={() => removeValue(idx)}>
-                                        <IconClose size="small"/>
-                                    </span>
-                                </div>
-                            );
-                        })
-                    ) : (
-                        <div>暂无内容,可从左侧勾选</div>
-                    )}
+          <Input
+            value={inputValue}
+            prefix="search"
+            clearable
+            onChange={value => setInputValue(value)}
+            placeholder={placeholder}
+          />
+        </div>
+        <div>
+          <span>{`共 ${options.length} 项`}</span>
+          <Button type="tertiary" size="small" theme="borderless" onClick={() => selectAllValue()}>
+            全选
+          </Button>
+        </div>
+        <div>
+          <CheckboxGroup
+            options={viewsOptions}
+            value={currentValue}
+            onChange={onSelectChange}
+            direction="vertical"
+          />
+        </div>
+      </div>
+      <div>
+        <div>
+          <span>{`已选 ${currentValue.length} 项`}</span>
+          <Button
+            type="tertiary"
+            size="small"
+            theme="borderless"
+            onClick={() => onSelectChange([])}
+          >
+            清空
+          </Button>
+        </div>
+        <div>
+          {currentValue.length > 0 ? (
+            currentValue.map((value, idx) => {
+              // 不存在不需要展示
+              const option = options.find(option => option.value === value);
+              return (
+                <div key={option.key ? option.key : idx}>
+                  <span>{option.label}</span>
+                  <span onClick={() => removeValue(idx)}>
+                    <IconClose size="small" />
+                  </span>
                 </div>
-            </div>
+              );
+            })
+          ) : (
+            <div>暂无内容,可从左侧勾选</div>
+          )}
         </div>
-    );
+      </div>
+    </div>
+  );
 };
 
-stories.add(`bugDemo`, () => <TransformSelect/>);
+export const BugDemo = () => <TransformSelect />;
 
-stories.add(`checkboxGroup card style`, () => (
-    <>
-        <div>常见情况</div>
-        <CheckboxGroup type='card' direction='horizontal' defaultValue={['1']}>
-            <Checkbox value='1' extra='Semi Design' style={{width: 280}}>
-                多选框标题
-            </Checkbox>
-            <Checkbox value='2' extra='Semi Design' style={{width: 280}}>
-                多选框标题
-            </Checkbox>
-            <Checkbox value='3' extra='Semi Design' style={{width: 280}}>
-                多选框标题
-            </Checkbox>
-        </CheckboxGroup>
-        <br/>
-        <br/>
-        <div>radio disabled</div>
-        <CheckboxGroup type='card' direction='horizontal' defaultValue={['1']}>
-            <Checkbox value='1' disabled extra='Semi Design' style={{width: 280}}>
-                多选框标题
-            </Checkbox>
-            <Checkbox value='2' extra='Semi Design' style={{width: 280}}>
-                多选框标题
-            </Checkbox>
-            <Checkbox value='3' extra='Semi Design' style={{width: 280}}>
-                多选框标题
-            </Checkbox>
-        </CheckboxGroup>
-        <br/>
-        <br/>
-        <div>checkboxGroup disabled</div>
-        <CheckboxGroup type='card' direction='horizontal' disabled defaultValue={['1']}>
-            <Checkbox value='1' extra='Semi Design' style={{width: 280}}>
-                多选框标题
-            </Checkbox>
-            <Checkbox value='2' extra='Semi Design' style={{width: 280}}>
-                多选框标题
-            </Checkbox>
-            <Checkbox value='3' extra='Semi Design' style={{width: 280}}>
-                多选框标题
-            </Checkbox>
-        </CheckboxGroup>
-        <br/>
-        <br/>
-        <div>文字很长,并且没有设置宽度,因此换行显示</div>
-        <CheckboxGroup type='card' direction='horizontal' defaultValue={['1']}>
-            <Checkbox value='1' extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统'>
-                多选框标题
-            </Checkbox>
-            <Checkbox value='2' extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统'>
-                多选框标题
-            </Checkbox>
-            <Checkbox value='3' extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统'>
-                多选框标题
-            </Checkbox>
-        </CheckboxGroup>
-        <br/>
-        <br/>
-        <div>设置了width=180</div>
-        <CheckboxGroup type='card' direction='horizontal' defaultValue={['1']}>
-            <Checkbox value='1' extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统' style={{width: 180}}>
-                多选框标题
-            </Checkbox>
-            <Checkbox value='2' extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统' style={{width: 180}}>
-                多选框标题
-            </Checkbox>
-            <Checkbox value='3' extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统' style={{width: 180}}>
-                多选框标题
-            </Checkbox>
-        </CheckboxGroup>
-        <br/>
-        <br/>
-        <div>没有extra,width=180</div>
-        <CheckboxGroup type='card' direction='horizontal' defaultValue={['1']}>
-            <Checkbox value='1' style={{width: 180}}>
-                多选框标题
-            </Checkbox>
-            <Checkbox value='2' style={{width: 180}}>
-                多选框标题
-            </Checkbox>
-            <Checkbox value='3' style={{width: 180}}>
-                多选框标题
-            </Checkbox>
-        </CheckboxGroup>
-        <br/>
-        <br/>
-        <div>没有标题,width=380</div>
-        <CheckboxGroup type='card' direction='horizontal' defaultValue={['1']}>
-            <Checkbox value='1' extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统' style={{width: 380}}>
-            </Checkbox>
-            <Checkbox value='2' extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统' style={{width: 380}}>
-            </Checkbox>
-            <Checkbox value='3' extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统' style={{width: 380}}>
-            </Checkbox>
-        </CheckboxGroup>
-        <br/>
-        <br/>
-        <hr/>
-        <div>下面是垂直的情况:</div>
-        <div>常见情况</div>
-        <CheckboxGroup direction='vertical' type='card' defaultValue={['1']}>
-            <Checkbox value='1' extra='Semi Design' style={{width: 280}}>
-                多选框标题
-            </Checkbox>
-            <Checkbox value='2' extra='Semi Design' style={{width: 280}}>
-                多选框标题
-            </Checkbox>
-            <Checkbox value='3' extra='Semi Design' style={{width: 280}}>
-                多选框标题
-            </Checkbox>
-        </CheckboxGroup>
-        <br/>
-        <br/>
-        <div>没有设置宽度</div>
-        <CheckboxGroup direction='vertical' type='card' defaultValue={['1']}>
-            <Checkbox value='1' extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统'>
-                多选框标题
-            </Checkbox>
-            <Checkbox value='2' extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统'>
-                多选框标题
-            </Checkbox>
-            <Checkbox value='3' extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统'>
-                多选框标题
-            </Checkbox>
-        </CheckboxGroup>
-        <br/>
-        <br/>
-        <div>设置了width=380</div>
-        <CheckboxGroup direction='vertical' type='card' defaultValue={['1']}>
-            <Checkbox value='1' extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统' style={{width: 380}}>
-                多选框标题
-            </Checkbox>
-            <Checkbox value='2' extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统' style={{width: 380}}>
-                多选框标题
-            </Checkbox>
-            <Checkbox value='3' extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统' style={{width: 380}}>
-                多选框标题
-            </Checkbox>
-        </CheckboxGroup>
-    </>
-));
+export const CheckboxGroupCardStyle = () => (
+  <>
+    <div>常见情况</div>
+    <CheckboxGroup type="card" direction="horizontal" defaultValue={['1']}>
+      <Checkbox value="1" extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Checkbox>
+      <Checkbox value="2" extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Checkbox>
+      <Checkbox value="3" extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Checkbox>
+    </CheckboxGroup>
+    <br />
+    <br />
+    <div>radio disabled</div>
+    <CheckboxGroup type="card" direction="horizontal" defaultValue={['1']}>
+      <Checkbox value="1" disabled extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Checkbox>
+      <Checkbox value="2" extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Checkbox>
+      <Checkbox value="3" extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Checkbox>
+    </CheckboxGroup>
+    <br />
+    <br />
+    <div>checkboxGroup disabled</div>
+    <CheckboxGroup type="card" direction="horizontal" disabled defaultValue={['1']}>
+      <Checkbox value="1" extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Checkbox>
+      <Checkbox value="2" extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Checkbox>
+      <Checkbox value="3" extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Checkbox>
+    </CheckboxGroup>
+    <br />
+    <br />
+    <div>文字很长,并且没有设置宽度,因此换行显示</div>
+    <CheckboxGroup type="card" direction="horizontal" defaultValue={['1']}>
+      <Checkbox
+        value="1"
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+      >
+        多选框标题
+      </Checkbox>
+      <Checkbox
+        value="2"
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+      >
+        多选框标题
+      </Checkbox>
+      <Checkbox
+        value="3"
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+      >
+        多选框标题
+      </Checkbox>
+    </CheckboxGroup>
+    <br />
+    <br />
+    <div>设置了width=180</div>
+    <CheckboxGroup type="card" direction="horizontal" defaultValue={['1']}>
+      <Checkbox
+        value="1"
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+        style={{ width: 180 }}
+      >
+        多选框标题
+      </Checkbox>
+      <Checkbox
+        value="2"
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+        style={{ width: 180 }}
+      >
+        多选框标题
+      </Checkbox>
+      <Checkbox
+        value="3"
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+        style={{ width: 180 }}
+      >
+        多选框标题
+      </Checkbox>
+    </CheckboxGroup>
+    <br />
+    <br />
+    <div>没有extra,width=180</div>
+    <CheckboxGroup type="card" direction="horizontal" defaultValue={['1']}>
+      <Checkbox value="1" style={{ width: 180 }}>
+        多选框标题
+      </Checkbox>
+      <Checkbox value="2" style={{ width: 180 }}>
+        多选框标题
+      </Checkbox>
+      <Checkbox value="3" style={{ width: 180 }}>
+        多选框标题
+      </Checkbox>
+    </CheckboxGroup>
+    <br />
+    <br />
+    <div>没有标题,width=380</div>
+    <CheckboxGroup type="card" direction="horizontal" defaultValue={['1']}>
+      <Checkbox
+        value="1"
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+        style={{ width: 380 }}
+      ></Checkbox>
+      <Checkbox
+        value="2"
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+        style={{ width: 380 }}
+      ></Checkbox>
+      <Checkbox
+        value="3"
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+        style={{ width: 380 }}
+      ></Checkbox>
+    </CheckboxGroup>
+    <br />
+    <br />
+    <hr />
+    <div>下面是垂直的情况:</div>
+    <div>常见情况</div>
+    <CheckboxGroup direction="vertical" type="card" defaultValue={['1']}>
+      <Checkbox value="1" extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Checkbox>
+      <Checkbox value="2" extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Checkbox>
+      <Checkbox value="3" extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Checkbox>
+    </CheckboxGroup>
+    <br />
+    <br />
+    <div>没有设置宽度</div>
+    <CheckboxGroup direction="vertical" type="card" defaultValue={['1']}>
+      <Checkbox
+        value="1"
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+      >
+        多选框标题
+      </Checkbox>
+      <Checkbox
+        value="2"
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+      >
+        多选框标题
+      </Checkbox>
+      <Checkbox
+        value="3"
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+      >
+        多选框标题
+      </Checkbox>
+    </CheckboxGroup>
+    <br />
+    <br />
+    <div>设置了width=380</div>
+    <CheckboxGroup direction="vertical" type="card" defaultValue={['1']}>
+      <Checkbox
+        value="1"
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+        style={{ width: 380 }}
+      >
+        多选框标题
+      </Checkbox>
+      <Checkbox
+        value="2"
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+        style={{ width: 380 }}
+      >
+        多选框标题
+      </Checkbox>
+      <Checkbox
+        value="3"
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+        style={{ width: 380 }}
+      >
+        多选框标题
+      </Checkbox>
+    </CheckboxGroup>
+  </>
+);
 
-stories.add(`checkboxGroup pureCard style`, () => (
-    <>
-        <div>常见情况</div>
-        <CheckboxGroup type='pureCard' defaultValue={['1']}>
-            <Checkbox value='1' extra='Semi Design' style={{width: 280}}>
-                多选框标题
-            </Checkbox>
-            <Checkbox value='2' extra='Semi Design' style={{width: 280}}>
-                多选框标题
-            </Checkbox>
-            <Checkbox value='3' extra='Semi Design' style={{width: 280}}>
-                多选框标题
-            </Checkbox>
-        </CheckboxGroup>
-        <br/>
-        <br/>
-        <div>radio disabled</div>
-        <CheckboxGroup type='pureCard' defaultValue={['1']}>
-            <Checkbox value='1' disabled extra='Semi Design' style={{width: 280}}>
-                多选框标题
-            </Checkbox>
-            <Checkbox value='2' extra='Semi Design' style={{width: 280}}>
-                多选框标题
-            </Checkbox>
-            <Checkbox value='3' extra='Semi Design' style={{width: 280}}>
-                多选框标题
-            </Checkbox>
-        </CheckboxGroup>
-        <br/>
-        <br/>
-        <div>checkboxGroup disabled</div>
-        <CheckboxGroup type='pureCard' disabled defaultValue={['1']}>
-            <Checkbox value='1' extra='Semi Design' style={{width: 280}}>
-                多选框标题
-            </Checkbox>
-            <Checkbox value='2' extra='Semi Design' style={{width: 280}}>
-                多选框标题
-            </Checkbox>
-            <Checkbox value='3' extra='Semi Design' style={{width: 280}}>
-                多选框标题
-            </Checkbox>
-        </CheckboxGroup>
-        <br/>
-        <br/>
-        <div>文字很长,并且没有设置宽度,因此换行显示</div>
-        <CheckboxGroup type='pureCard' defaultValue={['1']}>
-            <Checkbox value='1' extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统'>
-                多选框标题
-            </Checkbox>
-            <Checkbox value='2' extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统'>
-                多选框标题
-            </Checkbox>
-            <Checkbox value='3' extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统'>
-                多选框标题
-            </Checkbox>
-        </CheckboxGroup>
-        <br/>
-        <br/>
-        <div>设置了width=180</div>
-        <CheckboxGroup type='pureCard' defaultValue={['1']}>
-            <Checkbox value='1' extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统' style={{width: 180}}>
-                多选框标题
-            </Checkbox>
-            <Checkbox value='2' extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统' style={{width: 180}}>
-                多选框标题
-            </Checkbox>
-            <Checkbox value='3' extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统' style={{width: 180}}>
-                多选框标题
-            </Checkbox>
-        </CheckboxGroup>
-        <br/>
-        <br/>
-        <div>没有extra,width=180</div>
-        <CheckboxGroup type='pureCard' defaultValue={['1']}>
-            <Checkbox value='1' style={{width: 180}}>
-                多选框标题
-            </Checkbox>
-            <Checkbox value='2' style={{width: 180}}>
-                多选框标题
-            </Checkbox>
-            <Checkbox value='3' style={{width: 180}}>
-                多选框标题
-            </Checkbox>
-        </CheckboxGroup>
-        <br/>
-        <br/>
-        <div>没有标题,width=380</div>
-        <CheckboxGroup type='pureCard' defaultValue={['1']}>
-            <Checkbox value='1' extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统' style={{width: 380}}>
-            </Checkbox>
-            <Checkbox value='2' extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统' style={{width: 380}}>
-            </Checkbox>
-            <Checkbox value='3' extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统' style={{width: 380}}>
-            </Checkbox>
-        </CheckboxGroup>
-        <br/>
-        <br/>
-        <hr/>
-        <div>下面是垂直的情况:</div>
-        <div>常见情况</div>
-        <CheckboxGroup direction='vertical' type='pureCard' defaultValue={['1']}>
-            <Checkbox value='1' extra='Semi Design' style={{width: 280}}>
-                多选框标题
-            </Checkbox>
-            <Checkbox value='2' extra='Semi Design' style={{width: 280}}>
-                多选框标题
-            </Checkbox>
-            <Checkbox value='3' extra='Semi Design' style={{width: 280}}>
-                多选框标题
-            </Checkbox>
-        </CheckboxGroup>
-        <br/>
-        <br/>
-        <div>没有设置宽度</div>
-        <CheckboxGroup direction='vertical' type='pureCard' defaultValue={['1']}>
-            <Checkbox value='1' extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统'>
-                多选框标题
-            </Checkbox>
-            <Checkbox value='2' extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统'>
-                多选框标题
-            </Checkbox>
-            <Checkbox value='3' extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统'>
-                多选框标题
-            </Checkbox>
-        </CheckboxGroup>
-        <br/>
-        <br/>
-        <div>设置了width=380</div>
-        <CheckboxGroup direction='vertical' type='pureCard' defaultValue={['1']}>
-            <Checkbox value='1' extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统' style={{width: 380}}>
-                多选框标题
-            </Checkbox>
-            <Checkbox value='2' extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统' style={{width: 380}}>
-                多选框标题
-            </Checkbox>
-            <Checkbox value='3' extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统' style={{width: 380}}>
-                多选框标题
-            </Checkbox>
-        </CheckboxGroup>
-    </>
-));
+export const CheckboxGroupPureCardStyle = () => (
+  <>
+    <div>常见情况</div>
+    <CheckboxGroup type="pureCard" defaultValue={['1']}>
+      <Checkbox value="1" extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Checkbox>
+      <Checkbox value="2" extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Checkbox>
+      <Checkbox value="3" extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Checkbox>
+    </CheckboxGroup>
+    <br />
+    <br />
+    <div>radio disabled</div>
+    <CheckboxGroup type="pureCard" defaultValue={['1']}>
+      <Checkbox value="1" disabled extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Checkbox>
+      <Checkbox value="2" extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Checkbox>
+      <Checkbox value="3" extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Checkbox>
+    </CheckboxGroup>
+    <br />
+    <br />
+    <div>checkboxGroup disabled</div>
+    <CheckboxGroup type="pureCard" disabled defaultValue={['1']}>
+      <Checkbox value="1" extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Checkbox>
+      <Checkbox value="2" extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Checkbox>
+      <Checkbox value="3" extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Checkbox>
+    </CheckboxGroup>
+    <br />
+    <br />
+    <div>文字很长,并且没有设置宽度,因此换行显示</div>
+    <CheckboxGroup type="pureCard" defaultValue={['1']}>
+      <Checkbox
+        value="1"
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+      >
+        多选框标题
+      </Checkbox>
+      <Checkbox
+        value="2"
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+      >
+        多选框标题
+      </Checkbox>
+      <Checkbox
+        value="3"
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+      >
+        多选框标题
+      </Checkbox>
+    </CheckboxGroup>
+    <br />
+    <br />
+    <div>设置了width=180</div>
+    <CheckboxGroup type="pureCard" defaultValue={['1']}>
+      <Checkbox
+        value="1"
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+        style={{ width: 180 }}
+      >
+        多选框标题
+      </Checkbox>
+      <Checkbox
+        value="2"
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+        style={{ width: 180 }}
+      >
+        多选框标题
+      </Checkbox>
+      <Checkbox
+        value="3"
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+        style={{ width: 180 }}
+      >
+        多选框标题
+      </Checkbox>
+    </CheckboxGroup>
+    <br />
+    <br />
+    <div>没有extra,width=180</div>
+    <CheckboxGroup type="pureCard" defaultValue={['1']}>
+      <Checkbox value="1" style={{ width: 180 }}>
+        多选框标题
+      </Checkbox>
+      <Checkbox value="2" style={{ width: 180 }}>
+        多选框标题
+      </Checkbox>
+      <Checkbox value="3" style={{ width: 180 }}>
+        多选框标题
+      </Checkbox>
+    </CheckboxGroup>
+    <br />
+    <br />
+    <div>没有标题,width=380</div>
+    <CheckboxGroup type="pureCard" defaultValue={['1']}>
+      <Checkbox
+        value="1"
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+        style={{ width: 380 }}
+      ></Checkbox>
+      <Checkbox
+        value="2"
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+        style={{ width: 380 }}
+      ></Checkbox>
+      <Checkbox
+        value="3"
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+        style={{ width: 380 }}
+      ></Checkbox>
+    </CheckboxGroup>
+    <br />
+    <br />
+    <hr />
+    <div>下面是垂直的情况:</div>
+    <div>常见情况</div>
+    <CheckboxGroup direction="vertical" type="pureCard" defaultValue={['1']}>
+      <Checkbox value="1" extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Checkbox>
+      <Checkbox value="2" extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Checkbox>
+      <Checkbox value="3" extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Checkbox>
+    </CheckboxGroup>
+    <br />
+    <br />
+    <div>没有设置宽度</div>
+    <CheckboxGroup direction="vertical" type="pureCard" defaultValue={['1']}>
+      <Checkbox
+        value="1"
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+      >
+        多选框标题
+      </Checkbox>
+      <Checkbox
+        value="2"
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+      >
+        多选框标题
+      </Checkbox>
+      <Checkbox
+        value="3"
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+      >
+        多选框标题
+      </Checkbox>
+    </CheckboxGroup>
+    <br />
+    <br />
+    <div>设置了width=380</div>
+    <CheckboxGroup direction="vertical" type="pureCard" defaultValue={['1']}>
+      <Checkbox
+        value="1"
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+        style={{ width: 380 }}
+      >
+        多选框标题
+      </Checkbox>
+      <Checkbox
+        value="2"
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+        style={{ width: 380 }}
+      >
+        多选框标题
+      </Checkbox>
+      <Checkbox
+        value="3"
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+        style={{ width: 380 }}
+      >
+        多选框标题
+      </Checkbox>
+    </CheckboxGroup>
+  </>
+);

+ 121 - 116
packages/semi-ui/collapse/_story/accordion.stories.js

@@ -1,138 +1,143 @@
 import React from 'react';
-import { storiesOf } from '@storybook/react';
 import Collapse from '..';
 import { IconCopy } from '@douyinfe/semi-icons';
 
 const Panel = Collapse.Panel;
-const stories = storiesOf('Collapse', module);
+
 const text = `
   A dog is a type of domesticated animal.
   Known for its loyalty and faithfulness,
   it can be found:a welcome guest in many households across the world.
-`; // stories.addDecorator(withKnobs);;
+`;
+
+export default {
+  title: 'Collapse',
+}
+
+export const RegularCollapse = () => (
+  <div>
+    <Collapse onChange={k => console.log(k)}>
+      <Panel header="This is panel header 1" itemKey="1">
+        <p>{text}</p>
+      </Panel>
+      <Panel header="This is panel header 2" itemKey="2">
+        <p>{text}</p>
+      </Panel>
+      <Panel header="This is panel header 3" itemKey="3" disabled>
+        <p>{text}</p>
+      </Panel>
+    </Collapse>
+    <br />
+    <Collapse defaultActiveKey={'124'} onChange={k => console.log(k)}>
+      <Panel header="This is panel header 1" itemKey="1">
+        <p>{text}</p>
+      </Panel>
+      <Panel header="This is panel header 2" itemKey="124">
+        <p>{text}</p>
+      </Panel>
+      <Panel header="This is panel header 3" itemKey="3" disabled>
+        <p>{text}</p>
+      </Panel>
+    </Collapse>
+  </div>
+);
+
+export const Accordion = () => (
+  <div>
+    <Collapse defaultActiveKey={'123'} accordion onChange={k => console.log(k)}>
+      <Panel header="This is panel header 1" itemKey="123">
+        <p>{text}</p>
+      </Panel>
+      <Panel header="This is panel header 2" itemKey="234">
+        <p>{text}</p>
+      </Panel>
+      <Panel header="This is panel header 3" itemKey="3" disabled>
+        <p>{text}</p>
+      </Panel>
+    </Collapse>
+  </div>
+);
 
-stories.add('regular collapse', () => (
-    <div>
-        <Collapse onChange={k => console.log(k)}>
-            <Panel header="This is panel header 1" itemKey="1">
-                <p>{text}</p>
-            </Panel>
-            <Panel header="This is panel header 2" itemKey="2">
-                <p>{text}</p>
-            </Panel>
-            <Panel header="This is panel header 3" itemKey="3" disabled>
-                <p>{text}</p>
-            </Panel>
-        </Collapse>
-        <br />
-        <Collapse defaultActiveKey={'124'} onChange={k => console.log(k)}>
-            <Panel header="This is panel header 1" itemKey="1">
-                <p>{text}</p>
-            </Panel>
-            <Panel header="This is panel header 2" itemKey="124">
-                <p>{text}</p>
-            </Panel>
-            <Panel header="This is panel header 3" itemKey="3" disabled>
-                <p>{text}</p>
-            </Panel>
-        </Collapse>
-    </div>
-));
-stories.add('accordion', () => (
-    <div>
-        <Collapse defaultActiveKey={'123'} accordion onChange={k => console.log(k)}>
-            <Panel header="This is panel header 1" itemKey="123">
-                <p>{text}</p>
-            </Panel>
-            <Panel header="This is panel header 2" itemKey="234">
-                <p>{text}</p>
-            </Panel>
-            <Panel header="This is panel header 3" itemKey="3" disabled>
-                <p>{text}</p>
-            </Panel>
-        </Collapse>
-    </div>
-));
-stories.add('extra rendering', () => (
-    <div>
-        <Collapse activeKey={'123'} onChange={k => console.log(k)}>
-            <Panel header="This is panel header 1" itemKey="123" extra="1234">
-                <p>{text}</p>
-            </Panel>
-            <Panel header="This is panel header 2" itemKey="2" extra={<IconCopy />}>
-                <p>{text}</p>
-            </Panel>
-            <Panel header="This is panel header 3" itemKey="3" disabled>
-                <p>{text}</p>
-            </Panel>
-        </Collapse>
-    </div>
-));
+export const ExtraRendering = () => (
+  <div>
+    <Collapse activeKey={'123'} onChange={k => console.log(k)}>
+      <Panel header="This is panel header 1" itemKey="123" extra="1234">
+        <p>{text}</p>
+      </Panel>
+      <Panel header="This is panel header 2" itemKey="2" extra={<IconCopy />}>
+        <p>{text}</p>
+      </Panel>
+      <Panel header="This is panel header 3" itemKey="3" disabled>
+        <p>{text}</p>
+      </Panel>
+    </Collapse>
+  </div>
+);
 
 class ControlledDemo extends React.Component {
-    constructor() {
-        super();
-        this.state = {
-            value: [],
-        };
-    }
+  constructor() {
+    super();
+    this.state = {
+      value: [],
+    };
+  }
 
-    onChange(value) {
-        console.log(value);
-        this.setState({
-            value,
-        });
-    }
+  onChange(value) {
+    console.log(value);
+    this.setState({
+      value,
+    });
+  }
 
-    render() {
-        return (
-            <Collapse activeKey={this.state.value} onChange={k => this.onChange(k)}>
-                <Panel header="This is panel header 1" itemKey="123" extra="1234">
-                    <p>{text}</p>
-                </Panel>
-                <Panel header="This is panel header 2" itemKey="2" extra={<IconCopy />}>
-                    <p>{text}</p>
-                </Panel>
-                <Panel header="This is panel header 3" itemKey="3" disabled>
-                    <p>{text}</p>
-                </Panel>
-            </Collapse>
-        );
-    }
+  render() {
+    return (
+      <Collapse activeKey={this.state.value} onChange={k => this.onChange(k)}>
+        <Panel header="This is panel header 1" itemKey="123" extra="1234">
+          <p>{text}</p>
+        </Panel>
+        <Panel header="This is panel header 2" itemKey="2" extra={<IconCopy />}>
+          <p>{text}</p>
+        </Panel>
+        <Panel header="This is panel header 3" itemKey="3" disabled>
+          <p>{text}</p>
+        </Panel>
+      </Collapse>
+    );
+  }
 }
 
-stories.add('controlled component', () => <ControlledDemo />);
+export const ControlledComponent = () => <ControlledDemo />;
 
 class ControlledDemoAccordion extends React.Component {
-    constructor() {
-        super();
-        this.state = {
-            value: [],
-        };
-    }
+  constructor() {
+    super();
+    this.state = {
+      value: [],
+    };
+  }
 
-    onChange(value) {
-        console.log(value);
-        this.setState({
-            value,
-        });
-    }
+  onChange(value) {
+    console.log(value);
+    this.setState({
+      value,
+    });
+  }
 
-    render() {
-        return (
-            <Collapse activeKey={this.state.value} accordion onChange={k => this.onChange(k)}>
-                <Panel header="This is panel header 1" itemKey="123" extra="1234">
-                    <p>{text}</p>
-                </Panel>
-                <Panel header="This is panel header 2" itemKey="2" extra={<IconCopy />}>
-                    <p>{text}</p>
-                </Panel>
-                <Panel header="This is panel header 3" itemKey="3" disabled>
-                    <p>{text}</p>
-                </Panel>
-            </Collapse>
-        );
-    }
+  render() {
+    return (
+      <Collapse activeKey={this.state.value} accordion onChange={k => this.onChange(k)}>
+        <Panel header="This is panel header 1" itemKey="123" extra="1234">
+          <p>{text}</p>
+        </Panel>
+        <Panel header="This is panel header 2" itemKey="2" extra={<IconCopy />}>
+          <p>{text}</p>
+        </Panel>
+        <Panel header="This is panel header 3" itemKey="3" disabled>
+          <p>{text}</p>
+        </Panel>
+      </Collapse>
+    );
+  }
 }
 
-stories.add('controlled component accordion', () => <ControlledDemoAccordion />);
+export const ControlledComponentAccordion = () => <ControlledDemoAccordion />;

+ 524 - 510
packages/semi-ui/collapsible/_story/collapsible.stories.js

@@ -1,574 +1,588 @@
 /* argus-disable unPkgSensitiveInfo */
 import React, { useState } from 'react';
-import { storiesOf } from '@storybook/react';
 import { Button, CheckboxGroup, Upload, Table, Collapse, Tabs } from '../../index';
 import Collapsible from '..';
 import NestedDemo from './Nested';
 import { IconChevronDown, IconChevronRight, IconUpload } from '@douyinfe/semi-icons';
 
 const TabPane = Tabs.TabPane;
-const stories = storiesOf('Collapsible', module); // stories.addDecorator(withKnobs);;
 
-class Demo extends React.Component {
-    state = {
-        isOpen: false,
-    };
-    toggle = () => {
-        this.setState({
-            isOpen: !this.state.isOpen,
-        });
-    };
+export default {
+  title: 'Collapsible',
+}
 
-    render() {
-        const { isOpen } = this.state;
-        const collapsed = (
-            <ul>
-                <li>
-                    <p>Semi Design 以内容优先进行设计。</p>
-                </li>
-                <li>
-                    <p>更容易地自定义主题。</p>
-                </li>
-                <li>
-                    <p>适用国际化场景。</p>
-                </li>
-                <li>
-                    <p>效率场景加入人性化关怀。</p>
-                </li>
-            </ul>
-        );
-        return (
-            <div>
-                <Button onClick={() => this.toggle()}>显示更多</Button>
-                <Collapsible isOpen={isOpen}>{collapsed}</Collapsible>
-            </div>
-        );
-    }
+class Demo extends React.Component {
+  state = {
+    isOpen: false,
+  };
+  toggle = () => {
+    this.setState({
+      isOpen: !this.state.isOpen,
+    });
+  };
+
+  render() {
+    const { isOpen } = this.state;
+    const collapsed = (
+      <ul>
+        <li>
+          <p>Semi Design 以内容优先进行设计。</p>
+        </li>
+        <li>
+          <p>更容易地自定义主题。</p>
+        </li>
+        <li>
+          <p>适用国际化场景。</p>
+        </li>
+        <li>
+          <p>效率场景加入人性化关怀。</p>
+        </li>
+      </ul>
+    );
+    return (
+      <div>
+        <Button onClick={() => this.toggle()}>显示更多</Button>
+        <Collapsible isOpen={isOpen}>{collapsed}</Collapsible>
+      </div>
+    );
+  }
 }
 
-stories.add('regular collapsible', () => <Demo />);
+export const RegularCollapsible = () => <Demo />;
 
 class DemoDOM extends React.Component {
-    state = {
-        isOpen: false,
-    };
-    toggle = () => {
-        this.setState({
-            isOpen: !this.state.isOpen,
-        });
-    };
-
-    render() {
-        const { isOpen } = this.state;
-        const collapsed = (
-            <ul>
-                <li>
-                    <p>Semi Design 以内容优先进行设计。</p>
-                </li>
-                <li>
-                    <p>更容易地自定义主题。</p>
-                </li>
-                <li>
-                    <p>适用国际化场景。</p>
-                </li>
-                <li>
-                    <p>效率场景加入人性化关怀。</p>
-                </li>
-            </ul>
-        );
-        return (
-            <div>
-                <Button onClick={() => this.toggle()}>显示更多</Button>
-                <Collapsible keepDOM isOpen={isOpen}>
-                    {collapsed}
-                </Collapsible>
-            </div>
-        );
-    }
+  state = {
+    isOpen: false,
+  };
+  toggle = () => {
+    this.setState({
+      isOpen: !this.state.isOpen,
+    });
+  };
+
+  render() {
+    const { isOpen } = this.state;
+    const collapsed = (
+      <ul>
+        <li>
+          <p>Semi Design 以内容优先进行设计。</p>
+        </li>
+        <li>
+          <p>更容易地自定义主题。</p>
+        </li>
+        <li>
+          <p>适用国际化场景。</p>
+        </li>
+        <li>
+          <p>效率场景加入人性化关怀。</p>
+        </li>
+      </ul>
+    );
+    return (
+      <div>
+        <Button onClick={() => this.toggle()}>显示更多</Button>
+        <Collapsible keepDOM isOpen={isOpen}>
+          {collapsed}
+        </Collapsible>
+      </div>
+    );
+  }
 }
 
-stories.add('keepDOM', () => <DemoDOM />);
-
-class DefaultOPen extends React.Component {
-    state = {
-        isOpen: true,
-    };
-    toggle = () => {
-        this.setState({
-            isOpen: !this.state.isOpen,
-        });
-    };
-
-    render() {
-        const { isOpen } = this.state;
-        const collapsed = (
-            <ul>
-                <li>
-                    <p>Semi Design 以内容优先进行设计。</p>
-                </li>
-                <li>
-                    <p>更容易地自定义主题。</p>
-                </li>
-                <li>
-                    <p>适用国际化场景。</p>
-                </li>
-                <li>
-                    <p>效率场景加入人性化关怀。</p>
-                </li>
-            </ul>
-        );
-        return (
-            <div>
-                <Button onClick={() => this.toggle()}>toggle</Button>
-                <Collapsible isOpen={isOpen}>{collapsed}</Collapsible>
-            </div>
-        );
-    }
+export const KeepDom = () => <DemoDOM />;
+
+class DefaultOpen extends React.Component {
+  state = {
+    isOpen: true,
+  };
+  toggle = () => {
+    this.setState({
+      isOpen: !this.state.isOpen,
+    });
+  };
+
+  render() {
+    const { isOpen } = this.state;
+    const collapsed = (
+      <ul>
+        <li>
+          <p>Semi Design 以内容优先进行设计。</p>
+        </li>
+        <li>
+          <p>更容易地自定义主题。</p>
+        </li>
+        <li>
+          <p>适用国际化场景。</p>
+        </li>
+        <li>
+          <p>效率场景加入人性化关怀。</p>
+        </li>
+      </ul>
+    );
+    return (
+      <div>
+        <Button onClick={() => this.toggle()}>toggle</Button>
+        <Collapsible isOpen={isOpen}>{collapsed}</Collapsible>
+      </div>
+    );
+  }
 }
 
-stories.add('Default Open', () => <DefaultOPen />);
-stories.add('nested collapsible', () => <NestedDemo />);
+export const DefaultOpenDemo = () => <DefaultOpen />;
+export const NestedCollapsible = () => <NestedDemo />;
 
 class Wrap extends React.Component {
-    constructor(props) {
-        super(props);
-        this.state = {
-            isOpen: props.isOpen,
-            options: [
-                {
-                    label: '抖音',
-                    value: 'dy',
-                },
-                {
-                    label: '火山',
-                    value: 'hotsoon',
-                },
-                {
-                    label: '皮皮虾',
-                    value: 'pipixia',
-                },
-                {
-                    label: '今日头条',
-                    value: 'toutiao',
-                },
-            ],
-            values: [],
-        };
-        this.toggle = this.toggle.bind(this);
-        this.onChange = this.onChange.bind(this);
-    }
-
-    toggle() {
-        this.setState({
-            isOpen: !this.state.isOpen,
-        });
-    }
-
-    onChange(values) {
-        this.setState({
-            values,
-        });
-    }
-
-    render() {
-        const { isOpen, options, values } = this.state;
-        return (
-            <>
-                <div onClick={this.toggle}>
-                    {isOpen ? <IconChevronDown /> : <IconChevronRight />}
-                    权限点
-                    <span>
-                        {values.length}/{options.length}
-                    </span>
-                </div>
-                <Collapse defaultActiveKey="1" motion={false}>
-                    <Collapse.Panel header="This is panel header 1" itemKey="1">
-                        <p>Hi, bytedance dance dance. This is the docsite of Semi UI. </p>
-                    </Collapse.Panel>
-                    <Collapse.Panel header="This is panel header 2" itemKey="2">
-                        <p>Hi, bytedance dance dance. This is the docsite of Semi UI. </p>
-                    </Collapse.Panel>
-                    <Collapse.Panel header="This is panel header 3" itemKey="3">
-                        <p>Hi, bytedance dance dance. This is the docsite of Semi UI. </p>
-                    </Collapse.Panel>
-                </Collapse>
-                {/* <Collapsible isOpen={isOpen}>
+  constructor(props) {
+    super(props);
+    this.state = {
+      isOpen: props.isOpen,
+      options: [
+        {
+          label: '抖音',
+          value: 'dy',
+        },
+        {
+          label: '火山',
+          value: 'hotsoon',
+        },
+        {
+          label: '皮皮虾',
+          value: 'pipixia',
+        },
+        {
+          label: '今日头条',
+          value: 'toutiao',
+        },
+      ],
+      values: [],
+    };
+    this.toggle = this.toggle.bind(this);
+    this.onChange = this.onChange.bind(this);
+  }
+
+  toggle() {
+    this.setState({
+      isOpen: !this.state.isOpen,
+    });
+  }
+
+  onChange(values) {
+    this.setState({
+      values,
+    });
+  }
+
+  render() {
+    const { isOpen, options, values } = this.state;
+    return (
+      <>
+        <div onClick={this.toggle}>
+          {isOpen ? <IconChevronDown /> : <IconChevronRight />}
+          权限点
+          <span>
+            {values.length}/{options.length}
+          </span>
+        </div>
+        <Collapse defaultActiveKey="1" motion={false}>
+          <Collapse.Panel header="This is panel header 1" itemKey="1">
+            <p>Hi, bytedance dance dance. This is the docsite of Semi UI. </p>
+          </Collapse.Panel>
+          <Collapse.Panel header="This is panel header 2" itemKey="2">
+            <p>Hi, bytedance dance dance. This is the docsite of Semi UI. </p>
+          </Collapse.Panel>
+          <Collapse.Panel header="This is panel header 3" itemKey="3">
+            <p>Hi, bytedance dance dance. This is the docsite of Semi UI. </p>
+          </Collapse.Panel>
+        </Collapse>
+        {/* <Collapsible isOpen={isOpen}>
            <div style={{ height: '40px' }}>
                <CheckboxGroup options={options} direction="horizontal" onChange={this.onChange} value={values} />
            </div>
         </Collapsible> */}
-            </>
-        );
-    }
+      </>
+    );
+  }
 }
 
-stories.add('collapsible test', () => <Wrap />);
+export const CollapsibleTest = () => <Wrap />;
 
 class App extends React.Component {
-    render() {
-        const expandColumns = [
-            {
-                title: 'Name',
-                dataIndex: 'name',
-                key: 'name',
-            },
-            {
-                title: 'Age',
-                dataIndex: 'age',
-                key: 'age',
-            },
-            {
-                title: 'Address',
-                dataIndex: 'address',
-                key: 'address',
-            },
-            {
-                title: 'Action',
-                dataIndex: '',
-                key: 'x',
-                render: () => <a>Delete</a>,
-            },
-        ];
-        const rowSelection = {
-            onChange: (selectedRowKeys, selectedRows) => {
-                // console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
-            },
-            getCheckboxProps: record => ({
-                disabled: record.name === 'Michael James',
-                // Column configuration not to be checked
-                name: record.name,
-            }),
-        };
-        const expandData = [
-            {
-                name: 'John Brown',
-                age: 32,
-                address: 'New York No. 1 Lake Park',
-                description: 'My name is John Brown, I am 32 years old, living in New York No. 1 Lake Park.',
-            },
-            {
-                name: 'Jim Green',
-                age: 42,
-                address: 'London No. 1 Lake Park',
-                description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.',
-            },
-            {
-                name: 'Joe Black',
-                age: 32,
-                address: (
-                    <Collapse defaultActiveKey="1" motion={false}>
-                        <Collapse.Panel header="This is panel header 1" itemKey="1">
-                            <p>Hi, bytedance dance dance. This is the docsite of Semi UI. </p>
-                        </Collapse.Panel>
-                        <Collapse.Panel header="This is panel header 2" itemKey="2">
-                            <p>Hi, bytedance dance dance. This is the docsite of Semi UI. </p>
-                        </Collapse.Panel>
-                        <Collapse.Panel header="This is panel header 3" itemKey="3">
-                            <p>Hi, bytedance dance dance. This is the docsite of Semi UI. </p>
-                        </Collapse.Panel>
-                    </Collapse>
-                ),
-                description: 'My name is Joe Black, I am 32 years old, living in Sidney No. 1 Lake Park.',
-            },
-        ];
-
-        const expandRowRender = (record, index) => <Wrap isOpen={true} />;
-
-        return (
-            <Table
-                rowKey={'name'}
-                columns={expandColumns}
-                rowSelection={rowSelection}
-                expandedRowRender={expandRowRender}
-                dataSource={expandData}
-            />
-        );
-    }
+  render() {
+    const expandColumns = [
+      {
+        title: 'Name',
+        dataIndex: 'name',
+        key: 'name',
+      },
+      {
+        title: 'Age',
+        dataIndex: 'age',
+        key: 'age',
+      },
+      {
+        title: 'Address',
+        dataIndex: 'address',
+        key: 'address',
+      },
+      {
+        title: 'Action',
+        dataIndex: '',
+        key: 'x',
+        render: () => <a>Delete</a>,
+      },
+    ];
+    const rowSelection = {
+      onChange: (selectedRowKeys, selectedRows) => {
+        // console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
+      },
+      getCheckboxProps: record => ({
+        disabled: record.name === 'Michael James',
+        // Column configuration not to be checked
+        name: record.name,
+      }),
+    };
+    const expandData = [
+      {
+        name: 'John Brown',
+        age: 32,
+        address: 'New York No. 1 Lake Park',
+        description:
+          'My name is John Brown, I am 32 years old, living in New York No. 1 Lake Park.',
+      },
+      {
+        name: 'Jim Green',
+        age: 42,
+        address: 'London No. 1 Lake Park',
+        description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.',
+      },
+      {
+        name: 'Joe Black',
+        age: 32,
+        address: (
+          <Collapse defaultActiveKey="1" motion={false}>
+            <Collapse.Panel header="This is panel header 1" itemKey="1">
+              <p>Hi, bytedance dance dance. This is the docsite of Semi UI. </p>
+            </Collapse.Panel>
+            <Collapse.Panel header="This is panel header 2" itemKey="2">
+              <p>Hi, bytedance dance dance. This is the docsite of Semi UI. </p>
+            </Collapse.Panel>
+            <Collapse.Panel header="This is panel header 3" itemKey="3">
+              <p>Hi, bytedance dance dance. This is the docsite of Semi UI. </p>
+            </Collapse.Panel>
+          </Collapse>
+        ),
+        description: 'My name is Joe Black, I am 32 years old, living in Sidney No. 1 Lake Park.',
+      },
+    ];
+
+    const expandRowRender = (record, index) => <Wrap isOpen={true} />;
+
+    return (
+      <Table
+        rowKey={'name'}
+        columns={expandColumns}
+        rowSelection={rowSelection}
+        expandedRowRender={expandRowRender}
+        dataSource={expandData}
+      />
+    );
+  }
 }
 
-stories.add('collapsible in table', () => <App />);
+export const CollapsibleInTable = () => <App />;
 
 class InTab extends React.Component {
-    constructor() {
-        super();
-        this.state = {
-            isOpenFirst: false,
-            isOpenSecond: false,
-        };
-    }
-
-    render() {
-        const { isOpenFirst, isOpenSecond } = this.state;
-        return (
-            <div>
-                <Tabs
-                    onTabClick={e =>
-                        this.setState({
-                            active: e,
-                        })
-                    }
-                >
-                    <TabPane tab="第一" itemKey="1">
-                        <h3>第一个tabpane</h3>
-                        <Button
-                            onClick={() => {
-                                this.setState({
-                                    isOpenFirst: !isOpenFirst,
-                                });
-                            }}
-                        >
-                            开关
-                        </Button>
-                        <Collapsible isOpen={isOpenFirst}>第一个tabpane下的collapsible的open状态正常</Collapsible>
-                    </TabPane>
-                    <TabPane tab="第二" itemKey="2">
-                        <h3>第二个tabpane</h3>
-                        <Button
-                            onClick={() => {
-                                this.setState({
-                                    isOpenSecond: !isOpenSecond,
-                                });
-                            }}
-                        >
-                            开关
-                        </Button>
-                        <Collapsible isOpen={isOpenSecond}>第二个tabpane下的collapsibleopen状态异常</Collapsible>
-                    </TabPane>
-                </Tabs>
-            </div>
-        );
-    }
+  constructor() {
+    super();
+    this.state = {
+      isOpenFirst: false,
+      isOpenSecond: false,
+    };
+  }
+
+  render() {
+    const { isOpenFirst, isOpenSecond } = this.state;
+    return (
+      <div>
+        <Tabs
+          onTabClick={e =>
+            this.setState({
+              active: e,
+            })
+          }
+        >
+          <TabPane tab="第一" itemKey="1">
+            <h3>第一个tabpane</h3>
+            <Button
+              onClick={() => {
+                this.setState({
+                  isOpenFirst: !isOpenFirst,
+                });
+              }}
+            >
+              开关
+            </Button>
+            <Collapsible isOpen={isOpenFirst}>
+              第一个tabpane下的collapsible的open状态正常
+            </Collapsible>
+          </TabPane>
+          <TabPane tab="第二" itemKey="2">
+            <h3>第二个tabpane</h3>
+            <Button
+              onClick={() => {
+                this.setState({
+                  isOpenSecond: !isOpenSecond,
+                });
+              }}
+            >
+              开关
+            </Button>
+            <Collapsible isOpen={isOpenSecond}>
+              第二个tabpane下的collapsibleopen状态异常
+            </Collapsible>
+          </TabPane>
+        </Tabs>
+      </div>
+    );
+  }
 }
 
-stories.add('collapsible in tab', () => <InTab />);
+export const CollapsibleInTab = () => <InTab />;
+
+CollapsibleInTab.story = {
+  name: 'collapsible in tab',
+};
 
 class WithUpload extends React.Component {
-    constructor(props) {
-        super(props);
-        this.state = {
-            isOpen: true,
-        };
-        this.toggle = this.toggle.bind(this);
-        this.action = '//semi.design/api/upload/';
-        this.defaultFileList = [
-            {
+  constructor(props) {
+    super(props);
+    this.state = {
+      isOpen: true,
+    };
+    this.toggle = this.toggle.bind(this);
+    this.action = '//semi.design/api/upload/';
+    this.defaultFileList = [
+      {
+        preview: false,
+        name: '2D (2).ecpj',
+        status: 'success',
+        uid: 'd116a179410eb0ca18e66074509bde93-0',
+        url:
+          'https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/bf8647bffab13c38772c9ff94bf91a9d.jpg',
+      },
+      {
+        preview: false,
+        name: '2D-sticker-temp.psd',
+        status: 'success',
+        uid: 'b7d579069320590ba4b128672eedbae2-1',
+        url:
+          'https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/bf8647bffab13c38772c9ff94bf91a9d.jpg',
+      },
+      {
+        preview: false,
+        name: '2D-sticker-temp (1).psd',
+        status: 'success',
+        uid: 'b7d579069320590ba4b128672eedbae2-2',
+        url:
+          'https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/bf8647bffab13c38772c9ff94bf91a9d.jpg',
+      },
+    ];
+  }
+
+  toggle() {
+    this.setState({
+      isOpen: !this.state.isOpen,
+    });
+  }
+
+  render() {
+    const { isOpen } = this.state;
+    return (
+      <div>
+        <Collapsible isOpen={isOpen} collapseHeight={120}>
+          <Upload
+            dragable={true}
+            name="file" // accept={ALLOW_FILE}
+            defaultFileList={[
+              {
                 preview: false,
                 name: '2D (2).ecpj',
                 status: 'success',
                 uid: 'd116a179410eb0ca18e66074509bde93-0',
-                url: 'https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/bf8647bffab13c38772c9ff94bf91a9d.jpg',
-            },
-            {
+                url:
+                  'https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/bf8647bffab13c38772c9ff94bf91a9d.jpg',
+              },
+              {
                 preview: false,
                 name: '2D-sticker-temp.psd',
                 status: 'success',
                 uid: 'b7d579069320590ba4b128672eedbae2-1',
-                url: 'https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/bf8647bffab13c38772c9ff94bf91a9d.jpg',
-            },
-            {
+                url:
+                  'https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/bf8647bffab13c38772c9ff94bf91a9d.jpg',
+              },
+              {
                 preview: false,
                 name: '2D-sticker-temp (1).psd',
                 status: 'success',
                 uid: 'b7d579069320590ba4b128672eedbae2-2',
-                url: 'https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/bf8647bffab13c38772c9ff94bf91a9d.jpg',
-            },
-        ];
-    }
-
-    toggle() {
-        this.setState({
-            isOpen: !this.state.isOpen,
-        });
-    }
-
-    render() {
-        const { isOpen } = this.state;
-        return (
-            <div>
-                <Collapsible isOpen={isOpen} collapseHeight={120}>
-                    <Upload
-                        dragable={true}
-                        name="file" // accept={ALLOW_FILE}
-                        defaultFileList={[
-                            {
-                                preview: false,
-                                name: '2D (2).ecpj',
-                                status: 'success',
-                                uid: 'd116a179410eb0ca18e66074509bde93-0',
-                                url:
-                                    'https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/bf8647bffab13c38772c9ff94bf91a9d.jpg',
-                            },
-                            {
-                                preview: false,
-                                name: '2D-sticker-temp.psd',
-                                status: 'success',
-                                uid: 'b7d579069320590ba4b128672eedbae2-1',
-                                url:
-                                    'https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/bf8647bffab13c38772c9ff94bf91a9d.jpg',
-                            },
-                            {
-                                preview: false,
-                                name: '2D-sticker-temp (1).psd',
-                                status: 'success',
-                                uid: 'b7d579069320590ba4b128672eedbae2-2',
-                                url:
-                                    'https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/bf8647bffab13c38772c9ff94bf91a9d.jpg',
-                            },
-                        ]}
-                        dragMainText="点击上传文件或拖拽文件到这里"
-                        dragSubText="图片、PDF、PPT、Word、视频等"
-                        onError={this.uploadError}
-                        onSuccess={(...args) => this.uploadSuccess(i, ...args)}
-                        onRemove={(...args) => this.onRemoveFile(i, ...args)}
-                        onProgress={() =>
-                            this.setState({
-                                fileLoading: true,
-                            })
-                        }
-                    >
-                        <Button icon={<IconUpload />} theme="light">
-                            点击上传
-                        </Button>
-                    </Upload>
-                </Collapsible>
-                <Button onClick={this.toggle}>{isOpen ? '剩余1项' : '展开'}</Button>
-            </div>
-        );
-    }
+                url:
+                  'https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/bf8647bffab13c38772c9ff94bf91a9d.jpg',
+              },
+            ]}
+            dragMainText="点击上传文件或拖拽文件到这里"
+            dragSubText="图片、PDF、PPT、Word、视频等"
+            onError={this.uploadError}
+            onSuccess={(...args) => this.uploadSuccess(i, ...args)}
+            onRemove={(...args) => this.onRemoveFile(i, ...args)}
+            onProgress={() =>
+              this.setState({
+                fileLoading: true,
+              })
+            }
+          >
+            <Button icon={<IconUpload />} theme="light">
+              点击上传
+            </Button>
+          </Upload>
+        </Collapsible>
+        <Button onClick={this.toggle}>{isOpen ? '剩余1项' : '展开'}</Button>
+      </div>
+    );
+  }
 }
 
-stories.add('collapsible with Upload', () => <WithUpload />);
+export const CollapsibleWithUpload = () => <WithUpload />;
 
 class CusHeight extends React.Component {
-    constructor(props) {
-        super(props);
-        this.state = {
-            isOpen: false,
-        };
-        this.toggle = this.toggle.bind(this);
-    }
-
-    toggle() {
-        this.setState({
-            isOpen: !this.state.isOpen,
-        });
-    }
-
-    render() {
-        const { isOpen } = this.state;
-        const maskStyle = isOpen
-            ? {}
-            : {
-                  WebkitMaskImage:
-                      'linear-gradient(to bottom, black 0%, rgba(0, 0, 0, 1) 60%, rgba(0, 0, 0, 0.2) 80%, transparent 100%)',
-              };
-        const collapsed = (
-            <ul>
-                <li>
-                    <p>Semi Design 以内容优先进行设计。</p>
-                </li>
-                <li>
-                    <p>更容易地自定义主题。</p>
-                </li>
-                <li>
-                    <p>适用国际化场景。</p>
-                </li>
-                <li>
-                    <p>效率场景加入人性化关怀。</p>
-                </li>
-            </ul>
-        );
-        const linkStyle = {
-            position: 'absolute',
-            left: 0,
-            right: 0,
-            textAlign: 'center',
-            bottom: -10,
-            fontWeight: 700,
-            cursor: 'pointer',
+  constructor(props) {
+    super(props);
+    this.state = {
+      isOpen: false,
+    };
+    this.toggle = this.toggle.bind(this);
+  }
+
+  toggle() {
+    this.setState({
+      isOpen: !this.state.isOpen,
+    });
+  }
+
+  render() {
+    const { isOpen } = this.state;
+    const maskStyle = isOpen
+      ? {}
+      : {
+          WebkitMaskImage:
+            'linear-gradient(to bottom, black 0%, rgba(0, 0, 0, 1) 60%, rgba(0, 0, 0, 0.2) 80%, transparent 100%)',
         };
-        console.log('out state', isOpen);
-        return (
-            <>
-                <Button onClick={this.toggle}>Toggle</Button>
-                <div
-                    style={{
-                        position: 'relative',
-                    }}
-                >
-                    <Collapsible
-                        isOpen={isOpen}
-                        collapseHeight={40}
-                        style={{ ...maskStyle }}
-                        onInnerStateOpen={bool => {
-                            if (isOpen !== bool) {
-                                this.setState({
-                                    isOpen: bool,
-                                });
-                            }
-                        }}
-                    >
-                        {collapsed}
-                    </Collapsible>
-                    {isOpen ? null : (
-                        <a onClick={this.toggle} style={{ ...linkStyle }}>
-                            + Show More
-                        </a>
-                    )}
-                </div>
-            </>
-        );
-    }
+    const collapsed = (
+      <ul>
+        <li>
+          <p>Semi Design 以内容优先进行设计。</p>
+        </li>
+        <li>
+          <p>更容易地自定义主题。</p>
+        </li>
+        <li>
+          <p>适用国际化场景。</p>
+        </li>
+        <li>
+          <p>效率场景加入人性化关怀。</p>
+        </li>
+      </ul>
+    );
+    const linkStyle = {
+      position: 'absolute',
+      left: 0,
+      right: 0,
+      textAlign: 'center',
+      bottom: -10,
+      fontWeight: 700,
+      cursor: 'pointer',
+    };
+    console.log('out state', isOpen);
+    return (
+      <>
+        <Button onClick={this.toggle}>Toggle</Button>
+        <div
+          style={{
+            position: 'relative',
+          }}
+        >
+          <Collapsible
+            isOpen={isOpen}
+            collapseHeight={40}
+            style={{ ...maskStyle }}
+            onInnerStateOpen={bool => {
+              if (isOpen !== bool) {
+                this.setState({
+                  isOpen: bool,
+                });
+              }
+            }}
+          >
+            {collapsed}
+          </Collapsible>
+          {isOpen ? null : (
+            <a onClick={this.toggle} style={{ ...linkStyle }}>
+              + Show More
+            </a>
+          )}
+        </div>
+      </>
+    );
+  }
 }
 
-stories.add('collapse height', () => <CusHeight />);
+export const CollapseHeight = () => <CusHeight />;
 
 const Child = ({ onClick }) => {
-    const [isCOpen, setIsCOpen] = useState(false);
-    return (
-        <div>
-            <div
-                style={{
-                    display: isCOpen ? 'block' : 'none',
-                    height: 200,
-                    background: 'green',
-                }}
-            >
-                child
-            </div>
-            <Button
-                onClick={() => {
-                    setIsCOpen(!isCOpen);
-                    onClick();
-                }}
-            >
-                Toggle
-            </Button>
-        </div>
-    );
+  const [isCOpen, setIsCOpen] = useState(false);
+  return (
+    <div>
+      <div
+        style={{
+          display: isCOpen ? 'block' : 'none',
+          height: 200,
+          background: 'green',
+        }}
+      >
+        child
+      </div>
+      <Button
+        onClick={() => {
+          setIsCOpen(!isCOpen);
+          onClick();
+        }}
+      >
+        Toggle
+      </Button>
+    </div>
+  );
 }; // dynamic update content, children comp need to separate from parent to avoid rerender of entire comp
 
 const DynamDemo = () => {
-    const [isOpen, setIsOpen] = useState(true);
-    const [reCalcKey, setReCalcKey] = useState(0);
-    return (
+  const [isOpen, setIsOpen] = useState(true);
+  const [reCalcKey, setReCalcKey] = useState(0);
+  return (
+    <div>
+      <Button onClick={() => setIsOpen(!isOpen)}>折叠</Button>
+      <Collapsible isOpen={isOpen}>
         <div>
-            <Button onClick={() => setIsOpen(!isOpen)}>折叠</Button>
-            <Collapsible isOpen={isOpen}>
-                <div>
-                    <div
-                        style={{
-                            height: 200,
-                            background: 'blue',
-                        }}
-                    >
-                        father
-                    </div>
-                    <Child onClick={() => setReCalcKey(reCalcKey + 1)} />
-                </div>
-            </Collapsible>
+          <div
+            style={{
+              height: 200,
+              background: 'blue',
+            }}
+          >
+            father
+          </div>
+          <Child onClick={() => setReCalcKey(reCalcKey + 1)} />
         </div>
-    );
+      </Collapsible>
+    </div>
+  );
 };
 
-stories.add('dynamic collapsible', () => <DynamDemo />);
+export const DynamicCollapsible = () => <DynamDemo />;

+ 5 - 2
packages/semi-ui/configProvider/_story/RTLDirection/RTLWrapper.jsx → packages/semi-ui/configProvider/_story/RTLDirection/RTLWrapper.tsx

@@ -1,11 +1,14 @@
 import React, { useState } from 'react';
 import { ButtonGroup, Button, ConfigProvider } from '@douyinfe/semi-ui';
 
-export default function RTLWrapper({ children, onDirectionChange }) {
+export default function RTLWrapper({ children, onDirectionChange }: { children: React.ReactNode; onDirectionChange?: (direction: 'ltr' | 'rtl') => void }) {
     const [direction, setDirection] = useState();
     const handleDirectionChange = dir => {
         setDirection(dir);
-        onDirectionChange(dir);
+        
+        if (typeof onDirectionChange === 'function') {
+            onDirectionChange(dir);
+        }
     };
 
     return (

+ 23 - 9
packages/semi-ui/configProvider/_story/configProvider.stories.js

@@ -1,16 +1,30 @@
 import React from 'react';
-import { storiesOf } from '@storybook/react';
 import ChangeTimeZone from './ChangeTimeZone';
 import GetContainer from './GetPopupContainer';
-import RTLWrapper from './RTLDirection/RTLWrapper'
-import RTLTable  from './RTLDirection/RTLTable';
-import RTLForm  from './RTLDirection/RTLForm';
+import RTLWrapper from './RTLDirection/RTLWrapper';
+import RTLTable from './RTLDirection/RTLTable';
+import RTLForm from './RTLDirection/RTLForm';
 
-const stories = storiesOf('ConfigProvider', module);
-stories.add(`change timeZone`, () => <ChangeTimeZone />);
+export default {
+  title: 'ConfigProvider',
+  parameters: {
+    chromatic: { disableSnapshot: true },
+  },
+}
 
-stories.add(`getPopupContainer`, () => <GetContainer />);
+export {
+  ChangeTimeZone,
+  GetContainer,
+}
 
-stories.add(`RTL Table`, () => <RTLWrapper><RTLTable /></RTLWrapper>);
+export const RTLTableDemo = () => (
+  <RTLWrapper>
+    <RTLTable />
+  </RTLWrapper>
+);
 
-stories.add(`RTL Form`, () => <RTLWrapper><RTLForm /></RTLWrapper>);
+export const RTLFormDemo = () => (
+  <RTLWrapper>
+    <RTLForm />
+  </RTLWrapper>
+);

+ 4 - 0
packages/semi-ui/datePicker/_story/BetterRangePicker/index.jsx

@@ -25,6 +25,10 @@ const presets = [
 const baseDate = new Date(baseYear, baseMon, baseDay, 8, 8, 8, 8);
 const currentValue = [new Date(baseDate), new Date(baseDate).setDate(baseDay + dayOffset)];
 
+Demo.parameters = {
+    chromatic: { disableSnapshot: false },
+};
+
 export default function Demo(props = {}) {
     const style = { width: 240 };
     return (

+ 4 - 0
packages/semi-ui/datePicker/_story/CustomTrigger/index.jsx

@@ -4,6 +4,10 @@ import { IconClose, IconChevronDown } from '@douyinfe/semi-icons';
 
 import { DatePicker, Button } from '../../../index';
 
+Demo.parameters = {
+    chromatic: { disableSnapshot: true },
+};
+
 export default function Demo() {
     const [date, setDate] = useState(new Date());
     const formatToken = 'yyyy-MM-dd';

+ 83 - 0
packages/semi-ui/datePicker/_story/DatePickerSlot/index.jsx

@@ -0,0 +1,83 @@
+/* eslint-disable max-len */
+import React, { useState, useMemo } from 'react';
+import { DatePicker, Icon, Typography, Space, Tabs, TabPane } from '../../../index';
+import './index.scss';
+
+const { Text } = Typography;
+
+export default function Demo() {
+    const [activeTab, setActiveTab] = useState('1');
+    const [date, setDate] = useState();
+    const uedDisabledDate = currentDate => currentDate && currentDate.getDate() > 10 && currentDate.getDate() < 15;
+    const testDisabledDate = currentDate => currentDate && currentDate.getDate() > 15 && currentDate.getDate() < 25;
+
+    const handleTabChange = tab => {
+        setActiveTab(tab);
+        setDate();
+    };
+
+    const handleDateChange = value => {
+        setDate(value);
+    };
+
+    const disabledDate = useMemo(() => (activeTab === '1' ? uedDisabledDate : testDisabledDate), [activeTab]);
+
+    const TopSlot = function (props) {
+        const { style } = props;
+        return (
+            <Tabs size="small" onChange={handleTabChange} activeKey={activeTab} style={{ padding: '12px 20px 0', ...style }}>
+                <TabPane tab="UED 排期" itemKey="1" />
+                <TabPane tab="测试排期" itemKey="2" />
+            </Tabs>
+        );
+    };
+
+    const BottomSlot = function (props) {
+        const { style } = props;
+        return (
+            <Space style={{ padding: '12px 20px', ...style }}>
+                <Icon type="bulb" style={{ color: 'rgba(var(--amber-5), 1)' }} />
+                <Text strong style={{ color: 'var(--color-text-2)' }}>
+                    定版前请阅读
+                </Text>
+                <Text link={{ href: 'https://semi.design/', target: '_blank' }}>发版须知</Text>
+            </Space>
+        );
+    };
+
+    const MonthBottomSlot = function (props) {
+        const { style } = props;
+        return (
+            <Space style={{ padding: '12px 20px', ...style }}>
+                <Icon type="bulb" style={{ color: 'rgba(var(--amber-5), 1)' }} />
+                <Text strong style={{ color: 'var(--color-text-2)' }}>
+                    请阅读
+                </Text>
+                <Text link={{ href: 'https://semi.design/', target: '_blank' }}>须知</Text>
+            </Space>
+        );
+    };
+
+    return (
+        <div>
+            <span>topSlot</span>
+            <DatePicker topSlot={<TopSlot />} disabledDate={disabledDate} value={date} onChange={handleDateChange} />
+            <br />
+            <br />
+            <span>bottomSlot</span>
+            <DatePicker bottomSlot={<BottomSlot />} />
+            <br />
+            <br />
+            <span>bottomSlot+dateTimeRange</span>
+            <DatePicker type="dateTimeRange" bottomSlot={<BottomSlot />} style={{ width: 300 }} />
+            <br />
+            <br />
+            <span>topSlot+month</span>
+            <DatePicker type="month" bottomSlot={<MonthBottomSlot />} />
+            <br />
+            <br />
+            <span>topSlot+bottomSlot+compact</span>
+            <DatePicker topSlot={<TopSlot style={{ padding: '8px 12px 0' }} />} bottomSlot={<BottomSlot style={{ padding: '8px 12px' }} />} density="compact" />
+        </div>
+    );
+}

+ 223 - 164
packages/semi-ui/datePicker/_story/datePicker.stories.js

@@ -1,7 +1,15 @@
 import React, { useState, useRef } from 'react';
-import { storiesOf } from '@storybook/react';
-import withPropsCombinations from 'react-storybook-addon-props-combinations';
-import { addDays, addWeeks, addMonths, isBefore, startOfMonth, endOfMonth, parseISO, startOfWeek, endOfWeek } from 'date-fns';
+import {
+  addDays,
+  addWeeks,
+  addMonths,
+  isBefore,
+  startOfMonth,
+  endOfMonth,
+  parseISO,
+  startOfWeek,
+  endOfWeek,
+} from 'date-fns';
 import { Space, ConfigProvider, InputGroup, InputNumber, Form, withField } from '../../index';
 
 // stores
@@ -29,16 +37,43 @@ import DatePickerTimeZone from './DatePickerTimeZone';
 import BetterRangePicker from './BetterRangePicker';
 import SyncSwitchMonth from './SyncSwitchMonth';
 
-const stories = storiesOf('DatePicker', module);
+export default {
+  title: 'DatePicker',
+  parameters: {
+    chromatic: { disableSnapshot: true },
+  },
+}
 
-// stories.addDecorator(withKnobs);;
+export {
+  ControlledDemo,
+  NeedConfirmDemo,
+  ExceptionDemo,
+  AllTypesDemo,
+  Callbacks,
+  DisabledDate,
+  CustomTrigger,
+  OverPopover,
+  OnChangeWithDateFirst,
+  RenderDate,
+  RenderFullDate,
+  Autofocus,
+  DateOffset,
+  CycledDatePicker,
+  AutoSwitchDate,
+  TimepikcerOpts,
+  Density,
+  DatePickerSlot,
+  DatePickerTimeZone,
+  BetterRangePicker,
+  SyncSwitchMonth
+}
 
 const demoDiv = {
   marginTop: '20px',
   marginLeft: '20px',
 };
 
-stories.add('DatePicker default', () => (
+export const DatePickerDefault = () => (
   <div style={demoDiv}>
     <span>datePicker施工现场</span>
     <DatePicker
@@ -54,7 +89,10 @@ stories.add('DatePicker default', () => (
     <br />
 
     <span>defaultValue: new Date('2019-07-07')</span>
-    <DatePicker defaultValue={new Date('2019-07-07')} onOpenChange={isOpen => console.log(isOpen)} />
+    <DatePicker
+      defaultValue={new Date('2019-07-07')}
+      onOpenChange={isOpen => console.log(isOpen)}
+    />
     <br />
 
     <span>defaultValue: 2019-07-09</span>
@@ -62,11 +100,14 @@ stories.add('DatePicker default', () => (
     <br />
 
     <span>defaultValue: 1569888000000</span>
-    <DatePicker defaultValue={1569888000000} onChange={(input, value) => console.log({ input, value })} />
+    <DatePicker
+      defaultValue={1569888000000}
+      onChange={(input, value) => console.log({ input, value })}
+    />
   </div>
-));
+);
 
-stories.add('DatePicker callbacks', () => {
+export const DatePickerCallbacks = () => {
   const printArgs = (...args) => console.log(...args);
 
   return (
@@ -84,14 +125,17 @@ stories.add('DatePicker callbacks', () => {
       <br />
 
       <span>defaultValue: 1569888000000</span>
-      <DatePicker defaultValue={1569888000000} onChange={(input, value) => console.log(input, value)} />
+      <DatePicker
+        defaultValue={1569888000000}
+        onChange={(input, value) => console.log(input, value)}
+      />
     </div>
   );
-});
+};
 
-stories.add('DatePicker multiple', () => <Multiple />);
+export const DatePickerMultiple = () => <Multiple />;
 
-stories.add('DateRangePicker', () => (
+export const DateRangePicker = () => (
   <div style={demoDiv}>
     <div>dateRangePicker</div>
     <DatePicker type="dateRange" insetLabel="结束日期" prefix="test" validateStatus="error" />
@@ -106,18 +150,24 @@ stories.add('DateRangePicker', () => (
     <br />
 
     <div>compact dateRangePicker</div>
-    <DatePicker type="dateRange" density='compact' validateStatus="warning" />
+    <DatePicker type="dateRange" density="compact" validateStatus="warning" />
     <br />
 
     <div>dateRangePicker with offset</div>
-    <DatePicker type="dateRange" startDateOffset={date => startOfWeek(date, { weekStartsOn: 1 })}
-                endDateOffset={date => endOfWeek(date, { weekStartsOn: 1 })} />
+    <DatePicker
+      type="dateRange"
+      startDateOffset={date => startOfWeek(date, { weekStartsOn: 1 })}
+      endDateOffset={date => endOfWeek(date, { weekStartsOn: 1 })}
+    />
     <br />
 
     <div>defaultValue:07/01-08/02</div>
     <DatePicker type="dateRange" defaultValue={[new Date('2019-07-01'), new Date('2019-08-02')]} />
   </div>
-));
+);
+DateRangePicker.parameters = {
+  chromatic: { disableSnapshot: false },
+};
 
 const presets = [
   {
@@ -162,14 +212,19 @@ const presets = [
   },
 ];
 
-stories.add('DatePicker with presets', () => {
+export const DatePickerWithPresets = () => {
   const onPresetClick = (item, e) => {
     console.log('preset click', item, e);
-  }
-  return (    
+  };
+  return (
     <div style={demoDiv}>
       <span>带快捷选择的DatePicker</span>
-      <DatePicker type="dateRange" presets={presets} onPresetClick={onPresetClick} onChange={(...args) => console.log(...args)} />
+      <DatePicker
+        type="dateRange"
+        presets={presets}
+        onPresetClick={onPresetClick}
+        onChange={(...args) => console.log(...args)}
+      />
       <DatePicker
         type="dateTime"
         presets={presets.map(preset => ({
@@ -200,20 +255,20 @@ stories.add('DatePicker with presets', () => {
       />
     </div>
   );
-});
+};
 
 function isDisabled(dayStr) {
   return isBefore(new Date(dayStr), new Date());
 }
 
-stories.add('DatePicker disabledDate', () => (
+export const DatePickerDisabledDate = () => (
   <div style={demoDiv}>
     <span>不可选日期</span>
     <DatePicker type="dateRange" presets={presets} disabledDate={isDisabled} />
   </div>
-));
+);
 
-stories.add('DateTimePicker', () => (
+export const DateTimePicker = () => (
   <div style={demoDiv}>
     <span>dateTimePicker</span>
     <DatePicker
@@ -222,9 +277,9 @@ stories.add('DateTimePicker', () => (
       onChange={(...args) => console.log('onChange: ', ...args)}
     />
   </div>
-));
+);
 
-stories.add('DateTimeRange Picker', () => (
+export const DateTimeRangePicker = () => (
   <div style={demoDiv}>
     <span>dateTimeRangePicker</span>
     <DatePicker type="dateTimeRange" defaultPickerValue={parseISO('2020-02-20 20:00:00')} />
@@ -238,9 +293,9 @@ stories.add('DateTimeRange Picker', () => (
     <DatePicker type="dateTimeRange" multiple />
     <br />
   </div>
-));
+);
 
-stories.add('Year Picker', () => (
+export const YearPicker = () => (
   <>
     <div>
       <span>Year Picker</span>
@@ -251,9 +306,9 @@ stories.add('Year Picker', () => (
       <DatePicker type="dateTimeRange" presets={presets} />
     </div>
   </>
-));
+);
 
-stories.add('Month Picker', () => {
+export const MonthPicker = () => {
   const Demo = () => {
     const [controlledValue, setControlledValue] = useState('2019-09');
 
@@ -297,61 +352,31 @@ stories.add('Month Picker', () => {
   };
 
   return <Demo />;
-});
+};
 
-stories.add('propTypes and defaultProps', () => (
+export const PropTypesAndDefaultProps = () => (
   <div>
     <article>
       <p>{JSON.stringify(Object.keys(DatePicker.propTypes))}</p>
       <p>{JSON.stringify(DatePicker.defaultProps)}</p>
     </article>
   </div>
-));
-
-stories.add('受控组件', () => <ControlledDemo />);
-
-stories.add('inputReadOnly', () => <DatePicker inputReadOnly={true} />);
-
-stories.add('need confirm', () => <NeedConfirmDemo />);
-
-stories.add('边界问题', () => <ExceptionDemo />);
+);
 
-stories.add('all types', () => <AllTypesDemo />);
-stories.add('callbacks', () => <Callbacks />);
+export const InputReadOnly = () => <DatePicker inputReadOnly={true} />;
 
-stories.add('Disabled Date', () => <DisabledDate />);
-
-stories.add('custom trigger', () => <CustomTrigger />);
-stories.add('over popover', () => <OverPopover />);
-
-stories.add('onChange with Date first', () => <OnChangeWithDateFirst />);
-
-stories.add('renderDate', () => <RenderDate />);
-stories.add('renderFullDate', () => <RenderFullDate />);
-stories.add('autoFocus', () => <Autofocus />);
-stories.add('startDateOffset & endDateOffset', () => <DateOffset />);
-stories.add('cycled', () => <CycledDatePicker />);
-stories.add('autoSwitchDate', () => <AutoSwitchDate />);
-
-stories.add('dropdownClassName & dropdownStyle', () => (
+export const DropdownClassNameDropdownStyle = () => (
   <div>
     <h4>fontSize: 16,dropdownClassName: 'my-datePicker'</h4>
-    <DatePicker 
+    <DatePicker
       dropdownStyle={{ fontSize: 16 }}
-      dropdownClassName='my-datePicker'
+      dropdownClassName="my-datePicker"
       onChange={(date, dateString) => console.log(dateString)}
     />
   </div>
-));
-stories.add('timepickerOpts', () => <TimepikcerOpts />);
+);
 
-stories.add('density', () => <Density />);
-
-stories.add('topSlot/bottomSlot', () => <DatePickerSlot />);
-
-stories.add('timeZone', () => <DatePickerTimeZone />);
-
-stories.add('custom placeholder', () => (
+export const CustomPlaceholder = () => (
   <Space wrap>
     <DatePicker placeholder="请选择日期" insetLabel="默认" />
     <DatePicker placeholder={undefined} insetLabel="undefined" />
@@ -360,48 +385,51 @@ stories.add('custom placeholder', () => (
     <DatePicker placeholder={null} insetLabel="null" />
     <DatePicker placeholder="" type="dateRange" insetLabel="空字符串" />
   </Space>
-));
-
-stories.add('better range picker', () => <BetterRangePicker />);
-
-stories.add('syncSwitchMonth', () => <SyncSwitchMonth />);
+);
+CustomPlaceholder.parameters = {
+  chromatic: { disableSnapshot: false },
+};
 
-stories.add('fix notifyChange', () => {
+export const FixNotifyChange = () => {
   function Demo() {
-    const [tz,setTz] = useState(0);
+    const [tz, setTz] = useState(0);
     const [value, setVal] = useState();
     const [value2, setVal2] = useState();
     const [value3, setVal3] = useState();
     const [value4, setVal4] = useState();
-    const withLog = (fn) => {
-      return (val => {
-          console.log('notifyChange', val);
-          fn(val);
-      });
-    }
+    const withLog = fn => {
+      return val => {
+        console.log('notifyChange', val);
+        fn(val);
+      };
+    };
     return (
-        <ConfigProvider timeZone={tz}>
-            <InputGroup>
-                <InputNumber defaultValue={0} onChange={setTz} hideButtons />
-                <DatePicker type='dateTimeRange' value={value} onChange={withLog(setVal)}  />
-                <DatePicker type='dateTimeRange' needConfirm value={value2} onConfirm={withLog(setVal2)}  />
-                <DatePicker type='date' value={value3} onChange={withLog(setVal3)}  />
-                <DatePicker type='dateRange' value={value4} onChange={withLog(setVal4)}  />
-            </InputGroup>
-        </ConfigProvider> 
+      <ConfigProvider timeZone={tz}>
+        <InputGroup>
+          <InputNumber defaultValue={0} onChange={setTz} hideButtons />
+          <DatePicker type="dateTimeRange" value={value} onChange={withLog(setVal)} />
+          <DatePicker
+            type="dateTimeRange"
+            needConfirm
+            value={value2}
+            onConfirm={withLog(setVal2)}
+          />
+          <DatePicker type="date" value={value3} onChange={withLog(setVal3)} />
+          <DatePicker type="dateRange" value={value4} onChange={withLog(setVal4)} />
+        </InputGroup>
+      </ConfigProvider>
     );
-  };
+  }
   return <Demo />;
+};
 
-});
-
-stories.add('select not disabled date(v1.26+)', () => {
+export const SelectNotDisabledDateV126 = () => {
   const defaultValue = ['2021-08-06', '2021-08-15'];
   const disabledMonth = dateStr => {
     const date = new Date(dateStr);
     const month = date.getMonth();
     if (month === 7) {
-        return true;
+      return true;
     }
     return false;
   };
@@ -409,7 +437,7 @@ stories.add('select not disabled date(v1.26+)', () => {
     const date = new Date(dateStr);
     const day = date.getDate();
     if (day > 20 && day < 25) {
-        return true;
+      return true;
     }
     return false;
   };
@@ -419,7 +447,7 @@ stories.add('select not disabled date(v1.26+)', () => {
     motion: false,
     defaultValue,
     onChange: (...args) => console.log('changed', ...args),
-    style: { width: 300 }
+    style: { width: 300 },
   };
 
   return (
@@ -429,19 +457,21 @@ stories.add('select not disabled date(v1.26+)', () => {
       <h4>date type + multiple select + given disabled defaultValue</h4>
       <DatePicker {...props} type="date" multiple disabledDate={disabledDate} />
     </>
-  )
-});
+  );
+};
 
-const CustomDatePicker = (props) => {
+SelectNotDisabledDateV126.story = {
+  name: 'select not disabled date(v1.26+)',
+};
+
+const CustomDatePicker = props => {
   const { fieldRef, ...rest } = props;
-  return (
-    <DatePicker {...rest} ref={fieldRef}  />
-  );
+  return <DatePicker {...rest} ref={fieldRef} />;
 };
 
 const CustomFieldDatePicker = withField(CustomDatePicker);
 
-stories.add('fix onFocus', () => {
+export const FixOnFocus = () => {
   function FocusDemo() {
     const [open1, setOpen1] = useState(false);
     const [open2, setOpen2] = useState(false);
@@ -449,16 +479,16 @@ stories.add('fix onFocus', () => {
     const ref = useRef();
     const ref2 = useRef();
     const presets = [
-        {
-            text: 'Today',
-            start: new Date(),
-            end: new Date(),
-        },
-        {
-            text: 'Tomorrow',
-            start: new Date(new Date().valueOf() + 1000 * 3600 * 24),
-            end: new Date(new Date().valueOf() + 1000 * 3600 * 24),
-        },
+      {
+        text: 'Today',
+        start: new Date(),
+        end: new Date(),
+      },
+      {
+        text: 'Tomorrow',
+        start: new Date(new Date().valueOf() + 1000 * 3600 * 24),
+        end: new Date(new Date().valueOf() + 1000 * 3600 * 24),
+      },
     ];
     return (
       <>
@@ -467,16 +497,19 @@ stories.add('fix onFocus', () => {
           presets={presets}
           open={open1}
           onPresetClick={() => {
-              setOpen1(false);
+            setOpen1(false);
           }}
           onFocus={() => {
-              console.log('focus');
-              setOpen1(true);
+            console.log('focus');
+            setOpen1(true);
+          }}
+          onBlur={() => {
+            console.log('blur');
           }}
-          onBlur={() => {console.log('blur')}}
           style={{ width: 300 }}
         />
-        <br /><br />
+        <br />
+        <br />
         <DatePicker
           type="dateTimeRange"
           presets={presets}
@@ -493,40 +526,48 @@ stories.add('fix onFocus', () => {
             console.log('focus');
             setOpen2(true);
           }}
-          onBlur={() => {console.log('blur')}}
+          onBlur={() => {
+            console.log('blur');
+          }}
           style={{ width: 500 }}
           ref={ref}
         />
         <Form>
           <CustomFieldDatePicker
-              type="dateTimeRange"
-              field="a"
-              label="Form.DatePicker"
-              presets={presets}
-              open={open3}
-              onPresetClick={() => {
-                console.log('click presets', ref2);
-                setOpen3(false);
-                setTimeout(() => {
-                  ref2.current &&  ref2.current.foundation.closePanel();
-                }, 0);
-              }}
-              onFocus={() => {
-                console.log('focus');
-                setOpen3(true);
-              }}
-              onBlur={() => {console.log('blur')}}
-              style={{ width: 500 }}
-              fieldRef={ref2}
+            type="dateTimeRange"
+            field="a"
+            label="Form.DatePicker"
+            presets={presets}
+            open={open3}
+            onPresetClick={() => {
+              console.log('click presets', ref2);
+              setOpen3(false);
+              setTimeout(() => {
+                ref2.current && ref2.current.foundation.closePanel();
+              }, 0);
+            }}
+            onFocus={() => {
+              console.log('focus');
+              setOpen3(true);
+            }}
+            onBlur={() => {
+              console.log('blur');
+            }}
+            style={{ width: 500 }}
+            fieldRef={ref2}
           />
         </Form>
       </>
     );
-  };
-  return <FocusDemo />
-});
+  }
+  return <FocusDemo />;
+};
+
+FixOnFocus.story = {
+  name: 'fix onFocus',
+};
 
-stories.add('fix disabledTime callback #1418', () => {
+export const FixDisabledTimeCallback1418 = () => {
   function Demo() {
     const disabledTime2 = (date, panelType) => {
       console.log('disabledTime callback parameter: ', date, panelType);
@@ -541,37 +582,55 @@ stories.add('fix disabledTime callback #1418', () => {
       <>
         <strong>fix disabledTime callback parameter bug</strong>
         <DatePicker
-            type="dateTimeRange"
-            hideDisabledOptions={false}
-            disabledTime={disabledTime2}
-            defaultValue={['2021-09-08', '2021-10-03']}
-            style={{ width: 400 }}
+          type="dateTimeRange"
+          hideDisabledOptions={false}
+          disabledTime={disabledTime2}
+          defaultValue={['2021-09-08', '2021-10-03']}
+          style={{ width: 400 }}
         />
         <DatePicker
-            type="dateTime"
-            hideDisabledOptions={false}
-            defaultValue={'2021-09-08'}
-            disabledTime={disabledTime2}
-            style={{ width: 400 }}
+          type="dateTime"
+          hideDisabledOptions={false}
+          defaultValue={'2021-09-08'}
+          disabledTime={disabledTime2}
+          style={{ width: 400 }}
         />
       </>
     );
-  };
+  }
 
   return <Demo />;
-});
+};
 
-stories.add('rangeSeparator', () => (
+FixDisabledTimeCallback1418.story = {
+  name: 'fix disabledTime callback #1418',
+};
+
+export const RangeSeparator = () => (
   <Space wrap>
     <div>
       <div>custom rangeSeparator</div>
-      <DatePicker type="dateRange" rangeSeparator="-" defaultValue={[new Date('2019-07-01'), new Date('2019-08-02')]} />
-      <DatePicker type="dateTimeRange" rangeSeparator="-" defaultValue={[new Date('2019-07-01'), new Date('2019-08-02')]} />
+      <DatePicker
+        type="dateRange"
+        rangeSeparator="-"
+        defaultValue={[new Date('2019-07-01'), new Date('2019-08-02')]}
+      />
+      <DatePicker
+        type="dateTimeRange"
+        rangeSeparator="-"
+        defaultValue={[new Date('2019-07-01'), new Date('2019-08-02')]}
+      />
     </div>
     <div>
       <div>default rangeSeparator</div>
-      <DatePicker type="dateRange" defaultValue={[new Date('2019-07-01'), new Date('2019-08-02')]} />
-      <DatePicker type="dateTimeRange" defaultValue={[new Date('2019-07-01'), new Date('2019-08-02')]} />
+      <DatePicker
+        type="dateRange"
+        defaultValue={[new Date('2019-07-01'), new Date('2019-08-02')]}
+      />
+      <DatePicker
+        type="dateTimeRange"
+        defaultValue={[new Date('2019-07-01'), new Date('2019-08-02')]}
+      />
     </div>
   </Space>
-));
+);

+ 46 - 45
packages/semi-ui/descriptions/_story/descriptions.stories.js

@@ -1,10 +1,11 @@
 import React from 'react';
-import { storiesOf } from '@storybook/react';
 // import { withKnobs, text, boolean } from '@storybook/addon-knobs';
 
 import Descriptions from '../index';
 
-const stories = storiesOf('Descriptions', module);
+export default {
+  title: 'Descriptions',
+}
 
 let data = [
     // ShortId: '火山号',
@@ -46,49 +47,49 @@ let data4 = [
     { key: '7天留存', value: '103.4M' },
 ];
 
-stories.add('Descriptions default', () => (
-    <div>
-        <Descriptions data={data} />
-        <Descriptions align='justify' data={data2} />
-        <Descriptions align='left' data={data3} />
-        <Descriptions align='plain' data={data2} />
-    </div>
-));
+export const DescriptionsDefault = () => (
+  <div>
+    <Descriptions data={data} />
+    <Descriptions align="justify" data={data2} />
+    <Descriptions align="left" data={data3} />
+    <Descriptions align="plain" data={data2} />
+  </div>
+);
 
-stories.add('Descriptions double row', () => (
-    <div>
-        <Descriptions data={data4} row size='small' />
-        <Descriptions data={data4} row />
-        <Descriptions data={data4} row size='large' />
-    </div>
-));
+export const DescriptionsDoubleRow = () => (
+  <div>
+    <Descriptions data={data4} row size="small" />
+    <Descriptions data={data4} row />
+    <Descriptions data={data4} row size="large" />
+  </div>
+);
 
-stories.add('Descriptions.Item', () => (
-    <div>
-        <Descriptions>
-            <Descriptions.Item itemKey='实际用户数量'>1,480,000</Descriptions.Item>
-            <Descriptions.Item itemKey='7天留存'>98%</Descriptions.Item>
-            <Descriptions.Item itemKey='安全等级'>3级</Descriptions.Item>
-            <Descriptions.Item itemKey='垂类标签'>电商</Descriptions.Item>
-            <Descriptions.Item itemKey='认证状态'>未认证</Descriptions.Item>
-        </Descriptions>
-        <br />
-        <Descriptions row size='small'>
-            <Descriptions.Item itemKey='实际用户数量'>1,480,000</Descriptions.Item>
-            <Descriptions.Item itemKey='7天留存'>98%</Descriptions.Item>
-            <Descriptions.Item itemKey='安全等级'>3级</Descriptions.Item>
-            <Descriptions.Item itemKey='垂类标签'>电商</Descriptions.Item>
-            <Descriptions.Item itemKey='认证状态'>未认证</Descriptions.Item>
-        </Descriptions>
-        <br />
-        <Descriptions align='justify'>
-            <Descriptions.Item >1,480,000</Descriptions.Item>
-            <Descriptions.Item itemKey='7天留存'>98%</Descriptions.Item>
-            <Descriptions.Item itemKey='安全等级'>3级</Descriptions.Item>
-            <Descriptions.Item itemKey='垂类标签'>电商</Descriptions.Item>
-            <Descriptions.Item itemKey='认证状态'>未认证</Descriptions.Item>
-        </Descriptions>
-        <br />
-    </div>
-));
+export const DescriptionsItem = () => (
+  <div>
+    <Descriptions>
+      <Descriptions.Item itemKey="实际用户数量">1,480,000</Descriptions.Item>
+      <Descriptions.Item itemKey="7天留存">98%</Descriptions.Item>
+      <Descriptions.Item itemKey="安全等级">3级</Descriptions.Item>
+      <Descriptions.Item itemKey="垂类标签">电商</Descriptions.Item>
+      <Descriptions.Item itemKey="认证状态">未认证</Descriptions.Item>
+    </Descriptions>
+    <br />
+    <Descriptions row size="small">
+      <Descriptions.Item itemKey="实际用户数量">1,480,000</Descriptions.Item>
+      <Descriptions.Item itemKey="7天留存">98%</Descriptions.Item>
+      <Descriptions.Item itemKey="安全等级">3级</Descriptions.Item>
+      <Descriptions.Item itemKey="垂类标签">电商</Descriptions.Item>
+      <Descriptions.Item itemKey="认证状态">未认证</Descriptions.Item>
+    </Descriptions>
+    <br />
+    <Descriptions align="justify">
+      <Descriptions.Item>1,480,000</Descriptions.Item>
+      <Descriptions.Item itemKey="7天留存">98%</Descriptions.Item>
+      <Descriptions.Item itemKey="安全等级">3级</Descriptions.Item>
+      <Descriptions.Item itemKey="垂类标签">电商</Descriptions.Item>
+      <Descriptions.Item itemKey="认证状态">未认证</Descriptions.Item>
+    </Descriptions>
+    <br />
+  </div>
+);
 

+ 300 - 304
packages/semi-ui/dropdown/_story/dropdown.stories.js

@@ -1,7 +1,4 @@
 import React from 'react';
-import { storiesOf } from '@storybook/react'; // import { withKnobs, text, boolean } from '@storybook/addon-knobs';
-
-import withPropsCombinations from 'react-storybook-addon-props-combinations';
 import Dropdown from '../index';
 import Avatar from '../../avatar';
 import Button from '@douyinfe/semi-ui/button/index';
@@ -11,325 +8,324 @@ import MultiDropdown from './MultiDropdown';
 import DisabledItem from './DisabledItem';
 import InHoverElements from './InHoverElements';
 import WrapAvatar from './WrapAvatar';
-import { IconChevronDown, IconBox, IconSimiarlity } from '@douyinfe/semi-icons';
+import { IconChevronDown, IconBox, IconSimilarity } from '@douyinfe/semi-icons';
+
+export default {
+  title: 'Dropdown',
+  parameters: {
+    chromatic: { disableSnapshot: true },
+  }
+}
 
-const stories = storiesOf('Dropdown', module); // stories.addDecorator(withKnobs);;
+export {
+  InTableDemo,
+  MultiDropdown,
+  DisabledItem,
+  InHoverElements,
+  WrapAvatar
+}
 
 let style = {
-    display: 'inline-block',
-    padding: '20px',
+  display: 'inline-block',
+  padding: '20px',
 };
 
 const change = visible => {
-    debugger;
+  debugger;
 };
 
-stories.add('Dropdown 1', () => (
-    <div>
-        <div style={style}>
-            <Dropdown
-                trigger="click"
-                render={
-                    <Dropdown.Menu>
-                        <Dropdown.Item disabled>1111</Dropdown.Item>
-                        <Dropdown.Divider />
-                        <Dropdown.Item selected={true}>
-                            2222 What if the text is super long? Longer than whatever you've known
-                        </Dropdown.Item>
-                        <Dropdown.Item>It looks OK</Dropdown.Item>
-                    </Dropdown.Menu>
-                }
-            >
-                <div>分割线</div>
-            </Dropdown>
-        </div>
-
-        <div style={style}>
-            <Dropdown
-                onVisibleChange={change}
-                render={
-                    <Dropdown.Menu>
-                        <Dropdown.Item>333</Dropdown.Item>
-                        <Dropdown.Item>44444</Dropdown.Item>
-                    </Dropdown.Menu>
-                }
-            >
-                hover
-            </Dropdown>
-        </div>
-
-        <br />
+export const Dropdown1 = () => (
+  <div>
+    <div style={style}>
+      <Dropdown
+        trigger="click"
+        render={
+          <Dropdown.Menu>
+            <Dropdown.Item disabled>1111</Dropdown.Item>
+            <Dropdown.Divider />
+            <Dropdown.Item selected={true}>
+              2222 What if the text is super long? Longer than whatever you've known
+            </Dropdown.Item>
+            <Dropdown.Item>It looks OK</Dropdown.Item>
+          </Dropdown.Menu>
+        }
+      >
+        <div>分割线</div>
+      </Dropdown>
+    </div>
 
-        <div style={style}>
-            <Dropdown
-                position="bottomRight"
-                render={
-                    <Dropdown.Menu>
-                        <Dropdown.Item>333</Dropdown.Item>
-                        <Dropdown.Item>44444</Dropdown.Item>
-                    </Dropdown.Menu>
-                }
-            >
-                hover bottomRight
-            </Dropdown>
-        </div>
+    <div style={style}>
+      <Dropdown
+        onVisibleChange={change}
+        render={
+          <Dropdown.Menu>
+            <Dropdown.Item>333</Dropdown.Item>
+            <Dropdown.Item>44444</Dropdown.Item>
+          </Dropdown.Menu>
+        }
+      >
+        hover
+      </Dropdown>
+    </div>
 
-        <div style={style}>
-            <Dropdown
-                position="bottomLeft"
-                render={
-                    <Dropdown.Menu>
-                        <Dropdown.Item>333</Dropdown.Item>
-                        <Dropdown.Item>44444</Dropdown.Item>
-                    </Dropdown.Menu>
-                }
-            >
-                hover bottomLeft
-            </Dropdown>
-        </div>
+    <br />
 
-        {/* <div style={style}>
-       <Dropdown content="ies vigosss">
-           bottom hover
-       </Dropdown>
-    </div>
     <div style={style}>
-       <Dropdown trigger="click" content="ies vigo" trigger="click">
-           bottom click
-       </Dropdown>
+      <Dropdown
+        position="bottomRight"
+        render={
+          <Dropdown.Menu>
+            <Dropdown.Item>333</Dropdown.Item>
+            <Dropdown.Item>44444</Dropdown.Item>
+          </Dropdown.Menu>
+        }
+      >
+        hover bottomRight
+      </Dropdown>
     </div>
+
     <div style={style}>
-       <Dropdown content={<Button type="warning">btn</Button>}  trigger="click">
-           content is Node
-       </Dropdown>
-    </div> */}
+      <Dropdown
+        position="bottomLeft"
+        render={
+          <Dropdown.Menu>
+            <Dropdown.Item>333</Dropdown.Item>
+            <Dropdown.Item>44444</Dropdown.Item>
+          </Dropdown.Menu>
+        }
+      >
+        hover bottomLeft
+      </Dropdown>
     </div>
-));
-stories.add('Dropdown 2', () => {
-    return (
-        <div>
-            <Dropdown
-                trigger="click"
-                position="bottomLeft"
-                render={
-                    <Dropdown.Menu>
-                        <Dropdown.Item disabled>1111</Dropdown.Item>
-                        <Dropdown.Divider />
-                        <Dropdown.Item selected={true}>
-                            2222 What if the text is super long? Longer than whatever you've known
-                        </Dropdown.Item>
-                        <Dropdown.Item>It looks OK</Dropdown.Item>
-                    </Dropdown.Menu>
-                }
-            >
-                <Button>Open dropdown</Button>
-            </Dropdown>
-        </div>
-    );
-});
-stories.add('Avatar', () => {
-    return (
+  </div>
+);
+
+export const Dropdown2 = () => {
+  return (
+    <div>
+      <Dropdown
+        trigger="click"
+        position="bottomLeft"
+        render={
+          <Dropdown.Menu>
+            <Dropdown.Item disabled>1111</Dropdown.Item>
+            <Dropdown.Divider />
+            <Dropdown.Item selected={true}>
+              2222 What if the text is super long? Longer than whatever you've known
+            </Dropdown.Item>
+            <Dropdown.Item>It looks OK</Dropdown.Item>
+          </Dropdown.Menu>
+        }
+      >
+        <Button>Open dropdown</Button>
+      </Dropdown>
+    </div>
+  );
+};
+
+export const AvatarDemo = () => {
+  return (
+    <div
+      style={{
+        display: 'flex',
+        flexDirection: 'row-reverse',
+      }}
+    >
+      <Dropdown
+        autoAdjustOverflow={true}
+        trigger="click"
+        position="bottomRight"
+        getPopupContainer={() => document.querySelector('#dropdown-container')}
+        render={
+          <Dropdown.Menu>
+            <Dropdown.Item disabled>1111</Dropdown.Item>
+            <Dropdown.Divider />
+            <Dropdown.Item selected={true}>
+              2222 What if the text is super long? Longer than whatever you've known
+            </Dropdown.Item>
+            <Dropdown.Item>It looks OK</Dropdown.Item>
+          </Dropdown.Menu>
+        }
+      >
         <div
-            style={{
-                display: 'flex',
-                flexDirection: 'row-reverse',
-            }}
+          style={{
+            display: 'inline-block',
+          }}
         >
-            <Dropdown
-                autoAdjustOverflow={true}
-                trigger="click"
-                position="bottomRight"
-                getPopupContainer={() => document.querySelector('#dropdown-container')}
-                render={
-                    <Dropdown.Menu>
-                        <Dropdown.Item disabled>1111</Dropdown.Item>
-                        <Dropdown.Divider />
-                        <Dropdown.Item selected={true}>
-                            2222 What if the text is super long? Longer than whatever you've known
-                        </Dropdown.Item>
-                        <Dropdown.Item>It looks OK</Dropdown.Item>
-                    </Dropdown.Menu>
-                }
-            >
-                <div
-                    style={{
-                        display: 'inline-block',
-                    }}
-                >
-                    <Avatar size="small" src="" />
-                    <IconChevronDown />
-                </div>
-            </Dropdown>
-            <div id="dropdown-container" />
-        </div>
-    );
-});
-stories.add('Dropdown onVisibleChange', () => {
-    return (
-        <div>
-            <Dropdown
-                trigger="click"
-                onVisibleChange={(...args) => {
-                    console.log('onVisibleChange: ', ...args);
-                }}
-                render={
-                    <Dropdown.Menu>
-                        <Dropdown.Item disabled>1111</Dropdown.Item>
-                        <Dropdown.Divider />
-                        <Dropdown.Item selected={true}>
-                            2222 What if the text is super long? Longer than whatever you've known
-                        </Dropdown.Item>
-                        <Dropdown.Item>It looks OK</Dropdown.Item>
-                    </Dropdown.Menu>
-                }
-            >
-                <Button>Open dropdown</Button>
-            </Dropdown>
+          <Avatar size="small" src="" />
+          <IconChevronDown />
         </div>
-    );
-});
-stories.add('dropdown in table', () => <InTableDemo />);
-stories.add('dropdown auto close when clicked', () => <AutoClose />);
-stories.add('multi dropdown', () => <MultiDropdown />);
-stories.add('dropdownItem type', () => (
-    <>
-        <Dropdown
-            visible={true}
-            trigger="custom"
-            render={
-                <Dropdown.Menu>
-                    <Dropdown.Item type="primary">primary</Dropdown.Item>
-                    <Dropdown.Item type="secondary">secondary</Dropdown.Item>
-                    <Dropdown.Item type="tertiary">tertiary</Dropdown.Item>
-                    <Dropdown.Item type="warning">warning</Dropdown.Item>
-                    <Dropdown.Item type="danger">danger</Dropdown.Item>
-                    <Dropdown.Item>default</Dropdown.Item>
-                </Dropdown.Menu>
-            }
-        >
-            Different type Item
-        </Dropdown>
-        <Dropdown
-            visible={true}
-            trigger="custom"
-            showTick
-            render={
-                <Dropdown.Menu>
-                    <Dropdown.Item type="primary" active>
-                        primary
-                    </Dropdown.Item>
-                    <Dropdown.Item type="secondary">secondary</Dropdown.Item>
-                    <Dropdown.Item type="tertiary">tertiary</Dropdown.Item>
-                    <Dropdown.Item type="warning">warning</Dropdown.Item>
-                    <Dropdown.Item type="danger" active>
-                        编辑danger
-                    </Dropdown.Item>
-                    <Dropdown.Item>default</Dropdown.Item>
-                </Dropdown.Menu>
-            }
-        >
-            Different type Item
-        </Dropdown>
-    </>
-));
-stories.add('DisabledItem', () => <DisabledItem />);
-stories.add(`in hover elements`, () => <InHoverElements />);
-stories.add(`wrap avatar`, () => <WrapAvatar />);
+      </Dropdown>
+      <div id="dropdown-container" />
+    </div>
+  );
+};
+
+export const DropdownOnVisibleChange = () => {
+  return (
+    <div>
+      <Dropdown
+        trigger="click"
+        onVisibleChange={(...args) => {
+          console.log('onVisibleChange: ', ...args);
+        }}
+        render={
+          <Dropdown.Menu>
+            <Dropdown.Item disabled>1111</Dropdown.Item>
+            <Dropdown.Divider />
+            <Dropdown.Item selected={true}>
+              2222 What if the text is super long? Longer than whatever you've known
+            </Dropdown.Item>
+            <Dropdown.Item>It looks OK</Dropdown.Item>
+          </Dropdown.Menu>
+        }
+      >
+        <Button>Open dropdown</Button>
+      </Dropdown>
+    </div>
+  );
+};
+
+export const DropdownAutoCloseWhenClicked = () => <AutoClose />;
+
+DropdownAutoCloseWhenClicked.story = {
+  name: 'dropdown auto close when clicked',
+};
+
+export const DropdownItemType = () => (
+  <>
+    <Dropdown
+      visible={true}
+      trigger="custom"
+      render={
+        <Dropdown.Menu>
+          <Dropdown.Item type="primary">primary</Dropdown.Item>
+          <Dropdown.Item type="secondary">secondary</Dropdown.Item>
+          <Dropdown.Item type="tertiary">tertiary</Dropdown.Item>
+          <Dropdown.Item type="warning">warning</Dropdown.Item>
+          <Dropdown.Item type="danger">danger</Dropdown.Item>
+          <Dropdown.Item>default</Dropdown.Item>
+        </Dropdown.Menu>
+      }
+    >
+      Different type Item
+    </Dropdown>
+    <Dropdown
+      visible={true}
+      trigger="custom"
+      showTick
+      render={
+        <Dropdown.Menu>
+          <Dropdown.Item type="primary" active>
+            primary
+          </Dropdown.Item>
+          <Dropdown.Item type="secondary">secondary</Dropdown.Item>
+          <Dropdown.Item type="tertiary">tertiary</Dropdown.Item>
+          <Dropdown.Item type="warning">warning</Dropdown.Item>
+          <Dropdown.Item type="danger" active>
+            编辑danger
+          </Dropdown.Item>
+          <Dropdown.Item>default</Dropdown.Item>
+        </Dropdown.Menu>
+      }
+    >
+      Different type Item
+    </Dropdown>
+  </>
+);
 
-function DropdownItemPropsDemo() {
-    return (
-        <div>
-            <Dropdown
-                trigger="custom"
-                position="bottomLeft"
-                visible
-                render={
-                    <Dropdown.Menu>
-                        <Dropdown.Item icon={<IconBox />}>Menu Item 1</Dropdown.Item>
-                        <Dropdown.Item iconType="setting">Menu Item 2</Dropdown.Item>
-                        <Dropdown.Item disabled iconType="forward">
-                            Menu Item 3
-                        </Dropdown.Item>
-                        <Dropdown.Item iconType="align_center" type="primary" iconType="branch">
-                            primary
-                        </Dropdown.Item>
-                        <Dropdown.Item iconType="color_palette" type="secondary">
-                            secondary
-                        </Dropdown.Item>
-                        <Dropdown.Item iconType="refresh" type="tertiary">
-                            tertiary
-                        </Dropdown.Item>
-                        <Dropdown.Item iconType="search" type="warning">
-                            warning
-                        </Dropdown.Item>
-                        <Dropdown.Item
-                            icon={
-                                <IconSimiarlity
-                                    style={{
-                                        color: 'var(--semi-color-tertiary)',
-                                    }}
-                                />
-                            }
-                            type="danger"
-                        >
-                            danger
-                        </Dropdown.Item>
-                    </Dropdown.Menu>
-                }
+export function DropdownItemPropsDemo() {
+  return (
+    <div>
+      <Dropdown
+        trigger="custom"
+        position="bottomLeft"
+        visible
+        render={
+          <Dropdown.Menu>
+            <Dropdown.Item icon={<IconBox />}>Menu Item 1</Dropdown.Item>
+            <Dropdown.Item iconType="setting">Menu Item 2</Dropdown.Item>
+            <Dropdown.Item disabled iconType="forward">
+              Menu Item 3
+            </Dropdown.Item>
+            <Dropdown.Item iconType="align_center" type="primary" iconType="branch">
+              primary
+            </Dropdown.Item>
+            <Dropdown.Item iconType="color_palette" type="secondary">
+              secondary
+            </Dropdown.Item>
+            <Dropdown.Item iconType="refresh" type="tertiary">
+              tertiary
+            </Dropdown.Item>
+            <Dropdown.Item iconType="search" type="warning">
+              warning
+            </Dropdown.Item>
+            <Dropdown.Item
+              icon={
+                <IconSimilarity
+                  style={{
+                    color: 'var(--semi-color-tertiary)',
+                  }}
+                />
+              }
+              type="danger"
             >
-                <Button>始终展示</Button>
-            </Dropdown>
-            <Dropdown
-                trigger="custom"
-                position="bottomLeft"
-                showTick
-                visible
-                render={
-                    <Dropdown.Menu>
-                        <Dropdown.Item active icon={<IconBox />}>
-                            Menu Item 1
-                        </Dropdown.Item>
-                        <Dropdown.Item iconType="setting">Menu Item 2</Dropdown.Item>
-                        <Dropdown.Item disabled iconType="forward">
-                            Menu Item 3
-                        </Dropdown.Item>
-                        <Dropdown.Item iconType="align_center" type="primary" iconType="branch">
-                            primary
-                        </Dropdown.Item>
-                        <Dropdown.Item iconType="color_palette" type="secondary">
-                            secondary
-                        </Dropdown.Item>
-                        <Dropdown.Item iconType="refresh" type="tertiary">
-                            tertiary
-                        </Dropdown.Item>
-                        <Dropdown.Item iconType="search" type="warning">
-                            warning
-                        </Dropdown.Item>
-                        <Dropdown.Item
-                            icon={
-                                <IconSimiarlity
-                                    style={{
-                                        color: 'var(--semi-color-tertiary)',
-                                    }}
-                                />
-                            }
-                            type="danger"
-                        >
-                            danger
-                        </Dropdown.Item>
-                    </Dropdown.Menu>
-                }
+              danger
+            </Dropdown.Item>
+          </Dropdown.Menu>
+        }
+      >
+        <Button>始终展示</Button>
+      </Dropdown>
+      <Dropdown
+        trigger="custom"
+        position="bottomLeft"
+        showTick
+        visible
+        render={
+          <Dropdown.Menu>
+            <Dropdown.Item active icon={<IconBox />}>
+              Menu Item 1
+            </Dropdown.Item>
+            <Dropdown.Item iconType="setting">Menu Item 2</Dropdown.Item>
+            <Dropdown.Item disabled iconType="forward">
+              Menu Item 3
+            </Dropdown.Item>
+            <Dropdown.Item iconType="align_center" type="primary" iconType="branch">
+              primary
+            </Dropdown.Item>
+            <Dropdown.Item iconType="color_palette" type="secondary">
+              secondary
+            </Dropdown.Item>
+            <Dropdown.Item iconType="refresh" type="tertiary">
+              tertiary
+            </Dropdown.Item>
+            <Dropdown.Item iconType="search" type="warning">
+              warning
+            </Dropdown.Item>
+            <Dropdown.Item
+              icon={
+                <IconSimilarity
+                  style={{
+                    color: 'var(--semi-color-tertiary)',
+                  }}
+                />
+              }
+              type="danger"
             >
-                <Button
-                    style={{
-                        marginLeft: 200,
-                    }}
-                >
-                    始终展示
-                </Button>
-            </Dropdown>
-        </div>
-    );
-}
-
-stories.add(`Dropdown.Item props`, () => <DropdownItemPropsDemo />);
+              danger
+            </Dropdown.Item>
+          </Dropdown.Menu>
+        }
+      >
+        <Button
+          style={{
+            marginLeft: 200,
+          }}
+        >
+          始终展示
+        </Button>
+      </Dropdown>
+    </div>
+  );
+}

+ 44 - 40
packages/semi-ui/empty/_story/empty.stories.js

@@ -1,49 +1,53 @@
 import React from 'react';
-import { storiesOf } from '@storybook/react';
-// import { withKnobs, text, boolean } from '@storybook/addon-knobs';
 
 import Empty from '../index';
 import Button from '../../button';
 import { IllustrationSuccess } from '@douyinfe/semi-illustrations';
 
-const stories = storiesOf('Empty', module);
+export default {
+  title: 'Empty',
+}
 
-stories.add('empty simple', () => (
-    <div>
-        <Empty image={Success} description={'功能建设中'} />
-        <br />
-        <Empty image={Success} description={'功能建设中'}>
-            该模块功能建设中,敬请期待。该模块功能建设中,敬请期待。
-        </Empty>
-        <br />
-        <Empty image={Success}>该模块功能建设中,敬请期待。该模块功能建设中,敬请期待。</Empty>
-        <br />
-        <Empty description={'功能建设中'}>该模块功能建设中,敬请期待。该模块功能建设中,敬请期待。</Empty>
-    </div>
-));
+export const EmptySimple = () => (
+  <div>
+    <Empty image={<IllustrationSuccess />} description={'功能建设中'} />
+    <br />
+    <Empty image={<IllustrationSuccess />} description={'功能建设中'}>
+      该模块功能建设中,敬请期待。该模块功能建设中,敬请期待。
+    </Empty>
+    <br />
+    <Empty image={<IllustrationSuccess />}>
+      该模块功能建设中,敬请期待。该模块功能建设中,敬请期待。
+    </Empty>
+    <br />
+    <Empty description={'功能建设中'}>
+      该模块功能建设中,敬请期待。该模块功能建设中,敬请期待。
+    </Empty>
+  </div>
+);
 
-stories.add('empty cta', () => (
-    <div>
-        <Empty description={'功能建设中'} image={<IllustrationSuccess />}>
-            <div style={{ textAlign: 'center' }}>
-                <p>该模块功能建设中,敬请期待。该模块功能建设中,敬请期待。</p>
-                <Button type="primary" style={{ marginTop: 24 }}>
-                    建设中
-                </Button>
-            </div>
-        </Empty>
-    </div>
-));
+export const EmptyCta = () => (
+  <div>
+    <Empty description={'功能建设中'} image={<IllustrationSuccess />}>
+      <div style={{ textAlign: 'center' }}>
+        <p>该模块功能建设中,敬请期待。该模块功能建设中,敬请期待。</p>
+        <Button type="primary" style={{ marginTop: 24 }}>
+          建设中
+        </Button>
+      </div>
+    </Empty>
+  </div>
+);
 
-stories.add('empty layout', () => (
-    <div>
-        <Empty description={'功能建设中'} image={<IllustrationSuccess />} layout="horizontal">
-            <div>
-                <p>该模块功能建设中,敬请期待。该模块功能建设中,敬请期待。</p>
-                <Button type="primary" style={{ marginTop: 24 }}>
-                    建设中
-                </Button>
-            </div>
-        </Empty>
-    </div>
-));
+export const EmptyLayout = () => (
+  <div>
+    <Empty description={'功能建设中'} image={<IllustrationSuccess />} layout="horizontal">
+      <div>
+        <p>该模块功能建设中,敬请期待。该模块功能建设中,敬请期待。</p>
+        <Button type="primary" style={{ marginTop: 24 }}>
+          建设中
+        </Button>
+      </div>
+    </Empty>
+  </div>
+);

+ 442 - 188
packages/semi-ui/form/_story/form.stories.js

@@ -1,30 +1,51 @@
 import React, { useState, useLayoutEffect, useEffect, useRef } from 'react';
-import { storiesOf } from '@storybook/react';
-import { Button, Modal, TreeSelect, Row, Col, Avatar, Tabs, TabPane, Badge, Notification } from '../../index';
 import {
-    Form,
-    useFormState,
-    useFormApi,
-    useFieldApi,
-    useFieldState,
-    withFormState,
-    withFormApi,
-    withField,
-    ArrayField,
-    Icon,
+  Button,
+  Modal,
+  TreeSelect,
+  Row,
+  Col,
+  Avatar,
+  Tabs,
+  TabPane,
+  Badge,
+  Notification,
+} from '../../index';
+import {
+  Form,
+  useFormState,
+  useFormApi,
+  useFieldApi,
+  useFieldState,
+  withFormState,
+  withFormApi,
+  withField,
+  ArrayField,
+  Icon,
 } from '../../index';
 import { BasicDemoWithInit, LinkFieldForm, I18nDemo, DifferentDeclareUsage } from './demo';
-const { Input, Select, DatePicker, Switch, Slider, CheckboxGroup, Checkbox, RadioGroup, Radio, TimePicker } = Form;
+const {
+  Input,
+  Select,
+  DatePicker,
+  Switch,
+  Slider,
+  CheckboxGroup,
+  Checkbox,
+  RadioGroup,
+  Radio,
+  TimePicker,
+} = Form;
 
 import {
-    UseFormApiDemo,
-    UseFormStateDemo,
-    UseFieldApiDemo,
-    UseFieldStateDemo,
-    WithFormStateDemo,
-    WithFormApiDemo,
-    ComponentUsingFormState,
-    CustomStringify,
+  UseFormApiDemo,
+  UseFormStateDemo,
+  UseFieldApiDemo,
+  UseFieldStateDemo,
+  WithFormStateDemo,
+  WithFormApiDemo,
+  ComponentUsingFormState,
+  CustomStringify,
 } from './Hook/hookDemo';
 
 // layout
@@ -34,7 +55,15 @@ import { ModalFormDemo } from './Layout/modalFormDemo';
 
 import { WithFieldDemo, CustomFieldDemo, NumberRange } from './HOC/withFieldDemo';
 import { WithDisplayName } from './HOC/displayName';
-import { CustomValidateDemo, ValidateFieldsDemo, PartValidAndResetDemo, RulesValidateDemo, SetBugDemo, UnmountedLeafDemo, RulesExample } from './Validate/validateDemo';
+import {
+  CustomValidateDemo,
+  ValidateFieldsDemo,
+  PartValidAndResetDemo,
+  RulesValidateDemo,
+  SetBugDemo,
+  UnmountedLeafDemo,
+  RulesExample,
+} from './Validate/validateDemo';
 
 // field props
 import { ConvertDemo } from './FieldProps/convert';
@@ -45,208 +74,433 @@ import { FieldRefDemo } from './FieldProps/fieldRef';
 
 // arrayField
 import {
-    ArrayFieldCollapseDemo,
-    ArrayFieldDemo,
-    ArrayFieldWithFormInitValues,
-    ArrayFieldWithInitValue,
+  ArrayFieldCollapseDemo,
+  ArrayFieldDemo,
+  ArrayFieldWithFormInitValues,
+  ArrayFieldWithInitValue,
 } from './DynamicField/arrayFieldDemo';
 import { NestArrayField } from './DynamicField/nestArrayField';
 import { ArrayDemo } from './FormApi/arrayDemo';
 
 // performance
-import { ManyFieldDemo, EffectDemo, ModalFormSelectWithObject } from './Performance/performanceDemo';
+import {
+  ManyFieldDemo,
+  EffectDemo,
+  ModalFormSelectWithObject,
+} from './Performance/performanceDemo';
 import { SetValuesDemo, SetValuesWithArrayField } from './FormApi/setValuesDemo';
 import { SetValueUsingParentPath } from './FormApi/formApiDemo';
 import { FieldPathWithArrayDemo } from './Debug/bugDemo';
 import ChildDidMount from './Debug/childDidMount';
 
-const stories = storiesOf('Form', module);
+export default {
+  title: 'Form'
+}
+
 const Option = Select.Option;
 
-stories.add('Form declare usage', () => <DifferentDeclareUsage />);
-stories.add('BasicDemo', () => <BasicDemoWithInit />);
+export const FormDeclareUsage = () => <DifferentDeclareUsage />;
 
-stories.add('Layout-Form.InputGroup', () => <GroupFormDemo />);
-stories.add('Layout-Form wrapperCol/labelCol', () => <LayoutDemo />);
-stories.add('Layout-insetLabel', () => <InsetLabelDemo />);
-stories.add('Layout-Slot/ErrorMessage/Label', () => <AssistComponent />);
-stories.add('Layout- ModalDemo', () => <ModalFormDemo />);
+FormDeclareUsage.story = {
+  name: 'Form declare usage',
+};
 
-stories.add('formApi-setValues(override)', () => <SetValuesDemo />);
-stories.add('formApi-validate', () => <PartValidAndResetDemo />);
-stories.add('formApi-setValue using field parent path', () => <SetValueUsingParentPath />);
+export const BasicDemo = () => <BasicDemoWithInit />;
 
-stories.add('Dynamic Add / Remove Field', () => (
-    <Form>
-        {({ formState }) => (
-            <React.Fragment>
-                <Input field="name" label="First name:" />
-                <RadioGroup field="married" label="Are you married?">
-                    <Radio value="yes">yes</Radio>
-                    <Radio value="no">no</Radio>
-                </RadioGroup>
-                {formState.values.married === 'yes' ? <Input field="spouse" label="Spouse name:" /> : null}
-                <Button htmlType="submit">Submit</Button>
-                <ComponentUsingFormState />
-            </React.Fragment>
-        )}
-    </Form>
-));
+BasicDemo.story = {
+  name: 'BasicDemo',
+};
 
-stories.add('ArrayField-basic usage', () => <ArrayFieldDemo />);
-stories.add('ArrayField-with form initValues', () => <ArrayFieldWithFormInitValues />);
-stories.add('ArrayField-with arrayField initValue', () => <ArrayFieldWithInitValue />);
-stories.add('ArrayField-Nest Usage', () => <NestArrayField />);
-stories.add('ArrayField-CollapseDemo', () => <ArrayFieldCollapseDemo />);
+export const LayoutFormInputGroup = () => <GroupFormDemo />;
+
+LayoutFormInputGroup.story = {
+  name: 'Layout-Form.InputGroup',
+};
 
-stories.add('【数组】动态增删表单项-使用FormState、FormApi手动处理', () => <ArrayDemo />);
+export const LayoutFormWrapperColLabelCol = () => <LayoutDemo />;
 
-stories.add('LinkField', () => <LinkFieldForm />);
-stories.add('Validate-FormLevel', () => <ValidateFieldsDemo />);
-stories.add('Validate-FieldValel', () => <CustomValidateDemo />);
-stories.add('Validate-use rules', () => <RulesValidateDemo />);
+LayoutFormWrapperColLabelCol.story = {
+  name: 'Layout-Form wrapperCol/labelCol',
+};
 
-stories.add('Hooks-useFormApi', () => <UseFormApiDemo />);
-stories.add('Hooks-useFormState', () => <UseFormStateDemo />);
-stories.add('Hooks-useFieldApi', () => <UseFieldApiDemo />);
-stories.add('Hooks-useFieldState', () => <UseFieldStateDemo />);
+export const LayoutInsetLabel = () => <InsetLabelDemo />;
 
-stories.add('Hoc-withFormApi', () => <WithFormApiDemo />);
-stories.add('Hoc-withFormState', () => <WithFormStateDemo />);
+LayoutInsetLabel.story = {
+  name: 'Layout-insetLabel',
+};
 
-// stories.add('Hoc-withFieldApi', () => (<div></div>));
-// stories.add('Hoc-withFieldState', () => (<div></div>));
+export const LayoutSlotErrorMessageLabel = () => <AssistComponent />;
 
-stories.add('withField', () => <CustomFieldDemo />);
-stories.add('withField- with stateful component', () => <WithFieldDemo />);
-stories.add('withField - NumberRange', () => (
-    <Form onChange={v => console.log(v)}>
-        <NumberRange field="number" initValue={[1, 2]} noLabel={true}></NumberRange>
-    </Form>
-));
-
-stories.add('Performance-ManyField', () => <ManyFieldDemo />);
-stories.add('Performance-ModalFormSelectWithObject', () => <ModalFormSelectWithObject />);
-
-stories.add('Filed Prop-convert', () => <ConvertDemo />);
-stories.add('Filed Prop-helpText / extraText / extraTextPosition', () => (
-    <>
-        <HelpAndExtra />
-        <ExtraPositionDemo />
-        <GroupFormDemo />
-    </>
-));
-stories.add('Field Props-dynamic update rules.required', () => <RuleupdateDemo />);
-stories.add('Field Prop-initValue=""', () => <InitEmptyStringDemo />);
-stories.add('Field prop-big number field submit', () => <BigNumberFieldDemo />);
-stories.add('Field Prop-pure', () => (
-    <Form>
-        <Form.Select field="name" pure className="fefefe" fieldClassName="feichang" style={{ width: 400 }} />
-    </Form>
-));
-stories.add('Field Prop-ref', () => <FieldRefDemo />);
+LayoutSlotErrorMessageLabel.story = {
+  name: 'Layout-Slot/ErrorMessage/Label',
+};
+
+export const LayoutModalDemo = () => <ModalFormDemo />;
+
+LayoutModalDemo.story = {
+  name: 'Layout- ModalDemo',
+};
+
+export const FormApiSetValuesOverride = () => <SetValuesDemo />;
+
+FormApiSetValuesOverride.story = {
+  name: 'formApi-setValues(override)',
+};
+
+export const FormApiValidate = () => <PartValidAndResetDemo />;
+
+FormApiValidate.story = {
+  name: 'formApi-validate',
+};
+
+export const FormApiSetValueUsingFieldParentPath = () => <SetValueUsingParentPath />;
+
+FormApiSetValueUsingFieldParentPath.story = {
+  name: 'formApi-setValue using field parent path',
+};
+
+export const DynamicAddRemoveField = () => (
+  <Form>
+    {({ formState }) => (
+      <React.Fragment>
+        <Input field="name" label="First name:" />
+        <RadioGroup field="married" label="Are you married?">
+          <Radio value="yes">yes</Radio>
+          <Radio value="no">no</Radio>
+        </RadioGroup>
+        {formState.values.married === 'yes' ? <Input field="spouse" label="Spouse name:" /> : null}
+        <Button htmlType="submit">Submit</Button>
+        <ComponentUsingFormState />
+      </React.Fragment>
+    )}
+  </Form>
+);
+
+DynamicAddRemoveField.story = {
+  name: 'Dynamic Add / Remove Field',
+};
+
+export const ArrayFieldBasicUsage = () => <ArrayFieldDemo />;
+
+ArrayFieldBasicUsage.story = {
+  name: 'ArrayField-basic usage',
+};
+
+export const _ArrayFieldWithFormInitValues = () => <ArrayFieldWithFormInitValues />;
+
+_ArrayFieldWithFormInitValues.story = {
+  name: 'ArrayField-with form initValues',
+};
+
+export const ArrayFieldWithArrayFieldInitValue = () => <ArrayFieldWithInitValue />;
+
+ArrayFieldWithArrayFieldInitValue.story = {
+  name: 'ArrayField-with arrayField initValue',
+};
+
+export const ArrayFieldNestUsage = () => <NestArrayField />;
+
+ArrayFieldNestUsage.story = {
+  name: 'ArrayField-Nest Usage',
+};
+
+export const _ArrayFieldCollapseDemo = () => <ArrayFieldCollapseDemo />;
+
+_ArrayFieldCollapseDemo.story = {
+  name: 'ArrayField-CollapseDemo',
+};
+
+export const ArrayFieldDynamicUpdate = () => <ArrayDemo />;
+
+ArrayFieldDynamicUpdate.story = {
+  name: 'ArrayField-dynamic update',
+};
+
+export const LinkField = () => <LinkFieldForm />;
+
+LinkField.story = {
+  name: 'LinkField',
+};
+
+export const ValidateFormLevel = () => <ValidateFieldsDemo />;
+
+ValidateFormLevel.story = {
+  name: 'Validate-FormLevel',
+};
+
+export const ValidateFieldValel = () => <CustomValidateDemo />;
+
+ValidateFieldValel.story = {
+  name: 'Validate-FieldValel',
+};
+
+export const ValidateUseRules = () => <RulesValidateDemo />;
+
+ValidateUseRules.story = {
+  name: 'Validate-use rules',
+};
+
+export const HooksUseFormApi = () => <UseFormApiDemo />;
+
+HooksUseFormApi.story = {
+  name: 'Hooks-useFormApi',
+};
+
+export const HooksUseFormState = () => <UseFormStateDemo />;
+
+HooksUseFormState.story = {
+  name: 'Hooks-useFormState',
+};
+
+export const HooksUseFieldApi = () => <UseFieldApiDemo />;
+
+HooksUseFieldApi.story = {
+  name: 'Hooks-useFieldApi',
+};
+
+export const HooksUseFieldState = () => <UseFieldStateDemo />;
+
+HooksUseFieldState.story = {
+  name: 'Hooks-useFieldState',
+};
+
+export const HocWithFormApi = () => <WithFormApiDemo />;
+
+HocWithFormApi.story = {
+  name: 'Hoc-withFormApi',
+};
+
+export const HocWithFormState = () => <WithFormStateDemo />;
+
+HocWithFormState.story = {
+  name: 'Hoc-withFormState',
+};
+
+export const WithField = () => <CustomFieldDemo />;
+
+WithField.story = {
+  name: 'withField',
+};
+
+export const WithFieldWithStatefulComponent = () => <WithFieldDemo />;
+
+WithFieldWithStatefulComponent.story = {
+  name: 'withField- with stateful component',
+};
+
+export const WithFieldNumberRange = () => (
+  <Form onChange={v => console.log(v)}>
+    <NumberRange field="number" initValue={[1, 2]} noLabel={true}></NumberRange>
+  </Form>
+);
+
+WithFieldNumberRange.story = {
+  name: 'withField - NumberRange',
+};
+
+export const PerformanceManyField = () => <ManyFieldDemo />;
+
+PerformanceManyField.story = {
+  name: 'Performance-ManyField',
+};
+
+export const PerformanceModalFormSelectWithObject = () => <ModalFormSelectWithObject />;
+
+PerformanceModalFormSelectWithObject.story = {
+  name: 'Performance-ModalFormSelectWithObject',
+};
+
+export const FiledPropConvert = () => <ConvertDemo />;
+
+FiledPropConvert.story = {
+  name: 'Filed Prop-convert',
+};
+
+export const FiledPropHelpTextExtraTextExtraTextPosition = () => (
+  <>
+    <HelpAndExtra />
+    <ExtraPositionDemo />
+    <GroupFormDemo />
+  </>
+);
+
+FiledPropHelpTextExtraTextExtraTextPosition.story = {
+  name: 'Filed Prop-helpText / extraText / extraTextPosition',
+};
+
+export const FieldPropsDynamicUpdateRulesRequired = () => <RuleupdateDemo />;
+
+FieldPropsDynamicUpdateRulesRequired.story = {
+  name: 'Field Props-dynamic update rules.required',
+};
+
+export const FieldPropInitValue = () => <InitEmptyStringDemo />;
+
+FieldPropInitValue.story = {
+  name: 'Field Prop-initValue=""',
+};
+
+export const FieldPropBigNumberFieldSubmit = () => <BigNumberFieldDemo />;
+
+FieldPropBigNumberFieldSubmit.story = {
+  name: 'Field prop-big number field submit',
+};
+
+export const FieldPropPure = () => (
+  <Form>
+    <Form.Select
+      field="name"
+      pure
+      className="fefefe"
+      fieldClassName="feichang"
+      style={{ width: 400 }}
+    />
+  </Form>
+);
+
+FieldPropPure.story = {
+  name: 'Field Prop-pure',
+};
+
+export const FieldPropRef = () => <FieldRefDemo />;
+
+FieldPropRef.story = {
+  name: 'Field Prop-ref',
+};
 
 const InitEmptyStringDemo = () => {
-    return (
-        <Form allowEmpty>
-            <Form.Input field="name" initValue="" />
-            <ComponentUsingFormState />
-        </Form>
-    );
+  return (
+    <Form allowEmpty>
+      <Form.Input field="name" initValue="" />
+      <ComponentUsingFormState />
+    </Form>
+  );
 };
 
+export const DebugSetBugDemo = () => (
+  <>
+    <SetBugDemo />
+    <UnmountedLeafDemo />
+  </>
+);
+
+DebugSetBugDemo.story = {
+  name: 'Debug-SetBugDemo',
+};
 
-stories.add('Debug-SetBugDemo', () => (
-    <>
-        <SetBugDemo />
-        <UnmountedLeafDemo />
-    </>
-));
+export const DebugSetValuesWithArrayField = () => (
+  <>
+    <SetValuesWithArrayField />
+  </>
+);
 
-stories.add('Debug-SetValuesWithArrayField', () => (
-    <>
-        <SetValuesWithArrayField />
-    </>
-));
+DebugSetValuesWithArrayField.story = {
+  name: 'Debug-SetValuesWithArrayField',
+};
 
 import { SetValuesArray, DoubleRerender } from './Debug/bugDemo';
 
-stories.add('Debug-数组类fieldPath', () => <FieldPathWithArrayDemo />);
+export const DebugArrayFieldPath = () => <FieldPathWithArrayDemo />;
 
-stories.add('Debug-SetValuesDemo', () => (
-    <>
-        <SetValuesArray />
-    </>
-));
+DebugArrayFieldPath.story = {
+  name: 'Debug-数组类fieldPath',
+};
 
-// useFormState与rules使用时,会rerender两次
-stories.add('Debug-RerenderTwice', () => (
-    <>
-        <DoubleRerender />
-    </>
-));
+export const DebugSetValuesDemo = () => (
+  <>
+    <SetValuesArray />
+  </>
+);
+
+DebugSetValuesDemo.story = {
+  name: 'Debug-SetValuesDemo',
+};
 
-stories.add('Field displayName', () => <WithDisplayName attr="form" />);
+export const DebugRerenderTwice = () => (
+  <>
+    <DoubleRerender />
+  </>
+);
+
+DebugRerenderTwice.story = {
+  name: 'Debug-RerenderTwice',
+};
+
+export const FieldDisplayName = () => <WithDisplayName attr="form" />;
+
+FieldDisplayName.story = {
+  name: 'Field displayName',
+};
 
 class ReUseDemo extends React.Component {
-    constructor() {
-        super();
-        this.getFormApi = this.getFormApi.bind(this);
-        this.suppressRankOptions = [
-          { label: '不打压', value: 0 },
-          { label: 'top10以下', value: 10 },
-          { label: 'top30以下', value: 30 },
-        ];
-        this.citySuppressRankOptions = [
-          { label: '不打压', value: 0 },
-          { label: 'top3以下', value: 3 },
-          { label: 'top5以下', value: 5 },
-          { label: 'top10以下', value: 10 },
-        ];
-    }
-
-    getFormApi(formApi) { this.formApi = formApi; }
-
-    render() {
-        return (
-            <Form getFormApi={this.getFormApi} initValues={{ listType: 'online', attr: { suppress_rank: 0, city_suppress_rank: 5 }}} onValueChange={values => console.log(values) } style={{ width: 250 }}>
-                {({ formState }) => (<>
-                <Form.Select
-                    field="listType"
-                    label="榜单类型"
-                    disabled={this.ifUseOld}
-                    style={{ width: '100%' }}
-                    // onChange={val => this.onChangeListType(val)}
-                  >
-                    <Option value="online" >
-                      热点榜
-                    </Option>
-                    <Option value="riseHot" >
-                      上升热点榜
-                    </Option>
-                    <Option value="sameCity" >
-                      同城热点榜
-                    </Option>
-                  </Form.Select>
-                {formState.values.listType !== 'sameCity' ? (
-                    <Form.Select
-                      label="竞品打压类型"
-                      field="attr.suppress_rank"
-                      optionList={this.suppressRankOptions}
-                    />
-                ) : (
-                    <Form.Select
-                      label="同城竞品打压"
-                      field="attr.city_suppress_rank"
-                      optionList={this.citySuppressRankOptions}
-                    />
-                )}
-                </>)}
-            </Form>
-        );
-    }
+  constructor() {
+    super();
+    this.getFormApi = this.getFormApi.bind(this);
+    this.suppressRankOptions = [
+      { label: '不打压', value: 0 },
+      { label: 'top10以下', value: 10 },
+      { label: 'top30以下', value: 30 },
+    ];
+    this.citySuppressRankOptions = [
+      { label: '不打压', value: 0 },
+      { label: 'top3以下', value: 3 },
+      { label: 'top5以下', value: 5 },
+      { label: 'top10以下', value: 10 },
+    ];
+  }
+
+  getFormApi(formApi) {
+    this.formApi = formApi;
+  }
+
+  render() {
+    return (
+      <Form
+        getFormApi={this.getFormApi}
+        initValues={{ listType: 'online', attr: { suppress_rank: 0, city_suppress_rank: 5 } }}
+        onValueChange={values => console.log(values)}
+        style={{ width: 250 }}
+      >
+        {({ formState }) => (
+          <>
+            <Form.Select
+              field="listType"
+              label="榜单类型"
+              disabled={this.ifUseOld}
+              style={{ width: '100%' }}
+              // onChange={val => this.onChangeListType(val)}
+            >
+              <Option value="online">热点榜</Option>
+              <Option value="riseHot">上升热点榜</Option>
+              <Option value="sameCity">同城热点榜</Option>
+            </Form.Select>
+            {formState.values.listType !== 'sameCity' ? (
+              <Form.Select
+                label="竞品打压类型"
+                field="attr.suppress_rank"
+                optionList={this.suppressRankOptions}
+              />
+            ) : (
+              <Form.Select
+                label="同城竞品打压"
+                field="attr.city_suppress_rank"
+                optionList={this.citySuppressRankOptions}
+              />
+            )}
+          </>
+        )}
+      </Form>
+    );
+  }
 }
-stories.add('same field switch cause reuse', () => <ReUseDemo />);
+export const SameFieldSwitchCauseReuse = () => <ReUseDemo />;
+
+SameFieldSwitchCauseReuse.story = {
+  name: 'same field switch cause reuse',
+};
 
-stories.add('child didmount', () => <ChildDidMount />);
+export const _ChildDidMount = () => <ChildDidMount />;
 
+_ChildDidMount.story = {
+  name: 'child did mount',
+};

+ 283 - 223
packages/semi-ui/grid/_story/grid.stories.js

@@ -1,230 +1,290 @@
 import React from 'react';
-import { storiesOf } from '@storybook/react';
-// import { withKnobs, text, boolean } from '@storybook/addon-knobs';
 
 import './demo.scss';
 import { Col, Row } from '../index';
 
-const stories = storiesOf('Grid', module);
-
-// stories.addDecorator(withKnobs);;
-
-stories.add('grid default', () => (
-    <div>
-        <Row>
-            <Col span={24}>col-24</Col>
-        </Row>
-        <Row>
-            <Col span={12}>col-12</Col>
-            <Col span={12}>col-12</Col>
-        </Row>
-        <Row>
-            <Col span={8}>col-8</Col>
-            <Col span={8}>col-8</Col>
-            <Col span={8}>col-8</Col>
-        </Row>
-        <Row>
-            <Col span={6}>col-6</Col>
-            <Col span={6}>col-6</Col>
-            <Col span={6}>col-6</Col>
-            <Col span={6}>col-6</Col>
-        </Row>
-    </div>
-));
-
-stories.add('grid with gutter', () => (
-    <div className="gutter-example">
-        <p>横向间距16</p>
-        <hr/>
-        <Row gutter={16}>
-            <Col className="gutter-row" span={6}>
-                <div className="gutter-box">col-6</div>
-            </Col>
-            <Col className="gutter-row" span={6}>
-                <div className="gutter-box">col-6</div>
-            </Col>
-            <Col className="gutter-row" span={6}>
-                <div className="gutter-box">col-6</div>
-            </Col>
-            <Col className="gutter-row" span={6}>
-                <div className="gutter-box">col-6</div>
-            </Col>
-        </Row>
-        <p>横向间距16,纵向间距48</p>
-        <hr/>
-        <Row gutter={[16, 48]}>
-            <Col className="gutter-row" span={6}>
-                <div className="gutter-box">col-6</div>
-            </Col>
-            <Col className="gutter-row" span={6}>
-                <div className="gutter-box">col-6</div>
-            </Col>
-            <Col className="gutter-row" span={6}>
-                <div className="gutter-box">col-6</div>
-            </Col>
-            <Col className="gutter-row" span={6}>
-                <div className="gutter-box">col-6</div>
-            </Col>
-            <Col className="gutter-row" span={6}>
-                <div className="gutter-box">col-6</div>
-            </Col>
-            <Col className="gutter-row" span={6}>
-                <div className="gutter-box">col-6</div>
-            </Col>
-            <Col className="gutter-row" span={6}>
-                <div className="gutter-box">col-6</div>
-            </Col>
-            <Col className="gutter-row" span={6}>
-                <div className="gutter-box">col-6</div>
-            </Col>
-        </Row>
-        <p>横向间距16,纵向间距24</p>
-        <hr/>
-        <Row gutter={[16, 24]}>
-            <Col className="gutter-row" span={6}>
-                <div className="gutter-box">col-6</div>
-            </Col>
-            <Col className="gutter-row" span={6}>
-                <div className="gutter-box">col-6</div>
-            </Col>
-            <Col className="gutter-row" span={6}>
-                <div className="gutter-box">col-6</div>
-            </Col>
-            <Col className="gutter-row" span={6}>
-                <div className="gutter-box">col-6</div>
-            </Col>
-            <Col className="gutter-row" span={6}>
-                <div className="gutter-box">col-6</div>
-            </Col>
-            <Col className="gutter-row" span={6}>
-                <div className="gutter-box">col-6</div>
-            </Col>
-            <Col className="gutter-row" span={6}>
-                <div className="gutter-box">col-6</div>
-            </Col>
-            <Col className="gutter-row" span={6}>
-                <div className="gutter-box">col-6</div>
-            </Col>
-        </Row>
-    </div>
-));
-
-stories.add('grid with offset', () => (
-    <div>
-        <Row>
-            <Col span={8}>col-8</Col>
-            <Col span={8} offset={8}>col-8</Col>
-        </Row>
-        <Row>
-            <Col span={6} offset={6}>col-6 col-offset-6</Col>
-            <Col span={6} offset={6}>col-6 col-offset-6</Col>
-        </Row>
-        <Row>
-            <Col span={12} offset={6}>col-12 col-offset-6</Col>
-        </Row>
-    </div>
-));
-stories.add('grid with pull & push', () => (
-    <div>
-        <Row>
-            <Col span={18} push={6}>col-18 col-push-6</Col>
-            <Col span={6} pull={18}>col-6 col-pull-18</Col>
-        </Row>
-    </div>
-));
-stories.add('grid with type flex', () => (
-    <div>
-        <p>sub-element align left</p>
-        <Row type="flex" justify="start">
-            <Col span={4}>col-4</Col>
-            <Col span={4}>col-4</Col>
-            <Col span={4}>col-4</Col>
-            <Col span={4}>col-4</Col>
-        </Row>
-
-        <p>sub-element align center</p>
-        <Row type="flex" justify="center">
-            <Col span={4}>col-4</Col>
-            <Col span={4}>col-4</Col>
-            <Col span={4}>col-4</Col>
-            <Col span={4}>col-4</Col>
-        </Row>
-
-        <p>sub-element align right</p>
-        <Row type="flex" justify="end">
-            <Col span={4}>col-4</Col>
-            <Col span={4}>col-4</Col>
-            <Col span={4}>col-4</Col>
-            <Col span={4}>col-4</Col>
-        </Row>
-
-        <p>sub-element monospaced arrangement</p>
-        <Row type="flex" justify="space-between">
-            <Col span={4}>col-4</Col>
-            <Col span={4}>col-4</Col>
-            <Col span={4}>col-4</Col>
-            <Col span={4}>col-4</Col>
-        </Row>
-
-        <p>sub-element align full</p>
-        <Row type="flex" justify="space-around">
-            <Col span={4}>col-4</Col>
-            <Col span={4}>col-4</Col>
-            <Col span={4}>col-4</Col>
-            <Col span={4}>col-4</Col>
-        </Row>
-    </div>
-));
+export default {
+  title: 'Grid'
+}
+
+export const GridDefault = () => (
+  <div>
+    <Row>
+      <Col span={24}>col-24</Col>
+    </Row>
+    <Row>
+      <Col span={12}>col-12</Col>
+      <Col span={12}>col-12</Col>
+    </Row>
+    <Row>
+      <Col span={8}>col-8</Col>
+      <Col span={8}>col-8</Col>
+      <Col span={8}>col-8</Col>
+    </Row>
+    <Row>
+      <Col span={6}>col-6</Col>
+      <Col span={6}>col-6</Col>
+      <Col span={6}>col-6</Col>
+      <Col span={6}>col-6</Col>
+    </Row>
+  </div>
+);
+
+
+export const GridWithGutter = () => (
+  <div className="gutter-example">
+    <p>横向间距16</p>
+    <hr />
+    <Row gutter={16}>
+      <Col className="gutter-row" span={6}>
+        <div className="gutter-box">col-6</div>
+      </Col>
+      <Col className="gutter-row" span={6}>
+        <div className="gutter-box">col-6</div>
+      </Col>
+      <Col className="gutter-row" span={6}>
+        <div className="gutter-box">col-6</div>
+      </Col>
+      <Col className="gutter-row" span={6}>
+        <div className="gutter-box">col-6</div>
+      </Col>
+    </Row>
+    <p>横向间距16,纵向间距48</p>
+    <hr />
+    <Row gutter={[16, 48]}>
+      <Col className="gutter-row" span={6}>
+        <div className="gutter-box">col-6</div>
+      </Col>
+      <Col className="gutter-row" span={6}>
+        <div className="gutter-box">col-6</div>
+      </Col>
+      <Col className="gutter-row" span={6}>
+        <div className="gutter-box">col-6</div>
+      </Col>
+      <Col className="gutter-row" span={6}>
+        <div className="gutter-box">col-6</div>
+      </Col>
+      <Col className="gutter-row" span={6}>
+        <div className="gutter-box">col-6</div>
+      </Col>
+      <Col className="gutter-row" span={6}>
+        <div className="gutter-box">col-6</div>
+      </Col>
+      <Col className="gutter-row" span={6}>
+        <div className="gutter-box">col-6</div>
+      </Col>
+      <Col className="gutter-row" span={6}>
+        <div className="gutter-box">col-6</div>
+      </Col>
+    </Row>
+    <p>横向间距16,纵向间距24</p>
+    <hr />
+    <Row gutter={[16, 24]}>
+      <Col className="gutter-row" span={6}>
+        <div className="gutter-box">col-6</div>
+      </Col>
+      <Col className="gutter-row" span={6}>
+        <div className="gutter-box">col-6</div>
+      </Col>
+      <Col className="gutter-row" span={6}>
+        <div className="gutter-box">col-6</div>
+      </Col>
+      <Col className="gutter-row" span={6}>
+        <div className="gutter-box">col-6</div>
+      </Col>
+      <Col className="gutter-row" span={6}>
+        <div className="gutter-box">col-6</div>
+      </Col>
+      <Col className="gutter-row" span={6}>
+        <div className="gutter-box">col-6</div>
+      </Col>
+      <Col className="gutter-row" span={6}>
+        <div className="gutter-box">col-6</div>
+      </Col>
+      <Col className="gutter-row" span={6}>
+        <div className="gutter-box">col-6</div>
+      </Col>
+    </Row>
+  </div>
+);
+
+export const GridWithOffset = () => (
+  <div>
+    <Row>
+      <Col span={8}>col-8</Col>
+      <Col span={8} offset={8}>
+        col-8
+      </Col>
+    </Row>
+    <Row>
+      <Col span={6} offset={6}>
+        col-6 col-offset-6
+      </Col>
+      <Col span={6} offset={6}>
+        col-6 col-offset-6
+      </Col>
+    </Row>
+    <Row>
+      <Col span={12} offset={6}>
+        col-12 col-offset-6
+      </Col>
+    </Row>
+  </div>
+);
+
+export const GridWithPullPush = () => (
+  <div>
+    <Row>
+      <Col span={18} push={6}>
+        col-18 col-push-6
+      </Col>
+      <Col span={6} pull={18}>
+        col-6 col-pull-18
+      </Col>
+    </Row>
+  </div>
+);
+
+export const GridWithTypeFlex = () => (
+  <div>
+    <p>sub-element align left</p>
+    <Row type="flex" justify="start">
+      <Col span={4}>col-4</Col>
+      <Col span={4}>col-4</Col>
+      <Col span={4}>col-4</Col>
+      <Col span={4}>col-4</Col>
+    </Row>
+
+    <p>sub-element align center</p>
+    <Row type="flex" justify="center">
+      <Col span={4}>col-4</Col>
+      <Col span={4}>col-4</Col>
+      <Col span={4}>col-4</Col>
+      <Col span={4}>col-4</Col>
+    </Row>
+
+    <p>sub-element align right</p>
+    <Row type="flex" justify="end">
+      <Col span={4}>col-4</Col>
+      <Col span={4}>col-4</Col>
+      <Col span={4}>col-4</Col>
+      <Col span={4}>col-4</Col>
+    </Row>
+
+    <p>sub-element monospaced arrangement</p>
+    <Row type="flex" justify="space-between">
+      <Col span={4}>col-4</Col>
+      <Col span={4}>col-4</Col>
+      <Col span={4}>col-4</Col>
+      <Col span={4}>col-4</Col>
+    </Row>
+
+    <p>sub-element align full</p>
+    <Row type="flex" justify="space-around">
+      <Col span={4}>col-4</Col>
+      <Col span={4}>col-4</Col>
+      <Col span={4}>col-4</Col>
+      <Col span={4}>col-4</Col>
+    </Row>
+  </div>
+);
+
 const DemoBox = props => <p className={`height-${props.value}`}>{props.children}</p>;
 
-stories.add('grid with flex 子元素垂直对齐', () => (
-    <div className="demo5">
-        <p>Align Top</p>
-        <Row type="flex" justify="center" align="top">
-            <Col span={4}><DemoBox value={100}>col-4</DemoBox></Col>
-            <Col span={4}><DemoBox value={50}>col-4</DemoBox></Col>
-            <Col span={4}><DemoBox value={120}>col-4</DemoBox></Col>
-            <Col span={4}><DemoBox value={80}>col-4</DemoBox></Col>
-        </Row>
-
-        <p>Align Center</p>
-        <Row type="flex" justify="space-around" align="middle">
-            <Col span={4}><DemoBox value={100}>col-4</DemoBox></Col>
-            <Col span={4}><DemoBox value={50}>col-4</DemoBox></Col>
-            <Col span={4}><DemoBox value={120}>col-4</DemoBox></Col>
-            <Col span={4}><DemoBox value={80}>col-4</DemoBox></Col>
-        </Row>
-
-        <p>Align Bottom</p>
-        <Row type="flex" justify="space-between" align="bottom">
-            <Col span={4}><DemoBox value={100}>col-4</DemoBox></Col>
-            <Col span={4}><DemoBox value={50}>col-4</DemoBox></Col>
-            <Col span={4}><DemoBox value={120}>col-4</DemoBox></Col>
-            <Col span={4}><DemoBox value={80}>col-4</DemoBox></Col>
-        </Row>
-    </div>
-));
-stories.add('grid with flex & order', () => (
-    <div>
-        <Row type="flex">
-            <Col span={6} order={4}>1 col-order-4</Col>
-            <Col span={6} order={3}>2 col-order-3</Col>
-            <Col span={6} order={2}>3 col-order-2</Col>
-            <Col span={6} order={1}>4 col-order-1</Col>
-        </Row>
-    </div>
-));
-stories.add('grid bootstrap 响应式', () => (
-    <div>
-        <Row>
-            <Col xs={2} sm={4} md={6} lg={8} xl={10}>Col</Col>
-            <Col xs={20} sm={16} md={12} lg={8} xl={4}>Col</Col>
-            <Col xs={2} sm={4} md={6} lg={8} xl={10}>Col</Col>
-        </Row>
-        <Row>
-            <Col xs={{ span: 5, offset: 1 }} lg={{ span: 6, offset: 2 }}>Col</Col>
-            <Col xs={{ span: 11, offset: 1 }} lg={{ span: 6, offset: 2 }}>Col</Col>
-            <Col xs={{ span: 5, offset: 1 }} lg={{ span: 6, offset: 2 }}>Col</Col>
-        </Row>
-    </div>
-));
+export const GridWithFlexChildVerticalAlign = () => (
+  <div className="demo5">
+    <p>Align Top</p>
+    <Row type="flex" justify="center" align="top">
+      <Col span={4}>
+        <DemoBox value={100}>col-4</DemoBox>
+      </Col>
+      <Col span={4}>
+        <DemoBox value={50}>col-4</DemoBox>
+      </Col>
+      <Col span={4}>
+        <DemoBox value={120}>col-4</DemoBox>
+      </Col>
+      <Col span={4}>
+        <DemoBox value={80}>col-4</DemoBox>
+      </Col>
+    </Row>
+
+    <p>Align Center</p>
+    <Row type="flex" justify="space-around" align="middle">
+      <Col span={4}>
+        <DemoBox value={100}>col-4</DemoBox>
+      </Col>
+      <Col span={4}>
+        <DemoBox value={50}>col-4</DemoBox>
+      </Col>
+      <Col span={4}>
+        <DemoBox value={120}>col-4</DemoBox>
+      </Col>
+      <Col span={4}>
+        <DemoBox value={80}>col-4</DemoBox>
+      </Col>
+    </Row>
+
+    <p>Align Bottom</p>
+    <Row type="flex" justify="space-between" align="bottom">
+      <Col span={4}>
+        <DemoBox value={100}>col-4</DemoBox>
+      </Col>
+      <Col span={4}>
+        <DemoBox value={50}>col-4</DemoBox>
+      </Col>
+      <Col span={4}>
+        <DemoBox value={120}>col-4</DemoBox>
+      </Col>
+      <Col span={4}>
+        <DemoBox value={80}>col-4</DemoBox>
+      </Col>
+    </Row>
+  </div>
+);
+
+export const GridWithFlexOrder = () => (
+  <div>
+    <Row type="flex">
+      <Col span={6} order={4}>
+        1 col-order-4
+      </Col>
+      <Col span={6} order={3}>
+        2 col-order-3
+      </Col>
+      <Col span={6} order={2}>
+        3 col-order-2
+      </Col>
+      <Col span={6} order={1}>
+        4 col-order-1
+      </Col>
+    </Row>
+  </div>
+);
+
+export const GridBootstrap = () => (
+  <div>
+    <Row>
+      <Col xs={2} sm={4} md={6} lg={8} xl={10}>
+        Col
+      </Col>
+      <Col xs={20} sm={16} md={12} lg={8} xl={4}>
+        Col
+      </Col>
+      <Col xs={2} sm={4} md={6} lg={8} xl={10}>
+        Col
+      </Col>
+    </Row>
+    <Row>
+      <Col xs={{ span: 5, offset: 1 }} lg={{ span: 6, offset: 2 }}>
+        Col
+      </Col>
+      <Col xs={{ span: 11, offset: 1 }} lg={{ span: 6, offset: 2 }}>
+        Col
+      </Col>
+      <Col xs={{ span: 5, offset: 1 }} lg={{ span: 6, offset: 2 }}>
+        Col
+      </Col>
+    </Row>
+  </div>
+);

+ 56 - 47
packages/semi-ui/icons/_story/icon.stories.js

@@ -1,54 +1,63 @@
 import React from 'react';
-import { storiesOf } from '@storybook/react'; // import { withKnobs, text, boolean } from '@storybook/addon-knobs';
 
 import Others from './Others';
-import { IconHome, IconLock, IconClear, IconTickCircle, IconTick, IconClose, IconCaretUp } from '@douyinfe/semi-icons';
-const stories = storiesOf('Icon', module); // stories.addDecorator(withKnobs);;
+import {
+  IconHome,
+  IconLock,
+  IconClear,
+  IconTickCircle,
+  IconTick,
+  IconClose,
+  IconCaretup,
+} from '@douyinfe/semi-icons';
 
-stories.add('Icon', () => (
+export default {
+  title: 'Icon'
+}
+
+export {
+  Others
+}
+
+export const IconDemo = () => (
+  <div>
     <div>
-        <div>
-            <IconHome size="large" />
-            <IconLock size="small" />
-            <IconLock />
-            <IconClear />
-            <IconTickCircle />
-            <IconTick />
-            <IconClose />
-            <IconCaretUp />
-        </div>
-        <div
-            style={{
-                color: 'red',
-            }}
-        >
-            <IconHome size="large" />
-            <IconLock size="small" />
-            <IconLock />
-            <IconClear />
-            <IconTickCircle />
-            <IconTick />
-            <IconClose />
-            <IconCaretUp />
-        </div>
-        <div
-            style={{
-                color: 'pink',
-            }}
-        >
-            <IconHome size="large" />
-            <IconLock size="small" />
-            <IconLock />
-            <IconClear />
-            <IconTickCircle />
-            <IconTick />
-            <IconClose />
-            <IconCaretUp />
-        </div>
+      <IconHome size="large" />
+      <IconLock size="small" />
+      <IconLock />
+      <IconClear />
+      <IconTickCircle />
+      <IconTick />
+      <IconClose />
+      <IconCaretup />
     </div>
-));
-stories.add('others', () => (
-    <div>
-        <Others />
+    <div
+      style={{
+        color: 'red',
+      }}
+    >
+      <IconHome size="large" />
+      <IconLock size="small" />
+      <IconLock />
+      <IconClear />
+      <IconTickCircle />
+      <IconTick />
+      <IconClose />
+      <IconCaretup />
+    </div>
+    <div
+      style={{
+        color: 'pink',
+      }}
+    >
+      <IconHome size="large" />
+      <IconLock size="small" />
+      <IconLock />
+      <IconClear />
+      <IconTickCircle />
+      <IconTick />
+      <IconClose />
+      <IconCaretup />
     </div>
-));
+  </div>
+);

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 677 - 507
packages/semi-ui/input/_story/input.stories.js


+ 625 - 539
packages/semi-ui/inputNumber/_story/inputNumber.stories.js

@@ -1,557 +1,643 @@
 import React, { useRef, useState } from 'react';
-import { storiesOf } from '@storybook/react';
 // import { withKnobs, text, boolean } from '@storybook/addon-knobs';
 import './inputNumber.scss';
 import InputNumber from '../index';
 import Button from '../../button/index';
 import { withField, Form } from '../../index';
 
-const stories = storiesOf('InputNumber', module);
-
-// stories.addDecorator(withKnobs);;
+export default {
+  title: 'InputNumber',
+}
 
 function log(v, e) {
-    const type = typeof v;
-    console.log(type, v);
+  const type = typeof v;
+  console.log(type, v);
 }
 
 const createOnChange = changeFn => {
-    return (...args) => {
-        log(...args);
-        if (typeof changeFn === 'function') {
-            changeFn(...args);
-        }
-    };
+  return (...args) => {
+    log(...args);
+    if (typeof changeFn === 'function') {
+      changeFn(...args);
+    }
+  };
 };
 
-stories.add('Input number', () => {
-    const Demo = () => {
-        const [controlledValue, setControlledValue] = useState(10.1);
-        const controlledOnChange = createOnChange(setControlledValue);
-
-        const [controlledValue2, setControlledValue2] = useState(9);
-        const controlledOnChange2 = createOnChange(setControlledValue2);
-
-        const [decimal, setDecimal] = useState(10.01);
-        const decimalOnChange = createOnChange(setDecimal);
-
-        const [formattedVal, setFormattedVal] = useState(10.02);
-        const formattedValOnChange = createOnChange(setFormattedVal);
-
-        const [formattedDecimal, setFormattedDecimal] = useState(10.03);
-        const formattedDecimalOnChange = createOnChange(setFormattedDecimal);
-
-        return (
-            <div className="inputNumber">
-                <label>简单数字输入框</label>
-                <InputNumber onChange={log} />
-                <br />
-
-                <label>限定上下界与整数步长</label>
-                <InputNumber max={10} min={0} step={1} />
-                <br />
-
-                <label>限定上下界与小数步长</label>
-                <InputNumber max={10} min={0} step={0.1} defaultValue={0.2} precision={2} />
-                <br />
-
-                <label>格式化</label>
-                <InputNumber
-                    defaultValue={1000}
-                    onChange={log}
-                    formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
-                    parser={value => value.replace(/\$\s?|(,*)/g, '')}
-                />
-                <br />
-
-                <label>小数</label>
-                <InputNumber defaultValue={10.08} precision={2} onChange={log} />
-                <br />
-
-                <label>格式化+小数</label>
-                <InputNumber
-                    defaultValue={1000}
-                    precision={2}
-                    onChange={log}
-                    formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
-                    parser={value => value.replace(/\$\s?|(,*)/g, '')}
-                />
-                <br />
-
-                <label>受控</label>
-                <InputNumber value={controlledValue} onChange={controlledOnChange} />
-                <br />
-
-                <label>受控+上下界</label>
-                <InputNumber min={1} max={10} value={controlledValue2} onChange={controlledOnChange2} />
-                <br />
-
-                <label>小数+受控</label>
-                <InputNumber value={decimal} precision={2} onChange={decimalOnChange} />
-                <br />
-
-                <label>格式化+受控</label>
-                <InputNumber
-                    defaultValue={1000}
-                    precision={0}
-                    formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
-                    parser={value => value.replace(/\$\s?|(,*)/g, '')}
-                    onChange={formattedValOnChange}
-                    value={formattedVal}
-                />
-                <br />
-
-                <label>格式化+小数+受控</label>
-                <InputNumber
-                    precision={2}
-                    formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
-                    parser={value => value.replace(/\$\s?|(,*)/g, '')}
-                    onChange={formattedDecimalOnChange}
-                    value={formattedDecimal}
-                />
-            </div>
-        );
-    };
+export const _InputNumber = () => {
+  const Demo = () => {
+    const [controlledValue, setControlledValue] = useState(10.1);
+    const controlledOnChange = createOnChange(setControlledValue);
+
+    const [controlledValue2, setControlledValue2] = useState(9);
+    const controlledOnChange2 = createOnChange(setControlledValue2);
+
+    const [decimal, setDecimal] = useState(10.01);
+    const decimalOnChange = createOnChange(setDecimal);
+
+    const [formattedVal, setFormattedVal] = useState(10.02);
+    const formattedValOnChange = createOnChange(setFormattedVal);
+
+    const [formattedDecimal, setFormattedDecimal] = useState(10.03);
+    const formattedDecimalOnChange = createOnChange(setFormattedDecimal);
+
+    return (
+      <div className="inputNumber">
+        <label>简单数字输入框</label>
+        <InputNumber onChange={log} />
+        <br />
+
+        <label>限定上下界与整数步长</label>
+        <InputNumber max={10} min={0} step={1} />
+        <br />
+
+        <label>限定上下界与小数步长</label>
+        <InputNumber max={10} min={0} step={0.1} defaultValue={0.2} precision={2} />
+        <br />
+
+        <label>格式化</label>
+        <InputNumber
+          defaultValue={1000}
+          onChange={log}
+          formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
+          parser={value => value.replace(/\$\s?|(,*)/g, '')}
+        />
+        <br />
+
+        <label>小数</label>
+        <InputNumber defaultValue={10.08} precision={2} onChange={log} />
+        <br />
+
+        <label>格式化+小数</label>
+        <InputNumber
+          defaultValue={1000}
+          precision={2}
+          onChange={log}
+          formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
+          parser={value => value.replace(/\$\s?|(,*)/g, '')}
+        />
+        <br />
+
+        <label>受控</label>
+        <InputNumber value={controlledValue} onChange={controlledOnChange} />
+        <br />
+
+        <label>受控+上下界</label>
+        <InputNumber min={1} max={10} value={controlledValue2} onChange={controlledOnChange2} />
+        <br />
+
+        <label>小数+受控</label>
+        <InputNumber value={decimal} precision={2} onChange={decimalOnChange} />
+        <br />
+
+        <label>格式化+受控</label>
+        <InputNumber
+          defaultValue={1000}
+          precision={0}
+          formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
+          parser={value => value.replace(/\$\s?|(,*)/g, '')}
+          onChange={formattedValOnChange}
+          value={formattedVal}
+        />
+        <br />
+
+        <label>格式化+小数+受控</label>
+        <InputNumber
+          precision={2}
+          formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
+          parser={value => value.replace(/\$\s?|(,*)/g, '')}
+          onChange={formattedDecimalOnChange}
+          value={formattedDecimal}
+        />
+      </div>
+    );
+  };
+
+  return <Demo />;
+};
 
-    return <Demo />;
-});
-
-stories.add('inputnumber use ref call focus', () => {
-    const Demo = () => {
-        const ref = useRef();
-        const focus = () => {
-            ref.current && ref.current.focus();
-        };
-        const blur = () => ref.current && ref.current.blur();
-
-        return (
-            <>
-                <InputNumber ref={ref} />
-                <Button onClick={focus}>focus</Button>
-                <Button onClick={blur}>blur</Button>
-            </>
-        );
-    };
-    return <Demo />;
-});
-
-stories.add('uncontrolled InputNumber', () => {
-    const Demo = function Demo(props = {}) {
-        return (
-            <div style={{ width: 450, padding: 20 }}>
-                <h5>defaultValue</h5>
-                <InputNumber defaultValue={1020} onChange={log} />
-                <br />
-
-                <h5>defaultValue + formatter + parser</h5>
-                <InputNumber
-                    defaultValue={1020}
-                    onChange={log}
-                    formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
-                    parser={value => value.replace(/\$\s?|(,*)/g, '')}
-                />
-                <br />
-
-                <h5>defaultValue + precision + formatter + parser</h5>
-                <InputNumber
-                    defaultValue={1020}
-                    precision={2}
-                    onChange={log}
-                    formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
-                    parser={value => value.replace(/\$\s?|(,*)/g, '')}
-                />
-                <br />
-
-                <h5>defaultValue + precision + max + min + formatter + parser</h5>
-                <InputNumber
-                    defaultValue={1020}
-                    precision={2}
-                    onChange={log}
-                    max={1000}
-                    min={500}
-                    formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
-                    parser={value => value.replace(/\$\s?|(,*)/g, '')}
-                />
-                <br />
-            </div>
-        );
-    };
+_InputNumber.story = {
+  name: 'Input number',
+};
 
-    return <Demo />;
-});
-
-stories.add('controlled InputNumber', () => {
-    const ControlledDemo = function ControlledDemo(props = {}) {
-        const [value, setValue] = useState(0);
-        const _setValue = createOnChange(setValue);
-
-        const [value1, setValue1] = useState(0.234);
-        const _setValue1 = createOnChange(setValue1);
-
-        const [value2, setValue2] = useState(1000);
-        const _setValue2 = createOnChange(setValue2);
-
-        const [value3, setValue3] = useState(0.21);
-        const _setValue3 = createOnChange(setValue3);
-
-        const [value4, setValue4] = useState(3);
-        const randomSetValue4 = createOnChange(v => {
-            setValue4(Math.random() * 3 + 1);
-        });
-
-        const [value5, setValue5] = useState(5);
-        const randomSetValue5 = createOnChange(v => {
-            setValue5(Math.random() * 5 + 1);
-        });
-
-        const [value6, setValue6] = useState(6);
-        const randomSetValue6 = createOnChange(v => {
-            const num = Math.random() * 10 + 9;
-            console.log('random set: ', num);
-            setValue6(num);
-        });
-        const _setValue6 = createOnChange(setValue6);
-
-        return (
-            <div style={{ width: 450, padding: 20 }}>
-                <h5>defaultValue</h5>
-                <InputNumber defaultValue={1020} onChange={log} />
-                <br />
-                <h5>value</h5>
-                <InputNumber value={1000} onChange={log} />
-                <br />
-                <h5>value + onChange</h5>
-                <InputNumber value={value} onChange={_setValue} onBlur={() => console.log('blur')} />
-                <br />
-                <h5>value + precision + onChange</h5>
-                <InputNumber value={value1} onChange={_setValue1} precision={2} />
-                <br />
-                <h5>value + step + precision + onChange</h5>
-                <InputNumber step={0.2} value={value3} onChange={_setValue3} precision={2} />
-                <br />
-
-                <h5>value + precision + onChange + formatter + parser</h5>
-                <Button onClick={() => setValue2(undefined)}>Empty</Button>
-                <InputNumber
-                    value={value2}
-                    precision={2}
-                    onChange={_setValue2}
-                    formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
-                    parser={value => value.replace(/\$\s?|(,*)/g, '')}
-                />
-                <br />
-
-                <h5>random set value + precision</h5>
-                <Button onClick={randomSetValue4}>Random Set Value</Button>
-                <InputNumber value={value4} precision={2} onChange={log} />
-                <br />
-
-                <h5>random set value + precision + formatter + parser</h5>
-                <Button onClick={randomSetValue5}>Random Set Value</Button>
-                <Button onClick={() => setValue5(undefined)}>Empty</Button>
-                <InputNumber
-                    value={value5}
-                    precision={2}
-                    onChange={log}
-                    formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
-                    parser={value => value.replace(/\$\s?|(,*)/g, '')}
-                />
-                <br />
-
-                <h5>random set value + max + min + precision + onChange</h5>
-                <Button onClick={randomSetValue6}>Random Set Value</Button>
-                <Button onClick={() => setValue6(undefined)}>Empty</Button>
-                <InputNumber max={18} min={-8} value={value6} precision={2} onChange={_setValue6} />
-                <br />
-            </div>
-        );
+export const InputnumberUseRefCallFocus = () => {
+  const Demo = () => {
+    const ref = useRef();
+    const focus = () => {
+      ref.current && ref.current.focus();
     };
+    const blur = () => ref.current && ref.current.blur();
+
+    return (
+      <>
+        <InputNumber ref={ref} />
+        <Button onClick={focus}>focus</Button>
+        <Button onClick={blur}>blur</Button>
+      </>
+    );
+  };
+  return <Demo />;
+};
 
-    return <ControlledDemo />;
-});
-
-stories.add('innnerButtons', () => {
-    const Demo = () => {
-        return (
-            <div style={{ width: 450 }}>
-                <label>innerButtons=false</label>
-                <div>
-                    <InputNumber innerButtons={false} />
-                </div>
-                <br />
-                <label>innerButtons=true</label>
-                <div>
-                    <InputNumber innerButtons={true} suffix={'小时'} min={0} />
-                </div>
-            </div>
-        );
-    };
-    return <Demo />;
-});
-
-stories.add('shiftStep', () => {
-    const Demo = () => {
-        return (
-            <div style={{ width: 450 }}>
-                <label>shiftStep=100,可长按</label>
-                <div>
-                    <InputNumber shiftStep={100} />
-                </div>
-            </div>
-        );
-    };
-    return <Demo />;
-});
-
-stories.add('onChange无限触发问题', () => {
-    const Demo = () => {
-        const [disabled, setDisabled] = useState(true);
-        const [disabled2, setDisabled2] = useState(false);
-        const [val, setVal] = useState(2);
-
-        return (
-            <>
-                <h3>数值没有持续变化说明正常,v1.10.0修复</h3><br/><br/>
-                <div>点击2后点击输入框,然后点击按钮会触发</div>
-                {
-                    disabled ? (
-                    <div onClick={() => { setDisabled(false); }}>
-                        {val}
-                    </div>) :
-                    <InputNumber style={{width: 120}} val={val} innerButtons onChange={res => setVal(res)} />
-                }
-                <br/><br/>
-                <div>点击按钮后切换 disabled 状态</div>
-                <div>disablde: {String(disabled2)}</div>
-                <div>
-                    <InputNumber 
-                        defaultValue={12} 
-                        innerButtons 
-                        disabled={disabled2} 
-                        onChange={() => setDisabled2(true)} 
-                    />
-                </div>
-            </>
-        );
-    };
-    return <Demo />;
-});
-
-stories.add('clear icon 位置', () => {
-    const Demo = () => {
-        return (
-            <InputNumber 
-                autoFocus
-                defaultValue={12} 
-                innerButtons
-                showClear
-            />
-        );
-    };
-    return <Demo />;
-});
-
-stories.add('uncontrolled keepFocus', () => {
-    const Demo = () => {
-        const [val, setVal] = useState(2);
-        const [val2, setVal2] = useState(2);
-
-        return (
-            <div style={{ width: 450, padding: 20 }}>
-                <h5>defaultValue</h5>
-                <InputNumber defaultValue={1020} onChange={log} keepFocus={true} />
-                <br />
-                <h5>defaultValue + formatter + parser</h5>
-                <InputNumber
-                    keepFocus={true}
-                    defaultValue={1020}
-                    onChange={log}
-                    formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
-                    parser={value => value.replace(/\$\s?|(,*)/g, '')}
-                />
-                <br />
-                <h5>defaultValue + precision + formatter + parser</h5>
-                <InputNumber
-                    keepFocus={true}
-                    defaultValue={1020}
-                    precision={2}
-                    onChange={log}
-                    formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
-                    parser={value => value.replace(/\$\s?|(,*)/g, '')}
-                />
-                <br />
-                <h5>defaultValue + precision + max + min + formatter + parser</h5>
-                <InputNumber
-                    keepFocus={true}
-                    defaultValue={1020}
-                    precision={2}
-                    onChange={log}
-                    max={1000}
-                    min={500}
-                    formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
-                    parser={value => value.replace(/\$\s?|(,*)/g, '')}
-                />
-                <br />
-            </div>
-        );
-    };
-    return <Demo />;
-});
-
-stories.add('controlled keepFocus', () => {
-    const Demo = () => {
-        const [value, setValue] = useState(0);
-        const _setValue = createOnChange(setValue);
-
-        const [value1, setValue1] = useState(0.234);
-        const _setValue1 = createOnChange(setValue1);
-
-        const [value2, setValue2] = useState(1000);
-        const _setValue2 = createOnChange(setValue2);
-
-        const [value3, setValue3] = useState(0.21);
-        const _setValue3 = createOnChange(setValue3);
-
-        const [value4, setValue4] = useState(3);
-        const randomSetValue4 = createOnChange(v => {
-            setValue4(Math.random() * 3 + 1);
-        });
-
-        const [value5, setValue5] = useState(5);
-        const randomSetValue5 = createOnChange(v => {
-            setValue5(Math.random() * 5 + 1);
-        });
-
-        const [value6, setValue6] = useState(6);
-        const randomSetValue6 = createOnChange(v => {
-            const num = Math.random() * 10 + 9;
-            console.log('random set: ', num);
-            setValue6(num);
-        });
-        const _setValue6 = createOnChange(setValue6);
-
-        return (
-            <div style={{ width: 450, padding: 20 }}>
-                <h5>defaultValue</h5>
-                <InputNumber keepFocus={true} defaultValue={1020} onChange={log} />
-                <br />
-                <h5>value</h5>
-                <InputNumber keepFocus={true} value={1000} onChange={log} />
-                <br />
-                <h5>value + onChange</h5>
-                <InputNumber keepFocus={true} value={value} onChange={_setValue} onBlur={() => console.log('blur')} />
-                <br />
-                <h5>value + precision + onChange</h5>
-                <InputNumber keepFocus={true} value={value1} onChange={_setValue1} precision={2} />
-                <br />
-                <h5>value + step + precision + onChange</h5>
-                <InputNumber keepFocus={true} step={0.2} value={value3} onChange={_setValue3} precision={2} />
-                <br />
-
-                <h5>value + precision + onChange + formatter + parser</h5>
-                <Button onClick={() => setValue2(undefined)}>Empty</Button>
-                <InputNumber
-                    keepFocus={true}
-                    value={value2}
-                    precision={2}
-                    onChange={_setValue2}
-                    formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
-                    parser={value => value.replace(/\$\s?|(,*)/g, '')}
-                />
-                <br />
-
-                <h5>random set value + precision</h5>
-                <Button onClick={randomSetValue4}>Random Set Value</Button>
-                <InputNumber keepFocus={true} value={value4} precision={2} onChange={log} />
-                <br />
-
-                <h5>random set value + precision + formatter + parser</h5>
-                <Button onClick={randomSetValue5}>Random Set Value</Button>
-                <Button onClick={() => setValue5(undefined)}>Empty</Button>
-                <InputNumber
-                    keepFocus={true}
-                    value={value5}
-                    precision={2}
-                    onChange={log}
-                    formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
-                    parser={value => value.replace(/\$\s?|(,*)/g, '')}
-                />
-                <br />
-
-                <h5>random set value + max + min + precision + onChange</h5>
-                <Button onClick={randomSetValue6}>Random Set Value</Button>
-                <Button onClick={() => setValue6(undefined)}>Empty</Button>
-                <InputNumber keepFocus={true} max={18} min={-8} value={value6} precision={2} onChange={_setValue6} />
-                <br />
-            </div>
-        )
-    };
-    return <Demo />;
-});
-
-stories.add('disabled style', () => {
-    const Demo = () => {
-        return (
-            <>
-                <label>prop disabled</label>
-                <InputNumber disabled /><br /><br />
-                <label>max limit</label>
-                <InputNumber min={1} max={10} defaultValue={10} /><br /><br />
-                <label>min limit</label>
-                <InputNumber min={1} max={10} defaultValue={1} /><br /><br />
-            </>
-        );
-    }
-});
-
-stories.add('Form.CustomInput', () => {
-    const Demo = () => {
-        const CustomInput = withField(InputNumber, { onKeyChangeFnName: 'onNumberChange' });
-
-        return (
-            <>
-                <h4>not controlled + without formatter</h4>
-                <InputNumber 
-                    onChange={(...args) => console.log('inputNumber change', ...args)}
-                    onNumberChange={(...args) => console.log('inputNumber number change', ...args)}
-                />
-                <h4>not controlled + formatter(onChange会包括英文字符,onNumberChange不包括)</h4>
-                <InputNumber 
-                    formatter={value => `${value}`.replace(/\D/g, '')}
-                    onChange={(...args) => console.log('inputNumber change', ...args)}
-                    onNumberChange={(...args) => console.log('inputNumber number change', ...args)}
-                />
-                <Form onValueChange={(v)=>console.log(v)}>
-                    <h4>Form + Form.InputNumber + formatter + onChange(onChange包括英文字符,显示没有英文字符)</h4>
-                    <Form.InputNumber 
-                        field='formOriginalInputNumber' 
-                        noLabel
-                        formatter={value => `${value}`.replace(/\D/g, '')}
-                        onChange={(...args) => console.log('form inputNumber change', ...args)}
-                    />
-                    <h4>Form + withField InputNumber + formatter + onNumberChange(onNumberChange不包括英文字符,显示也不包括英文字符)</h4>
-                    <CustomInput
-                        field='formCustomInputNumber' 
-                        noLabel
-                        formatter={value => `${value}`.replace(/\D/g, '')}
-                    />
-                </Form>
-                <h4>type=number (TODO:需要关注内置的按钮+不同浏览器对type=number的支持情况,比如 safari 貌似就不支持)</h4>
-                <InputNumber
-                    type="number"
-                    onChange={(...args) => console.log('inputNumber change', ...args)}
-                    onNumberChange={(...args) => console.log('inputNumber number change', ...args)}
-                />
-                <h4>测试 formatter + parser 是否正常</h4>
-                <InputNumber
-                    onChange={(v) => console.log(`Changed to: [${typeof v}] ${v}`)}
-                    defaultValue={1000}
-                    min={0}
-                    formatter={value => `¥ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
-                    parser={value => value.replace(/\¥\s?|(,*)/g, '')}
-                />
-            </>
-        );
-    };
-    return <Demo />;
-});
+InputnumberUseRefCallFocus.story = {
+  name: 'inputnumber use ref call focus',
+};
+
+export const UncontrolledInputNumber = () => {
+  const Demo = function Demo(props = {}) {
+    return (
+      <div style={{ width: 450, padding: 20 }}>
+        <h5>defaultValue</h5>
+        <InputNumber defaultValue={1020} onChange={log} />
+        <br />
+
+        <h5>defaultValue + formatter + parser</h5>
+        <InputNumber
+          defaultValue={1020}
+          onChange={log}
+          formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
+          parser={value => value.replace(/\$\s?|(,*)/g, '')}
+        />
+        <br />
+
+        <h5>defaultValue + precision + formatter + parser</h5>
+        <InputNumber
+          defaultValue={1020}
+          precision={2}
+          onChange={log}
+          formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
+          parser={value => value.replace(/\$\s?|(,*)/g, '')}
+        />
+        <br />
+
+        <h5>defaultValue + precision + max + min + formatter + parser</h5>
+        <InputNumber
+          defaultValue={1020}
+          precision={2}
+          onChange={log}
+          max={1000}
+          min={500}
+          formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
+          parser={value => value.replace(/\$\s?|(,*)/g, '')}
+        />
+        <br />
+      </div>
+    );
+  };
+
+  return <Demo />;
+};
+
+UncontrolledInputNumber.story = {
+  name: 'uncontrolled InputNumber',
+};
+
+export const ControlledInputNumber = () => {
+  const ControlledDemo = function ControlledDemo(props = {}) {
+    const [value, setValue] = useState(0);
+    const _setValue = createOnChange(setValue);
+
+    const [value1, setValue1] = useState(0.234);
+    const _setValue1 = createOnChange(setValue1);
+
+    const [value2, setValue2] = useState(1000);
+    const _setValue2 = createOnChange(setValue2);
+
+    const [value3, setValue3] = useState(0.21);
+    const _setValue3 = createOnChange(setValue3);
+
+    const [value4, setValue4] = useState(3);
+    const randomSetValue4 = createOnChange(v => {
+      setValue4(Math.random() * 3 + 1);
+    });
+
+    const [value5, setValue5] = useState(5);
+    const randomSetValue5 = createOnChange(v => {
+      setValue5(Math.random() * 5 + 1);
+    });
+
+    const [value6, setValue6] = useState(6);
+    const randomSetValue6 = createOnChange(v => {
+      const num = Math.random() * 10 + 9;
+      console.log('random set: ', num);
+      setValue6(num);
+    });
+    const _setValue6 = createOnChange(setValue6);
+
+    return (
+      <div style={{ width: 450, padding: 20 }}>
+        <h5>defaultValue</h5>
+        <InputNumber defaultValue={1020} onChange={log} />
+        <br />
+        <h5>value</h5>
+        <InputNumber value={1000} onChange={log} />
+        <br />
+        <h5>value + onChange</h5>
+        <InputNumber value={value} onChange={_setValue} onBlur={() => console.log('blur')} />
+        <br />
+        <h5>value + precision + onChange</h5>
+        <InputNumber value={value1} onChange={_setValue1} precision={2} />
+        <br />
+        <h5>value + step + precision + onChange</h5>
+        <InputNumber step={0.2} value={value3} onChange={_setValue3} precision={2} />
+        <br />
+
+        <h5>value + precision + onChange + formatter + parser</h5>
+        <Button onClick={() => setValue2(undefined)}>Empty</Button>
+        <InputNumber
+          value={value2}
+          precision={2}
+          onChange={_setValue2}
+          formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
+          parser={value => value.replace(/\$\s?|(,*)/g, '')}
+        />
+        <br />
+
+        <h5>random set value + precision</h5>
+        <Button onClick={randomSetValue4}>Random Set Value</Button>
+        <InputNumber value={value4} precision={2} onChange={log} />
+        <br />
+
+        <h5>random set value + precision + formatter + parser</h5>
+        <Button onClick={randomSetValue5}>Random Set Value</Button>
+        <Button onClick={() => setValue5(undefined)}>Empty</Button>
+        <InputNumber
+          value={value5}
+          precision={2}
+          onChange={log}
+          formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
+          parser={value => value.replace(/\$\s?|(,*)/g, '')}
+        />
+        <br />
+
+        <h5>random set value + max + min + precision + onChange</h5>
+        <Button onClick={randomSetValue6}>Random Set Value</Button>
+        <Button onClick={() => setValue6(undefined)}>Empty</Button>
+        <InputNumber max={18} min={-8} value={value6} precision={2} onChange={_setValue6} />
+        <br />
+      </div>
+    );
+  };
+
+  return <ControlledDemo />;
+};
+
+ControlledInputNumber.story = {
+  name: 'controlled InputNumber',
+};
+
+export const InnnerButtons = () => {
+  const Demo = () => {
+    return (
+      <div style={{ width: 450 }}>
+        <label>innerButtons=false</label>
+        <div>
+          <InputNumber innerButtons={false} />
+        </div>
+        <br />
+        <label>innerButtons=true</label>
+        <div>
+          <InputNumber innerButtons={true} suffix={'小时'} min={0} />
+        </div>
+      </div>
+    );
+  };
+  return <Demo />;
+};
+
+InnnerButtons.story = {
+  name: 'innnerButtons',
+};
+
+export const ShiftStep = () => {
+  const Demo = () => {
+    return (
+      <div style={{ width: 450 }}>
+        <label>shiftStep=100,可长按</label>
+        <div>
+          <InputNumber shiftStep={100} />
+        </div>
+      </div>
+    );
+  };
+  return <Demo />;
+};
+
+ShiftStep.story = {
+  name: 'shiftStep',
+};
+
+export const OnChangeLimit = () => {
+  const Demo = () => {
+    const [disabled, setDisabled] = useState(true);
+    const [disabled2, setDisabled2] = useState(false);
+    const [val, setVal] = useState(2);
+
+    return (
+      <>
+        <h3>数值没有持续变化说明正常,v1.10.0修复</h3>
+        <br />
+        <br />
+        <div>点击2后点击输入框,然后点击按钮会触发</div>
+        {disabled ? (
+          <div
+            onClick={() => {
+              setDisabled(false);
+            }}
+          >
+            {val}
+          </div>
+        ) : (
+          <InputNumber
+            style={{ width: 120 }}
+            val={val}
+            innerButtons
+            onChange={res => setVal(res)}
+          />
+        )}
+        <br />
+        <br />
+        <div>点击按钮后切换 disabled 状态</div>
+        <div>disablde: {String(disabled2)}</div>
+        <div>
+          <InputNumber
+            defaultValue={12}
+            innerButtons
+            disabled={disabled2}
+            onChange={() => setDisabled2(true)}
+          />
+        </div>
+      </>
+    );
+  };
+  return <Demo />;
+};
+
+OnChangeLimit.story = {
+  name: 'onChange无限触发问题',
+};
+
+export const ClearIconPosition = () => {
+  const Demo = () => {
+    return <InputNumber autoFocus defaultValue={12} innerButtons showClear />;
+  };
+  return <Demo />;
+};
+
+ClearIconPosition.story = {
+  name: 'clear icon 位置',
+};
+
+export const UncontrolledKeepFocus = () => {
+  const Demo = () => {
+    const [val, setVal] = useState(2);
+    const [val2, setVal2] = useState(2);
+
+    return (
+      <div style={{ width: 450, padding: 20 }}>
+        <h5>defaultValue</h5>
+        <InputNumber defaultValue={1020} onChange={log} keepFocus={true} />
+        <br />
+        <h5>defaultValue + formatter + parser</h5>
+        <InputNumber
+          keepFocus={true}
+          defaultValue={1020}
+          onChange={log}
+          formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
+          parser={value => value.replace(/\$\s?|(,*)/g, '')}
+        />
+        <br />
+        <h5>defaultValue + precision + formatter + parser</h5>
+        <InputNumber
+          keepFocus={true}
+          defaultValue={1020}
+          precision={2}
+          onChange={log}
+          formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
+          parser={value => value.replace(/\$\s?|(,*)/g, '')}
+        />
+        <br />
+        <h5>defaultValue + precision + max + min + formatter + parser</h5>
+        <InputNumber
+          keepFocus={true}
+          defaultValue={1020}
+          precision={2}
+          onChange={log}
+          max={1000}
+          min={500}
+          formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
+          parser={value => value.replace(/\$\s?|(,*)/g, '')}
+        />
+        <br />
+      </div>
+    );
+  };
+  return <Demo />;
+};
+
+UncontrolledKeepFocus.story = {
+  name: 'uncontrolled keepFocus',
+};
+
+export const ControlledKeepFocus = () => {
+  const Demo = () => {
+    const [value, setValue] = useState(0);
+    const _setValue = createOnChange(setValue);
+
+    const [value1, setValue1] = useState(0.234);
+    const _setValue1 = createOnChange(setValue1);
+
+    const [value2, setValue2] = useState(1000);
+    const _setValue2 = createOnChange(setValue2);
+
+    const [value3, setValue3] = useState(0.21);
+    const _setValue3 = createOnChange(setValue3);
+
+    const [value4, setValue4] = useState(3);
+    const randomSetValue4 = createOnChange(v => {
+      setValue4(Math.random() * 3 + 1);
+    });
+
+    const [value5, setValue5] = useState(5);
+    const randomSetValue5 = createOnChange(v => {
+      setValue5(Math.random() * 5 + 1);
+    });
+
+    const [value6, setValue6] = useState(6);
+    const randomSetValue6 = createOnChange(v => {
+      const num = Math.random() * 10 + 9;
+      console.log('random set: ', num);
+      setValue6(num);
+    });
+    const _setValue6 = createOnChange(setValue6);
+
+    return (
+      <div style={{ width: 450, padding: 20 }}>
+        <h5>defaultValue</h5>
+        <InputNumber keepFocus={true} defaultValue={1020} onChange={log} />
+        <br />
+        <h5>value</h5>
+        <InputNumber keepFocus={true} value={1000} onChange={log} />
+        <br />
+        <h5>value + onChange</h5>
+        <InputNumber
+          keepFocus={true}
+          value={value}
+          onChange={_setValue}
+          onBlur={() => console.log('blur')}
+        />
+        <br />
+        <h5>value + precision + onChange</h5>
+        <InputNumber keepFocus={true} value={value1} onChange={_setValue1} precision={2} />
+        <br />
+        <h5>value + step + precision + onChange</h5>
+        <InputNumber
+          keepFocus={true}
+          step={0.2}
+          value={value3}
+          onChange={_setValue3}
+          precision={2}
+        />
+        <br />
+
+        <h5>value + precision + onChange + formatter + parser</h5>
+        <Button onClick={() => setValue2(undefined)}>Empty</Button>
+        <InputNumber
+          keepFocus={true}
+          value={value2}
+          precision={2}
+          onChange={_setValue2}
+          formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
+          parser={value => value.replace(/\$\s?|(,*)/g, '')}
+        />
+        <br />
+
+        <h5>random set value + precision</h5>
+        <Button onClick={randomSetValue4}>Random Set Value</Button>
+        <InputNumber keepFocus={true} value={value4} precision={2} onChange={log} />
+        <br />
+
+        <h5>random set value + precision + formatter + parser</h5>
+        <Button onClick={randomSetValue5}>Random Set Value</Button>
+        <Button onClick={() => setValue5(undefined)}>Empty</Button>
+        <InputNumber
+          keepFocus={true}
+          value={value5}
+          precision={2}
+          onChange={log}
+          formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
+          parser={value => value.replace(/\$\s?|(,*)/g, '')}
+        />
+        <br />
+
+        <h5>random set value + max + min + precision + onChange</h5>
+        <Button onClick={randomSetValue6}>Random Set Value</Button>
+        <Button onClick={() => setValue6(undefined)}>Empty</Button>
+        <InputNumber
+          keepFocus={true}
+          max={18}
+          min={-8}
+          value={value6}
+          precision={2}
+          onChange={_setValue6}
+        />
+        <br />
+      </div>
+    );
+  };
+  return <Demo />;
+};
+
+ControlledKeepFocus.story = {
+  name: 'controlled keepFocus',
+};
+
+export const DisabledStyle = () => {
+  const Demo = () => {
+    return (
+      <>
+        <label>prop disabled</label>
+        <InputNumber disabled />
+        <br />
+        <br />
+        <label>max limit</label>
+        <InputNumber min={1} max={10} defaultValue={10} />
+        <br />
+        <br />
+        <label>min limit</label>
+        <InputNumber min={1} max={10} defaultValue={1} />
+        <br />
+        <br />
+      </>
+    );
+  };
+
+  return <Demo />;
+};
+
+DisabledStyle.story = {
+  name: 'disabled style',
+};
+
+export const FormCustomInput = () => {
+  const Demo = () => {
+    const CustomInput = withField(InputNumber, { onKeyChangeFnName: 'onNumberChange' });
+
+    return (
+      <>
+        <h4>not controlled + without formatter</h4>
+        <InputNumber
+          onChange={(...args) => console.log('inputNumber change', ...args)}
+          onNumberChange={(...args) => console.log('inputNumber number change', ...args)}
+        />
+        <h4>not controlled + formatter(onChange会包括英文字符,onNumberChange不包括)</h4>
+        <InputNumber
+          formatter={value => `${value}`.replace(/\D/g, '')}
+          onChange={(...args) => console.log('inputNumber change', ...args)}
+          onNumberChange={(...args) => console.log('inputNumber number change', ...args)}
+        />
+        <Form onValueChange={v => console.log(v)}>
+          <h4>
+            Form + Form.InputNumber + formatter + onChange(onChange包括英文字符,显示没有英文字符)
+          </h4>
+          <Form.InputNumber
+            field="formOriginalInputNumber"
+            noLabel
+            formatter={value => `${value}`.replace(/\D/g, '')}
+            onChange={(...args) => console.log('form inputNumber change', ...args)}
+          />
+          <h4>
+            Form + withField InputNumber + formatter +
+            onNumberChange(onNumberChange不包括英文字符,显示也不包括英文字符)
+          </h4>
+          <CustomInput
+            field="formCustomInputNumber"
+            noLabel
+            formatter={value => `${value}`.replace(/\D/g, '')}
+          />
+        </Form>
+        <h4>
+          type=number (TODO:需要关注内置的按钮+不同浏览器对type=number的支持情况,比如 safari
+          貌似就不支持)
+        </h4>
+        <InputNumber
+          type="number"
+          onChange={(...args) => console.log('inputNumber change', ...args)}
+          onNumberChange={(...args) => console.log('inputNumber number change', ...args)}
+        />
+        <h4>测试 formatter + parser 是否正常</h4>
+        <InputNumber
+          onChange={v => console.log(`Changed to: [${typeof v}] ${v}`)}
+          defaultValue={1000}
+          min={0}
+          formatter={value => `¥ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
+          parser={value => value.replace(/\¥\s?|(,*)/g, '')}
+        />
+      </>
+    );
+  };
+  return <Demo />;
+};
+
+FormCustomInput.story = {
+  name: 'Form.CustomInput',
+};

+ 265 - 239
packages/semi-ui/layout/_story/layout.stories.js

@@ -1,279 +1,305 @@
 import React from 'react';
-import { storiesOf } from '@storybook/react'; // import { withKnobs, text, boolean } from '@storybook/addon-knobs';
 
 import { Layout } from '../index';
 import Nav from '../../navigation';
 import { Button } from '../../index';
-import { IconBytedanceLogo, IconVigoLogo, IconDescend, IconList, IconEdit, IconCamera, IconFile, IconGlobe } from '@douyinfe/semi-icons';
-const stories = storiesOf('Layout', module); // stories.addDecorator(withKnobs);;
+import {
+  IconBytedanceLogo,
+  IconVigoLogo,
+  IconDescend,
+  IconList,
+  IconEdit,
+  IconCamera,
+  IconFile,
+  IconGlobe,
+} from '@douyinfe/semi-icons';
+
+export default {
+  title: 'Layout'
+}
 
 const { Header, Footer, Sider, Content } = Layout;
 const style = {
-    textAlign: 'center',
-    margin: 60,
+  textAlign: 'center',
+  margin: 60,
 };
 const contentStyle = {
-    height: 300,
-    backgroundColor: '#ddd',
+  height: 300,
+  backgroundColor: '#ddd',
 };
 const siderStyle = {
-    width: 100,
-    backgroundColor: '#ccc',
+  width: 100,
+  backgroundColor: '#ccc',
 };
 const headerStyle = {
-    height: 64,
-    paddingLeft: 50,
-    paddingRight: 50,
-    color: '#333',
-    background: '#f0f2f5',
+  height: 64,
+  paddingLeft: 50,
+  paddingRight: 50,
+  color: '#333',
+  background: '#f0f2f5',
 };
 const footerStyle = {
-    height: 64,
-    paddingLeft: 50,
-    paddingRight: 50,
-    color: '#333',
-    background: '#f0f2f5',
+  height: 64,
+  paddingLeft: 50,
+  paddingRight: 50,
+  color: '#333',
+  background: '#f0f2f5',
 };
-stories.add('Layout default', () => (
-    <div>
-        <Layout style={style}>
-            <Header style={headerStyle}>Header</Header>
-            <Content style={contentStyle}>Content</Content>
-            <Footer style={footerStyle}>Footer</Footer>
-        </Layout>
 
-        <Layout style={style}>
-            <Header style={headerStyle}>Header</Header>
-            <Layout>
-                <Sider style={siderStyle}>Sider</Sider>
-                <Content style={contentStyle}>Content</Content>
-            </Layout>
-            <Footer style={footerStyle}>Footer</Footer>
-        </Layout>
+export const LayoutDefault = () => (
+  <div>
+    <Layout style={style}>
+      <Header style={headerStyle}>Header</Header>
+      <Content style={contentStyle}>Content</Content>
+      <Footer style={footerStyle}>Footer</Footer>
+    </Layout>
 
-        <Layout style={style}>
-            <Header style={headerStyle}>Header</Header>
-            <Layout>
-                <Content style={contentStyle}>Content</Content>
-                <Sider style={siderStyle}>Sider</Sider>
-            </Layout>
-            <Footer style={footerStyle}>Footer</Footer>
-        </Layout>
+    <Layout style={style}>
+      <Header style={headerStyle}>Header</Header>
+      <Layout>
+        <Sider style={siderStyle}>Sider</Sider>
+        <Content style={contentStyle}>Content</Content>
+      </Layout>
+      <Footer style={footerStyle}>Footer</Footer>
+    </Layout>
 
-        <Layout style={style}>
-            <Sider style={siderStyle}>Sider</Sider>
-            <Layout>
-                <Header style={headerStyle}>Header</Header>
-                <Content style={contentStyle}>Content</Content>
-                <Footer style={footerStyle}>Footer</Footer>
-            </Layout>
-        </Layout>
-    </div>
-));
-stories.add('Layout demo', () => (
-    <div>
-        <Layout style={style}>
-            <Sider>
-                <Nav
-                    style={{
-                        width: 200,
-                    }}
-                    items={[
-                        {
-                            itemKey: '1',
-                            text: 'Option 1',
-                            icon: <IconEdit />,
-                        },
-                        {
-                            itemKey: '2',
-                            text: 'Option 2',
-                            icon: <IconCamera />,
-                        },
-                        {
-                            text: 'Group 3',
-                            icon: <IconFile />,
-                            itemKey: '3',
-                            items: ['3-1', '3-2'],
-                        },
-                        {
-                            text: 'Group 4',
-                            icon: <IconGlobe />,
-                            itemKey: '4',
-                            items: ['4-1', '4-2'],
-                        },
-                    ]}
-                />
-            </Sider>
-            <Layout>
-                <Header style={headerStyle}>Header</Header>
-                <Content style={contentStyle}>Content</Content>
-                <Footer style={footerStyle}>Footer</Footer>
-            </Layout>
-        </Layout>
-    </div>
-));
+    <Layout style={style}>
+      <Header style={headerStyle}>Header</Header>
+      <Layout>
+        <Content style={contentStyle}>Content</Content>
+        <Sider style={siderStyle}>Sider</Sider>
+      </Layout>
+      <Footer style={footerStyle}>Footer</Footer>
+    </Layout>
 
-class NavApp extends React.Component {
-    constructor() {
-        super();
-        this.state = {
-            isCollapsed: true,
-            defaultOpenKeys: [],
-            mode: 'vertical',
-            navHeight: 480,
-            selectedKeys: [],
-            openKeys: [],
-        };
+    <Layout style={style}>
+      <Sider style={siderStyle}>Sider</Sider>
+      <Layout>
+        <Header style={headerStyle}>Header</Header>
+        <Content style={contentStyle}>Content</Content>
+        <Footer style={footerStyle}>Footer</Footer>
+      </Layout>
+    </Layout>
+  </div>
+);
 
-        this.onSelect = (data = {}) => {
-            console.log('trigger onSelect: ', data);
-            let selectedKeys = Array.from(data.selectedKeys);
-            this.setState({
-                selectedKeys,
-            });
-        };
+LayoutDefault.story = {
+  name: 'Layout default',
+};
 
-        this.onOpenChange = (data = {}) => {
-            console.log('trigger onOpenChange: ', data);
-            let openKeys = Array.from(data.openKeys);
-            this.setState({
-                openKeys,
-            });
-        };
-    }
+export const LayoutDemo = () => (
+  <div>
+    <Layout style={style}>
+      <Sider>
+        <Nav
+          style={{
+            width: 200,
+          }}
+          items={[
+            {
+              itemKey: '1',
+              text: 'Option 1',
+              icon: <IconEdit />,
+            },
+            {
+              itemKey: '2',
+              text: 'Option 2',
+              icon: <IconCamera />,
+            },
+            {
+              text: 'Group 3',
+              icon: <IconFile />,
+              itemKey: '3',
+              items: ['3-1', '3-2'],
+            },
+            {
+              text: 'Group 4',
+              icon: <IconGlobe />,
+              itemKey: '4',
+              items: ['4-1', '4-2'],
+            },
+          ]}
+        />
+      </Sider>
+      <Layout>
+        <Header style={headerStyle}>Header</Header>
+        <Content style={contentStyle}>Content</Content>
+        <Footer style={footerStyle}>Footer</Footer>
+      </Layout>
+    </Layout>
+  </div>
+);
 
-    updateCollapsed(isCollapsed) {
-        this.setState({
-            isCollapsed,
-        });
-    }
+LayoutDemo.story = {
+  name: 'Layout demo',
+};
 
-    toggleMode() {
-        let { mode, navHeight } = this.state;
+class NavApp extends React.Component {
+  constructor() {
+    super();
+    this.state = {
+      isCollapsed: true,
+      defaultOpenKeys: [],
+      mode: 'vertical',
+      navHeight: 480,
+      selectedKeys: [],
+      openKeys: [],
+    };
 
-        if (mode === 'vertical') {
-            mode = 'horizontal';
-            navHeight = 60;
-        } else {
-            mode = 'vertical';
-            navHeight = 480;
-        }
+    this.onSelect = (data = {}) => {
+      console.log('trigger onSelect: ', data);
+      let selectedKeys = Array.from(data.selectedKeys);
+      this.setState({
+        selectedKeys,
+      });
+    };
 
-        this.setState({
-            mode,
-            navHeight,
-        });
-    }
+    this.onOpenChange = (data = {}) => {
+      console.log('trigger onOpenChange: ', data);
+      let openKeys = Array.from(data.openKeys);
+      this.setState({
+        openKeys,
+      });
+    };
+  }
+
+  updateCollapsed(isCollapsed) {
+    this.setState({
+      isCollapsed,
+    });
+  }
 
-    render() {
-        let { isCollapsed, defaultOpenKeys, mode, navHeight, selectedKeys, openKeys } = this.state;
-        return (
-            <div>
-                <Nav
-                    isCollapsed={isCollapsed}
-                    defaultOpenKeys={defaultOpenKeys}
-                    style={{
-                        height: navHeight,
-                    }}
-                    mode={mode}
-                    selectedKeys={selectedKeys}
-                    openKeys={openKeys}
-                    onSelect={this.onSelect}
-                    onOpenChange={this.onOpenChange}
-                >
-                    <Nav.Header logo={<IconBytedanceLogo size="extra-large" />} text="互娱运营" />
-                    <Nav.Item itemKey={'1'} text={<strong>火山运营</strong>} icon={<IconVigoLogo />} />
-                    <Nav.Sub itemKey={'2'} text={<strong>运营</strong>} icon={<IconVigoLogo />}>
-                        {['2-1', '2-2'].map(k => (
-                            <Nav.Item key={k} itemKey={String(k)} text={'Option ' + k} />
-                        ))}
-                        <Nav.Sub text={'Group 2-3'} icon={<IconDescend />} itemKey="2-3">
-                            <Nav.Item itemKey={'2-3-1'} text={'Option 2-3-1'} />
-                            <Nav.Item itemKey={'2-3-2'} text={'Option 2-3-2'} />
-                        </Nav.Sub>
-                    </Nav.Sub>
-                    <Nav.Footer>
-                        <Button
-                            title="展开/收起切换"
-                            icon={<IconList />}
-                            onClick={() => this.updateCollapsed(!isCollapsed)}
-                        />
-                    </Nav.Footer>
-                </Nav>
-            </div>
-        );
+  toggleMode() {
+    let { mode, navHeight } = this.state;
+
+    if (mode === 'vertical') {
+      mode = 'horizontal';
+      navHeight = 60;
+    } else {
+      mode = 'vertical';
+      navHeight = 480;
     }
+
+    this.setState({
+      mode,
+      navHeight,
+    });
+  }
+
+  render() {
+    let { isCollapsed, defaultOpenKeys, mode, navHeight, selectedKeys, openKeys } = this.state;
+    return (
+      <div>
+        <Nav
+          isCollapsed={isCollapsed}
+          defaultOpenKeys={defaultOpenKeys}
+          style={{
+            height: navHeight,
+          }}
+          mode={mode}
+          selectedKeys={selectedKeys}
+          openKeys={openKeys}
+          onSelect={this.onSelect}
+          onOpenChange={this.onOpenChange}
+        >
+          <Nav.Header logo={<IconBytedanceLogo size="extra-large" />} text="互娱运营" />
+          <Nav.Item itemKey={'1'} text={<strong>火山运营</strong>} icon={<IconVigoLogo />} />
+          <Nav.Sub itemKey={'2'} text={<strong>运营</strong>} icon={<IconVigoLogo />}>
+            {['2-1', '2-2'].map(k => (
+              <Nav.Item key={k} itemKey={String(k)} text={'Option ' + k} />
+            ))}
+            <Nav.Sub text={'Group 2-3'} icon={<IconDescend />} itemKey="2-3">
+              <Nav.Item itemKey={'2-3-1'} text={'Option 2-3-1'} />
+              <Nav.Item itemKey={'2-3-2'} text={'Option 2-3-2'} />
+            </Nav.Sub>
+          </Nav.Sub>
+          <Nav.Footer>
+            <Button
+              title="展开/收起切换"
+              icon={<IconList />}
+              onClick={() => this.updateCollapsed(!isCollapsed)}
+            />
+          </Nav.Footer>
+        </Nav>
+      </div>
+    );
+  }
 }
 
-stories.add('collapse nav demo', () => (
-    <div>
-        <Layout style={style}>
-            <Sider>
-                <NavApp />
-            </Sider>
-            <Layout>
-                <Header style={headerStyle}>Header</Header>
-                <Content style={contentStyle}>Content</Content>
-                <Footer style={footerStyle}>Footer</Footer>
-            </Layout>
-        </Layout>
-    </div>
-));
+export const CollapseNavDemo = () => (
+  <div>
+    <Layout style={style}>
+      <Sider>
+        <NavApp />
+      </Sider>
+      <Layout>
+        <Header style={headerStyle}>Header</Header>
+        <Content style={contentStyle}>Content</Content>
+        <Footer style={footerStyle}>Footer</Footer>
+      </Layout>
+    </Layout>
+  </div>
+);
+
+CollapseNavDemo.story = {
+  name: 'collapse nav demo',
+};
 
 class SimpleNav extends React.Component {
-    constructor() {
-        super();
-        this.state = {
-            isCollapsed: true,
-            mode: 'vertical',
-            navHeight: 480,
-        };
-    }
+  constructor() {
+    super();
+    this.state = {
+      isCollapsed: true,
+      mode: 'vertical',
+      navHeight: 480,
+    };
+  }
 
-    updateCollapsed(isCollapsed) {
-        this.setState({
-            isCollapsed,
-        });
-    }
+  updateCollapsed(isCollapsed) {
+    this.setState({
+      isCollapsed,
+    });
+  }
 
-    render() {
-        let { isCollapsed, mode, navHeight } = this.state;
-        return (
-            <div>
-                <Nav
-                    isCollapsed={isCollapsed}
-                    style={{
-                        height: navHeight,
-                    }}
-                    mode={mode}
-                >
-                    <Button
-                        icon={<IconList />}
-                        onClick={() => this.updateCollapsed(!isCollapsed)}
-                    >
-                        展开/收起切换
-                    </Button>
-                </Nav>
-            </div>
-        );
-    }
+  render() {
+    let { isCollapsed, mode, navHeight } = this.state;
+    return (
+      <div>
+        <Nav
+          isCollapsed={isCollapsed}
+          style={{
+            height: navHeight,
+          }}
+          mode={mode}
+        >
+          <Button icon={<IconList />} onClick={() => this.updateCollapsed(!isCollapsed)}>
+            展开/收起切换
+          </Button>
+        </Nav>
+      </div>
+    );
+  }
 }
 
 const onbreakpoint = (screen, bool) => {
-    console.log(screen, bool);
+  console.log(screen, bool);
 };
 
-stories.add('collapse SimpleNav demo', () => (
-    <div>
-        <Layout style={style}>
-            <Sider breakpoint={['md']} onBreakpoint={onbreakpoint}>
-                <SimpleNav />
-            </Sider>
-            <Layout>
-                <Header style={headerStyle}>Header</Header>
-                <Content style={contentStyle}>Content</Content>
-                <Footer style={footerStyle}>Footer</Footer>
-            </Layout>
-        </Layout>
-    </div>
-));
+export const CollapseSimpleNavDemo = () => (
+  <div>
+    <Layout style={style}>
+      <Sider breakpoint={['md']} onBreakpoint={onbreakpoint}>
+        <SimpleNav />
+      </Sider>
+      <Layout>
+        <Header style={headerStyle}>Header</Header>
+        <Content style={contentStyle}>Content</Content>
+        <Footer style={footerStyle}>Footer</Footer>
+      </Layout>
+    </Layout>
+  </div>
+);
+
+CollapseSimpleNavDemo.story = {
+  name: 'collapse SimpleNav demo',
+};

+ 827 - 699
packages/semi-ui/list/_story/list.stories.js

@@ -5,788 +5,916 @@ import InfiniteScroll from 'react-infinite-scroller';
 import { DndProvider, DragSource, DropTarget, useDrag, useDrop } from 'react-dnd';
 import HTML5Backend from 'react-dnd-html5-backend';
 import update from 'immutability-helper';
-import { storiesOf } from '@storybook/react';
 import { Skeleton, Avatar, Button, ButtonGroup, Spin } from '../../index';
 import List from '..';
-
-import WindowScroller from 'react-virtualized/dist/commonjs/WindowScroller';
 import AutoSizer from 'react-virtualized/dist/commonjs/AutoSizer';
 import VList from 'react-virtualized/dist/commonjs/List';
 import InfiniteLoader from 'react-virtualized/dist/commonjs/InfiniteLoader';
 
-
 const Item = List.Item;
-const stories = storiesOf('List', module);
+
+
+export default {
+  title: 'List'
+}
+
 const data = [
-    '从明天起,做一个幸福的人',
-    '喂马,劈柴,周游世界',
-    '从明天起,关心粮食和蔬菜',
-    '我有一所房子,面朝大海,春暖花开'
+  '从明天起,做一个幸福的人',
+  '喂马,劈柴,周游世界',
+  '从明天起,关心粮食和蔬菜',
+  '我有一所房子,面朝大海,春暖花开',
 ];
 
-const titles = [
-    '示例标题1',
-    '示例标题2',
-    '示例标题3',
-    '示例标题4',
-    '示例标题5',
-    '示例标题6'
-];
+const titles = ['示例标题1', '示例标题2', '示例标题3', '示例标题4', '示例标题5', '示例标题6'];
+
+export const BasicList = () => (
+  <div>
+    <h3 style={{ marginBottom: 16 }}>Default Size</h3>
+    <List
+      header={<div>Header</div>}
+      footer={<div>Footer</div>}
+      bordered
+      dataSource={data}
+      renderItem={item => <Item>{item}</Item>}
+    />
+    <h3 style={{ marginBottom: 16 }}>Default Size</h3>
+    <List header={<div>Header</div>} footer={<div>Footer</div>} bordered>
+      <Item onRightClick={() => console.log('key 1')}>
+        <span>从明天起,做一个幸福的人</span>
+      </Item>
+      <Item>
+        <span>喂马,劈柴,周游世界</span>
+      </Item>
+      <Item>
+        <span>从明天起,关心粮食和蔬菜'</span>
+      </Item>
+      <Item>
+        <span>我有一所房子,面朝大海,春暖花开</span>
+      </Item>
+    </List>
+    <h3 style={{ margin: '16px 0' }}>Small Size</h3>
+    <List
+      size="small"
+      header={<div>Header</div>}
+      footer={<div>Footer</div>}
+      bordered
+      onClick={e => console.log(e.target)}
+      onRightClick={e => console.log(e.target)}
+      dataSource={data}
+      renderItem={item => <List.Item>{item}</List.Item>}
+    />
+    <h3 style={{ margin: '16px 0' }}>Large Size</h3>
+    <List
+      size="large"
+      header={<div>Header</div>}
+      footer={<div>Footer</div>}
+      bordered
+      dataSource={data}
+      renderItem={item => <List.Item>{item}</List.Item>}
+    />
+  </div>
+);
+
+BasicList.story = {
+  name: 'basic list',
+};
 
-// stories.addDecorator(withKnobs);;
+export const EmptyList = () => (
+  <div>
+    <List header={<div>Header</div>} footer={<div>Footer</div>} bordered />
+  </div>
+);
 
-stories.add('basic list', () => (
-    <div>
-        <h3 style={{ marginBottom: 16 }}>Default Size</h3>
-        <List
-            header={<div>Header</div>}
-            footer={<div>Footer</div>}
-            bordered
-            dataSource={data}
-            renderItem={item => (
-                <Item>{item}</Item>
-            )}
-        />
-        <h3 style={{ marginBottom: 16 }}>Default Size</h3>
-        <List
-            header={<div>Header</div>}
-            footer={<div>Footer</div>}
-            bordered
-        >
-            <Item onRightClick={() => console.log('key 1')}><span>从明天起,做一个幸福的人</span></Item>
-            <Item><span>喂马,劈柴,周游世界</span></Item>
-            <Item><span>从明天起,关心粮食和蔬菜'</span></Item>
-            <Item><span>我有一所房子,面朝大海,春暖花开</span></Item>
-        </List>
-        <h3 style={{ margin: '16px 0' }}>Small Size</h3>
-        <List
-            size="small"
-            header={<div>Header</div>}
-            footer={<div>Footer</div>}
-            bordered
-            onClick={(e) => console.log(e.target)}
-            onRightClick={(e) => console.log(e.target)}
-            dataSource={data}
-            renderItem={item => <List.Item>{item}</List.Item>}
-        />
-        <h3 style={{ margin: '16px 0' }}>Large Size</h3>
-        <List
-            size="large"
-            header={<div>Header</div>}
-            footer={<div>Footer</div>}
-            bordered
-            dataSource={data}
-            renderItem={item => <List.Item>{item}</List.Item>}
-        />
-    </div>
-));
-
-stories.add('empty list', () => (
-    <div>
-        <List
-            header={<div>Header</div>}
-            footer={<div>Footer</div>}
-            bordered
-        />
-    </div>
-));
+EmptyList.story = {
+  name: 'empty list',
+};
+
+export const JsxList = () => (
+  <List
+    header={<div>Header</div>}
+    footer={<div>Footer</div>}
+    bordered
+    split={false}
+    // layout="horizontal"
+    // grid
+    grid={{
+      gutter: 12,
+      span: 6,
+    }}
+  >
+    <Item>
+      <span>从明天起,做一个幸福的人</span>
+    </Item>
+    <Item>
+      <span>喂马,劈柴,周游世界</span>
+    </Item>
+    <Item>
+      <span>从明天起,关心粮食和蔬菜'</span>
+    </Item>
+    <Item>
+      <span>我有一所房子,面朝大海,春暖花开</span>
+    </Item>
+  </List>
+);
+
+JsxList.story = {
+  name: 'jsx list',
+};
 
-stories.add('jsx list', () => (
+export const NoBorder = () => (
+  <div>
     <List
-        header={<div>Header</div>}
-        footer={<div>Footer</div>}
-        bordered
-        split={false}
-        // layout="horizontal"
-        // grid
-        grid={{
-            gutter: 12,
-            span: 6,
-        }}
-    >
-        <Item><span>从明天起,做一个幸福的人</span></Item>
-        <Item><span>喂马,劈柴,周游世界</span></Item>
-        <Item><span>从明天起,关心粮食和蔬菜'</span></Item>
-        <Item><span>我有一所房子,面朝大海,春暖花开</span></Item>
-    </List>
-));
-
-stories.add('no border', () => (
-    <div>
-        <List
-            header={<div>Header</div>}
-            footer={<div>Footer</div>}
-            dataSource={data}
-            renderItem={item => <List.Item>{item}</List.Item>}
-        />
-        <br />
-        <br />
-        <List
-            header={<div>Header</div>}
-            footer={<div>Footer</div>}
-            split={false}
-            dataSource={data}
-            renderItem={item => <List.Item>{item}</List.Item>}
-        />
-    </div>
-));
+      header={<div>Header</div>}
+      footer={<div>Footer</div>}
+      dataSource={data}
+      renderItem={item => <List.Item>{item}</List.Item>}
+    />
+    <br />
+    <br />
+    <List
+      header={<div>Header</div>}
+      footer={<div>Footer</div>}
+      split={false}
+      dataSource={data}
+      renderItem={item => <List.Item>{item}</List.Item>}
+    />
+  </div>
+);
+
+NoBorder.story = {
+  name: 'no border',
+};
 
-stories.add('item structure', () => (
-    <div style={{ padding: 12, border: '1px solid var(--semi-color-border)', margin: 12 }}>
-        <List
-            dataSource={data}
-            renderItem={item => (
-                <List.Item
-                    header={<Avatar color='red' >CA</Avatar>}
-                    main={<div><span style={{ color: 'var(--semi-color-text-0)' }}>示例标题</span><p style={{ color: 'var(--semi-color-text-2)', margin: '4px 0' }}>Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的 Web 应用。</p></div>}
-                    extra={
-                        <ButtonGroup theme='borderless'>
-                            <Button>编辑</Button>
-                            <Button>更多</Button>
-                        </ButtonGroup>
-                    }
-                />)
-            }
-        />
-    </div>
-));
-
-stories.add('item layout', () => (
-    <div style={{ padding: 12, border: '1px solid var(--semi-color-border)', margin: 12 }}>
-        <List
-            dataSource={data}
-            layout='horizontal'
-            renderItem={item => (
-                <List.Item
-                    header={<Avatar color='red' >CA</Avatar>}
-                    main={<div><span style={{ color: 'var(--semi-color-text-0)' }}>示例标题</span><p style={{ color: 'var(--semi-color-text-2)', margin: '4px 0' }}>Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的 Web 应用。</p></div>}
-                    extra={
-                        <ButtonGroup theme='borderless'>
-                            <Button>编辑</Button>
-                            <Button>更多</Button>
-                        </ButtonGroup>
-                    }
-                />)
-            }
-        />
-    </div>
-));
-
-stories.add('item layout align', () => (
-    <div style={{ padding: 12, border: '1px solid var(--semi-color-border)', margin: 12 }}>
-        <List
-            dataSource={data}
-            layout='horizontal'
-            renderItem={item => (
-                <List.Item
-                    header={<Avatar color='red' >CA</Avatar>}
-                    main={<div><span style={{ color: 'var(--semi-color-text-0)' }}>示例标题</span><p style={{ color: 'var(--semi-color-text-2)', margin: '4px 0' }}>Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的 Web 应用。</p></div>}
-                    align='flex-end'
-                    extra={
-                        <ButtonGroup theme='borderless'>
-                            <Button>编辑</Button>
-                            <Button>更多</Button>
-                        </ButtonGroup>
-                    }
-                />)
-            }
+export const ItemStructure = () => (
+  <div style={{ padding: 12, border: '1px solid var(--semi-color-border)', margin: 12 }}>
+    <List
+      dataSource={data}
+      renderItem={item => (
+        <List.Item
+          header={<Avatar color="red">CA</Avatar>}
+          main={
+            <div>
+              <span style={{ color: 'var(--semi-color-text-0)' }}>示例标题</span>
+              <p style={{ color: 'var(--semi-color-text-2)', margin: '4px 0' }}>
+                Semi Design 是由互娱社区前端团队与 UED
+                团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的
+                Web 应用。
+              </p>
+            </div>
+          }
+          extra={
+            <ButtonGroup theme="borderless">
+              <Button>编辑</Button>
+              <Button>更多</Button>
+            </ButtonGroup>
+          }
         />
-        <br />
-        <List
-            dataSource={data}
-            layout='horizontal'
-            renderItem={item => (
-                <List.Item
-                    header={<Avatar color='red' >CA</Avatar>}
-                    main={<div><span style={{ color: 'var(--semi-color-text-0)' }}>示例标题</span><p style={{ color: 'var(--semi-color-text-2)', margin: '4px 0' }}>Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的 Web 应用。</p></div>}
-                    align='center'
-                    extra={
-                        <ButtonGroup theme='borderless'>
-                            <Button>编辑</Button>
-                            <Button>更多</Button>
-                        </ButtonGroup>
-                    }
-                />)
-            }
+      )}
+    />
+  </div>
+);
+
+ItemStructure.story = {
+  name: 'item structure',
+};
+
+export const ItemLayout = () => (
+  <div style={{ padding: 12, border: '1px solid var(--semi-color-border)', margin: 12 }}>
+    <List
+      dataSource={data}
+      layout="horizontal"
+      renderItem={item => (
+        <List.Item
+          header={<Avatar color="red">CA</Avatar>}
+          main={
+            <div>
+              <span style={{ color: 'var(--semi-color-text-0)' }}>示例标题</span>
+              <p style={{ color: 'var(--semi-color-text-2)', margin: '4px 0' }}>
+                Semi Design 是由互娱社区前端团队与 UED
+                团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的
+                Web 应用。
+              </p>
+            </div>
+          }
+          extra={
+            <ButtonGroup theme="borderless">
+              <Button>编辑</Button>
+              <Button>更多</Button>
+            </ButtonGroup>
+          }
         />
-        <br />
-        <List
-            dataSource={data}
-            layout='horizontal'
-            renderItem={item => (
-                <List.Item
-                    header={<Avatar color='red' >CA</Avatar>}
-                    main={<div><span style={{ color: 'var(--semi-color-text-0)' }}>示例标题</span><p style={{ color: 'var(--semi-color-text-2)', margin: '4px 0' }}>Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的 Web 应用。</p></div>}
-                    align='baseline'
-                    extra={
-                        <ButtonGroup theme='borderless'>
-                            <Button>编辑</Button>
-                            <Button>更多</Button>
-                        </ButtonGroup>
-                    }
-                />)
-            }
+      )}
+    />
+  </div>
+);
+
+ItemLayout.story = {
+  name: 'item layout',
+};
+
+export const ItemLayoutAlign = () => (
+  <div style={{ padding: 12, border: '1px solid var(--semi-color-border)', margin: 12 }}>
+    <List
+      dataSource={data}
+      layout="horizontal"
+      renderItem={item => (
+        <List.Item
+          header={<Avatar color="red">CA</Avatar>}
+          main={
+            <div>
+              <span style={{ color: 'var(--semi-color-text-0)' }}>示例标题</span>
+              <p style={{ color: 'var(--semi-color-text-2)', margin: '4px 0' }}>
+                Semi Design 是由互娱社区前端团队与 UED
+                团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的
+                Web 应用。
+              </p>
+            </div>
+          }
+          align="flex-end"
+          extra={
+            <ButtonGroup theme="borderless">
+              <Button>编辑</Button>
+              <Button>更多</Button>
+            </ButtonGroup>
+          }
         />
-        <br />
-        <List
-            dataSource={data}
-            layout='horizontal'
-            renderItem={item => (
-                <List.Item
-                    header={<Avatar color='red' >CA</Avatar>}
-                    main={<div><span style={{ color: 'var(--semi-color-text-0)' }}>示例标题</span><p style={{ color: 'var(--semi-color-text-2)', margin: '4px 0' }}>Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的 Web 应用。</p></div>}
-                    align='stretch'
-                    extra={
-                        <ButtonGroup theme='borderless'>
-                            <Button>编辑</Button>
-                            <Button>更多</Button>
-                        </ButtonGroup>
-                    }
-                />)
-            }
+      )}
+    />
+    <br />
+    <List
+      dataSource={data}
+      layout="horizontal"
+      renderItem={item => (
+        <List.Item
+          header={<Avatar color="red">CA</Avatar>}
+          main={
+            <div>
+              <span style={{ color: 'var(--semi-color-text-0)' }}>示例标题</span>
+              <p style={{ color: 'var(--semi-color-text-2)', margin: '4px 0' }}>
+                Semi Design 是由互娱社区前端团队与 UED
+                团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的
+                Web 应用。
+              </p>
+            </div>
+          }
+          align="center"
+          extra={
+            <ButtonGroup theme="borderless">
+              <Button>编辑</Button>
+              <Button>更多</Button>
+            </ButtonGroup>
+          }
         />
-    </div>
-));
-
-stories.add('grid', () => (
-    <div style={{ padding: 12, border: '1px solid var(--semi-color-border)', margin: 12 }}>
-        <List
-            grid={{
-                gutter: 24,
-                span: 6,
-            }}
-            dataSource={data}
-            renderItem={item => (
-                <List.Item>
-                    <div style={{ border: '1px solid var(--semi-color-border)', height: '50px' }}>{item}</div>
-                </List.Item>
-            )}
+      )}
+    />
+    <br />
+    <List
+      dataSource={data}
+      layout="horizontal"
+      renderItem={item => (
+        <List.Item
+          header={<Avatar color="red">CA</Avatar>}
+          main={
+            <div>
+              <span style={{ color: 'var(--semi-color-text-0)' }}>示例标题</span>
+              <p style={{ color: 'var(--semi-color-text-2)', margin: '4px 0' }}>
+                Semi Design 是由互娱社区前端团队与 UED
+                团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的
+                Web 应用。
+              </p>
+            </div>
+          }
+          align="baseline"
+          extra={
+            <ButtonGroup theme="borderless">
+              <Button>编辑</Button>
+              <Button>更多</Button>
+            </ButtonGroup>
+          }
         />
-    </div>
-));
-
-stories.add('responsive grid', () => (
-    <div style={{ padding: 12, border: '1px solid var(--semi-color-border)', margin: 12 }}>
-        <List
-            grid={{
-                gutter: 16,
-                xs: 24,
-                sm: 12,
-                md: 6,
-                lg: 6,
-                xl: 4,
-                xxl: 8,
-            }}
-            dataSource={titles}
-            renderItem={item => (
-                <List.Item
-                    style={{ padding: 12 }}
-                    header={<Avatar color='red' >CA</Avatar>}
-                    main={<div><span style={{ color: 'var(--semi-color-text-0)' }}>示例标题</span><p style={{ color: 'var(--semi-color-text-2)', margin: '4px 0' }}>Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统。</p></div>}
-                    extra={
-                        <ButtonGroup theme='borderless'>
-                            <Button>编辑</Button>
-                            <Button>更多</Button>
-                        </ButtonGroup>
-                    }
-                />)
-            }
+      )}
+    />
+    <br />
+    <List
+      dataSource={data}
+      layout="horizontal"
+      renderItem={item => (
+        <List.Item
+          header={<Avatar color="red">CA</Avatar>}
+          main={
+            <div>
+              <span style={{ color: 'var(--semi-color-text-0)' }}>示例标题</span>
+              <p style={{ color: 'var(--semi-color-text-2)', margin: '4px 0' }}>
+                Semi Design 是由互娱社区前端团队与 UED
+                团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的
+                Web 应用。
+              </p>
+            </div>
+          }
+          align="stretch"
+          extra={
+            <ButtonGroup theme="borderless">
+              <Button>编辑</Button>
+              <Button>更多</Button>
+            </ButtonGroup>
+          }
         />
-    </div>
-));
+      )}
+    />
+  </div>
+);
 
+ItemLayoutAlign.story = {
+  name: 'item layout align',
+};
 
-class LoadMoreList extends React.Component {
-    constructor() {
-        super();
-
-        const count = 3;
-        const dataList = [];
-        for (let i = 0; i < 40; i++) {
-            dataList.push({
-                color: 'grey',
-                title: `Semi Design Title ${i}`,
-                loading: false,
-            });
-        }
-        this.data = dataList;
-        this.count = 0;
-
-        this.fetchData = () => {
-            let placeholders = [0, 1, 2].map(key => ({ loading: true }));
-            this.setState({
-                loading: true,
-                list: [...this.state.dataSource, ...placeholders],
-            });
-            return new Promise((res, rej) => {
-                setTimeout(() => {
-                    let dataSource = this.data.slice(this.count * count, this.count * count + count);
-                    res(dataSource);
-                }, 1500);
-            }).then(dataSource => {
-                let newData = [...this.state.dataSource, ...dataSource];
-                this.setState({
-                    loading: false,
-                    dataSource: newData,
-                    list: newData,
-                    noMore: !dataSource.length,
-                });
-            });
-        }
+export const Grid = () => (
+  <div style={{ padding: 12, border: '1px solid var(--semi-color-border)', margin: 12 }}>
+    <List
+      grid={{
+        gutter: 24,
+        span: 6,
+      }}
+      dataSource={data}
+      renderItem={item => (
+        <List.Item>
+          <div style={{ border: '1px solid var(--semi-color-border)', height: '50px' }}>{item}</div>
+        </List.Item>
+      )}
+    />
+  </div>
+);
+
+Grid.story = {
+  name: 'grid',
+};
 
-        this.state = {
-            loading: false,
-            dataSource: [],
-            list: [],
-            noMore: false
-        };
-    }
+export const ResponsiveGrid = () => (
+  <div style={{ padding: 12, border: '1px solid var(--semi-color-border)', margin: 12 }}>
+    <List
+      grid={{
+        gutter: 16,
+        xs: 24,
+        sm: 12,
+        md: 6,
+        lg: 6,
+        xl: 4,
+        xxl: 8,
+      }}
+      dataSource={titles}
+      renderItem={item => (
+        <List.Item
+          style={{ padding: 12 }}
+          header={<Avatar color="red">CA</Avatar>}
+          main={
+            <div>
+              <span style={{ color: 'var(--semi-color-text-0)' }}>示例标题</span>
+              <p style={{ color: 'var(--semi-color-text-2)', margin: '4px 0' }}>
+                Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统。
+              </p>
+            </div>
+          }
+          extra={
+            <ButtonGroup theme="borderless">
+              <Button>编辑</Button>
+              <Button>更多</Button>
+            </ButtonGroup>
+          }
+        />
+      )}
+    />
+  </div>
+);
 
-    componentDidMount() {
-        this.fetchData();
-    }
+ResponsiveGrid.story = {
+  name: 'responsive grid',
+};
 
-    onLoadMore() {
-        this.count++;
-        this.fetchData();
+class LoadMoreList extends React.Component {
+  constructor() {
+    super();
+
+    const count = 3;
+    const dataList = [];
+    for (let i = 0; i < 40; i++) {
+      dataList.push({
+        color: 'grey',
+        title: `Semi Design Title ${i}`,
+        loading: false,
+      });
     }
+    this.data = dataList;
+    this.count = 0;
+
+    this.fetchData = () => {
+      let placeholders = [0, 1, 2].map(key => ({ loading: true }));
+      this.setState({
+        loading: true,
+        list: [...this.state.dataSource, ...placeholders],
+      });
+      return new Promise((res, rej) => {
+        setTimeout(() => {
+          let dataSource = this.data.slice(this.count * count, this.count * count + count);
+          res(dataSource);
+        }, 1500);
+      }).then(dataSource => {
+        let newData = [...this.state.dataSource, ...dataSource];
+        this.setState({
+          loading: false,
+          dataSource: newData,
+          list: newData,
+          noMore: !dataSource.length,
+        });
+      });
+    };
 
-    render() {
-        const { loading, list, noMore } = this.state;
-        const loadMore = !loading && !noMore ? (
-            <div
-                style={{
-                    textAlign: 'center',
-                    marginTop: 12,
-                    height: 32,
-                    lineHeight: '32px',
-                }}
-            >
-                <Button onClick={() => this.onLoadMore()}>显示更多</Button>
-            </div>
-        ) : null;
-
-        const placeholder = (
-            <div style={{ display: 'flex', alignItems: 'flex-start', padding: 12, borderBottom: '1px solid var(--semi-color-border)' }}>
-                <Skeleton.Avatar style={{ marginRight: 12 }} />
+    this.state = {
+      loading: false,
+      dataSource: [],
+      list: [],
+      noMore: false,
+    };
+  }
+
+  componentDidMount() {
+    this.fetchData();
+  }
+
+  onLoadMore() {
+    this.count++;
+    this.fetchData();
+  }
+
+  render() {
+    const { loading, list, noMore } = this.state;
+    const loadMore =
+      !loading && !noMore ? (
+        <div
+          style={{
+            textAlign: 'center',
+            marginTop: 12,
+            height: 32,
+            lineHeight: '32px',
+          }}
+        >
+          <Button onClick={() => this.onLoadMore()}>显示更多</Button>
+        </div>
+      ) : null;
+
+    const placeholder = (
+      <div
+        style={{
+          display: 'flex',
+          alignItems: 'flex-start',
+          padding: 12,
+          borderBottom: '1px solid var(--semi-color-border)',
+        }}
+      >
+        <Skeleton.Avatar style={{ marginRight: 12 }} />
+        <div>
+          <Skeleton.Title style={{ width: 120, marginBottom: 12, marginTop: 12 }} />
+          <Skeleton.Paragraph style={{ width: 600 }} rows={2} />
+        </div>
+      </div>
+    );
+    return (
+      <List
+        loading={loading}
+        loadMore={loadMore}
+        dataSource={list}
+        renderItem={item => (
+          <Skeleton placeholder={placeholder} loading={item.loading}>
+            <List.Item
+              header={<Avatar color={item.color}>SE</Avatar>}
+              main={
                 <div>
-                    <Skeleton.Title style={{ width: 120, marginBottom: 12, marginTop: 12 }} />
-                    <Skeleton.Paragraph style={{ width: 600 }} rows={2} />
+                  <span style={{ color: 'var(--semi-color-text-0)', fontWeight: 500 }}>
+                    {item.title}
+                  </span>
+                  <p style={{ color: 'var(--semi-color-text-2)', margin: '4px 0' }}>
+                    Semi Design
+                    设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的
+                    Web 应用。
+                  </p>
                 </div>
-            </div>
-        )
-        return (
-            <List
-                loading={loading}
-                loadMore={loadMore}
-                dataSource={list}
-                renderItem={item => (
-                    <Skeleton placeholder={placeholder} loading={item.loading}>
-                        <List.Item
-                            header={<Avatar color={item.color} >SE</Avatar>}
-                            main={
-                                <div>
-                                    <span style={{ color: 'var(--semi-color-text-0)', fontWeight: 500 }}>{item.title}</span>
-                                    <p style={{ color: 'var(--semi-color-text-2)', margin: '4px 0' }}>
-                                        Semi Design 设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的 Web 应用。
-                                </p>
-                                </div>
-                            }
-                        />
-                    </Skeleton>
-                )}
+              }
             />
-        );
-    }
+          </Skeleton>
+        )}
+      />
+    );
+  }
 }
-stories.add('load more', () => <LoadMoreList />);
+export const LoadMore = () => <LoadMoreList />;
 
+LoadMore.story = {
+  name: 'load more',
+};
 
 class ScrollLoad extends React.Component {
-    constructor() {
-        super();
-
-        const count = 6;
-        const dataList = [];
-        for (let i = 0; i < 100; i++) {
-            dataList.push({
-                color: 'grey',
-                title: `Semi Design Title ${i}`,
-                loading: false,
-            });
-        }
-        this.data = dataList;
-        this.count = 0;
-
-        this.fetchData = () => {
-            this.setState({
-                loading: true,
-            });
-            return new Promise((res, rej) => {
-                setTimeout(() => {
-                    let dataSource = this.data.slice(this.count * count, this.count * count + count);
-                    res(dataSource);
-                }, 1500);
-            }).then(dataSource => {
-                let newData = [...this.state.dataSource, ...dataSource];
-                this.count++;
-                this.setState({
-                    loading: false,
-                    dataSource: newData,
-                    noMore: !dataSource.length,
-                });
-            });
-        }
-
-        this.state = {
-            loading: false,
-            dataSource: [],
-            hasMore: true,
-        };
-    }
-
-    componentDidMount() {
-        this.fetchData();
+  constructor() {
+    super();
+
+    const count = 6;
+    const dataList = [];
+    for (let i = 0; i < 100; i++) {
+      dataList.push({
+        color: 'grey',
+        title: `Semi Design Title ${i}`,
+        loading: false,
+      });
     }
+    this.data = dataList;
+    this.count = 0;
+
+    this.fetchData = () => {
+      this.setState({
+        loading: true,
+      });
+      return new Promise((res, rej) => {
+        setTimeout(() => {
+          let dataSource = this.data.slice(this.count * count, this.count * count + count);
+          res(dataSource);
+        }, 1500);
+      }).then(dataSource => {
+        let newData = [...this.state.dataSource, ...dataSource];
+        this.count++;
+        this.setState({
+          loading: false,
+          dataSource: newData,
+          noMore: !dataSource.length,
+        });
+      });
+    };
 
-    render() {
-        const { loading, dataSource, hasMore } = this.state;
-        const showLoadMore = this.count % 3 === 0;
-        const loadMore = !loading && hasMore && showLoadMore ? (
-            <div
-                style={{
-                    textAlign: 'center',
-                    marginTop: 12,
-                    height: 32,
-                    lineHeight: '32px',
-                }}
-            >
-                <Button onClick={this.fetchData}>显示更多</Button>
-            </div>
-        ) : null;
-
-        return (
-            <div className="demo-infinite-container" style={{ height: 420, overflow: 'auto' }}>
-                <InfiniteScroll
-                    initialLoad={false}
-                    pageStart={0}
-                    threshold={20}
-                    loadMore={this.fetchData}
-                    hasMore={!this.state.loading && this.state.hasMore && !showLoadMore}
-                    useWindow={false}
-                >
-                    <List
-                        loadMore={loadMore}
-                        dataSource={dataSource}
-                        renderItem={item => (
-                            <List.Item
-                                header={<Avatar color={item.color} >SE</Avatar>}
-                                main={
-                                    <div>
-                                        <span style={{ color: 'var(--semi-color-text-0)', fontWeight: 500 }}>{item.title}</span>
-                                        <p style={{ color: 'var(--semi-color-text-2)', margin: '4px 0' }}>
-                                            Semi Design 设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的 Web 应用。
-                                        </p>
-                                    </div>
-                                }
-                            />
-                        )}
-                    />
-                    {this.state.loading && this.state.hasMore && (
-                        <div style={{ textAlign: 'center' }}>
-                            <Spin />
-                        </div>
-                    )}
-                </InfiniteScroll>
+    this.state = {
+      loading: false,
+      dataSource: [],
+      hasMore: true,
+    };
+  }
+
+  componentDidMount() {
+    this.fetchData();
+  }
+
+  render() {
+    const { loading, dataSource, hasMore } = this.state;
+    const showLoadMore = this.count % 3 === 0;
+    const loadMore =
+      !loading && hasMore && showLoadMore ? (
+        <div
+          style={{
+            textAlign: 'center',
+            marginTop: 12,
+            height: 32,
+            lineHeight: '32px',
+          }}
+        >
+          <Button onClick={this.fetchData}>显示更多</Button>
+        </div>
+      ) : null;
+
+    return (
+      <div className="demo-infinite-container" style={{ height: 420, overflow: 'auto' }}>
+        <InfiniteScroll
+          initialLoad={false}
+          pageStart={0}
+          threshold={20}
+          loadMore={this.fetchData}
+          hasMore={!this.state.loading && this.state.hasMore && !showLoadMore}
+          useWindow={false}
+        >
+          <List
+            loadMore={loadMore}
+            dataSource={dataSource}
+            renderItem={item => (
+              <List.Item
+                header={<Avatar color={item.color}>SE</Avatar>}
+                main={
+                  <div>
+                    <span style={{ color: 'var(--semi-color-text-0)', fontWeight: 500 }}>
+                      {item.title}
+                    </span>
+                    <p style={{ color: 'var(--semi-color-text-2)', margin: '4px 0' }}>
+                      Semi Design
+                      设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的
+                      Web 应用。
+                    </p>
+                  </div>
+                }
+              />
+            )}
+          />
+          {this.state.loading && this.state.hasMore && (
+            <div style={{ textAlign: 'center' }}>
+              <Spin />
             </div>
-        );
-    }
+          )}
+        </InfiniteScroll>
+      </div>
+    );
+  }
 }
-stories.add('scroll load', () => <ScrollLoad />);
+export const _ScrollLoad = () => <ScrollLoad />;
+
+_ScrollLoad.story = {
+  name: 'scroll load',
+};
 
 const listItems = [
-    {
-        title: 'Semi Design Title 1',
-        color: 'red',
-    },
-    {
-        title: 'Semi Design Title 2',
-        color: 'grey'
-    },
-    {
-        title: 'Semi Design Title 3',
-        color: 'light-green',
-    },
-    {
-        title: 'Semi Design Title 4',
-        color: 'light-blue',
-    },
-    {
-        title: 'Semi Design Title 5',
-        color: 'pink',
-    }
+  {
+    title: 'Semi Design Title 1',
+    color: 'red',
+  },
+  {
+    title: 'Semi Design Title 2',
+    color: 'grey',
+  },
+  {
+    title: 'Semi Design Title 3',
+    color: 'light-green',
+  },
+  {
+    title: 'Semi Design Title 4',
+    color: 'light-blue',
+  },
+  {
+    title: 'Semi Design Title 5',
+    color: 'pink',
+  },
 ];
 
 const cardSource = {
-    beginDrag(props) {
-        return {
-            id: props.id,
-            index: props.index
-        };
-    }
+  beginDrag(props) {
+    return {
+      id: props.id,
+      index: props.index,
+    };
+  },
 };
 
 const cardTarget = {
-    hover(props, monitor, component) {
-        // test demo below is from react-dnd and react-dnd-html5-backend. https://react-dnd.github.io/react-dnd/about
-        const dragIndex = monitor.getItem().index;
-        const hoverIndex = props.index;
-
-        if (dragIndex === hoverIndex) {
-            return;
-        }
-        const hoverBoundingRect = ReactDOM.findDOMNode(component).getBoundingClientRect();
-        const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
-        const clientOffset = monitor.getClientOffset();
-        const hoverClientY = clientOffset.y - hoverBoundingRect.top;
-        if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
-            return;
-        }
+  hover(props, monitor, component) {
+    // test demo below is from react-dnd and react-dnd-html5-backend. https://react-dnd.github.io/react-dnd/about
+    const dragIndex = monitor.getItem().index;
+    const hoverIndex = props.index;
 
-        if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
-            return;
-        }
+    if (dragIndex === hoverIndex) {
+      return;
+    }
+    const hoverBoundingRect = ReactDOM.findDOMNode(component).getBoundingClientRect();
+    const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
+    const clientOffset = monitor.getClientOffset();
+    const hoverClientY = clientOffset.y - hoverBoundingRect.top;
+    if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
+      return;
+    }
 
-        monitor.getItem().index = hoverIndex;
-        props.moveItem(dragIndex, hoverIndex);
+    if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
+      return;
     }
+
+    monitor.getItem().index = hoverIndex;
+    props.moveItem(dragIndex, hoverIndex);
+  },
 };
 
 function collectDragSource(connect, monitor) {
-    return {
-        connectDragSource: connect.dragSource(),
-        // isDragging: monitor.isDragging()
-        draggingItem: monitor.getItem()
-    };
+  return {
+    connectDragSource: connect.dragSource(),
+    // isDragging: monitor.isDragging()
+    draggingItem: monitor.getItem(),
+  };
 }
 
 function collectDropTarget(connect) {
-    return {
-        connectDropTarget: connect.dropTarget()
-    };
+  return {
+    connectDropTarget: connect.dropTarget(),
+  };
 }
 
 class DraggableItem extends React.Component {
-    render() {
-        const { component, draggingItem, index, connectDragSource, connectDropTarget } = this.props;
-        const opacity = draggingItem && draggingItem.index === index ? .3 : 1;
-        const style = {
-            border: '1px solid var(--semi-color-border)',
-            marginBottom: 12,
-            backgroundColor: 'white',
-            cursor: 'move',
-        }
+  render() {
+    const { component, draggingItem, index, connectDragSource, connectDropTarget } = this.props;
+    const opacity = draggingItem && draggingItem.index === index ? 0.3 : 1;
+    const style = {
+      border: '1px solid var(--semi-color-border)',
+      marginBottom: 12,
+      backgroundColor: 'white',
+      cursor: 'move',
+    };
 
-        return connectDragSource(connectDropTarget(
-            <div ref={node => this.node = node} style={{ ...style, opacity }}>
-                {component}
-            </div>
-        ));
-    }
+    return connectDragSource(
+      connectDropTarget(
+        <div ref={node => (this.node = node)} style={{ ...style, opacity }}>
+          {component}
+        </div>
+      )
+    );
+  }
 }
 
 DraggableItem = DragSource('item', cardSource, collectDragSource)(DraggableItem);
 DraggableItem = DropTarget('item', cardTarget, collectDropTarget)(DraggableItem);
 
 class DraggableList extends React.Component {
-    constructor() {
-        super();
-        this.state = {
-            data: listItems,
+  constructor() {
+    super();
+    this.state = {
+      data: listItems,
+    };
+  }
+
+  moveItem = (dragIndex, hoverIndex) => {
+    const { data } = this.state;
+    const draggingItem = data[dragIndex];
+    this.setState(
+      update(this.state, {
+        data: {
+          $splice: [
+            [dragIndex, 1],
+            [hoverIndex, 0, draggingItem],
+          ],
+        },
+      })
+    );
+  };
+
+  renderDraggable = (item, id) => {
+    const content = (
+      <List.Item
+        header={<Avatar color={item.color}>SE</Avatar>}
+        main={
+          <div>
+            <span style={{ color: 'var(--semi-color-text-0)', fontWeight: 500 }}>{item.title}</span>
+            <p style={{ color: 'var(--semi-color-text-2)', margin: '4px 0' }}>
+              Semi Design
+              设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的
+              Web 应用。
+            </p>
+          </div>
         }
-    }
-
-    moveItem = (dragIndex, hoverIndex) => {
-        const { data } = this.state;
-        const draggingItem = data[dragIndex];
-        this.setState(update(this.state, {
-            data: {
-                $splice: [
-                    [dragIndex, 1],
-                    [hoverIndex, 0, draggingItem]
-                ]
-            }
-        }))
-    }
-
-    renderDraggable = (item, id) => {
-        const content = (
-            <List.Item
-                header={<Avatar color={item.color} >SE</Avatar>}
-                main={
-                    <div>
-                        <span style={{ color: 'var(--semi-color-text-0)', fontWeight: 500 }}>{item.title}</span>
-                        <p style={{ color: 'var(--semi-color-text-2)', margin: '4px 0' }}>
-                            Semi Design 设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的 Web 应用。
-                        </p>
-                    </div>
-                }
-            />
-        )
-        return (
-            <DraggableItem
-                key={item.title}
-                index={id}
-                id={item.title}
-                component={content}
-                moveItem={this.moveItem}
-            />
-        );
-    }
-
-    render() {
-        const { data } = this.state;
-        return (
-            <div style={{ padding: 12, border: '1px solid var(--semi-color-border)', margin: 12 }}>
-                <DndProvider backend={HTML5Backend}>
-                    <List
-                        dataSource={data}
-                        renderItem={this.renderDraggable}
-                    />
-                </DndProvider>
-            </div>
-        )
-    }
+      />
+    );
+    return (
+      <DraggableItem
+        key={item.title}
+        index={id}
+        id={item.title}
+        component={content}
+        moveItem={this.moveItem}
+      />
+    );
+  };
+
+  render() {
+    const { data } = this.state;
+    return (
+      <div style={{ padding: 12, border: '1px solid var(--semi-color-border)', margin: 12 }}>
+        <DndProvider backend={HTML5Backend}>
+          <List dataSource={data} renderItem={this.renderDraggable} />
+        </DndProvider>
+      </div>
+    );
+  }
 }
 
-stories.add('draggable', () => <DraggableList />);
-
+export const Draggable = () => <DraggableList />;
 
+Draggable.story = {
+  name: 'draggable',
+};
 
 class VirtualizedScroll extends React.Component {
-    constructor() {
-        super();
-
-        const dataList = [];
-        for (let i = 0; i < 50; i++) {
-            dataList.push({
-                color: 'grey',
-                title: `Semi Design Title ${i}`,
-            });
-        }
-        this.data = dataList;
-
-        this.fetchData = (startIndex, stopIndex) => {
-            return new Promise((res, rej) => {
-                setTimeout(() => {
-                    let dataSource = this.data.slice(startIndex, stopIndex + 1);
-                    res(dataSource);
-                }, 1000);
-            }).then(dataSource => {
-                let newData = [...this.state.dataSource, ...dataSource];
-                const { loadedRowsMap, loadingRowCount } = this.state;
-                const increment = stopIndex - startIndex + 1;
-                for (let i = startIndex; i <= stopIndex; i++) {
-                    loadedRowsMap[i] = this.statusLoaded;
-                }
-                this.setState({
-                    dataSource: newData,
-                    loadedRowsMap,
-                    loadingRowCount: loadingRowCount - increment,
-                });
-            });
-        }
-
-        this.state = {
-            dataSource: [],
-            loadedRowsMap: {},
-            loadingRowCount: 0,
-        };
-
-        this.statusLoading = 0;
-        this.statusLoaded = 1;
-        this.loadLimit = this.data.length;
-        this.renderItem = this.renderItem.bind(this);
-        this.fetchData = this.fetchData.bind(this);
-        this.handleInfiniteOnLoad = this.handleInfiniteOnLoad.bind(this);
-        this.isRowLoaded = this.isRowLoaded.bind(this);
+  constructor() {
+    super();
+
+    const dataList = [];
+    for (let i = 0; i < 50; i++) {
+      dataList.push({
+        color: 'grey',
+        title: `Semi Design Title ${i}`,
+      });
     }
-
-    handleInfiniteOnLoad({ startIndex, stopIndex }) {
-        let { dataSource, loadedRowsMap, loadingRowCount } = this.state;
+    this.data = dataList;
+
+    this.fetchData = (startIndex, stopIndex) => {
+      return new Promise((res, rej) => {
+        setTimeout(() => {
+          let dataSource = this.data.slice(startIndex, stopIndex + 1);
+          res(dataSource);
+        }, 1000);
+      }).then(dataSource => {
+        let newData = [...this.state.dataSource, ...dataSource];
+        const { loadedRowsMap, loadingRowCount } = this.state;
         const increment = stopIndex - startIndex + 1;
-        if (stopIndex >= this.loadLimit || loadingRowCount > 0) {
-            return;
-        }
         for (let i = startIndex; i <= stopIndex; i++) {
-            loadedRowsMap[i] = this.statusLoading;
+          loadedRowsMap[i] = this.statusLoaded;
         }
         this.setState({
-            loadingRowCount: loadingRowCount + increment,
+          dataSource: newData,
+          loadedRowsMap,
+          loadingRowCount: loadingRowCount - increment,
         });
-        return this.fetchData(startIndex, stopIndex);
-    }
-
-    isRowLoaded({ index }) {
-        const { loadedRowsMap } = this.state;
-        return !!loadedRowsMap[index];
+      });
     };
 
-    renderItem({ index, key, style }) {
-        const { dataSource, loadedRowsMap } = this.state;
-        const item = dataSource[index];
+    this.state = {
+      dataSource: [],
+      loadedRowsMap: {},
+      loadingRowCount: 0,
+    };
 
-        if (!item) {
-            return;
-        }
-        const content = (
-            <List.Item
-                key={key}
-                style={style}
-                header={<Avatar color={item.color} >SE</Avatar>}
-                main={
-                    <div>
-                        <span style={{ color: 'var(--semi-color-text-0)', fontWeight: 500 }}>{item.title}</span>
-                        <p style={{ color: 'var(--semi-color-text-2)', margin: '4px 0' }}>
-                            Semi Design 设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的 Web 应用。
-                        </p>
-                    </div>
-                }
-            />
-        );
-        return content;
+    this.statusLoading = 0;
+    this.statusLoaded = 1;
+    this.loadLimit = this.data.length;
+    this.renderItem = this.renderItem.bind(this);
+    this.fetchData = this.fetchData.bind(this);
+    this.handleInfiniteOnLoad = this.handleInfiniteOnLoad.bind(this);
+    this.isRowLoaded = this.isRowLoaded.bind(this);
+  }
+
+  handleInfiniteOnLoad({ startIndex, stopIndex }) {
+    let { dataSource, loadedRowsMap, loadingRowCount } = this.state;
+    const increment = stopIndex - startIndex + 1;
+    if (stopIndex >= this.loadLimit || loadingRowCount > 0) {
+      return;
     }
-
-    render() {
-        const { dataSource } = this.state;
-        const height = 500;
-        return (
-            <List style={{ border: '1px solid var(--semi-color-border)', padding: 10 }}>
-                <InfiniteLoader
-                    isRowLoaded={this.isRowLoaded}
-                    loadMoreRows={this.handleInfiniteOnLoad}
-                    rowCount={this.loadLimit}
-                >
-                    {({ onRowsRendered, registerChild }) => (
-                        <AutoSizer disableHeight>
-                            {({ width }) => (
-                                <VList
-                                    ref={registerChild}
-                                    height={height}
-                                    onRowsRendered={onRowsRendered}
-                                    rowCount={this.loadLimit}
-                                    rowHeight={118}
-                                    rowRenderer={this.renderItem}
-                                    width={width}
-                                />
-                            )}
-                        </AutoSizer>
-                    )}
-                </InfiniteLoader>
-            </List>
-        );
+    for (let i = startIndex; i <= stopIndex; i++) {
+      loadedRowsMap[i] = this.statusLoading;
     }
+    this.setState({
+      loadingRowCount: loadingRowCount + increment,
+    });
+    return this.fetchData(startIndex, stopIndex);
+  }
+
+  isRowLoaded({ index }) {
+    const { loadedRowsMap } = this.state;
+    return !!loadedRowsMap[index];
+  }
+
+  renderItem({ index, key, style }) {
+    const { dataSource, loadedRowsMap } = this.state;
+    const item = dataSource[index];
+
+    if (!item) {
+      return;
+    }
+    const content = (
+      <List.Item
+        key={key}
+        style={style}
+        header={<Avatar color={item.color}>SE</Avatar>}
+        main={
+          <div>
+            <span style={{ color: 'var(--semi-color-text-0)', fontWeight: 500 }}>{item.title}</span>
+            <p style={{ color: 'var(--semi-color-text-2)', margin: '4px 0' }}>
+              Semi Design
+              设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的
+              Web 应用。
+            </p>
+          </div>
+        }
+      />
+    );
+    return content;
+  }
+
+  render() {
+    const { dataSource } = this.state;
+    const height = 500;
+    return (
+      <List style={{ border: '1px solid var(--semi-color-border)', padding: 10 }}>
+        <InfiniteLoader
+          isRowLoaded={this.isRowLoaded}
+          loadMoreRows={this.handleInfiniteOnLoad}
+          rowCount={this.loadLimit}
+        >
+          {({ onRowsRendered, registerChild }) => (
+            <AutoSizer disableHeight>
+              {({ width }) => (
+                <VList
+                  ref={registerChild}
+                  height={height}
+                  onRowsRendered={onRowsRendered}
+                  rowCount={this.loadLimit}
+                  rowHeight={118}
+                  rowRenderer={this.renderItem}
+                  width={width}
+                />
+              )}
+            </AutoSizer>
+          )}
+        </InfiniteLoader>
+      </List>
+    );
+  }
 }
 
+export const Virtualized = () => <VirtualizedScroll />;
 
-stories.add('virtualized', () => <VirtualizedScroll />);
+Virtualized.story = {
+  name: 'virtualized',
+};

+ 188 - 150
packages/semi-ui/locale/_story/locale.stories.js

@@ -1,7 +1,15 @@
 import React from 'react';
-import { storiesOf } from '@storybook/react';
 import { useState } from 'react';
-import { Modal, Pagination, DatePicker, TimePicker, Table, Select, Button, Cascader } from '../../index';
+import {
+  Modal,
+  Pagination,
+  DatePicker,
+  TimePicker,
+  Select,
+  Button,
+  Cascader,
+  LocaleProvider
+} from '../../index';
 
 import zh_CN from '@douyinfe/semi-ui/locale/source/zh_CN';
 import en_GB from '@douyinfe/semi-ui/locale/source/en_GB';
@@ -11,9 +19,11 @@ import ja_JP from '@douyinfe/semi-ui/locale/source/ja_JP';
 import ru_RU from '@douyinfe/semi-ui/locale/source/ru_RU';
 import vi_VN from '@douyinfe/semi-ui/locale/source/vi_VN';
 
-import { LocaleProvider } from '@douyinfe/semi-ui';
+const { Option } = Select;
 
-const stories = storiesOf('Locale', module);
+export default {
+  title: 'LocaleProvider'
+}
 // -√ Pagination
 // -√ Modal
 // -× DatePicker
@@ -25,159 +35,187 @@ const stories = storiesOf('Locale', module);
 const TableDemo = () => {};
 
 const CascaderDemo = () => {
-    const treeData = [
+  const treeData = [
+    {
+      label: '亚洲',
+      value: 'yazhou',
+      children: [
+        {
+          label: '中国',
+          value: 'zhongguo',
+          children: [
+            {
+              label: '北京',
+              value: 'beijing',
+            },
+            {
+              label: '上海',
+              value: 'shanghai',
+            },
+          ],
+        },
         {
-            label: '亚洲',
-            value: 'yazhou',
-            children: [
-                {
-                    label: '中国',
-                    value: 'zhongguo',
-                    children: [
-                        {
-                            label: '北京',
-                            value: 'beijing',
-                        },
-                        {
-                            label: '上海',
-                            value: 'shanghai',
-                        },
-                    ],
-                },
-                {
-                    label: '日本',
-                    value: 'riben',
-                    children: [
-                        {
-                            label: '大阪',
-                            value: 'daban',
-                        },
-                    ],
-                },
-            ],
+          label: '日本',
+          value: 'riben',
+          children: [
+            {
+              label: '大阪',
+              value: 'daban',
+            },
+          ],
         },
-    ];
-    return <Cascader style={{ width: 300, margin: 10 }} treeData={treeData} filterTreeNode />;
+      ],
+    },
+  ];
+  return <Cascader style={{ width: 300, margin: 10 }} treeData={treeData} filterTreeNode />;
 };
 
 const I18nComponent = () => {
-    const [modalVisible, setModalVisible] = useState(false);
-    const style = { margin: 10 };
-    return (
-        <>
-            <Pagination total={100} showTotal showSizeChanger style={style} />
-            <div style={style}>
-                <Button onClick={() => setModalVisible(true)}>Show Modal</Button>
-            </div>
-            <div style={style}>
-                <Select filter style={{ width: '180px' }}>
-                    <Option value="abc">abc</Option>
-                    <Option value="vigo" disabled>
-                        vigo
-                    </Option>
-                    <Option value="hotsoon">hotsoon</Option>
-                </Select>
-                <CascaderDemo />
-            </div>
-            <Modal
-                title="Modal"
-                visible={modalVisible}
-                onOk={() => setModalVisible(false)}
-                onCancel={() => setModalVisible(false)}
-            >
-                <p>This is the content of a basic modal.</p>
-                <p>More content...</p>
-            </Modal>
-            <DatePicker style={{ ...style, width: 200 }} />
-            <DatePicker style={{ ...style, width: 250 }} type="dateTime" />
-            <DatePicker style={{ ...style, width: 250 }} type="dateRange" />
-            <DatePicker style={{ ...style, width: 400 }} type="dateTimeRange" />
-            <TimePicker style={style} />
-            <TimePicker use12Hours style={style} />
-            <br />
-            <br />
-        </>
-    );
+  const [modalVisible, setModalVisible] = useState(false);
+  const style = { margin: 10 };
+  return (
+    <>
+      <Pagination total={100} showTotal showSizeChanger style={style} />
+      <div style={style}>
+        <Button onClick={() => setModalVisible(true)}>Show Modal</Button>
+      </div>
+      <div style={style}>
+        <Select filter style={{ width: '180px' }}>
+          <Option value="abc">abc</Option>
+          <Option value="vigo" disabled>
+            vigo
+          </Option>
+          <Option value="hotsoon">hotsoon</Option>
+        </Select>
+        <CascaderDemo />
+      </div>
+      <Modal
+        title="Modal"
+        visible={modalVisible}
+        onOk={() => setModalVisible(false)}
+        onCancel={() => setModalVisible(false)}
+      >
+        <p>This is the content of a basic modal.</p>
+        <p>More content...</p>
+      </Modal>
+      <DatePicker style={{ ...style, width: 200 }} />
+      <DatePicker style={{ ...style, width: 250 }} type="dateTime" />
+      <DatePicker style={{ ...style, width: 250 }} type="dateRange" />
+      <DatePicker style={{ ...style, width: 400 }} type="dateTimeRange" />
+      <TimePicker style={style} />
+      <TimePicker use12Hours style={style} />
+      <br />
+      <br />
+    </>
+  );
 };
 
 class I18nDemo extends React.Component {
-    constructor(props) {
-        super(props);
-        this.state = {
-            locale: zh_CN,
-        };
-        this.onLanguageChange = this.onLanguageChange.bind(this);
-    }
-
-    onLanguageChange(code) {
-        let language = {
-            zh_CN: zh_CN,
-            en_GB: en_GB,
-            ko_KR: ko_KR,
-            ja_JP: ja_JP,
-        };
-        this.setState({ locale: language[code] });
-    }
-
-    render() {
-        const { locale } = this.state;
-        return (
-            <>
-                <Select onChange={this.onLanguageChange}>
-                    <Option value="zh_CN">中文</Option>
-                    <Option value="en_GB">英语(英)</Option>
-                    <Option value="ja_JP">日语</Option>
-                    <Option value="ko_KR">韩语</Option>
-                </Select>
-                <hr />
-                <LocaleProvider locale={locale}>
-                    <I18nComponent />
-                </LocaleProvider>
-            </>
-        );
-    }
+  constructor(props) {
+    super(props);
+    this.state = {
+      locale: zh_CN,
+    };
+    this.onLanguageChange = this.onLanguageChange.bind(this);
+  }
+
+  onLanguageChange(code) {
+    let language = {
+      zh_CN: zh_CN,
+      en_GB: en_GB,
+      ko_KR: ko_KR,
+      ja_JP: ja_JP,
+    };
+    this.setState({ locale: language[code] });
+  }
+
+  render() {
+    const { locale } = this.state;
+    return (
+      <>
+        <Select onChange={this.onLanguageChange}>
+          <Option value="zh_CN">中文</Option>
+          <Option value="en_GB">英语(英)</Option>
+          <Option value="ja_JP">日语</Option>
+          <Option value="ko_KR">韩语</Option>
+        </Select>
+        <hr />
+        <LocaleProvider locale={locale}>
+          <I18nComponent />
+        </LocaleProvider>
+      </>
+    );
+  }
 }
 
-stories.add('Locale zh_CN', () => (
-    <LocaleProvider locale={zh_CN}>
-        <I18nComponent />
-    </LocaleProvider>
-));
-
-stories.add('Locale en-GB', () => (
-    <LocaleProvider locale={en_GB}>
-        <I18nComponent />
-    </LocaleProvider>
-));
-
-stories.add('Locale en-US', () => (
-    <LocaleProvider locale={en_US}>
-        <I18nComponent />
-    </LocaleProvider>
-));
-
-stories.add('Locale ja_JP', () => (
-    <LocaleProvider locale={ja_JP}>
-        <I18nComponent />
-    </LocaleProvider>
-));
-
-stories.add('Locale ko_KR', () => (
-    <LocaleProvider locale={ko_KR}>
-        <I18nComponent />
-    </LocaleProvider>
-));
-
-stories.add('Locale ru_RU', () => (
-    <LocaleProvider locale={ru_RU}>
-        <I18nComponent />
-    </LocaleProvider>
-));
-
-stories.add('Locale vi_VN', () => (
-    <LocaleProvider locale={vi_VN}>
-        <I18nComponent />
-    </LocaleProvider>
-));
-
-stories.add('Locale', () => <I18nDemo />);
+export const LocaleZhCn = () => (
+  <LocaleProvider locale={zh_CN}>
+    <I18nComponent />
+  </LocaleProvider>
+);
+
+LocaleZhCn.story = {
+  name: 'Locale zh_CN',
+};
+
+export const LocaleEnGb = () => (
+  <LocaleProvider locale={en_GB}>
+    <I18nComponent />
+  </LocaleProvider>
+);
+
+LocaleEnGb.story = {
+  name: 'Locale en-GB',
+};
+
+export const LocaleEnUs = () => (
+  <LocaleProvider locale={en_US}>
+    <I18nComponent />
+  </LocaleProvider>
+);
+
+LocaleEnUs.story = {
+  name: 'Locale en-US',
+};
+
+export const LocaleJaJp = () => (
+  <LocaleProvider locale={ja_JP}>
+    <I18nComponent />
+  </LocaleProvider>
+);
+
+LocaleJaJp.story = {
+  name: 'Locale ja_JP',
+};
+
+export const LocaleKoKr = () => (
+  <LocaleProvider locale={ko_KR}>
+    <I18nComponent />
+  </LocaleProvider>
+);
+
+LocaleKoKr.story = {
+  name: 'Locale ko_KR',
+};
+
+export const LocaleRuRu = () => (
+  <LocaleProvider locale={ru_RU}>
+    <I18nComponent />
+  </LocaleProvider>
+);
+
+LocaleRuRu.story = {
+  name: 'Locale ru_RU',
+};
+
+export const LocaleViVn = () => (
+  <LocaleProvider locale={vi_VN}>
+    <I18nComponent />
+  </LocaleProvider>
+);
+
+LocaleViVn.story = {
+  name: 'Locale vi_VN',
+};
+
+export const Locale = () => <I18nDemo />;

+ 47 - 62
packages/semi-ui/modal/Modal.tsx

@@ -8,18 +8,10 @@ import Portal from '../_portal';
 import LocaleConsumer from '../locale/localeConsumer';
 import cls from 'classnames';
 import PropTypes from 'prop-types';
-import { isUndefined } from 'lodash-es';
-import '@douyinfe/semi-foundation/modal/modal.scss';
 import { noop } from 'lodash-es';
-import ContentTransition from './ModalTransition';
+import '@douyinfe/semi-foundation/modal/modal.scss';
 import BaseComponent from '../_base/baseComponent';
-import confirm, {
-    withConfirm,
-    withError,
-    withInfo,
-    withSuccess,
-    withWarning
-} from '../modal/confirm';
+import confirm, { withConfirm, withError, withInfo, withSuccess, withWarning } from '../modal/confirm';
 import { Locale } from '../locale/interface';
 import useModal from '../modal/useModal';
 import { ButtonProps } from '../button/Button';
@@ -165,9 +157,9 @@ class Modal extends BaseComponent<ModalReactProps, ModalState> {
             notifyClose: () => {
                 this.props.afterClose();
             },
-            toggleHidden: (hidden: boolean) => {
+            toggleHidden: (hidden: boolean, callback?: (hidden: boolean) => void) => {
                 if (hidden !== this.state.hidden) {
-                    this.setState({ hidden });
+                    this.setState({ hidden }, callback || noop);
                 }
             },
             notifyFullScreen: (isFullScreen: boolean) => {
@@ -181,17 +173,11 @@ class Modal extends BaseComponent<ModalReactProps, ModalState> {
     static getDerivedStateFromProps(props: ModalReactProps, prevState: ModalState) {
         const newState: Partial<ModalState> = {};
 
-        if (props.visible && prevState.hidden) {
-            newState.hidden = false;
-        }
         if (props.fullScreen !== prevState.isFullScreen) {
             newState.isFullScreen = props.fullScreen;
         }
 
-        // if not using animation, need to update hidden state from props
-        if (!props.visible && !props.motion && !prevState.hidden) {
-            newState.hidden = true;
-        }
+
         return newState;
     }
 
@@ -252,6 +238,10 @@ class Modal extends BaseComponent<ModalReactProps, ModalState> {
         if (prevProps.visible && !this.props.visible) {
             this.foundation.afterHide();
         }
+
+        if (!this.props.motion) {
+            this.updateHiddenState();
+        }
     }
 
     componentWillUnmount() {
@@ -268,6 +258,16 @@ class Modal extends BaseComponent<ModalReactProps, ModalState> {
         this.foundation.handleOk(e);
     };
 
+    updateHiddenState = () => {
+        const { visible } = this.props;
+        const { hidden } = this.state;
+        if (!visible && !hidden) {
+            this.foundation.toggleHidden(true, () => this.foundation.afterClose());
+        } else if (visible && this.state.hidden) {
+            this.foundation.toggleHidden(false)
+        }
+    }
+
     renderFooter = (): ReactNode => {
         const {
             okText,
@@ -314,22 +314,16 @@ class Modal extends BaseComponent<ModalReactProps, ModalState> {
         );
     };
 
-    getDialog = () => {
-        const {
-            footer,
-            ...restProps
-        } = this.props;
-        const renderFooter = 'footer' in this.props ? footer : this.renderFooter();
-        return <ModalContent {...restProps} footer={renderFooter} onClose={this.handleCancel} />;
-    };
+    // getDialog = () => {
+    //     const {
+    //         footer,
+    //         ...restProps
+    //     } = this.props;
+    //     const renderFooter = 'footer' in this.props ? footer : this.renderFooter();
+    //     return <ModalContent {...restProps} footer={renderFooter} onClose={this.handleCancel}/>;
+    // };
 
-    renderDialogWithTransition = ({
-        opacity,
-        scale,
-    }: {
-        opacity?: CSSProperties['opacity'];
-        scale?: number;
-    } = {}) => {
+    renderDialog = () => {
         let {
             footer,
             className,
@@ -339,10 +333,11 @@ class Modal extends BaseComponent<ModalReactProps, ModalState> {
             style: styleFromProps,
             zIndex,
             getPopupContainer,
+            visible,
             ...restProps
         } = this.props;
-        let maskStyle = maskStyleFromProps;
         let style = styleFromProps;
+        const maskStyle = maskStyleFromProps;
         const renderFooter = 'footer' in this.props ? footer : this.renderFooter();
         if (this.props.centered) {
             style = {
@@ -350,20 +345,6 @@ class Modal extends BaseComponent<ModalReactProps, ModalState> {
                 top: '50%', ...style,
             };
         }
-        if (!isUndefined(opacity)) {
-            maskStyle = { opacity, ...maskStyle };
-            style = { opacity, ...style };
-        }
-
-        if (!isUndefined(scale)) {
-            style = { transform: `scale(${scale})`, ...style };
-            if (this.props.centered) {
-                style = {
-                    ...style,
-                    transform: `scale(${scale}) translateY(-${50 / scale}%)`,
-                };
-            }
-        }
         let wrapperStyle: {
             zIndex?: CSSProperties['zIndex'];
             position?: CSSProperties['position'];
@@ -378,18 +359,32 @@ class Modal extends BaseComponent<ModalReactProps, ModalState> {
         }
 
         const classList = cls(className, {
-            [`${cssClasses.DIALOG}-hidden`]: keepDOM && this.state.hidden,
+            [`${cssClasses.DIALOG}-displayNone`]: keepDOM && this.state.hidden && !visible,
         });
+        const contentClassName = motion ? cls({
+            [`${cssClasses.DIALOG}-content-animate-hide`]: !visible,
+            [`${cssClasses.DIALOG}-content-animate-show`]: visible
+        }) : null;
+        const maskClassName = motion ? cls({
+            [`${cssClasses.DIALOG}-mask-animate-hide`]: !visible,
+            [`${cssClasses.DIALOG}-mask-animate-show`]: visible
+        }) : null;
+
         return (
             <Portal style={wrapperStyle} getPopupContainer={getPopupContainer}>
                 <ModalContent
                     {...restProps}
                     isFullScreen={this.state.isFullScreen}
+                    contentClassName={contentClassName}
+                    maskClassName={maskClassName}
                     className={classList}
                     getPopupContainer={getPopupContainer}
                     maskStyle={maskStyle}
                     style={style}
                     ref={this.modalRef}
+                    onAnimationEnd={() => {
+                        this.updateHiddenState();
+                    }}
                     footer={renderFooter}
                     onClose={this.handleCancel}
 
@@ -405,19 +400,9 @@ class Modal extends BaseComponent<ModalReactProps, ModalState> {
             lazyRender,
         } = this.props;
         this._active = this._active || visible;
-        const shouldRender = (visible || keepDOM) && (!lazyRender || this._active);
-
-        const mergedMotion = this.foundation.getMergedMotion();
-        if (mergedMotion) {
-            return (
-                <ContentTransition motion={mergedMotion} controlled={keepDOM} visible={visible}>
-                    {shouldRender ? (...animationState) => this.renderDialogWithTransition(...animationState) : null}
-                </ContentTransition>
-            );
-        }
-
+        const shouldRender = ((visible || keepDOM) && (!lazyRender || this._active)) || !this.state.hidden;
         if (shouldRender) {
-            return this.renderDialogWithTransition();
+            return this.renderDialog();
         }
 
         return null;

+ 15 - 6
packages/semi-ui/modal/ModalContent.tsx

@@ -23,11 +23,16 @@ export default class ModalContent extends BaseComponent<ModalContentProps, Modal
     static propTypes = {
         close: PropTypes.func,
         getContainerContext: PropTypes.func,
+        contentClassName: PropTypes.string,
+        maskClassName: PropTypes.string,
+        onAnimationEnd: PropTypes.func
     };
 
     static defaultProps = {
         close: noop,
         getContainerContext: noop,
+        contentClassName: '',
+        maskClassName: ''
     };
     dialogId: string;
     private timeoutId: NodeJS.Timeout;
@@ -107,12 +112,12 @@ export default class ModalContent extends BaseComponent<ModalContentProps, Modal
 
     getMaskElement = () => {
         const { ...props } = this.props;
-        const { mask } = props;
+        const { mask, maskClassName } = props;
         if (mask) {
             const className = cls(`${cssClasses.DIALOG}-mask`, {
                 // [`${cssClasses.DIALOG}-mask-hidden`]: !props.visible,
             });
-            return <div key="mask" className={className} style={props.maskStyle} />;
+            return <div key="mask" className={cls(className, maskClassName)} style={props.maskStyle}/>;
         }
         return null;
     };
@@ -124,7 +129,7 @@ export default class ModalContent extends BaseComponent<ModalContentProps, Modal
         } = this.props;
         let closer;
         if (closable) {
-            const iconType = closeIcon || <IconClose />;
+            const iconType = closeIcon || <IconClose/>;
             closer = (
                 <Button
                     className={`${cssClasses.DIALOG}-close`}
@@ -216,8 +221,11 @@ export default class ModalContent extends BaseComponent<ModalContentProps, Modal
                 style={{ ...props.style, ...style }}
                 id={this.dialogId}
             >
-                <div className={cls([`${cssClasses.DIALOG}-content`,
-                    { [`${cssClasses.DIALOG}-content-fullScreen`]: props.isFullScreen }])}>
+                <div
+                    onAnimationEnd={props.onAnimationEnd}
+                    className={cls([`${cssClasses.DIALOG}-content`,
+                        props.contentClassName,
+                        {[`${cssClasses.DIALOG}-content-fullScreen`]: props.isFullScreen }])}>
                     {header}
                     {body}
                     {footer}
@@ -262,6 +270,7 @@ export default class ModalContent extends BaseComponent<ModalContentProps, Modal
 
         // @ts-ignore Unreachable branch
         // eslint-disable-next-line max-len
-        return containerContext && containerContext.Provider ? <containerContext.Provider value={containerContext.value}>{elem}</containerContext.Provider> : elem;
+        return containerContext && containerContext.Provider ?
+            <containerContext.Provider value={containerContext.value}>{elem}</containerContext.Provider> : elem;
     }
 }

+ 0 - 43
packages/semi-ui/modal/ModalTransition.tsx

@@ -1,43 +0,0 @@
-// @ts-ignore Temporarily do not proceed  the action package ts
-import { Transition } from '@douyinfe/semi-animation-react';
-import React, { JSXElementConstructor } from 'react';
-import { Motion } from '../_base/base';
-
-interface ContentTransitionProps {
-    // eslint-disable-next-line max-len
-    motion?: Motion<ContentTransitionProps>;
-    children?: React.ReactNode | JSXElementConstructor<any>;
-    controlled?: boolean;
-    visible?: boolean;
-}
-
-export default function ContentTransition(props: ContentTransitionProps = {}) {
-    const { motion: motionFromProps, children, controlled, visible } = props;
-    let motion = motionFromProps;
-    let extra = {};
-    if (typeof motion === 'function') {
-        motion = motion(props);
-    } else if (!motion || typeof motion !== 'object') {
-        motion = {};
-    }
-
-    if (controlled) {
-        extra = {
-            // immediate: true,
-            state: visible ? 'enter' : 'leave',
-        };
-    }
-
-    return (
-        <Transition
-            config={{ tension: 600, friction: 30 } as any}
-            from={{ scale: 0.7, opacity: { val: 0, duration: 180 } }}
-            enter={{ scale: { val: 1 }, opacity: { val: 1, duration: 90 } } as any}
-            leave={{ scale: { val: 0.7 }, opacity: { val: 0, duration: 75 } } as any}
-            {...extra}
-            {...motion}
-        >
-            {children}
-        </Transition>
-    );
-}

+ 1 - 17
packages/semi-ui/modal/__test__/modal.test.js

@@ -279,7 +279,7 @@ describe('modal', () => {
         let modal = mount(com, { attachTo: document.getElementById('container') });
         setTimeout(() => {
             modal.update();
-            expect(modal.find(`div.${BASE_CLASS_PREFIX}-modal`)).toHaveStyle({ transform: 'scale(1) translateY(-50%)', top: '50%' });
+            expect(modal.find(`div.${BASE_CLASS_PREFIX}-modal-content`)).toHaveClassName(`semi-modal-content-animate-show`);
             done();
         }, 2000);
     });
@@ -290,22 +290,6 @@ describe('modal', () => {
         expect(modal.find(`div.${BASE_CLASS_PREFIX}-modal`)).toHaveStyle({ transform: 'translateY(-50%)', top: '50%' });
     });
 
-    // didLeave motion need to call clear() in beforeEach, while other confirm tests do not need, so it is tested here
-    it('motion didLeave', (done) => {
-        let leave = () => { };
-        let spyLeave = sinon.spy(leave);
-        Modal.confirm({ 'title': 'Semi', 'content': 'Content', motion: { didLeave: spyLeave } });
-        let modal = document.querySelector(`.${BASE_CLASS_PREFIX}-modal-confirm`);
-        let btn = modal.querySelectorAll(`.${BASE_CLASS_PREFIX}-button`)
-        btn[2].click();
-        expect(spyLeave.notCalled).toBe(true);
-        setTimeout(() => {
-            debugger
-            expect(spyLeave.calledOnce).toBe(true);
-            done();
-        }, 3000);
-    });
-
     it('keepDOM', () => {
         let component = getModal({ keepDOM: true });
         let modal = mount(component, { attachTo: document.getElementById('container') });

+ 1 - 1
packages/semi-ui/modal/_story/CollapsibleInModal/index.jsx

@@ -97,4 +97,4 @@ class Demo extends React.Component {
         );
     }
 }
-export default Demo;
+export default () => <Demo />;

+ 201 - 152
packages/semi-ui/modal/_story/modal.stories.js

@@ -1,202 +1,251 @@
 import React, { useState } from 'react';
-import { storiesOf } from '@storybook/react';
 import { Select, Modal, Button, Tooltip, Popover } from '../../index';
 import CollapsibleInModal from './CollapsibleInModal';
 import DynamicContextDemo from './DynamicContext';
 
-const stories = storiesOf('Modal', module);
+export default {
+  title: 'Modal',
+  parameters: {
+    chromatic: { disableSnapshot: true },
+  },
+}
+
+export {
+  CollapsibleInModal,
+  DynamicContextDemo
+}
 
 const Option = Select.Option;
 
 const DialogComponent = props => {
-    const [visible, setVisible] = useState(false);
-
-    const handleOk = e => {
-        setVisible(false);
-    };
-
-    const handleCancel = e => {
-        setVisible(false);
-    };
-
-    return (
-        <React.Fragment>
-            <Button onClick={() => setVisible(true)}>show dialog</Button>
-            <Modal title="对话框标题" visible={visible} onOk={handleOk} onCancel={handleCancel} {...props}>
-                <input autoFocus />
-                <p>basic modal</p>
-                <Button onClick={handleCancel}>hide dialog</Button>
-            </Modal>
-        </React.Fragment>
-    );
+  const [visible, setVisible] = useState(false);
+
+  const handleOk = e => {
+    setVisible(false);
+  };
+
+  const handleCancel = e => {
+    setVisible(false);
+  };
+
+  return (
+    <React.Fragment>
+      <Button onClick={() => setVisible(true)}>show dialog</Button>
+      <Modal
+        title="对话框标题"
+        visible={visible}
+        onOk={handleOk}
+        onCancel={handleCancel}
+        {...props}
+      >
+        <input autoFocus />
+        <p>basic modal</p>
+        <Button onClick={handleCancel}>hide dialog</Button>
+      </Modal>
+    </React.Fragment>
+  );
+};
+
+export const Default = () => <DialogComponent />;
+
+Default.story = {
+  name: 'default',
 };
 
-stories.add('模态框默认', () => <DialogComponent />);
+export const ClickMaskClosableFalse = () => <DialogComponent maskClosable={false} />;
 
-stories.add('模态框-点击遮罩层不可关闭', () => <DialogComponent maskClosable={false} />);
+ClickMaskClosableFalse.story = {
+  name: 'click mask closable false',
+};
 
 function useLoading() {
-    const [loading, setLoading] = useState(false);
-    function startQuery() {
-        setLoading(true);
-    }
-    return [loading, { startQuery }];
+  const [loading, setLoading] = useState(false);
+  function startQuery() {
+    setLoading(true);
+  }
+  return [loading, { startQuery }];
 }
 
 function DialogComponentWithLoading() {
-    const [loading, actions] = useLoading();
-    return <DialogComponent confirmLoading={loading} onOk={actions.startQuery} />;
+  const [loading, actions] = useLoading();
+  return <DialogComponent confirmLoading={loading} onOk={actions.startQuery} />;
 }
 
-// button 组件的 loading ui还没有实现
-stories.add('模态框-点击确认按钮展现loading, button组件的loading没有实现,所以现在还没有', () => (
-    <DialogComponentWithLoading />
-));
+export const WithLoadingTodo = () => <DialogComponentWithLoading />;
+
+WithLoadingTodo.story = {
+  name: 'with loading todo',
+};
 
 function success() {
-    Modal.success('bla bla bla...');
+  Modal.success('bla bla bla...');
 }
 
 function info() {
-    Modal.info('info');
+  Modal.info('info');
 }
 
 function error() {
-    Modal.error({ title: 'Unfortunately, there is an error', content: 'bla bla bla...' });
+  Modal.error({ title: 'Unfortunately, there is an error', content: 'bla bla bla...' });
 }
 
 function warning() {
-    Modal.warning({ title: 'Warning: be cautious ahead', content: 'bla bla bla...' });
+  Modal.warning({ title: 'Warning: be cautious ahead', content: 'bla bla bla...' });
 }
 
 function confirm() {
-    Modal.confirm({ title: 'Are you sure ?', content: 'bla bla bla...' });
+  Modal.confirm({ title: 'Are you sure ?', content: 'bla bla bla...' });
 }
 
-stories.add('命令式调用', () => (
-    <div>
-        <Button onClick={info}>Info</Button>
-        <Button onClick={success}>Success</Button>
-        <Button onClick={error}>Error</Button>
-        <Button onClick={warning}>Warning</Button>
-        <Button onClick={confirm}>Confirm</Button>
-    </div>
-));
+export const ConfirmModal = () => (
+  <div>
+    <Button onClick={info}>Info</Button>
+    <Button onClick={success}>Success</Button>
+    <Button onClick={error}>Error</Button>
+    <Button onClick={warning}>Warning</Button>
+    <Button onClick={confirm}>Confirm</Button>
+  </div>
+);
+
+ConfirmModal.story = {
+  name: 'confirm modal',
+};
 
 const Test = () => {
-    let modal;
-
-    const showModal = () => {
-        modal = Modal.info({
-            title: '修改的标题',
-            content: (
-                <>
-                    <Button onClick={() => modal && modal.destroy()}>close</Button>
-                    <Button onClick={() => modal && modal.update({ title: 'lalala updating' })}>update</Button>
-                </>
-            ),
-        });
-    };
-
-    return <Button onClick={() => showModal()}>Info</Button>;
+  let modal;
+
+  const showModal = () => {
+    modal = Modal.info({
+      title: '修改的标题',
+      content: (
+        <>
+          <Button onClick={() => modal && modal.destroy()}>close</Button>
+          <Button onClick={() => modal && modal.update({ title: 'lalala updating' })}>
+            update
+          </Button>
+        </>
+      ),
+    });
+  };
+
+  return <Button onClick={() => showModal()}>Info</Button>;
 };
 
-stories.add('modal.destroy', () => <Test />);
+export const ModalDestroy = () => <Test />;
+
+ModalDestroy.story = {
+  name: 'modal.destroy',
+};
 
 const ScrollComponent = props => {
-    const [visible, setVisible] = useState(true);
-
-    const handleOk = e => {
-        setVisible(false);
-    };
-
-    const handleCancel = e => {
-        setVisible(false);
-    };
-
-    return (
-        <div style={{ paddingTop: 900, paddingBotttom: 800 }}>
-            <Button onClick={() => setVisible(true)}>show dialog</Button>
-            <Modal
-                id="modal-test"
-                title="对话框标题"
-                visible={visible}
-                onOk={handleOk}
-                onCancel={handleCancel}
-                {...props}
-            >
-                <Select>
-                    <Option value={1}>opt1</Option>
-                    <Option value={2}>opt2</Option>
-                    <Option value={3}>opt3</Option>
-                    <Option value={4}>opt4</Option>
-                    <Option value={5}>opt5</Option>
-                    <Option value={6}>opt6</Option>
-                </Select>
-                <Tooltip content="fefefefeef">test tooltip in modal</Tooltip>
-                <Button onClick={handleCancel}>hide dialog</Button>
-                <Popover content={'1,2,3'}>
-                    <Button>hover</Button>
-                </Popover>
-            </Modal>
-            <Select>
-                <Option value={1}>opt1</Option>
-                <Option value={2}>opt2</Option>
-                <Option value={3}>opt3</Option>
-                <Option value={4}>opt4</Option>
-                <Option value={5}>opt5</Option>
-                <Option value={6}>opt6</Option>
-            </Select>
-        </div>
-    );
+  const [visible, setVisible] = useState(true);
+
+  const handleOk = e => {
+    setVisible(false);
+  };
+
+  const handleCancel = e => {
+    setVisible(false);
+  };
+
+  return (
+    <div style={{ paddingTop: 900, paddingBotttom: 800 }}>
+      <Button onClick={() => setVisible(true)}>show dialog</Button>
+      <Modal
+        id="modal-test"
+        title="对话框标题"
+        visible={visible}
+        onOk={handleOk}
+        onCancel={handleCancel}
+        {...props}
+      >
+        <Select>
+          <Option value={1}>opt1</Option>
+          <Option value={2}>opt2</Option>
+          <Option value={3}>opt3</Option>
+          <Option value={4}>opt4</Option>
+          <Option value={5}>opt5</Option>
+          <Option value={6}>opt6</Option>
+        </Select>
+        <Tooltip content="fefefefeef">test tooltip in modal</Tooltip>
+        <Button onClick={handleCancel}>hide dialog</Button>
+        <Popover content={'1,2,3'}>
+          <Button>hover</Button>
+        </Popover>
+      </Modal>
+      <Select>
+        <Option value={1}>opt1</Option>
+        <Option value={2}>opt2</Option>
+        <Option value={3}>opt3</Option>
+        <Option value={4}>opt4</Option>
+        <Option value={5}>opt5</Option>
+        <Option value={6}>opt6</Option>
+      </Select>
+    </div>
+  );
 };
 
-stories.add('滚动', () => <ScrollComponent />);
+export const Scroll = () => <ScrollComponent />;
+
+Scroll.story = {
+  name: 'scroll',
+};
 
 const Popup = () => {
-    const [visible, setVisible] = useState(false);
-    const getContainer = () => {
-        return document.querySelector('.modal-container');
-    };
-    return (
-        <div
-            style={{
-                height: 320,
-                overflow: 'hidden',
-                position: 'relative',
-                border: '1px solid var(--semi-color-border)',
-                borderRadius: 2,
-                padding: 24,
-                textAlign: 'center',
-                background: 'var(--semi-color-fill-0)',
-            }}
-            className="modal-container"
-        >
-            <span>Render in this</span>
-            <br />
-            <br />
-            <Button onClick={() => setVisible(true)}>Open Modal</Button>
-            <Modal
-                title="渲染在指定容器内部"
-                visible={visible}
-                onCancel={() => setVisible(false)}
-                width={200}
-                // centered
-                // style={{ top: '10px' }}
-                getPopupContainer={getContainer}
-            >
-                <p>This is the content of a basic sidesheet.</p>
-                <p>Here is more content...</p>
-            </Modal>
-        </div>
-    );
+  const [visible, setVisible] = useState(false);
+  const getContainer = () => {
+    return document.querySelector('.modal-container');
+  };
+  return (
+    <div
+      style={{
+        height: 320,
+        overflow: 'hidden',
+        position: 'relative',
+        border: '1px solid var(--semi-color-border)',
+        borderRadius: 2,
+        padding: 24,
+        textAlign: 'center',
+        background: 'var(--semi-color-fill-0)',
+      }}
+      className="modal-container"
+    >
+      <span>Render in this</span>
+      <br />
+      <br />
+      <Button onClick={() => setVisible(true)}>Open Modal</Button>
+      <Modal
+        title="渲染在指定容器内部"
+        visible={visible}
+        onCancel={() => setVisible(false)}
+        width={200}
+        // centered
+        // style={{ top: '10px' }}
+        getPopupContainer={getContainer}
+      >
+        <p>This is the content of a basic sidesheet.</p>
+        <p>Here is more content...</p>
+      </Modal>
+    </div>
+  );
+};
+
+export const RenderInCustomContainer = () => <Popup />;
+
+RenderInCustomContainer.story = {
+  name: 'render in custom container',
+};
+
+export const KeepDom = () => <DialogComponent keepDOM />;
+
+KeepDom.story = {
+  name: 'keepDOM',
 };
 
-stories.add('渲染在指定容器内部', () => <Popup />);
+export const KeepDomNotLazy = () => <DialogComponent keepDOM lazyRender={false} />;
 
-stories.add(`dynamic context demo`, () => <DynamicContextDemo />);
-stories.add(`collapsible in modal`, () => <CollapsibleInModal />);
+KeepDomNotLazy.story = {
+  name: 'keepDOM && not lazy',
+};
 
-stories.add('keepDOM', () => <DialogComponent keepDOM />);
 
-stories.add('keepDOM && not lazy', () => <DialogComponent keepDOM lazyRender={false} />);

+ 286 - 218
packages/semi-ui/navigation/_story/navigation.stories.js

@@ -1,5 +1,4 @@
 import React from 'react';
-import { storiesOf } from '@storybook/react';
 
 import Nav from '..';
 import Switch from '../../switch';
@@ -13,250 +12,319 @@ import ItemsChange from './ItemsChange';
 import DisabledNav from './DisabledNav';
 import Button from '../../button';
 
-import { IconMail, IconFolder, IconGift, IconList,
-     IconFlag, IconStar, IconCloud, IconEdit,
-     IconFile,IconCamera,IconArticle,IconUser,IconAscend,IconDescend,IconSetting,IconUserGroup } from '@douyinfe/semi-icons';
+import {
+  IconMail,
+  IconFolder,
+  IconGift,
+  IconList,
+  IconFlag,
+  IconStar,
+  IconCloud,
+  IconEdit,
+  IconFile,
+  IconCamera,
+  IconArticle,
+  IconUser,
+  IconAscend,
+  IconDescend,
+  IconSetting,
+  IconUserGroup,
+} from '@douyinfe/semi-icons';
 
-const stories = storiesOf('Navigation', module);
+export default {
+  title: 'Navigation'
+}
+
+export const Default = () => {
+  return (
+    <div style={{ height: '100vh', display: 'inline-block' }}>
+      <Nav onSelect={(...args) => console.log(...args)}>
+        <Nav.Item itemKey={'1'} text={'Option 1'} icon={<IconMail />} />
+        <Nav.Sub text={'Group 2'} icon={<IconFolder />} stayWhenClick={true} itemKey={'2'}>
+          {['2-1', '2-2'].map(k => (
+            <Nav.Item key={k} itemKey={String(k)} text={'Option ' + k} />
+          ))}
+          <Nav.Item itemKey={'2-3'} text={'Option 2-3'} />
+          <Nav.Sub text={'Group 2-4'} itemKey={'2-4'}>
+            <Nav.Item itemKey={'2-4-1'} text={'Option 2-3-1'} />
+            <Nav.Item itemKey={'2-4-2'} text={'Option 2-3-2'} />
+          </Nav.Sub>
+        </Nav.Sub>
+        <Nav.Item key={3} itemKey={'3'} text={'Option 3'} icon={<IconGift />} />
+        <Nav.Item key={4} itemKey={'4'} text={'Option 4'} icon={<IconList />} />
+        <Nav.Sub text={'Group 5'} icon={<IconFlag />} stayWhenClick={true} itemKey={'5'}>
+          {['5-1', '5-2'].map(k => (
+            <Nav.Item key={k} itemKey={String(k)} text={'Option ' + k} />
+          ))}
+        </Nav.Sub>
+        <Nav.Item itemKey={'6'} text={'Option 6 (with link)'} icon={<IconStar />} link="/star" />
+        <Nav.Sub text={'Group 7'} icon={<IconFolder />} stayWhenClick={true} itemKey={'7'}>
+          {['7-1', '7-2'].map(k => (
+            <Nav.Item
+              key={k}
+              itemKey={String(k)}
+              text={'Option ' + k + ' (with link)'}
+              link={`folder/${k}`}
+            />
+          ))}
+          <Nav.Item itemKey={'7-3'} text={'Option 7-3'} />
+        </Nav.Sub>
+      </Nav>
+    </div>
+  );
+};
 
-// stories.addDecorator(withKnobs);;
+Default.story = {
+  name: 'default',
+};
+
+class NavApp extends React.Component {
+  state = {
+    isCollapsed: true,
+  };
 
-stories.add('普通导航', () => {
+  updateCollapsed = isCollapsed => {
+    this.setState({ isCollapsed });
+  };
+
+  render() {
+    let { isCollapsed } = this.state;
     return (
-        <div style={{ height: '100vh', display: 'inline-block' }}>
-            <Nav onSelect={(...args) => console.log(...args)}>
-                <Nav.Item itemKey={'1'} text={'Option 1'} icon={<IconMail />} />
-                <Nav.Sub text={'Group 2'} icon={<IconFolder />} stayWhenClick={true} itemKey={'2'}>
-                    {['2-1', '2-2'].map(k => (
-                        <Nav.Item key={k} itemKey={String(k)} text={'Option ' + k} />
-                    ))}
-                    <Nav.Item itemKey={'2-3'} text={'Option 2-3'} />
-                    <Nav.Sub text={'Group 2-4'} itemKey={'2-4'}>
-                        <Nav.Item itemKey={'2-4-1'} text={'Option 2-3-1'} />
-                        <Nav.Item itemKey={'2-4-2'} text={'Option 2-3-2'} />
-                    </Nav.Sub>
-                </Nav.Sub>
-                <Nav.Item key={3} itemKey={'3'} text={'Option 3'} icon={<IconGift />} />
-                <Nav.Item key={4} itemKey={'4'} text={'Option 4'} icon={<IconList />} />
-                <Nav.Sub text={'Group 5'} icon={<IconFlag />} stayWhenClick={true} itemKey={'5'}>
-                    {['5-1', '5-2'].map(k => (
-                        <Nav.Item key={k} itemKey={String(k)} text={'Option ' + k} />
-                    ))}
-                </Nav.Sub>
-                <Nav.Item itemKey={'6'} text={'Option 6 (with link)'} icon={<IconStar />} link="/star" />
-                <Nav.Sub text={'Group 7'} icon={<IconFolder />} stayWhenClick={true} itemKey={'7'}>
-                    {['7-1', '7-2'].map(k => (
-                        <Nav.Item key={k} itemKey={String(k)} text={'Option ' + k + ' (with link)'} link={`folder/${k}`} />
-                    ))}
-                    <Nav.Item itemKey={'7-3'} text={'Option 7-3'} />
-                </Nav.Sub>
-            </Nav>
+      <div style={{ height: '100vh', display: 'inline-block' }}>
+        <div>
+          {'收起到左侧'}
+          <Switch defaultChecked={isCollapsed} onChange={v => this.updateCollapsed(v)} />
         </div>
+        <Nav isCollapsed={isCollapsed}>
+          <Nav.Item itemKey={'1'} text={'Option 1'} icon={<IconCloud />} />
+          <Nav.Sub text={'Group 2'} icon={<IconEdit />} stayWhenClick={true}>
+            {['2-1', '2-2'].map(k => (
+              <Nav.Item key={k} itemKey={String(k)} text={'Option ' + k} />
+            ))}
+            <Nav.Sub text={'Group 2-3'} icon={<IconFile />}>
+              <Nav.Item itemKey={'2-3-1'} text={'Option 2-3-1'} />
+              <Nav.Item itemKey={'2-3-2'} text={'Option 2-3-2'} />
+            </Nav.Sub>
+          </Nav.Sub>
+          <Nav.Item key={3} itemKey={'3'} text={'Option 3'} icon={<IconCamera />} />
+          <Nav.Item key={4} itemKey={'4'} text={'Option 4'} icon={<IconArticle />} />
+          <Nav.Sub text={'Group 5'} stayWhenClick={true} icon={<IconFolder />}>
+            {['5-1', '5-2'].map(k => (
+              <Nav.Item key={k} itemKey={String(k)} text={'Option ' + k} />
+            ))}
+          </Nav.Sub>
+        </Nav>
+      </div>
     );
-});
+  }
+}
 
-class NavApp extends React.Component {
-    state = {
-        isCollapsed: true,
-    };
+export const CollapseExpand = () => <NavApp />;
 
-    updateCollapsed = isCollapsed => {
-        this.setState({ isCollapsed });
-    };
+CollapseExpand.story = {
+  name: 'collapse/expand',
+};
 
-    render() {
-        let { isCollapsed } = this.state;
-        return (
-            <div style={{ height: '100vh', display: 'inline-block' }}>
-                <div>
-                    {'收起到左侧'}
-                    <Switch defaultChecked={isCollapsed} onChange={v => this.updateCollapsed(v)} />
-                </div>
-                <Nav isCollapsed={isCollapsed}>
-                    <Nav.Item itemKey={'1'} text={'Option 1'} icon={<IconCloud />} />
-                    <Nav.Sub text={'Group 2'} icon={<IconEdit />} stayWhenClick={true}>
-                        {['2-1', '2-2'].map(k => (
-                            <Nav.Item key={k} itemKey={String(k)} text={'Option ' + k} />
-                        ))}
-                        <Nav.Sub text={'Group 2-3'} icon={<IconFile />}>
-                            <Nav.Item itemKey={'2-3-1'} text={'Option 2-3-1'} />
-                            <Nav.Item itemKey={'2-3-2'} text={'Option 2-3-2'} />
-                        </Nav.Sub>
-                    </Nav.Sub>
-                    <Nav.Item key={3} itemKey={'3'} text={'Option 3'} icon={<IconCamera />} />
-                    <Nav.Item key={4} itemKey={'4'} text={'Option 4'} icon={<IconArticle />} />
-                    <Nav.Sub text={'Group 5'} stayWhenClick={true} icon={<IconFolder />}>
-                        {['5-1', '5-2'].map(k => (
-                            <Nav.Item key={k} itemKey={String(k)} text={'Option ' + k} />
-                        ))}
-                    </Nav.Sub>
-                </Nav>
-            </div>
-        );
-    }
-}
+export const ConfigItems = () => (
+  <div style={{ border: '1px solid black', height: '100vh', display: 'inline-block' }}>
+    <Nav
+      items={[
+        { itemKey: 'user', text: '用户管理', icon: <IconUser />, link: '/user' },
+        { itemKey: 'union', text: '公会中心', icon: <IconUser />, link: '/star' },
+        {
+          text: '任务平台',
+          icon: <IconSetting />,
+          itemKey: 'job',
+          items: ['任务管理', '用户任务查询'],
+        },
+      ]}
+      onSelect={key => console.log(key)}
+    />
+  </div>
+);
 
-stories.add('收起/展开导航', () => <NavApp />);
+ConfigItems.story = {
+  name: 'config items',
+};
 
-stories.add('基于配置渲染的导航', () => (
-    <div style={{ border: '1px solid black', height: '100vh', display: 'inline-block' }}>
-        <Nav
-            items={[
-                { itemKey: 'user', text: '用户管理', icon: <IconUser />, link: '/user' },
-                { itemKey: 'union', text: '公会中心', icon: <IconUser />, link: '/star' },
-                {
-                    text: '任务平台',
-                    icon: <IconSetting />,
-                    itemKey: 'job',
-                    items: ['任务管理', '用户任务查询'],
-                },
-            ]}
-            onSelect={key => console.log(key)}
-        />
-    </div>
-));
+export const Horizontal = () => (
+  <div>
+    <Nav
+      mode="horizontal"
+      items={[
+        '1',
+        { itemKey: '2', text: 'Option 2 Option 2 Option 2 Option 2', icon: <IconCamera /> },
+        {
+          text: 'Group 3',
+          itemKey: '3',
+          icon: <IconFile />,
+          items: ['3-1', '3-2', { text: 'Group 3-3', items: ['3-3-1', '3-3-2'] }],
+        },
+      ]}
+      onSelect={key => console.log(key)}
+    />
+  </div>
+);
 
-stories.add('横向导航', () => (
-    <div>
-        <Nav
-            mode="horizontal"
-            items={[
-                '1',
-                { itemKey: '2', text: 'Option 2 Option 2 Option 2 Option 2', icon: <IconCamera /> },
-                {
-                    text: 'Group 3',
-                    itemKey: '3',
-                    icon: <IconFile />,
-                    items: ['3-1', '3-2', { text: 'Group 3-3', items: ['3-3-1', '3-3-2'] }],
-                },
-            ]}
-            onSelect={key => console.log(key)}
-        />
-    </div>
-));
+Horizontal.story = {
+  name: 'horizontal',
+};
 
 class Demo extends React.Component {
-    constructor() {
-        super();
-        this.state = {
-            isCollapsed: false,
-            defaultOpenKeys: ['2', '2-3'],
-            mode: 'vertical',
-            navHeight: '100vh',
-        };
-    }
+  constructor() {
+    super();
+    this.state = {
+      isCollapsed: false,
+      defaultOpenKeys: ['2', '2-3'],
+      mode: 'vertical',
+      navHeight: '100vh',
+    };
+  }
 
-    updateCollapsed(isCollapsed) {
-        this.setState({ isCollapsed });
-    }
+  updateCollapsed(isCollapsed) {
+    this.setState({ isCollapsed });
+  }
 
-    render() {
-        let { isCollapsed, defaultOpenKeys, mode, navHeight } = this.state;
-        let logo = '//lf1-cdn-tos.bytescm.com/obj/ttfe/ies/semi/logo_huoshan.png';
-        let testIcon = '//lf1-cdn-tos.bytescm.com/obj/mosaic-legacy/da9d0015af0f09667998';
-        let vigoIcon = '//lf1-cdn-tos.bytescm.com/obj/mosaic-legacy/504100070cbe0498d66f';
-        return (
-            <div>
-                <Nav
-                    isCollapsed={isCollapsed}
-                    defaultOpenKeys={defaultOpenKeys}
-                    style={{ height: navHeight }}
-                    mode={mode}
-                >
-                    <Nav.Header logo={<img src={logo} />} text="互娱运营" />
-                    <Nav.Item
-                        itemKey={'1'}
-                        text={<strong>火山运营</strong>}
-                        icon={<img width="20" height="20" src={vigoIcon} />}
-                    />
-                    <Nav.Sub
-                        itemKey={'2'}
-                        text={<span>抖音运营</span>}
-                        icon={<img width="20" height="20" src={testIcon} />}
-                        stayWhenClick={true}
-                    >
-                        {['2-1', '2-2'].map(k => (
-                            <Nav.Item key={k} itemKey={String(k)} text={'Option ' + k} />
-                        ))}
-                    </Nav.Sub>
-                    <Nav.Footer>
-                        <Button
-                            title="展开/收起切换"
-                            icon={isCollapsed ? <IconAscend /> : <IconDescend />}
-                            onClick={() => this.updateCollapsed(!isCollapsed)}
-                        />
-                    </Nav.Footer>
-                </Nav>
-            </div>
-        );
-    }
+  render() {
+    let { isCollapsed, defaultOpenKeys, mode, navHeight } = this.state;
+    let logo = '//lf1-cdn-tos.bytescm.com/obj/ttfe/ies/semi/logo_huoshan.png';
+    let testIcon = '//lf1-cdn-tos.bytescm.com/obj/mosaic-legacy/da9d0015af0f09667998';
+    let vigoIcon = '//lf1-cdn-tos.bytescm.com/obj/mosaic-legacy/504100070cbe0498d66f';
+    return (
+      <div>
+        <Nav
+          isCollapsed={isCollapsed}
+          defaultOpenKeys={defaultOpenKeys}
+          style={{ height: navHeight }}
+          mode={mode}
+        >
+          <Nav.Header logo={<img src={logo} />} text="互娱运营" />
+          <Nav.Item
+            itemKey={'1'}
+            text={<strong>火山运营</strong>}
+            icon={<img width="20" height="20" src={vigoIcon} />}
+          />
+          <Nav.Sub
+            itemKey={'2'}
+            text={<span>抖音运营</span>}
+            icon={<img width="20" height="20" src={testIcon} />}
+            stayWhenClick={true}
+          >
+            {['2-1', '2-2'].map(k => (
+              <Nav.Item key={k} itemKey={String(k)} text={'Option ' + k} />
+            ))}
+          </Nav.Sub>
+          <Nav.Footer>
+            <Button
+              title="展开/收起切换"
+              icon={isCollapsed ? <IconAscend /> : <IconDescend />}
+              onClick={() => this.updateCollapsed(!isCollapsed)}
+            />
+          </Nav.Footer>
+        </Nav>
+      </div>
+    );
+  }
 }
-stories.add('配logo,展开/收起切换', () => <Demo />);
+export const ExpandCollapseWithLogo = () => <Demo />;
+
+ExpandCollapseWithLogo.story = {
+  name: 'expand collapse with logo',
+};
 
 class HorizontalDemo extends React.Component {
-    render() {
-        return (
-            <div style={{ width: '100%' }}>
-                <Nav
-                    bodyStyle={{ height: 320 }}
-                    items={[
-                        { itemKey: 'user', text: '用户管理', icon: <IconUser /> },
-                        { itemKey: 'union', text: '公会中心', icon: <IconStar /> },
-                        {
-                            itemKey: 'union-management',
-                            text: '公会管理',
-                            icon: <IconUserGroup />,
-                            items: ['公告设置', '公会查询', '信息录入'],
-                        },
-                        {
-                            itemKey: 'approve-management',
-                            text: '审批管理',
-                            icon: <IconEdit />,
-                            items: [
-                                '入驻审核',
-                                {
-                                    itemKey: 'operation-management',
-                                    text: '运营管理',
-                                    items: ['人员管理', '人员变更'],
-                                },
-                            ],
-                        },
-                        {
-                            text: '任务平台',
-                            icon: <IconSetting />,
-                            itemKey: 'job',
-                            items: ['任务管理', '用户任务查询'],
-                        },
-                    ]}
-                    onSelect={key => console.log(key)}
-                    header={{
-                        logo: <img src="https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/webcast_logo.svg" />,
-                        text: '直播运营后台',
-                    }}
-                    footer={{
-                        collapseButton: true,
-                    }}
-                />
-            </div>
-        );
-    }
+  render() {
+    return (
+      <div style={{ width: '100%' }}>
+        <Nav
+          bodyStyle={{ height: 320 }}
+          items={[
+            { itemKey: 'user', text: '用户管理', icon: <IconUser /> },
+            { itemKey: 'union', text: '公会中心', icon: <IconStar /> },
+            {
+              itemKey: 'union-management',
+              text: '公会管理',
+              icon: <IconUserGroup />,
+              items: ['公告设置', '公会查询', '信息录入'],
+            },
+            {
+              itemKey: 'approve-management',
+              text: '审批管理',
+              icon: <IconEdit />,
+              items: [
+                '入驻审核',
+                {
+                  itemKey: 'operation-management',
+                  text: '运营管理',
+                  items: ['人员管理', '人员变更'],
+                },
+              ],
+            },
+            {
+              text: '任务平台',
+              icon: <IconSetting />,
+              itemKey: 'job',
+              items: ['任务管理', '用户任务查询'],
+            },
+          ]}
+          onSelect={key => console.log(key)}
+          header={{
+            logo: (
+              <img src="https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/webcast_logo.svg" />
+            ),
+            text: '直播运营后台',
+          }}
+          footer={{
+            collapseButton: true,
+          }}
+        />
+      </div>
+    );
+  }
 }
-stories.add('配logo,横向导航栏', () => <HorizontalDemo />);
+export const HorizontalWithLogo = () => <HorizontalDemo />;
 
-stories.add('auto open', () => <AutoOpenDemo />);
+HorizontalWithLogo.story = {
+  name: 'horizontal with logo',
+};
 
-stories.add(`link nav`, () => <LinkNavDemo />);
+export const AutoOpen = () => <AutoOpenDemo />;
 
-stories.add(`mount unmount`, () => <MountUnmount />);
+AutoOpen.story = {
+  name: 'auto open',
+};
 
-stories.add(`controlled selected keys`, () => <ControlledSelectedKeys />);
+export const LinkNav = () => <LinkNavDemo />;
+LinkNav.story = {
+  name: 'link nav',
+}
 
-stories.add(`with router`, () => <WithRouter />);
+export const MountUnmountDemo = () => <MountUnmount />;
+MountUnmountDemo.story = {
+  name: 'mount unmount'
+}
 
-stories.add(`with children`, () => <WithChildren />);
+export const ControlledSelectedKeysDemo = () => <ControlledSelectedKeys />;
+ControlledSelectedKeysDemo.story = {
+  name: 'controlled selected keys'
+};
 
-stories.add(`nav cannot set item to 0 dynaicly`, () => <ItemsChange />);
+export const WithRouterDemo = () => <WithRouter />;
+WithRouter.story = {
+  name: 'with router'
+};
 
-stories.add(`disabled nav`, () => <DisabledNav />);
+export const WithChildrenDemo = () => <WithChildren />;
+WithChildrenDemo.story = {
+  name: 'with children'
+}
 
+export const ItemsChangeDemo = () => <ItemsChange />;
+ItemsChangeDemo.story = {
+  name: 'nav cannot set item to 0 dynamically'
+};
 
+export const DisabledNavDemo = () => <DisabledNav />;
+DisabledNavDemo.story = {
+  name: 'disabled nav'
+}

+ 195 - 162
packages/semi-ui/notification/_story/notification.stories.js

@@ -1,192 +1,225 @@
 import React from 'react';
-import { storiesOf } from '@storybook/react';
-// import { withKnobs, text, boolean } from '@storybook/addon-knobs';
-import withPropsCombinations from 'react-storybook-addon-props-combinations';
-import {IconWifi, IconToutiaoLogo} from '@douyinfe/semi-icons';
 
+import { IconWifi, IconToutiaoLogo } from '@douyinfe/semi-icons';
 import Notification from '../index';
-
 import Button from '@douyinfe/semi-ui/button/index';
-
 import UseNotificationDemo from './useNotification';
 
-const stories = storiesOf('Notification', module);
+export default {
+  title: 'Notification',
+  parameters: {
+    chromatic: { disableSnapshot: true },
+  },
+}
 
-// stories.addDecorator(withKnobs);;
 
 let noticeIds = [];
 const fnc = () => {
-    let id = Notification.info({ content: '0', duration: 0 });
-    noticeIds.push(id);
+  let id = Notification.info({ content: '0', duration: 0 });
+  noticeIds.push(id);
 };
 
 const remove = () => {
-    let id = noticeIds[0];
-    console.log(noticeIds);
-    Notification.close(id);
-    noticeIds = noticeIds.filter(key => id !== key);
+  let id = noticeIds[0];
+  console.log(noticeIds);
+  Notification.close(id);
+  noticeIds = noticeIds.filter(key => id !== key);
 };
 
 let pos = ['topRight', 'topLeft', 'bottomRight', 'bottomLeft'];
 let opts = {
-    title: 'Title ies',
-    content: 'Hi,Bytedance dance dance dance dance dance dance dance dance dance dance dance dance dance dance dance',
-    duration: 3,
+  title: 'Title ies',
+  content:
+    'Hi,Bytedance dance dance dance dance dance dance dance dance dance dance dance dance dance dance dance',
+  duration: 3,
 };
 
 function randomPos() {
-    return pos[Math.floor(Math.random() * pos.length)];
+  return pos[Math.floor(Math.random() * pos.length)];
 }
-stories.add('notification', () => (
-    <div>
-        <Button
-            type="primary"
-            onClick={() => Notification.info({ ...opts, content: '我三秒后会被关闭', position: randomPos() })}
-        >
-            After 3s
-        </Button>
-        <Button type="primary" onClick={() => Notification.open({ ...opts, duration: 2, position: 'topRight' })}>
-            After 2s
-        </Button>
-    </div>
-));
-
-stories.add('manaul open & close', () => (
-    <div>
-        <Button type="primary" onClick={fnc}>
-            Duration:0
-        </Button>
-        <Button type="primary" onClick={remove}>
-            remove duration:
-        </Button>
-    </div>
-));
-
-stories.add('不同位置', () => {
-    let opts = {
-        duration: 0,
-        position: 'topRight',
-        content: 'semi-ui-notification',
-        title: 'Hi bytedance',
-    };
-    return (
-        <>
-            <Button onClick={() => Notification.info({ ...opts, position: 'top' })}>top</Button>
-            <Button onClick={() => Notification.info({ ...opts, position: 'topLeft' })}>topLeft</Button>
-            <Button onClick={() => Notification.info(opts)}>topRight</Button>
-            <Button onClick={() => Notification.info({ ...opts, position: 'bottom' })}>bottom</Button>
-            <Button onClick={() => Notification.info({ ...opts, position: 'bottomRight' })}>bottomRight</Button>
-            <Button onClick={() => Notification.info({ ...opts, position: 'bottomLeft' })}>bottomLeft</Button>
-        </>
-    );
-});
-
-stories.add('自定义icon', () => {
-    let opts = {
-        duration: 0,
-        position: 'topRight',
-        content: 'semi-ui-notification',
-        title: 'Hi bytedance',
-    };
-    return (
-        <>
-            <Button onClick={() => Notification.info({ ...opts, position: 'top' })}>info</Button>
-            <Button onClick={() => Notification.warning({ ...opts, position: 'top' })}>warning</Button>
-            <Button
-                onClick={() =>
-                    Notification.info({ ...opts, position: 'top', icon: <IconWifi style={{color: 'green'}} /> })
-                }
-            >
-                wifi
-            </Button>
-            <Button
-                onClick={() =>
-                    Notification.info({
-                        ...opts,
-                        position: 'bottomLeft',
-                        icon: <IconToutiaoLogo style={{ color: 'red' }} />,
-                    })
-                }
-            >
-                toutiao
-            </Button>
-        </>
-    );
-});
-
-stories.add('事件', () => {
-    let opts = {
-        duration: 0,
-        position: 'topRight',
-        content: 'semi-ui-notification',
-        title: 'Hi bytedance',
-        onClick: e => console.log('clicking'),
-        onClose: e => console.log('closing da da da...'),
-        onCloseClick: e => console.log('you closed me'),
-    };
-    return (
-        <>
-            <Button onClick={() => Notification.info({ ...opts, position: 'top' })}>info</Button>
-            <Button onClick={() => Notification.warning({ ...opts, position: 'top' })}>warning</Button>
-            <Button
-                onClick={() =>
-                    Notification.info({ ...opts, position: 'top', icon: <IconWifi style={{color: 'green'}} /> })
-                }
-            >
-                wifi
-            </Button>
-            <Button
-                onClick={() =>
-                    Notification.info({
-                        ...opts,
-                        position: 'bottomLeft',
-                        icon: <IconToutiaoLogo style={{ color: 'red' }} />,
-                    })
-                }
-            >
-                toutiao
-            </Button>
-        </>
-    );
-});
 
-class Demo extends React.Component {
-    constructor() {
-        super();
-        this.state = { test: 0 };
-        this.onClick = this.onClick.bind(this);
-    }
+export const _Notification = () => (
+  <div>
+    <Button
+      type="primary"
+      onClick={() =>
+        Notification.info({ ...opts, content: '我三秒后会被关闭', position: randomPos() })
+      }
+    >
+      After 3s
+    </Button>
+    <Button
+      type="primary"
+      onClick={() => Notification.open({ ...opts, duration: 2, position: 'topRight' })}
+    >
+      After 2s
+    </Button>
+  </div>
+);
+
+_Notification.story = {
+  name: 'notification',
+};
+
+export const ManaulOpenClose = () => (
+  <div>
+    <Button type="primary" onClick={fnc}>
+      Duration:0
+    </Button>
+    <Button type="primary" onClick={remove}>
+      remove duration:
+    </Button>
+  </div>
+);
+
+ManaulOpenClose.story = {
+  name: 'manaul open & close',
+};
 
-    componentDidMount() {
-        this.onClick();
-    }
+export const Position = () => {
+  let opts = {
+    duration: 0,
+    position: 'topRight',
+    content: 'semi-ui-notification',
+    title: 'Hi bytedance',
+  };
+  return (
+    <>
+      <Button onClick={() => Notification.info({ ...opts, position: 'top' })}>top</Button>
+      <Button onClick={() => Notification.info({ ...opts, position: 'topLeft' })}>topLeft</Button>
+      <Button onClick={() => Notification.info(opts)}>topRight</Button>
+      <Button onClick={() => Notification.info({ ...opts, position: 'bottom' })}>bottom</Button>
+      <Button onClick={() => Notification.info({ ...opts, position: 'bottomRight' })}>
+        bottomRight
+      </Button>
+      <Button onClick={() => Notification.info({ ...opts, position: 'bottomLeft' })}>
+        bottomLeft
+      </Button>
+    </>
+  );
+};
+
+export const CustomIcon = () => {
+  let opts = {
+    duration: 0,
+    position: 'topRight',
+    content: 'semi-ui-notification',
+    title: 'Hi bytedance',
+  };
+  return (
+    <>
+      <Button onClick={() => Notification.info({ ...opts, position: 'top' })}>info</Button>
+      <Button onClick={() => Notification.warning({ ...opts, position: 'top' })}>warning</Button>
+      <Button
+        onClick={() =>
+          Notification.info({
+            ...opts,
+            position: 'top',
+            icon: <IconWifi style={{ color: 'green' }} />,
+          })
+        }
+      >
+        wifi
+      </Button>
+      <Button
+        onClick={() =>
+          Notification.info({
+            ...opts,
+            position: 'bottomLeft',
+            icon: <IconToutiaoLogo style={{ color: 'red' }} />,
+          })
+        }
+      >
+        toutiao
+      </Button>
+    </>
+  );
+};
+
+export const EventDemo = () => {
+  let opts = {
+    duration: 0,
+    position: 'topRight',
+    content: 'semi-ui-notification',
+    title: 'Hi bytedance',
+    onClick: e => console.log('clicking'),
+    onClose: e => console.log('closing da da da...'),
+    onCloseClick: e => console.log('you closed me'),
+  };
+  return (
+    <>
+      <Button onClick={() => Notification.info({ ...opts, position: 'top' })}>info</Button>
+      <Button onClick={() => Notification.warning({ ...opts, position: 'top' })}>warning</Button>
+      <Button
+        onClick={() =>
+          Notification.info({
+            ...opts,
+            position: 'top',
+            icon: <IconWifi style={{ color: 'green' }} />,
+          })
+        }
+      >
+        wifi
+      </Button>
+      <Button
+        onClick={() =>
+          Notification.info({
+            ...opts,
+            position: 'bottomLeft',
+            icon: <IconToutiaoLogo style={{ color: 'red' }} />,
+          })
+        }
+      >
+        toutiao
+      </Button>
+    </>
+  );
+};
 
-    onClick() {
+class Demo extends React.Component {
+  constructor() {
+    super();
+    this.state = { test: 0 };
+    this.onClick = this.onClick.bind(this);
+  }
+
+  componentDidMount() {
+    this.onClick();
+  }
+
+  onClick() {
+    this.setState(
+      {
+        test: 1,
+      },
+      () => {
         this.setState(
-            {
-                test: 1,
-            },
-            () => {
-                this.setState(
-                    {
-                        test: 2,
-                    },
-                    () => {
-                        this.id = Notification.success({
-                            title: 'success',
-                            duration: 3,
-                        });
-                    }
-                );
-            }
+          {
+            test: 2,
+          },
+          () => {
+            this.id = Notification.success({
+              title: 'success',
+              duration: 3,
+            });
+          }
         );
-    }
+      }
+    );
+  }
 
-    render() {
-        return <Button>test</Button>;
-    }
+  render() {
+    return <Button>test</Button>;
+  }
 }
 
-stories.add('useNotification demo', () => <UseNotificationDemo />);
+export const _UseNotificationDemo = () => <UseNotificationDemo />;
 
-stories.add('二次异步回调', () => <Demo />);
+_UseNotificationDemo.story = {
+  name: 'useNotification demo',
+};
+
+export const AsyncCallback = () => <Demo />;
+AsyncCallback.story = {
+  name: '二次异步回调'
+}

+ 313 - 254
packages/semi-ui/overflowList/_story/overflowList.stories.js

@@ -1,297 +1,356 @@
 import React, { useState } from 'react';
-import { storiesOf } from '@storybook/react';
 import { Icon, Tag, Table, Slider } from '../../index';
 import OverflowList from '..';
-import { IconAlarm, IconCamera, IconBookmark, IconDuration, IconEdit, IconFolder, IconFolderOpen, IconBolt } from '@douyinfe/semi-icons';
+import {
+  IconAlarm,
+  IconCamera,
+  IconBookmark,
+  IconDuration,
+  IconEdit,
+  IconFolder,
+  IconFolderOpen,
+  IconBolt,
+} from '@douyinfe/semi-icons';
 
-const stories = storiesOf('OverflowList', module);
-
-// stories.addDecorator(withKnobs);;
+export default {
+  title: 'OverflowList'
+}
 
 const ITEMS = [
-    { icon: <IconFolderOpen />, key: "All" },
-    { icon: <IconFolderOpen />, key: "Users" },
-    { icon: <IconFolderOpen />, key: "Janet" },
-    { href: "#", icon: <IconFolderOpen />, key: "Photos" },
-    { href: "#", icon: <IconFolderOpen />, key: "Wednesday" },
-    { icon: <IconBolt />, key: "image", current: true },
+  { icon: <IconFolderOpen />, key: 'All' },
+  { icon: <IconFolderOpen />, key: 'Users' },
+  { icon: <IconFolderOpen />, key: 'Janet' },
+  { href: '#', icon: <IconFolderOpen />, key: 'Photos' },
+  { href: '#', icon: <IconFolderOpen />, key: 'Wednesday' },
+  { icon: <IconBolt />, key: 'image', current: true },
 ];
 
 class Demo extends React.Component {
-    renderOverflow = (items) => {
-        // console.log('overflow items: ', items);
-        return (<Tag>{items.length}</Tag>)
-    }
-    renderItem = (item, ind) => {
-        // console.log('visible item: ', item);
-        return (<span key={item.key} style={{ marginRight: 8 }}>{item.key}</span>)
-    }
-    render() {
-        return (
-            <div style={{ width: '30%' }}>
-                <OverflowList
-                    items={ITEMS}
-                    overflowRenderer={this.renderOverflow}
-                    visibleItemRenderer={this.renderItem}
-                />
-            </div>
-        );
-    }
+  renderOverflow = items => {
+    // console.log('overflow items: ', items);
+    return <Tag>{items.length}</Tag>;
+  };
+  renderItem = (item, ind) => {
+    // console.log('visible item: ', item);
+    return (
+      <span key={item.key} style={{ marginRight: 8 }}>
+        {item.key}
+      </span>
+    );
+  };
+  render() {
+    return (
+      <div style={{ width: '30%' }}>
+        <OverflowList
+          items={ITEMS}
+          overflowRenderer={this.renderOverflow}
+          visibleItemRenderer={this.renderItem}
+        />
+      </div>
+    );
+  }
 }
 
-stories.add('a simple overflow list', () => <Demo />);
+export const ASimpleOverflowList = () => <Demo />;
+
+ASimpleOverflowList.story = {
+  name: 'a simple semi overflow list',
+};
 
 class StartCollapse extends React.Component {
-    renderOverflow = (items) => {
-        // console.log('overflow items: ', items);
-        return (<Tag>{items.length}</Tag>)
-    }
-    renderItem = (item, ind) => {
-        // console.log('visible item: ', item);
-        return (<span key={item.key} style={{ marginRight: 8 }}>{item.key}</span>)
-    }
-    render() {
-        return (
-            <div style={{ width: '30%' }}>
-                <OverflowList
-                    items={ITEMS}
-                    collapseFrom="start"
-                    overflowRenderer={this.renderOverflow}
-                    visibleItemRenderer={this.renderItem}
-                />
-            </div>
-        );
-    }
+  renderOverflow = items => {
+    // console.log('overflow items: ', items);
+    return <Tag>{items.length}</Tag>;
+  };
+  renderItem = (item, ind) => {
+    // console.log('visible item: ', item);
+    return (
+      <span key={item.key} style={{ marginRight: 8 }}>
+        {item.key}
+      </span>
+    );
+  };
+  render() {
+    return (
+      <div style={{ width: '30%' }}>
+        <OverflowList
+          items={ITEMS}
+          collapseFrom="start"
+          overflowRenderer={this.renderOverflow}
+          visibleItemRenderer={this.renderItem}
+        />
+      </div>
+    );
+  }
 }
 
-stories.add('collapse from start', () => <StartCollapse />);
+export const CollapseFromStart = () => <StartCollapse />;
+
+CollapseFromStart.story = {
+  name: 'collapse from start',
+};
 
 class MinCollapse extends React.Component {
-    renderOverflow = (items) => {
-        // console.log('overflow items: ', items);
-        return (<Tag>{items.length}</Tag>)
-    }
-    renderItem = (item, ind) => {
-        // console.log('visible item: ', item);
-        return (<span key={item.key} style={{ marginRight: 8 }}>{item.key}</span>)
-    }
-    render() {
-        return (
-            <div style={{ width: '30%' }}>
-                <OverflowList
-                    items={ITEMS}
-                    minVisibleItems={3}
-                    overflowRenderer={this.renderOverflow}
-                    visibleItemRenderer={this.renderItem}
-                    onOverflow={(item) => console.log(item)}
-                />
-            </div>
-        );
-    }
+  renderOverflow = items => {
+    // console.log('overflow items: ', items);
+    return <Tag>{items.length}</Tag>;
+  };
+  renderItem = (item, ind) => {
+    // console.log('visible item: ', item);
+    return (
+      <span key={item.key} style={{ marginRight: 8 }}>
+        {item.key}
+      </span>
+    );
+  };
+  render() {
+    return (
+      <div style={{ width: '30%' }}>
+        <OverflowList
+          items={ITEMS}
+          minVisibleItems={3}
+          overflowRenderer={this.renderOverflow}
+          visibleItemRenderer={this.renderItem}
+          onOverflow={item => console.log(item)}
+        />
+      </div>
+    );
+  }
 }
 
-stories.add('minVisibleItems', () => <MinCollapse />);
+export const MinVisibleItems = () => <MinCollapse />;
+
+MinVisibleItems.story = {
+  name: 'minVisibleItems',
+};
 
 class OverlapDemo extends React.Component {
-    renderOverflow = (items) => {
-        return items.map(item => <Tag>{item.length}</Tag>)
-    }
-    renderItem = (item, ind) => {
-        return (<div key={item.key} style={{ marginRight: 8 }}>{item.key}</div>)
-    }
-    render() {
-        return (
-            <div style={{ width: '40%' }}>
-                <OverflowList
-                    items={ITEMS}
-                    overflowRenderer={this.renderOverflow}
-                    visibleItemRenderer={this.renderItem}
-                    renderMode="scroll"
-                />
-            </div>
-        );
-    }
+  renderOverflow = items => {
+    return items.map(item => <Tag>{item.length}</Tag>);
+  };
+  renderItem = (item, ind) => {
+    return (
+      <div key={item.key} style={{ marginRight: 8 }}>
+        {item.key}
+      </div>
+    );
+  };
+  render() {
+    return (
+      <div style={{ width: '40%' }}>
+        <OverflowList
+          items={ITEMS}
+          overflowRenderer={this.renderOverflow}
+          visibleItemRenderer={this.renderItem}
+          renderMode="scroll"
+        />
+      </div>
+    );
+  }
 }
 
-stories.add('overlap overflow list', () => <OverlapDemo />);
+export const OverlapOverflowList = () => <OverlapDemo />;
 
+OverlapOverflowList.story = {
+  name: 'overlap overflow list',
+};
 
 class OverlapDemo2 extends React.Component {
-    renderOverflow = (items) => {
-        return items.map(item => <Tag>{item.length}</Tag>)
-    }
-    renderItem = (item, ind) => {
-        return (<div key={item.key} style={{ marginRight: 8 }}>{item.key}</div>)
-    }
-    render() {
-        return (
-            <div style={{ width: '40%' }}>
-                <OverflowList
-                    items={ITEMS}
-                    threshold={0.2}
-                    onIntersect={(item) => console.log(item)}
-                    overflowRenderer={this.renderOverflow}
-                    visibleItemRenderer={this.renderItem}
-                    renderMode="scroll"
-                />
-            </div>
-        );
-    }
+  renderOverflow = items => {
+    return items.map(item => <Tag>{item.length}</Tag>);
+  };
+  renderItem = (item, ind) => {
+    return (
+      <div key={item.key} style={{ marginRight: 8 }}>
+        {item.key}
+      </div>
+    );
+  };
+  render() {
+    return (
+      <div style={{ width: '40%' }}>
+        <OverflowList
+          items={ITEMS}
+          threshold={0.2}
+          onIntersect={item => console.log(item)}
+          overflowRenderer={this.renderOverflow}
+          visibleItemRenderer={this.renderItem}
+          renderMode="scroll"
+        />
+      </div>
+    );
+  }
 }
 
-stories.add('overlap overflow threshold', () => <OverlapDemo2 />);
+export const OverlapOverflowThreshold = () => <OverlapDemo2 />;
+
+OverlapOverflowThreshold.story = {
+  name: 'overlap overflow threshold',
+};
 
 const data = [
-    {
-        key: '1',
-        name: 'John Brown',
-        age: 32,
-        age1: 23,
-        age2: 11,
-        address: [1, 2, 3, 4, 5],
-    },
-    {
-        key: '2',
-        name: 'Jim Green',
-        age: 42,
-        age1: 23,
-        age2: 11,
-        address: [1, 2, 3, 4, 5],
-    },
-    {
-        key: '3',
-        name: 'Joe Black',
-        age: 32,
-        age1: 23,
-        age2: 11,
-        address: [1, 2, 3, 4, 5],
-    },
-    {
-        key: '4',
-        name: 'Disabled User',
-        age: 99,
-        age1: 23,
-        age2: 11,
-        address: [1, 2, 3, 4, 5],
-    },
+  {
+    key: '1',
+    name: 'John Brown',
+    age: 32,
+    age1: 23,
+    age2: 11,
+    address: [1, 2, 3, 4, 5],
+  },
+  {
+    key: '2',
+    name: 'Jim Green',
+    age: 42,
+    age1: 23,
+    age2: 11,
+    address: [1, 2, 3, 4, 5],
+  },
+  {
+    key: '3',
+    name: 'Joe Black',
+    age: 32,
+    age1: 23,
+    age2: 11,
+    address: [1, 2, 3, 4, 5],
+  },
+  {
+    key: '4',
+    name: 'Disabled User',
+    age: 99,
+    age1: 23,
+    age2: 11,
+    address: [1, 2, 3, 4, 5],
+  },
 ];
 
 class TableDemo extends React.Component {
-    renderOverflow = (items) => {
-        return <Tag>{items.length}</Tag>
-    }
-    renderItem = (item, ind) => {
-        return (<div key={`${ind}-item`} style={{ marginRight: 8 }}>{item}</div>)
-    }
-    renderColumn(items) {
-        return (
-            <div
-            // style={{ width: '99%' }}
-            >
-                <OverflowList
-                    items={items.concat(items)}
-                    // observeAll={true}
-                    style={{ width: 88 }}
-                    overflowRenderer={items => <Tag>{items.length}</Tag>}
-                    visibleItemRenderer={(item, ind) => <div key={`${ind}-item`} style={{ marginRight: 8 }}>{item}</div>}
-                />
+  renderOverflow = items => {
+    return <Tag>{items.length}</Tag>;
+  };
+  renderItem = (item, ind) => {
+    return (
+      <div key={`${ind}-item`} style={{ marginRight: 8 }}>
+        {item}
+      </div>
+    );
+  };
+  renderColumn(items) {
+    return (
+      <div
+      // style={{ width: '99%' }}
+      >
+        <OverflowList
+          items={items.concat(items)}
+          // observeAll={true}
+          style={{ width: 88 }}
+          overflowRenderer={items => <Tag>{items.length}</Tag>}
+          visibleItemRenderer={(item, ind) => (
+            <div key={`${ind}-item`} style={{ marginRight: 8 }}>
+              {item}
             </div>
-        );
-        // return (
-        //     <div>
-        //         <OverflowList
-        //             items={items.concat(items)}
-        //             style={{ width: 88 }}
-        //             overflowRenderer={this.renderOverflow}
-        //             visibleItemRenderer={this.renderItem}
-        //         />
-        //     </div>
-        // );
-    }
-    render() {
-        const columns = [
-            {
-                title: 'Name',
-                dataIndex: 'name',
-                width: '30%',
-            },
-            {
-                title: 'combine',
-                dataIndex: 'test',
-                children: [
-                    {
-                        title: 'Age',
-                        children: [
-                            {
-                                title: 'Age1',
-                                dataIndex: 'age1',
-                            },
-                            {
-                                title: 'Age2',
-                                dataIndex: 'age2',
-                            },
-                        ],
-                    },
-                    {
-                        title: 'Key',
-                        dataIndex: 'key',
-                    },
-                ],
-            },
-            {
-                title: 'Address',
-                width: '20%',
-                dataIndex: 'address',
-                render: item => this.renderColumn(item),
-                className: 'table-width-test'
-            },
-        ];
-        return <Table columns={columns} dataSource={data} />
-    }
+          )}
+        />
+      </div>
+    );
+    // return (
+    //     <div>
+    //         <OverflowList
+    //             items={items.concat(items)}
+    //             style={{ width: 88 }}
+    //             overflowRenderer={this.renderOverflow}
+    //             visibleItemRenderer={this.renderItem}
+    //         />
+    //     </div>
+    // );
+  }
+  render() {
+    const columns = [
+      {
+        title: 'Name',
+        dataIndex: 'name',
+        width: '30%',
+      },
+      {
+        title: 'combine',
+        dataIndex: 'test',
+        children: [
+          {
+            title: 'Age',
+            children: [
+              {
+                title: 'Age1',
+                dataIndex: 'age1',
+              },
+              {
+                title: 'Age2',
+                dataIndex: 'age2',
+              },
+            ],
+          },
+          {
+            title: 'Key',
+            dataIndex: 'key',
+          },
+        ],
+      },
+      {
+        title: 'Address',
+        width: '20%',
+        dataIndex: 'address',
+        render: item => this.renderColumn(item),
+        className: 'table-width-test',
+      },
+    ];
+    return <Table columns={columns} dataSource={data} />;
+  }
 }
 
-stories.add('overflow in table', () => <TableDemo />);
+export const OverflowInTable = () => <TableDemo />;
+
+OverflowInTable.story = {
+  name: 'overflow in table',
+};
 
 const LargeData = () => {
-    const [width, setWidth] = useState(100)
-    const renderOverflow = (items) => {
-        // console.log('overflow items: ', items);
-        return (items.length ? <Tag style={{ flex: '0 0 auto' }}>+{items.length}</Tag> : null)
-    }
-    const renderItem = (item, ind) => {
-        // console.log('visible item: ', item);
-        return (
-            <Tag color='blue' key={item.key} style={{ marginRight: 8, flex: '0 0 auto' }}>
-                {item.icon}
-                {item.key}
-            </Tag>
-        )
-    }
-    const items = [
-            { icon: <IconAlarm style={{ marginRight: 4 }} />, key: "alarm" },
-            { icon: <IconBookmark style={{ marginRight: 4 }} />, key: "bookmark" },
-            { icon: <IconCamera style={{ marginRight: 4 }} />, key: "camera" },
-            { icon: <IconDuration style={{ marginRight: 4 }} />, key: "duration" },
-            { icon: <IconEdit style={{ marginRight: 4 }} />, key: "edit" },
-            { icon: <IconFolder style={{ marginRight: 4 }} />, key: "folder" },
-        ];
-        
+  const [width, setWidth] = useState(100);
+  const renderOverflow = items => {
+    // console.log('overflow items: ', items);
+    return items.length ? <Tag style={{ flex: '0 0 auto' }}>+{items.length}</Tag> : null;
+  };
+  const renderItem = (item, ind) => {
+    // console.log('visible item: ', item);
     return (
-        <div>
-            <Slider step={1} value={width} onChange={(value) => setWidth(value)} />
-            <br/>
-            <br/>
-            <div style={{ width: `${width}%` }}>
-                <OverflowList
-                    items={items}
-                    minVisibleItems={3}
-                    overflowRenderer={renderOverflow}
-                    visibleItemRenderer={renderItem}
-                />
-            </div>
-        </div>
+      <Tag color="blue" key={item.key} style={{ marginRight: 8, flex: '0 0 auto' }}>
+        {item.icon}
+        {item.key}
+      </Tag>
     );
-}
+  };
+  const items = [
+    { icon: <IconAlarm style={{ marginRight: 4 }} />, key: 'alarm' },
+    { icon: <IconBookmark style={{ marginRight: 4 }} />, key: 'bookmark' },
+    { icon: <IconCamera style={{ marginRight: 4 }} />, key: 'camera' },
+    { icon: <IconDuration style={{ marginRight: 4 }} />, key: 'duration' },
+    { icon: <IconEdit style={{ marginRight: 4 }} />, key: 'edit' },
+    { icon: <IconFolder style={{ marginRight: 4 }} />, key: 'folder' },
+  ];
+
+  return (
+    <div>
+      <Slider step={1} value={width} onChange={value => setWidth(value)} />
+      <br />
+      <br />
+      <div style={{ width: `${width}%` }}>
+        <OverflowList
+          items={items}
+          minVisibleItems={3}
+          overflowRenderer={renderOverflow}
+          visibleItemRenderer={renderItem}
+        />
+      </div>
+    </div>
+  );
+};
 
 // TODO large data will cause memory heap
 // stories.add('large amount of data', () => <LargeData />);

+ 7 - 7
packages/semi-ui/package.json

@@ -1,6 +1,6 @@
 {
     "name": "@douyinfe/semi-ui",
-    "version": "2.0.4",
+    "version": "2.0.8",
     "description": "",
     "main": "lib/es/index.js",
     "module": "lib/es/index.js",
@@ -19,11 +19,11 @@
     },
     "dependencies": {
         "@babel/runtime-corejs3": "^7.15.4",
-        "@douyinfe/semi-animation-react": "2.0.4",
-        "@douyinfe/semi-foundation": "2.0.4",
-        "@douyinfe/semi-icons": "2.0.4",
-        "@douyinfe/semi-illustrations": "2.0.4",
-        "@douyinfe/semi-theme-default": "2.0.4",
+        "@douyinfe/semi-animation-react": "2.0.8",
+        "@douyinfe/semi-foundation": "2.0.8",
+        "@douyinfe/semi-icons": "2.0.8",
+        "@douyinfe/semi-illustrations": "2.0.8",
+        "@douyinfe/semi-theme-default": "2.0.8",
         "async-validator": "^3.5.0",
         "classnames": "^2.2.6",
         "copy-text-to-clipboard": "^2.1.1",
@@ -70,7 +70,7 @@
         "@babel/plugin-transform-runtime": "^7.15.8",
         "@babel/preset-env": "^7.15.8",
         "@babel/preset-react": "^7.14.5",
-        "@douyinfe/semi-scss-compile": "2.0.4",
+        "@douyinfe/semi-scss-compile": "2.0.8",
         "@storybook/addon-knobs": "^6.3.1",
         "babel-loader": "^8.2.2",
         "case-sensitive-paths-webpack-plugin": "^2.4.0",

+ 124 - 107
packages/semi-ui/pagination/_story/pagination.stories.js

@@ -1,131 +1,148 @@
 import React, { useState } from 'react';
-import { storiesOf } from '@storybook/react';
-// import { withKnobs, text, boolean } from '@storybook/addon-knobs';
-import withPropsCombinations from 'react-storybook-addon-props-combinations';
 
 import 'normalize.css';
 import { Button } from '../../index';
 import Pagination from '../index';
 
-const stories = storiesOf('Pagination', module);
+export default {
+  title: 'Pagination'
+}
 
-// stories.addDecorator(withKnobs);;
+export const PaginationSmall = () => <Pagination total={90} size="small"></Pagination>;
 
-stories.add('Pagination small', () => (
-    <Pagination total={90} size="small"></Pagination>
-));
+PaginationSmall.story = {
+  name: 'Pagination small',
+};
 
-stories.add('Pagination default', () => (
-    <div>
-        <Pagination total={1}></Pagination>
-        <Pagination total={0}></Pagination>
-        <Pagination total={9}></Pagination>
-        <Pagination total={30}></Pagination>
-        <Pagination total={80}></Pagination>
-        <Pagination total={200}></Pagination>
-        <Pagination total={80} pageSize={30}></Pagination>
-        <Pagination total={1000000000} ></Pagination>
-    </div>
-));
+export const PaginationDefault = () => (
+  <div>
+    <Pagination total={1}></Pagination>
+    <Pagination total={0}></Pagination>
+    <Pagination total={9}></Pagination>
+    <Pagination total={30}></Pagination>
+    <Pagination total={80}></Pagination>
+    <Pagination total={200}></Pagination>
+    <Pagination total={80} pageSize={30}></Pagination>
+    <Pagination total={1000000000}></Pagination>
+  </div>
+);
+
+PaginationDefault.story = {
+  name: 'Pagination default',
+};
 
-stories.add('Pagination hideOnSinglePage', () => (
-    <div>
-        <Pagination total={1} hideOnSinglePage></Pagination>
-        <Pagination total={0} hideOnSinglePage></Pagination>
-        <Pagination total={9} hideOnSinglePage></Pagination>
-        <Pagination total={30} hideOnSinglePage></Pagination>
-    </div>
-));
+export const PaginationHideOnSinglePage = () => (
+  <div>
+    <Pagination total={1} hideOnSinglePage></Pagination>
+    <Pagination total={0} hideOnSinglePage></Pagination>
+    <Pagination total={9} hideOnSinglePage></Pagination>
+    <Pagination total={30} hideOnSinglePage></Pagination>
+  </div>
+);
+
+PaginationHideOnSinglePage.story = {
+  name: 'Pagination hideOnSinglePage',
+};
 
-stories.add('Pagination 指定当前页', () => (
-    <div>
-        <Pagination total={20000} defaultCurrentPage={2}></Pagination>
-    </div>
-));
+export const DefaultCurrentPageDemo = () => (
+  <div>
+    <Pagination total={20000} defaultCurrentPage={2}></Pagination>
+  </div>
+);
 
-const ControlPage = () => {
-    const [page, setPage] = useState(3);
-    function onPageChange(currentPage) {
-        setPage(currentPage);
-    }
-    return (
-        <div>
-            <Pagination total={200} currentPage={page} onPageChange={onPageChange}></Pagination>
-        </div>
-    );
+DefaultCurrentPageDemo.story = {
+  name: 'Pagination 指定当前页',
 };
-stories.add('Pagination 页码受控', () => <ControlPage />);
 
-stories.add('Pagination showPageSizeChanger', () => (
+const ControlPage = () => {
+  const [page, setPage] = useState(3);
+  function onPageChange(currentPage) {
+    setPage(currentPage);
+  }
+  return (
     <div>
-        <Pagination total={100} showSizeChanger showTotal></Pagination>
-        <Pagination total={200}></Pagination>
-        <Pagination total={300}
-            showSizeChanger
-            pageSizeOpts={[10, 20, 50, 200]}
-            onPageChange={(page, pageSize)=>console.log(`pageChange:${page},pageSize:${pageSize}`)}
-            onPageSizeChange={pageSize=>console.log(`pageSizeChange${pageSize}`)}
-        >
-        </Pagination>
-        <Pagination total={300} showSizeChanger></Pagination>
+      <Pagination total={200} currentPage={page} onPageChange={onPageChange}></Pagination>
     </div>
-));
+  );
+};
+export const ControlledPageDemo = () => <ControlPage />;
 
-stories.add('Pagination pageSizeOpts', () => (
-    <div>
-        <Pagination total={80} showSizeChanger></Pagination>
-        <Pagination total={200}></Pagination>
-        
-        <Pagination total={300} showSizeChanger pageSizeOpts={[50, 80, 90, 200]}></Pagination>
-    </div>
-));
+ControlledPageDemo.story = {
+  name: 'Pagination 页码受控',
+};
 
-stories.add('Pagination showQuickJumper', () => (
-    <div>
-        <Pagination total={1} showSizeChanger showQuickJumper></Pagination>
-        <Pagination total={80} showSizeChanger showQuickJumper></Pagination>
-        <Pagination total={200} showQuickJumper></Pagination>
-        <Pagination total={300} showSizeChanger pageSizeOpts={[50, 80, 90, 200]} showQuickJumper></Pagination>
-    </div>
-));
+export const PaginationShowPageSizeChanger = () => (
+  <div>
+    <Pagination total={100} showSizeChanger showTotal></Pagination>
+    <Pagination total={200}></Pagination>
+    <Pagination
+      total={300}
+      showSizeChanger
+      pageSizeOpts={[10, 20, 50, 200]}
+      onPageChange={(page, pageSize) => console.log(`pageChange:${page},pageSize:${pageSize}`)}
+      onPageSizeChange={pageSize => console.log(`pageSizeChange${pageSize}`)}
+    ></Pagination>
+    <Pagination total={300} showSizeChanger></Pagination>
+  </div>
+);
+
+PaginationShowPageSizeChanger.story = {
+  name: 'Pagination showPageSizeChanger',
+};
 
+export const PaginationPageSizeOpts = () => (
+  <div>
+    <Pagination total={80} showSizeChanger></Pagination>
+    <Pagination total={200}></Pagination>
 
+    <Pagination total={300} showSizeChanger pageSizeOpts={[50, 80, 90, 200]}></Pagination>
+  </div>
+);
+
+PaginationPageSizeOpts.story = {
+  name: 'Pagination pageSizeOpts',
+};
+
+export const PaginationShowQuickJumper = () => (
+  <div>
+    <Pagination total={1} showSizeChanger showQuickJumper></Pagination>
+    <Pagination total={80} showSizeChanger showQuickJumper></Pagination>
+    <Pagination total={200} showQuickJumper></Pagination>
+    <Pagination
+      total={300}
+      showSizeChanger
+      pageSizeOpts={[50, 80, 90, 200]}
+      showQuickJumper
+    ></Pagination>
+  </div>
+);
+
+PaginationShowQuickJumper.story = {
+  name: 'Pagination showQuickJumper',
+};
 
 const DynamicPageSize = () => {
-    const [pageSize, setPageSize] = useState(10); 
-    function changePageSize() {
-        let map = {
-            10: 40,
-            40: 100,
-            100: 20,
-            100: 10
-        }
-        setPageSize(map[pageSize]);
-    }
-    return (
-        <>
-        <Pagination
-            total={200}
-            showSizeChanger
-            pageSize={pageSize}
-         >
-        </Pagination>
-        <br/>
-        <Button onClick={changePageSize}>change</Button>
-        </>
-    );
+  const [pageSize, setPageSize] = useState(10);
+  function changePageSize() {
+    let map = {
+      10: 40,
+      40: 100,
+      100: 20,
+      100: 10,
+    };
+    setPageSize(map[pageSize]);
+  }
+  return (
+    <>
+      <Pagination total={200} showSizeChanger pageSize={pageSize}></Pagination>
+      <br />
+      <Button onClick={changePageSize}>change</Button>
+    </>
+  );
 };
 
-stories.add('Pagination dynamic update pageSize', () => <DynamicPageSize />);
-
-// stories.add('combination', withPropsCombinations(
-//     Button,
-//     {
-//         disaled: [false, true],
-//         children: ['hello button'],
-//         size: ['large', 'default', 'small'],
-//         type: ['default', 'primary', 'warning', 'danger'],
-//         // block: [false, true],
-//         ghost: [false, true]
-//     }
-// ));
+export const PaginationDynamicUpdatePageSize = () => <DynamicPageSize />;
+
+PaginationDynamicUpdatePageSize.story = {
+  name: 'Pagination dynamic update pageSize',
+};

+ 112 - 79
packages/semi-ui/popconfirm/_story/popconfirm.stories.js

@@ -1,7 +1,4 @@
 import React, { useState } from 'react';
-import { storiesOf } from '@storybook/react';
-// import { withKnobs, text, boolean } from '@storybook/addon-knobs';
-import withPropsCombinations from 'react-storybook-addon-props-combinations';
 
 import Popconfirm from '../index';
 import Button from '../../button';
@@ -14,95 +11,131 @@ import TitleConfirmDemo from './TitlePopconfirm';
 import InTableDemo from './InTable';
 import ShowArrow from './ShowArrow';
 
-const stories = storiesOf('popconfirm', module);
-
-// stories.addDecorator(withKnobs);;
+export default {
+  title: 'Popconfirm',
+  parameters: {
+    chromatic: { disableSnapshot: true },
+  },
+}
 
 let style = {
-    display: 'inline-block',
-    padding: '20px',
+  display: 'inline-block',
+  padding: '20px',
 };
 
-stories.add('simple', () => (
-    <div>
-        <div style={style}>
-            <Popconfirm
-                title="确定是否要保存此修改?确定是否要保存此修改?确定是否要保存此修改?确定是否要保存此修改?确定是否要保存此修改?确定是否要保存此修改?确定是否要保存此修改?确定是否要保存此修改?"
-                content="此修改将不可逆"
-            >
-                <a>Delete</a>
-            </Popconfirm>
-        </div>
+export const Simple = () => (
+  <div>
+    <div style={style}>
+      <Popconfirm
+        title="确定是否要保存此修改?确定是否要保存此修改?确定是否要保存此修改?确定是否要保存此修改?确定是否要保存此修改?确定是否要保存此修改?确定是否要保存此修改?确定是否要保存此修改?"
+        content="此修改将不可逆"
+      >
+        <a>Delete</a>
+      </Popconfirm>
     </div>
-));
-
-stories.add('button', () => (
-    <div>
-        <div style={style}>
-            <Popconfirm position="bottomLeft" title="确定是否要保存此修改?" content="此修改将不可逆">
-                <Button>Save</Button>
-            </Popconfirm>
-        </div>
+  </div>
+);
+
+Simple.story = {
+  name: 'simple',
+};
+
+export const _Button = () => (
+  <div>
+    <div style={style}>
+      <Popconfirm position="bottomLeft" title="确定是否要保存此修改?" content="此修改将不可逆">
+        <Button>Save</Button>
+      </Popconfirm>
     </div>
-));
+  </div>
+);
+
+_Button.story = {
+  name: 'button',
+};
 
 const dataSource = [
-    {
-        key: '1',
-        name: 'John Brown',
-        age: 32,
-        address: 'New York No. 1 Lake Park, New York No. 1 Lake Park',
-    },
-    {
-        key: '2',
-        name: 'Jim Green',
-        age: 42,
-        address: 'London No. 1 Lake Park',
-    },
-    {
-        key: '3',
-        name: 'Joe Black',
-        age: 32,
-        address: 'Sidney No. 1 Lake Park',
-    },
-    {
-        key: '4',
-        name: 'Disabled User',
-        age: 99,
-        address: 'Sidney No. 1 Lake Park',
-    },
+  {
+    key: '1',
+    name: 'John Brown',
+    age: 32,
+    address: 'New York No. 1 Lake Park, New York No. 1 Lake Park',
+  },
+  {
+    key: '2',
+    name: 'Jim Green',
+    age: 42,
+    address: 'London No. 1 Lake Park',
+  },
+  {
+    key: '3',
+    name: 'Joe Black',
+    age: 32,
+    address: 'Sidney No. 1 Lake Park',
+  },
+  {
+    key: '4',
+    name: 'Disabled User',
+    age: 99,
+    address: 'Sidney No. 1 Lake Park',
+  },
 ];
 const columns = [
-    {
-        title: 'Name',
-        dataIndex: 'name',
-        render: text => (
-            <Popconfirm position="bottomLeft" title="确定是否要保存此修改?" content="此修改将不可逆">
-                <Button>{text}</Button>
-            </Popconfirm>
-        ),
-    },
-    {
-        title: 'Age',
-        dataIndex: 'age',
-    },
-    {
-        title: 'Address',
-        dataIndex: 'address',
-    },
+  {
+    title: 'Name',
+    dataIndex: 'name',
+    render: text => (
+      <Popconfirm position="bottomLeft" title="确定是否要保存此修改?" content="此修改将不可逆">
+        <Button>{text}</Button>
+      </Popconfirm>
+    ),
+  },
+  {
+    title: 'Age',
+    dataIndex: 'age',
+  },
+  {
+    title: 'Address',
+    dataIndex: 'address',
+  },
 ];
 
-stories.add('table', () => (
-    <div>
-        <Table dataSource={dataSource} columns={columns} />
-    </div>
-));
+export const _Table = () => (
+  <div>
+    <Table dataSource={dataSource} columns={columns} />
+  </div>
+);
 
-stories.add('types-confirm', () => <TypesConfrimDemo />);
+_Table.story = {
+  name: 'table',
+};
 
-stories.add('dynamic disable', () => <DynamicDisableDemo />);
+export const TypesConfirm = () => <TypesConfrimDemo />;
+
+TypesConfirm.story = {
+  name: 'types-confirm',
+};
+
+export const DynamicDisable = () => <DynamicDisableDemo />;
+
+DynamicDisable.story = {
+  name: 'dynamic disable',
+};
+
+export const TitlePopconfirm = () => <TitleConfirmDemo />;
+
+TitlePopconfirm.story = {
+  name: 'title popconfirm',
+};
+
+export const InTable = () => <InTableDemo />;
+
+InTable.story = {
+  name: 'in table',
+};
 
-stories.add('title popconfirm', () => <TitleConfirmDemo />);
 
-stories.add('in table', () => <InTableDemo />);
-stories.add(`show arrow`, () => <ShowArrow />);
+export const ShowArrowDemo = () => <ShowArrow />;
+ShowArrowDemo.style = {
+  name: 'show arrow'
+}

+ 523 - 456
packages/semi-ui/popover/_story/popover.stories.js

@@ -1,7 +1,5 @@
 import React, { useState } from 'react';
-import { storiesOf } from '@storybook/react'; // import { withKnobs, text, boolean } from '@storybook/addon-knobs';
 
-import withPropsCombinations from 'react-storybook-addon-props-combinations';
 import Popover from '../index';
 import { strings } from '@douyinfe/semi-foundation/tooltip/constants';
 import { Button, Input, Table, IconButton, Modal, Tag } from '@douyinfe/semi-ui';
@@ -11,497 +9,566 @@ import PopRight from './PopRight';
 import NestedPopover from './NestedPopover';
 import ArrowPointAtCenter from './ArrowPointAtCenter';
 import { IconDelete } from '@douyinfe/semi-icons';
-const stories = storiesOf('popover', module); // stories.addDecorator(withKnobs);;
+
+export default {
+  title: 'Popover',
+  parameters: {
+    chromatic: { disableSnapshot: true },
+  },
+}
 
 let style = {
-    display: 'inline-block',
-    padding: '20px',
+  display: 'inline-block',
+  padding: '20px',
 };
-stories.add('popover', () => (
-    <div>
-        <div style={style}>
-            <Popover content="ies vigo" title="bytedance" position="bottom" visible={true} showArrow>
-                bottom hover
-            </Popover>
-        </div>
 
-        <div style={style}>
-            <Popover content="ies vigo" title="bytedance" trigger="click" position="bottom">
-                bottom click
-            </Popover>
-        </div>
+export const _Popover = () => (
+  <div>
+    <div style={style}>
+      <Popover content="ies vigo" title="bytedance" position="bottom" visible={true} showArrow>
+        bottom hover
+      </Popover>
+    </div>
 
-        <div style={style}>
-            <Popover content="ies vigo" title="bytedance" trigger="click" position="right">
-                <Button>Pos:right, trigger: Click</Button>
-            </Popover>
-        </div>
+    <div style={style}>
+      <Popover content="ies vigo" title="bytedance" trigger="click" position="bottom">
+        bottom click
+      </Popover>
+    </div>
 
-        <div style={style}>
-            <Popover content={<Button type="warning">btn</Button>} title="bytedance" trigger="click" position="right">
-                content is Node
-            </Popover>
-        </div>
+    <div style={style}>
+      <Popover content="ies vigo" title="bytedance" trigger="click" position="right">
+        <Button>Pos:right, trigger: Click</Button>
+      </Popover>
+    </div>
 
-        <div style={style}>
-            <Popover content={<Input />} title="bytedance" trigger="click" position="right">
-                content is Node
-            </Popover>
-        </div>
+    <div style={style}>
+      <Popover
+        content={<Button type="warning">btn</Button>}
+        title="bytedance"
+        trigger="click"
+        position="right"
+      >
+        content is Node
+      </Popover>
     </div>
-));
-stories.add('positions', () => (
-    <div
-        style={{
-            width: 480,
-            height: 360,
-            boxSizing: 'content-box',
-            padding: '150px 50px',
-            display: 'flex',
-            flexWrap: 'wrap',
-            justifyContent: 'space-evenly',
-        }}
-    >
-        {strings.POSITION_SET.map(pos => (
-            <Popover
-                key={pos}
-                content={
-                    <div
-                        style={{
-                            padding: 20,
-                        }}
-                    >
-                        <p>Hi Bytedancer!</p>
-                    </div>
-                }
-                trigger="click"
-                position={pos}
-            >
-                <Button key={pos}>{pos}</Button>
-            </Popover>
-        ))}
+
+    <div style={style}>
+      <Popover content={<Input />} title="bytedance" trigger="click" position="right">
+        content is Node
+      </Popover>
     </div>
-)); // TODO
-
-stories.add('popConfirm', () => (
-    <div>
-        <div style={style}>
-            <Popover isConfirmMode content="hi byteddance ies">
-                <a>IconDelete</a>
-            </Popover>
-        </div>
+  </div>
+);
+
+_Popover.story = {
+  name: 'popover',
+};
+
+export const Positions = () => (
+  <div
+    style={{
+      width: 480,
+      height: 360,
+      boxSizing: 'content-box',
+      padding: '150px 50px',
+      display: 'flex',
+      flexWrap: 'wrap',
+      justifyContent: 'space-evenly',
+    }}
+  >
+    {strings.POSITION_SET.map(pos => (
+      <Popover
+        key={pos}
+        content={
+          <div
+            style={{
+              padding: 20,
+            }}
+          >
+            <p>Hi Bytedancer!</p>
+          </div>
+        }
+        trigger="click"
+        position={pos}
+      >
+        <Button key={pos}>{pos}</Button>
+      </Popover>
+    ))}
+  </div>
+);
+
+Positions.story = {
+  name: 'positions',
+};
+
+export const PopConfirm = () => (
+  <div>
+    <div style={style}>
+      <Popover isConfirmMode content="hi byteddance ies">
+        <a>IconDelete</a>
+      </Popover>
     </div>
-));
+  </div>
+);
+
+PopConfirm.story = {
+  name: 'popConfirm',
+};
 
 class Demo extends React.Component {
-    constructor(props) {
-        super(props);
-        this.state = {
-            visible: false,
-        };
-        this.changeVisible = this.changeVisible.bind(this);
-        this.renderContent = this.renderContent.bind(this);
-    }
+  constructor(props) {
+    super(props);
+    this.state = {
+      visible: false,
+    };
+    this.changeVisible = this.changeVisible.bind(this);
+    this.renderContent = this.renderContent.bind(this);
+  }
 
-    changeVisible(visible = true) {
-        this.setState({
-            visible,
-        });
-    }
+  changeVisible(visible = true) {
+    this.setState({
+      visible,
+    });
+  }
 
-    renderContent() {
-        return (
-            <>
-                <p>hi byteddance ies</p>
-                <Button onClick={() => this.changeVisible(false)}>cancel</Button>
-                <Button onClick={() => this.changeVisible(false)}>confirm</Button>
-            </>
-        );
-    }
+  renderContent() {
+    return (
+      <>
+        <p>hi byteddance ies</p>
+        <Button onClick={() => this.changeVisible(false)}>cancel</Button>
+        <Button onClick={() => this.changeVisible(false)}>confirm</Button>
+      </>
+    );
+  }
 
-    render() {
-        const content = this.renderContent();
-        const { visible } = this.state;
-        return (
-            <Popover trigger="custom" content={content} visible={visible} position="bottomLeft">
-                <Button onClick={() => this.changeVisible(true)}>show Popover</Button>
-            </Popover>
-        );
-    }
+  render() {
+    const content = this.renderContent();
+    const { visible } = this.state;
+    return (
+      <Popover trigger="custom" content={content} visible={visible} position="bottomLeft">
+        <Button onClick={() => this.changeVisible(true)}>show Popover</Button>
+      </Popover>
+    );
+  }
 }
 
-stories.add('popover custom visible', () => <Demo />);
-stories.add('复合组件', () => {
-    class TableApp extends React.Component {
-        constructor(props) {
-            super(props);
-            this.raw = [
-                {
-                    key: '1',
-                    name: 'John Brown',
-                    age: 32,
-                    address: 'New York No. 1 Lake Park, New York No. 1 Lake Park',
-                },
-                {
-                    key: '2',
-                    name: 'Jim Green',
-                    age: 42,
-                    address: 'London No. 1 Lake Park',
-                },
-                {
-                    key: '3',
-                    name: 'Joe Black',
-                    age: 32,
-                    address: 'Sidney No. 1 Lake Park',
-                },
-                {
-                    key: '4',
-                    name: 'Disabled User',
-                    age: 99,
-                    address: 'Sidney No. 1 Lake Park',
-                },
-            ];
-            this.state = {
-                dataSource: [...this.raw],
-                modalVisible: false,
-                columns: [
-                    {
-                        title: 'Name',
-                        dataIndex: 'name',
-                        render: text => <a href="javascript:;">{text}</a>,
-                    },
-                    {
-                        title: 'Age',
-                        dataIndex: 'age',
-                    },
-                    {
-                        title: 'Address',
-                        dataIndex: 'address',
-                    },
-                    {
-                        title: 'Operation',
-                        render: (text, record) => (
-                            <div>
-                                <Button icon={<IconDelete />} onClick={() => this.removeRecord(record.key)} />
-                                <Button onClick={() => this.toggleModal(true)}>编辑</Button>
-                            </div>
-                        ),
-                    },
-                ],
-            };
-        }
+export const PopoverCustomVisible = () => <Demo />;
+
+PopoverCustomVisible.story = {
+  name: 'popover custom visible',
+};
 
-        removeRecord(key) {
-            let dataSource = [...this.state.dataSource];
 
-            if (key != null) {
-                let idx = dataSource.findIndex(data => data.key === key); // console.log(key, dataSource, idx);
+CompositeComponent.story = { name: '复合组件' };
+export function CompositeComponent() {
+  class TableApp extends React.Component {
+    constructor(props) {
+      super(props);
+      this.raw = [
+        {
+          key: '1',
+          name: 'John Brown',
+          age: 32,
+          address: 'New York No. 1 Lake Park, New York No. 1 Lake Park',
+        },
+        {
+          key: '2',
+          name: 'Jim Green',
+          age: 42,
+          address: 'London No. 1 Lake Park',
+        },
+        {
+          key: '3',
+          name: 'Joe Black',
+          age: 32,
+          address: 'Sidney No. 1 Lake Park',
+        },
+        {
+          key: '4',
+          name: 'Disabled User',
+          age: 99,
+          address: 'Sidney No. 1 Lake Park',
+        },
+      ];
+      this.state = {
+        dataSource: [...this.raw],
+        modalVisible: false,
+        columns: [
+          {
+            title: 'Name',
+            dataIndex: 'name',
+            render: text => <a href="javascript:;">{text}</a>,
+          },
+          {
+            title: 'Age',
+            dataIndex: 'age',
+          },
+          {
+            title: 'Address',
+            dataIndex: 'address',
+          },
+          {
+            title: 'Operation',
+            render: (text, record) => (
+              <div>
+                <Button icon={<IconDelete />} onClick={() => this.removeRecord(record.key)} />
+                <Button onClick={() => this.toggleModal(true)}>编辑</Button>
+              </div>
+            ),
+          },
+        ],
+      };
+    }
 
-                if (idx > -1) {
-                    dataSource.splice(idx, 1);
-                    this.setState({
-                        dataSource,
-                    });
-                }
-            }
-        }
+    removeRecord(key) {
+      let dataSource = [...this.state.dataSource];
 
-        resetData() {
-            let dataSource = [...this.raw];
-            this.setState({
-                dataSource,
-            });
-        }
+      if (key != null) {
+        let idx = dataSource.findIndex(data => data.key === key); // console.log(key, dataSource, idx);
 
-        toggleModal = modalVisible => {
-            this.setState({
-                modalVisible,
-            });
-        };
-        renderModalContent = () => {
-            const { modalVisible } = this.state;
-            return (
-                <Modal
-                    visible={modalVisible}
-                    onCancel={() => this.toggleModal(false)}
-                    onOk={() => this.toggleModal(false)}
-                >
-                    <p>This is a modal with customized styles.</p>
-                    <p>More content...</p>
-                    <Popover
-                        content={
-                            <div>
-                                <Button>按钮1</Button>
-                                <Button>按钮2</Button>
-                            </div>
-                        }
-                    >
-                        <Button>hover</Button>
-                    </Popover>
-                </Modal>
-            );
-        };
-
-        render() {
-            let { columns, dataSource } = this.state;
-            return (
-                <>
-                    <Button onClick={() => this.resetData()}>Reset</Button>
-                    <Table columns={columns} dataSource={dataSource} pagination={false} />
-                    {this.renderModalContent()}
-                </>
-            );
+        if (idx > -1) {
+          dataSource.splice(idx, 1);
+          this.setState({
+            dataSource,
+          });
         }
+      }
     }
 
-    return <TableApp />;
-});
+    resetData() {
+      let dataSource = [...this.raw];
+      this.setState({
+        dataSource,
+      });
+    }
 
-const ScrollDemo = function ScrollDemo(props = {}) {
-    const tops = [
-        ['topLeft', 'TL'],
-        ['top', 'Top'],
-        ['topRight', 'TR'],
-    ];
-    const lefts = [
-        ['leftTop', 'LT'],
-        ['left', 'Left'],
-        ['leftBottom', 'LB'],
-    ];
-    const rights = [
-        ['rightTop', 'RT'],
-        ['right', 'Right'],
-        ['rightBottom', 'RB'],
-    ];
-    const bottoms = [
-        ['bottomLeft', 'BL'],
-        ['bottom', 'Bottom'],
-        ['bottomRight', 'BR'],
-    ];
-    const { tagstyle, ...restProps } = props;
-    return (
-        <div
-            style={{
-                paddingLeft: 40,
-            }}
+    toggleModal = modalVisible => {
+      this.setState({
+        modalVisible,
+      });
+    };
+    renderModalContent = () => {
+      const { modalVisible } = this.state;
+      return (
+        <Modal
+          visible={modalVisible}
+          onCancel={() => this.toggleModal(false)}
+          onOk={() => this.toggleModal(false)}
         >
-            <div
-                style={{
-                    marginLeft: 40,
-                    whiteSpace: 'nowrap',
-                }}
-            >
-                {tops.map((pos, index) => (
-                    <Popover
-                        content={
-                            <article>
-                                <p>hi bytedance</p>
-                                <p>hi bytedance</p>
-                            </article>
-                        }
-                        position={Array.isArray(pos) ? pos[0] : pos}
-                        key={index}
-                        trigger={'click'}
-                        {...restProps}
-                    >
-                        <Tag style={tagstyle}>{Array.isArray(pos) ? pos[1] : pos}</Tag>
-                    </Popover>
-                ))}
-            </div>
-            <div
-                style={{
-                    width: 40,
-                    float: 'left',
-                }}
-            >
-                {lefts.map((pos, index) => (
-                    <Popover
-                        content={
-                            <article>
-                                <p>hi bytedance</p>
-                                <p>hi bytedance</p>
-                            </article>
-                        }
-                        position={Array.isArray(pos) ? pos[0] : pos}
-                        key={index}
-                        trigger={'click'}
-                        {...restProps}
-                    >
-                        <Tag style={tagstyle}>{Array.isArray(pos) ? pos[1] : pos}</Tag>
-                    </Popover>
-                ))}
-            </div>
-            <div
-                style={{
-                    width: 40,
-                    marginLeft: 180,
-                }}
-            >
-                {rights.map((pos, index) => (
-                    <Popover
-                        content={
-                            <article>
-                                <p>hi bytedance</p>
-                                <p>hi bytedance</p>
-                            </article>
-                        }
-                        position={Array.isArray(pos) ? pos[0] : pos}
-                        key={index}
-                        trigger={'click'}
-                        {...restProps}
-                    >
-                        <Tag style={tagstyle}>{Array.isArray(pos) ? pos[1] : pos}</Tag>
-                    </Popover>
-                ))}
-            </div>
-            <div
-                style={{
-                    marginLeft: 40,
-                    clear: 'both',
-                    whiteSpace: 'nowrap',
-                }}
-            >
-                {bottoms.map((pos, index) => (
-                    <Popover
-                        content={
-                            <article>
-                                <p>hi bytedance</p>
-                                <p>hi bytedance</p>
-                            </article>
-                        }
-                        position={Array.isArray(pos) ? pos[0] : pos}
-                        key={index}
-                        trigger={'click'}
-                        {...restProps}
-                    >
-                        <Tag style={tagstyle}>{Array.isArray(pos) ? pos[1] : pos}</Tag>
-                    </Popover>
-                ))}
-            </div>
-        </div>
-    );
-};
+          <p>This is a modal with customized styles.</p>
+          <p>More content...</p>
+          <Popover
+            content={
+              <div>
+                <Button>按钮1</Button>
+                <Button>按钮2</Button>
+              </div>
+            }
+          >
+            <Button>hover</Button>
+          </Popover>
+        </Modal>
+      );
+    };
 
-stories.add('scroll popover', () => {
-    return (
+    render() {
+      let { columns, dataSource } = this.state;
+      return (
         <>
-            <div id="wrapper">
-                <div
-                    style={{
-                        height: '200vh',
-                        width: '200vw',
-                        padding: 50,
-                    }}
-                >
-                    滚动到下面
-                </div>
-            </div>
-            <div
-                style={{
-                    padding: 1200,
-                }}
-            >
-                <ScrollDemo
-                    content={
-                        <article
-                            style={{
-                                padding: 12,
-                            }}
-                        >
-                            <p>hi bytedance</p>
-                            <p>hi bytedance</p>
-                        </article>
-                    }
-                />
-            </div>
+          <Button onClick={() => this.resetData()}>Reset</Button>
+          <Table columns={columns} dataSource={dataSource} pagination={false} />
+          {this.renderModalContent()}
         </>
-    );
-});
-stories.add('with arrow', () => (
-    <div>
-        <div
-            style={{
-                padding: 120,
-            }}
-        >
-            <ScrollDemo showArrow />
-        </div>
-        <div
-            style={{
-                padding: 120,
-            }}
-        >
-            <ScrollDemo
-                showArrow
-                tagstyle={{
-                    minHeight: 80,
-                    minWidth: 120,
-                }}
-            />
-        </div>
-        <div
-            style={{
-                padding: 120,
-            }}
-        >
-            <ScrollDemo
-                showArrow
-                tagstyle={{
-                    minHeight: 80,
-                    minWidth: 120,
-                }}
-                style={{
-                    backgroundColor: 'green',
-                }}
-            />
-        </div>
+      );
+    }
+  }
+
+  return <TableApp />;
+};
+
+const ScrollDemo = function ScrollDemo(props = {}) {
+  const tops = [
+    ['topLeft', 'TL'],
+    ['top', 'Top'],
+    ['topRight', 'TR'],
+  ];
+  const lefts = [
+    ['leftTop', 'LT'],
+    ['left', 'Left'],
+    ['leftBottom', 'LB'],
+  ];
+  const rights = [
+    ['rightTop', 'RT'],
+    ['right', 'Right'],
+    ['rightBottom', 'RB'],
+  ];
+  const bottoms = [
+    ['bottomLeft', 'BL'],
+    ['bottom', 'Bottom'],
+    ['bottomRight', 'BR'],
+  ];
+  const { tagstyle, ...restProps } = props;
+  return (
+    <div
+      style={{
+        paddingLeft: 40,
+      }}
+    >
+      <div
+        style={{
+          marginLeft: 40,
+          whiteSpace: 'nowrap',
+        }}
+      >
+        {tops.map((pos, index) => (
+          <Popover
+            content={
+              <article>
+                <p>hi bytedance</p>
+                <p>hi bytedance</p>
+              </article>
+            }
+            position={Array.isArray(pos) ? pos[0] : pos}
+            key={index}
+            trigger={'click'}
+            {...restProps}
+          >
+            <Tag style={tagstyle}>{Array.isArray(pos) ? pos[1] : pos}</Tag>
+          </Popover>
+        ))}
+      </div>
+      <div
+        style={{
+          width: 40,
+          float: 'left',
+        }}
+      >
+        {lefts.map((pos, index) => (
+          <Popover
+            content={
+              <article>
+                <p>hi bytedance</p>
+                <p>hi bytedance</p>
+              </article>
+            }
+            position={Array.isArray(pos) ? pos[0] : pos}
+            key={index}
+            trigger={'click'}
+            {...restProps}
+          >
+            <Tag style={tagstyle}>{Array.isArray(pos) ? pos[1] : pos}</Tag>
+          </Popover>
+        ))}
+      </div>
+      <div
+        style={{
+          width: 40,
+          marginLeft: 180,
+        }}
+      >
+        {rights.map((pos, index) => (
+          <Popover
+            content={
+              <article>
+                <p>hi bytedance</p>
+                <p>hi bytedance</p>
+              </article>
+            }
+            position={Array.isArray(pos) ? pos[0] : pos}
+            key={index}
+            trigger={'click'}
+            {...restProps}
+          >
+            <Tag style={tagstyle}>{Array.isArray(pos) ? pos[1] : pos}</Tag>
+          </Popover>
+        ))}
+      </div>
+      <div
+        style={{
+          marginLeft: 40,
+          clear: 'both',
+          whiteSpace: 'nowrap',
+        }}
+      >
+        {bottoms.map((pos, index) => (
+          <Popover
+            content={
+              <article>
+                <p>hi bytedance</p>
+                <p>hi bytedance</p>
+              </article>
+            }
+            position={Array.isArray(pos) ? pos[0] : pos}
+            key={index}
+            trigger={'click'}
+            {...restProps}
+          >
+            <Tag style={tagstyle}>{Array.isArray(pos) ? pos[1] : pos}</Tag>
+          </Popover>
+        ))}
+      </div>
     </div>
-));
-stories.add('no content', () => (
-    <div>
-        <div
-            style={{
-                padding: 50,
-            }}
-        >
-            <ScrollDemo content={<div></div>} />
-        </div>
-        <div
-            style={{
-                padding: 50,
-            }}
-        >
-            <ScrollDemo showArrow content={''} />
-        </div>
+  );
+};
+
+export const ScrollPopover = () => {
+  return (
+    <>
+      <div id="wrapper">
         <div
-            style={{
-                padding: 50,
-            }}
+          style={{
+            height: '200vh',
+            width: '200vw',
+            padding: 50,
+          }}
         >
-            <ScrollDemo
-                showArrow
-                content={''}
-                tagstyle={{
-                    height: 80,
-                    minWidth: 100,
-                }}
-                style={{
-                    padding: 20,
-                }}
-            />
+          滚动到下面
         </div>
+      </div>
+      <div
+        style={{
+          padding: 1200,
+        }}
+      >
+        <ScrollDemo
+          content={
+            <article
+              style={{
+                padding: 12,
+              }}
+            >
+              <p>hi bytedance</p>
+              <p>hi bytedance</p>
+            </article>
+          }
+        />
+      </div>
+    </>
+  );
+};
+
+ScrollPopover.story = {
+  name: 'scroll popover',
+};
+
+export const WithArrow = () => (
+  <div>
+    <div
+      style={{
+        padding: 120,
+      }}
+    >
+      <ScrollDemo showArrow />
+    </div>
+    <div
+      style={{
+        padding: 120,
+      }}
+    >
+      <ScrollDemo
+        showArrow
+        tagstyle={{
+          minHeight: 80,
+          minWidth: 120,
+        }}
+      />
     </div>
-));
-stories.add('select in popover', () => (
     <div
+      style={{
+        padding: 120,
+      }}
+    >
+      <ScrollDemo
+        showArrow
+        tagstyle={{
+          minHeight: 80,
+          minWidth: 120,
+        }}
         style={{
-            padding: 50,
+          backgroundColor: 'green',
         }}
+      />
+    </div>
+  </div>
+);
+
+WithArrow.story = {
+  name: 'with arrow',
+};
+
+export const NoContent = () => (
+  <div>
+    <div
+      style={{
+        padding: 50,
+      }}
+    >
+      <ScrollDemo content={<div></div>} />
+    </div>
+    <div
+      style={{
+        padding: 50,
+      }}
+    >
+      <ScrollDemo showArrow content={''} />
+    </div>
+    <div
+      style={{
+        padding: 50,
+      }}
     >
-        <SelectInPopover />
+      <ScrollDemo
+        showArrow
+        content={''}
+        tagstyle={{
+          height: 80,
+          minWidth: 100,
+        }}
+        style={{
+          padding: 20,
+        }}
+      />
     </div>
-));
-stories.add('close btn in popover', () => <BtnClose />);
-stories.add('popover float right', () => <PopRight />);
-stories.add(`nested popover`, () => <NestedPopover />);
-stories.add(`arrow point at center`, () => <ArrowPointAtCenter />);
+  </div>
+);
+
+NoContent.story = {
+  name: 'no content',
+};
+
+export const _SelectInPopover = () => (
+  <div
+    style={{
+      padding: 50,
+    }}
+  >
+    <SelectInPopover />
+  </div>
+);
+
+_SelectInPopover.story = {
+  name: 'select in popover',
+};
+
+export const CloseBtnInPopover = () => <BtnClose />;
+
+CloseBtnInPopover.story = {
+  name: 'close btn in popover',
+};
+
+export const PopoverFloatRight = () => <PopRight />;
+
+PopoverFloatRight.story = {
+  name: 'popover float right',
+};
+
+export const NestedPopoverDemo = () => <NestedPopover />;
+NestedPopoverDemo.story = {
+  name: 'nested popover'
+}
+
+export const ArrowPointAtCenterDemo = () => <ArrowPointAtCenter />;
+ArrowPointAtCenterDemo.story = {
+  name: 'arrow point at center'
+}

+ 68 - 47
packages/semi-ui/progress/_story/progress.stories.js

@@ -1,50 +1,71 @@
 import React, { useState } from 'react';
-import { storiesOf } from '@storybook/react';
 import { Progress, IconButton } from '../../index';
 
-const stories = storiesOf('Progress', module);
-
-stories.add('progress', () => (
-    <div style={{ width: 200 }}>
-        {/* <Progress percent={10} style= {{ height: 10 }}/> */}
-        <Progress percent={25} />
-        <Progress percent={50} />
-        <Progress percent={80} />
-    </div>
-));
-
-stories.add('vertical', () => (
-    <div style={{ height: 200 }}>
-        <Progress percent={10} direction="vertical" style={{ width: 10 }} />
-        <Progress percent={25} direction="vertical" />
-        <Progress percent={50} direction="vertical" />
-        <Progress percent={80} direction="vertical" />
-    </div>
-));
-
-stories.add('circle progress', () => (
-    <React.Fragment>
-        <Progress percent={10} type="circle" />
-        <Progress percent={25} type="circle" />
-        <Progress percent={50} type="circle" />
-        <Progress percent={80} type="circle" />
-    </React.Fragment>
-));
-
-stories.add('circle progress small', () => (
-    <React.Fragment>
-        <Progress percent={10} type="circle" size="small" />
-        <Progress percent={25} type="circle" size="small" />
-        <Progress percent={50} type="circle" size="small" />
-        <Progress percent={80} type="circle" size="small" />
-    </React.Fragment>
-));
-
-stories.add('progress showInfo', () => (
-    <div style={{ width: 200 }}>
-        {/* <Progress percent={10} style= {{ height: 10 }}/> */}
-        <Progress percent={25} showInfo />
-        <Progress percent={50} showInfo />
-        <Progress percent={80} showInfo />
-    </div>
-));
+export default {
+  title: 'Progress'
+}
+
+export const _Progress = () => (
+  <div style={{ width: 200 }}>
+    {/* <Progress percent={10} style= {{ height: 10 }}/> */}
+    <Progress percent={25} />
+    <Progress percent={50} />
+    <Progress percent={80} />
+  </div>
+);
+
+_Progress.story = {
+  name: 'progress',
+};
+
+export const Vertical = () => (
+  <div style={{ height: 200 }}>
+    <Progress percent={10} direction="vertical" style={{ width: 10 }} />
+    <Progress percent={25} direction="vertical" />
+    <Progress percent={50} direction="vertical" />
+    <Progress percent={80} direction="vertical" />
+  </div>
+);
+
+Vertical.story = {
+  name: 'vertical',
+};
+
+export const CircleProgress = () => (
+  <React.Fragment>
+    <Progress percent={10} type="circle" />
+    <Progress percent={25} type="circle" />
+    <Progress percent={50} type="circle" />
+    <Progress percent={80} type="circle" />
+  </React.Fragment>
+);
+
+CircleProgress.story = {
+  name: 'circle progress',
+};
+
+export const CircleProgressSmall = () => (
+  <React.Fragment>
+    <Progress percent={10} type="circle" size="small" />
+    <Progress percent={25} type="circle" size="small" />
+    <Progress percent={50} type="circle" size="small" />
+    <Progress percent={80} type="circle" size="small" />
+  </React.Fragment>
+);
+
+CircleProgressSmall.story = {
+  name: 'circle progress small',
+};
+
+export const ProgressShowInfo = () => (
+  <div style={{ width: 200 }}>
+    {/* <Progress percent={10} style= {{ height: 10 }}/> */}
+    <Progress percent={25} showInfo />
+    <Progress percent={50} showInfo />
+    <Progress percent={80} showInfo />
+  </div>
+);
+
+ProgressShowInfo.story = {
+  name: 'progress showInfo',
+};

+ 812 - 634
packages/semi-ui/radio/_story/radio.stories.js

@@ -1,5 +1,4 @@
 import React, { useState } from 'react';
-import { storiesOf } from '@storybook/react';
 import Button from '../../button';
 import Space from '../../space';
 
@@ -7,673 +6,852 @@ import { Radio, RadioGroup } from '../../index';
 import { Row, Col } from '../../grid';
 import './radio.scss';
 
-const stories = storiesOf('Radio', module);
+export default {
+  title: 'Radio'
+}
 
-// stories.addDecorator(withKnobs);;
+export const _Radio = () => {
+  let cssStyle = {
+    width: '200px',
+  };
+  return (
+    <div style={cssStyle}>
+      <Radio value="1">
+        Experts say the abandonment of book reading may have some unappealing consequences for
+        cognition. “People are clearly reading fewer books now than they used to, and that has to
+        have a cost because we know book reading is very good cognitive exercise,” says Ken Pugh,
+        director of research at the Yale-affiliated Haskins Laboratories, which examines the
+        importance of spoken and written language.
+      </Radio>
+    </div>
+  );
+};
 
-stories.add('radio', () => {
-    let cssStyle = {
-        width: '200px',
-    };
-    return (
-        <div style={cssStyle}>
-            <Radio value="1">
-                Experts say the abandonment of book reading may have some unappealing consequences for cognition.
-                “People are clearly reading fewer books now than they used to, and that has to have a cost because we
-                know book reading is very good cognitive exercise,” says Ken Pugh, director of research at the
-                Yale-affiliated Haskins Laboratories, which examines the importance of spoken and written language.
-            </Radio>
-        </div>
-    );
-});
+_Radio.story = {
+  name: 'radio',
+};
 
-stories.add('radio with extra', () => {
-    return (
-        <>
-            <Radio value="1" extra="这是辅助的文本,同厂辅助文本会更长一些,甚至还可能换行">
-                示例文本
-            </Radio>
-            <Radio style={{ width: 200 }} value="1" extra="这是辅助的文本,同厂辅助文本会更长一些,甚至还可能换行">
-                示例文本
-            </Radio>
-        </>
-    );
-});
-stories.add('radio checked', () => {
-    return (
-        <div>
-            {'受控的checked = true'}
-            <Radio value="1" checked>
-                111
-            </Radio>
-            <br />
-            {'受控的checked = false'}
-            <Radio value="1" checked={false}>
-                111
-            </Radio>
-            <br />
-            {'不受控的defaultChecked = true'}
-            <Radio value="1" defaultChecked={true}>
-                111
-            </Radio>
-            <br />
-            {'不受控的defaultChecked = false'}
-            <Radio value="1" defaultChecked={false}>
-                111
-            </Radio>
-        </div>
-    );
-});
+export const RadioWithExtra = () => {
+  return (
+    <>
+      <Radio value="1" extra="这是辅助的文本,同厂辅助文本会更长一些,甚至还可能换行">
+        示例文本
+      </Radio>
+      <Radio
+        style={{ width: 200 }}
+        value="1"
+        extra="这是辅助的文本,同厂辅助文本会更长一些,甚至还可能换行"
+      >
+        示例文本
+      </Radio>
+    </>
+  );
+};
 
-stories.add('radio disabled', () => {
-    return (
-        <div>
-            <Radio value="1" checked disabled>
-                111
-            </Radio>
-            <Radio value="1" disabled>
-                111
-            </Radio>
-        </div>
-    );
-});
+RadioWithExtra.story = {
+  name: 'radio with extra',
+};
 
-class RadioControl extends React.Component {
-    state = {
-        checked: true,
-        disabled: false,
-    };
+export const RadioChecked = () => {
+  return (
+    <div>
+      {'受控的checked = true'}
+      <Radio value="1" checked>
+        111
+      </Radio>
+      <br />
+      {'受控的checked = false'}
+      <Radio value="1" checked={false}>
+        111
+      </Radio>
+      <br />
+      {'不受控的defaultChecked = true'}
+      <Radio value="1" defaultChecked={true}>
+        111
+      </Radio>
+      <br />
+      {'不受控的defaultChecked = false'}
+      <Radio value="1" defaultChecked={false}>
+        111
+      </Radio>
+    </div>
+  );
+};
 
-    toggleChecked = () => {
-        this.setState({ checked: !this.state.checked });
-    };
+RadioChecked.story = {
+  name: 'radio checked',
+};
 
-    toggleDisable = () => {
-        this.setState({ disabled: !this.state.disabled });
-    };
+export const RadioDisabled = () => {
+  return (
+    <div>
+      <Radio value="1" checked disabled>
+        111
+      </Radio>
+      <Radio value="1" disabled>
+        111
+      </Radio>
+    </div>
+  );
+};
 
-    onChange = e => {
-        console.log('checked = ', e.target.checked);
-        this.setState({
-            checked: e.target.checked,
-        });
-    };
+RadioDisabled.story = {
+  name: 'radio disabled',
+};
 
-    render() {
-        const label = `${this.state.checked ? 'Checked' : 'Unchecked'}-${this.state.disabled ? 'Disabled' : 'Enabled'}`;
-        return (
-            <div>
-                <p style={{ marginBottom: '20px' }}>
-                    <Radio checked={this.state.checked} disabled={this.state.disabled} onChange={this.onChange}>
-                        {label}
-                    </Radio>
-                </p>
-                <p>
-                    <Button type="primary" size="small" onClick={this.toggleChecked}>
-                        {!this.state.checked ? 'Check' : 'Uncheck'}
-                    </Button>
-                    <Button style={{ marginLeft: '10px' }} type="primary" size="small" onClick={this.toggleDisable}>
-                        {!this.state.disabled ? 'Disable' : 'Enable'}
-                    </Button>
-                </p>
-            </div>
-        );
-    }
+class RadioControl extends React.Component {
+  state = {
+    checked: true,
+    disabled: false,
+  };
+
+  toggleChecked = () => {
+    this.setState({ checked: !this.state.checked });
+  };
+
+  toggleDisable = () => {
+    this.setState({ disabled: !this.state.disabled });
+  };
+
+  onChange = e => {
+    console.log('checked = ', e.target.checked);
+    this.setState({
+      checked: e.target.checked,
+    });
+  };
+
+  render() {
+    const label = `${this.state.checked ? 'Checked' : 'Unchecked'}-${
+      this.state.disabled ? 'Disabled' : 'Enabled'
+    }`;
+    return (
+      <div>
+        <p style={{ marginBottom: '20px' }}>
+          <Radio
+            checked={this.state.checked}
+            disabled={this.state.disabled}
+            onChange={this.onChange}
+          >
+            {label}
+          </Radio>
+        </p>
+        <p>
+          <Button type="primary" size="small" onClick={this.toggleChecked}>
+            {!this.state.checked ? 'Check' : 'Uncheck'}
+          </Button>
+          <Button
+            style={{ marginLeft: '10px' }}
+            type="primary"
+            size="small"
+            onClick={this.toggleDisable}
+          >
+            {!this.state.disabled ? 'Disable' : 'Enable'}
+          </Button>
+        </p>
+      </div>
+    );
+  }
 }
 
-stories.add('Radio controlled disabled & checked', () => <RadioControl />);
+export const RadioControlledDisabledChecked = () => <RadioControl />;
 
-const RadioGroup1 = () => {
-    const [state, setChecked] = useState('1');
-    console.log(state);
+RadioControlledDisabledChecked.story = {
+  name: 'Radio controlled disabled & checked',
+};
 
-    return (
-        <div>
-            <Radio.Group
-                value={state}
-                onChange={evt => {
-                    setChecked(evt.target.value);
-                }}
-            >
-                <Radio value="1" grouped>
-                    1
-                </Radio>
-                <Radio value="2" grouped>
-                    2
-                </Radio>
-            </Radio.Group>
-            点击触发state变化,state变化触发展示变化
-            <Radio.Group
-                value={state}
-                onChange={evt => {
-                    setChecked(evt.target.value);
-                }}
-            >
-                <Radio value="2" grouped>
-                    2
-                </Radio>
-                <Radio value="1" grouped>
-                    1
-                </Radio>
-            </Radio.Group>
-        </div>
-    );
+const RadioGroup1 = () => {
+  const [state, setChecked] = useState('1');
+  console.log(state);
+
+  return (
+    <div>
+      <Radio.Group
+        value={state}
+        onChange={evt => {
+          setChecked(evt.target.value);
+        }}
+      >
+        <Radio value="1" grouped>
+          1
+        </Radio>
+        <Radio value="2" grouped>
+          2
+        </Radio>
+      </Radio.Group>
+      点击触发state变化,state变化触发展示变化
+      <Radio.Group
+        value={state}
+        onChange={evt => {
+          setChecked(evt.target.value);
+        }}
+      >
+        <Radio value="2" grouped>
+          2
+        </Radio>
+        <Radio value="1" grouped>
+          1
+        </Radio>
+      </Radio.Group>
+    </div>
+  );
 };
 class RadioWithControled extends React.Component {
-    constructor(props) {
-        super(props);
-        this.state = {
-            value: false,
-        };
-    }
-
-    onChange(value) {
-        this.setState({
-            value: value.target.value,
-        });
-    }
-
-    render() {
-        return (
-            <RadioGroup name="apple" value={this.state.value} onChange={this.onChange.bind(this)}>
-                <Radio value={true}>111</Radio>
-                <Radio value={false}>222</Radio>
-            </RadioGroup>
-        );
-    }
-}
-stories.add('radio group', () => {
-    let onChange = data => {
-        console.log('change', data);
+  constructor(props) {
+    super(props);
+    this.state = {
+      value: false,
     };
+  }
 
-    return (
-        <div>
-            value=1
-            <RadioGroup name="pie" value="1" onChange={onChange}>
-                <Radio value="1">111</Radio>
-                <Radio value="2">222</Radio>
-            </RadioGroup>
-            <br />
-            defaultValue=1
-            <RadioGroup name="pie" defaultValue="1" onChange={onChange}>
-                <Radio value="1">111</Radio>
-                <Radio value="2">222</Radio>
-            </RadioGroup>
-            <br />
-            value+onchange
-            <RadioWithControled />
-            <br />
-            联动
-            <RadioGroup1 />
-        </div>
-    );
-});
+  onChange(value) {
+    this.setState({
+      value: value.target.value,
+    });
+  }
 
-stories.add('radio with vertical', () => {
+  render() {
     return (
-        <Radio.Group>
-            <Radio value="A" displayMode="vertical">
-                无限长的一串字The Storybook webapp UI can be customised with this addon. It can be used to change the
-                header, show/hide various UI elements and to enable full-screen mode by default.
-            </Radio>
-            <Radio value="C" displayMode="vertical">
-                C
-            </Radio>
-            <Radio value="D" displayMode="vertical">
-                D
-            </Radio>
-            <Radio value="E" displayMode="vertical">
-                E
-            </Radio>
-        </Radio.Group>
+      <RadioGroup name="apple" value={this.state.value} onChange={this.onChange.bind(this)}>
+        <Radio value={true}>111</Radio>
+        <Radio value={false}>222</Radio>
+      </RadioGroup>
     );
-});
-
-stories.add('radio group with options', () => {
-    const plainOptions = ['Apple', 'Pear', 'Orange'];
-    const options = [
-        { label: 'Apple', value: 'Apple' },
-        { label: 'Pear', value: 'Pear' },
-        { label: 'Orange', value: 'Orange', disabled: true },
-    ];
-    const optionsWithDisabled = [
-        { label: 'Apple', value: 'Apple' },
-        { label: 'Pear', value: 'Pear' },
-        { label: 'Orange', value: 'Orange', disabled: false },
-    ];
-
-    function onChange(event) {
-        console.log(event);
-    }
+  }
+}
 
-    return (
-        <div>
-            <RadioGroup name="apple" options={plainOptions} onChange={onChange} />
-            <RadioGroup name="apple" options={options} onChange={onChange} />
-            <RadioGroup name="apple" disabled options={optionsWithDisabled} onChange={onChange} />
-        </div>
-    );
-});
+export const _RadioGroup = () => {
+  let onChange = data => {
+    console.log('change', data);
+  };
+
+  return (
+    <div>
+      value=1
+      <RadioGroup name="pie" value="1" onChange={onChange}>
+        <Radio value="1">111</Radio>
+        <Radio value="2">222</Radio>
+      </RadioGroup>
+      <br />
+      defaultValue=1
+      <RadioGroup name="pie" defaultValue="1" onChange={onChange}>
+        <Radio value="1">111</Radio>
+        <Radio value="2">222</Radio>
+      </RadioGroup>
+      <br />
+      value+onchange
+      <RadioWithControled />
+      <br />
+      联动
+      <RadioGroup1 />
+    </div>
+  );
+};
+
+_RadioGroup.story = {
+  name: 'radio group',
+};
+
+export const RadioWithVertical = () => {
+  return (
+    <Radio.Group>
+      <Radio value="A" displayMode="vertical">
+        无限长的一串字The Storybook webapp UI can be customised with this addon. It can be used to
+        change the header, show/hide various UI elements and to enable full-screen mode by default.
+      </Radio>
+      <Radio value="C" displayMode="vertical">
+        C
+      </Radio>
+      <Radio value="D" displayMode="vertical">
+        D
+      </Radio>
+      <Radio value="E" displayMode="vertical">
+        E
+      </Radio>
+    </Radio.Group>
+  );
+};
+
+RadioWithVertical.story = {
+  name: 'radio with vertical',
+};
+
+export const RadioGroupWithOptions = () => {
+  const plainOptions = ['Apple', 'Pear', 'Orange'];
+  const options = [
+    { label: 'Apple', value: 'Apple' },
+    { label: 'Pear', value: 'Pear' },
+    { label: 'Orange', value: 'Orange', disabled: true },
+  ];
+  const optionsWithDisabled = [
+    { label: 'Apple', value: 'Apple' },
+    { label: 'Pear', value: 'Pear' },
+    { label: 'Orange', value: 'Orange', disabled: false },
+  ];
+
+  function onChange(event) {
+    console.log(event);
+  }
+
+  return (
+    <div>
+      <RadioGroup name="apple" options={plainOptions} onChange={onChange} />
+      <RadioGroup name="apple" options={options} onChange={onChange} />
+      <RadioGroup name="apple" disabled options={optionsWithDisabled} onChange={onChange} />
+    </div>
+  );
+};
+
+RadioGroupWithOptions.story = {
+  name: 'radio group with options',
+};
 
 const RadioWithAdvancedMode = () => {
-    const [state, setChecked] = useState([true]);
+  const [state, setChecked] = useState([true]);
+
+  return (
+    <div>
+      <Radio
+        checked={state}
+        mode="advanced"
+        onChange={e => {
+          console.log(e);
+          setChecked(e.target.checked);
+        }}
+      >
+        111
+      </Radio>
+    </div>
+  );
+};
+export const _RadioWithAdvancedMode = () => <RadioWithAdvancedMode />;
 
-    return (
-        <div>
-            <Radio
-                checked={state}
-                mode="advanced"
-                onChange={e => {
-                    console.log(e);
-                    setChecked(e.target.checked);
-                }}
-            >
-                111
-            </Radio>
+_RadioWithAdvancedMode.story = {
+  name: 'radio with advanced mode',
+};
+
+export const RadioGroupWithAdvancedMode = () => {
+  function onChange(evt) {
+    console.log(evt);
+  }
+
+  return (
+    <>
+      <RadioGroup mode="advanced" onChange={onChange}>
+        <Radio value="1">111</Radio>
+        <Radio value="2">222</Radio>
+        <Radio value="3">333</Radio>
+      </RadioGroup>
+      <br />
+      <br />
+      <RadioGroup mode="advanced" onChange={onChange} direction="horizontal">
+        <div className="block-radio-wrapper">
+          <Radio value="1">111</Radio>
         </div>
-    );
+        <div className="block-radio-wrapper">
+          <Radio value="2">222</Radio>
+        </div>
+        <div className="block-radio-wrapper">
+          <Radio value="3">333</Radio>
+        </div>
+      </RadioGroup>
+    </>
+  );
 };
-stories.add('radio with advanced mode', () => <RadioWithAdvancedMode />);
 
-stories.add('radio group with advanced mode', () => {
-    function onChange(evt) {
-        console.log(evt);
-    }
+RadioGroupWithAdvancedMode.story = {
+  name: 'radio group with advanced mode',
+};
 
-    return (
-        <>
-            <RadioGroup mode="advanced" onChange={onChange}>
-                <Radio value="1">111</Radio>
-                <Radio value="2">222</Radio>
-                <Radio value="3">333</Radio>
-            </RadioGroup>
-            <br />
-            <br />
-            <RadioGroup mode="advanced" onChange={onChange} direction='horizontal'>
-                <div className='block-radio-wrapper'>
-                    <Radio value="1">111</Radio>
-                </div>
-                <div className='block-radio-wrapper'>
-                    <Radio value="2">222</Radio>
-                </div>
-                <div className='block-radio-wrapper'>
-                    <Radio value="3">333</Radio>
-                </div>
-            </RadioGroup>
-        </>
-    );
-});
+export const RadioGrid = () => {
+  return (
+    <Radio.Group style={{ width: '100%' }}>
+      <Row>
+        <Col span={8}>
+          <Radio value="A">
+            无限长的一串字The Storybook webapp UI can be customised with this addon. It can be used
+            to change the header, show/hide various UI elements and to enable full-screen mode by
+            default.
+          </Radio>
+        </Col>
+        <Col span={8}>
+          <Radio value="B">B</Radio>
+        </Col>
+        <Col span={8}>
+          <Radio value="C">C</Radio>
+        </Col>
+        <Col span={8}>
+          <Radio value="D">D</Radio>
+        </Col>
+        <Col span={8}>
+          <Radio value="E">E</Radio>
+        </Col>
+      </Row>
+    </Radio.Group>
+  );
+};
 
-stories.add('radio + grid', () => {
-    return (
-        <Radio.Group style={{ width: '100%' }}>
-            <Row>
-                <Col span={8}>
-                    <Radio value="A">
-                        无限长的一串字The Storybook webapp UI can be customised with this addon. It can be used to
-                        change the header, show/hide various UI elements and to enable full-screen mode by default.
-                    </Radio>
-                </Col>
-                <Col span={8}>
-                    <Radio value="B">B</Radio>
-                </Col>
-                <Col span={8}>
-                    <Radio value="C">C</Radio>
-                </Col>
-                <Col span={8}>
-                    <Radio value="D">D</Radio>
-                </Col>
-                <Col span={8}>
-                    <Radio value="E">E</Radio>
-                </Col>
-            </Row>
-        </Radio.Group>
-    );
-});
-
-stories.add(`dynamic radioGroup`, () => {
-    const Demo = () => {
-        const [value, setValue] = useState(1);
-        const onChange = e => {
-            console.log('radio checked', e.target.value);
-
-            setValue(e.target.value);
-        };
-        return (
-            <RadioGroup onChange={onChange} value={value}>
-                {value !== 4 ? <Radio value={1}>A</Radio> : null}
-                <Radio value={2}>B</Radio>
-                <Radio value={3}>C</Radio>
-                <Radio value={4}>D</Radio>
-            </RadioGroup>
-        );
-    };
+RadioGrid.story = {
+  name: 'radio + grid',
+};
 
-    return <Demo />;
-});
-
-stories.add(`radioGroup button style`, () => {
-    const Demo = () => {
-        const [value1, setValue1] = useState(1);
-        const [value2, setValue2] = useState(2);
-        const [value3, setValue3] = useState(3);
-        const onChange1 = e => {
-            setValue1(e.target.value);
-        };
-        const onChange2 = e => {
-            setValue2(e.target.value);
-        };
-        const onChange3 = e => {
-            setValue3(e.target.value);
-        };
-        return (
-            <Space vertical spacing='loose' align='start'>
-                <RadioGroup type='button' buttonSize='small' onChange={onChange1} value={value1}>
-                    <Radio value={1}>semi</Radio>
-                    <Radio value={2}>pipixia</Radio>
-                    <Radio value={3}>hotsoon</Radio>
-                    <Radio value={4}>toutiao</Radio>
-                </RadioGroup>
-                <RadioGroup type='button' buttonSize='middle' onChange={onChange2} value={value2}>
-                    <Radio value={1}>semi</Radio>
-                    <Radio value={2}>pipixia</Radio>
-                    <Radio value={3}>hotsoon</Radio>
-                    <Radio value={4}>toutiao</Radio>
-                </RadioGroup>
-                <RadioGroup type='button' buttonSize='large' onChange={onChange3} value={value3}>
-                    <Radio value={1}>semi</Radio>
-                    <Radio value={2}>pipixia</Radio>
-                    <Radio value={3}>hotsoon</Radio>
-                    <Radio value={4}>toutiao</Radio>
-                </RadioGroup>
-            </Space>
-        );
+export const DynamicRadioGroup = () => {
+  const Demo = () => {
+    const [value, setValue] = useState(1);
+    const onChange = e => {
+      console.log('radio checked', e.target.value);
+
+      setValue(e.target.value);
     };
+    return (
+      <RadioGroup onChange={onChange} value={value}>
+        {value !== 4 ? <Radio value={1}>A</Radio> : null}
+        <Radio value={2}>B</Radio>
+        <Radio value={3}>C</Radio>
+        <Radio value={4}>D</Radio>
+      </RadioGroup>
+    );
+  };
 
-    return <Demo />;
-});
+  return <Demo />;
+};
+DynamicRadioGroup.style = {
+  name: 'dynamic radioGroup'
+};
 
-stories.add(`radioGroup card style`, () => (
-    <>
-        <div>常见情况</div>
-        <RadioGroup type='card' defaultValue={1}>
-            <Radio value={1} extra='Semi Design' style={{ width: 280 }}>
-                多选框标题
-            </Radio>
-            <Radio value={2} extra='Semi Design' style={{ width: 280 }}>
-                多选框标题
-            </Radio>
-            <Radio value={3} extra='Semi Design' style={{ width: 280 }}>
-                多选框标题
-            </Radio>
-        </RadioGroup>
-        <br />
-        <br />
-        <div>radio disabled</div>
-        <RadioGroup type='card' defaultValue={1}>
-            <Radio value={1} disabled extra='Semi Design' style={{ width: 280 }}>
-                多选框标题
-            </Radio>
-            <Radio value={2} extra='Semi Design' style={{ width: 280 }}>
-                多选框标题
-            </Radio>
-            <Radio value={3} extra='Semi Design' style={{ width: 280 }}>
-                多选框标题
-            </Radio>
-        </RadioGroup>
-        <br />
-        <br />
-        <div>radioGroup disabled</div>
-        <RadioGroup type='card' disabled defaultValue={1}>
-            <Radio value={1} extra='Semi Design' style={{ width: 280 }}>
-                多选框标题
-            </Radio>
-            <Radio value={2} extra='Semi Design' style={{ width: 280 }}>
-                多选框标题
-            </Radio>
-            <Radio value={3} extra='Semi Design' style={{ width: 280 }}>
-                多选框标题
-            </Radio>
-        </RadioGroup>
-        <br />
-        <br />
-        <div>文字很长,并且没有设置宽度,因此换行显示</div>
-        <RadioGroup type='card' defaultValue={1}>
-            <Radio value={1} extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统'>
-                多选框标题
-            </Radio>
-            <Radio value={2} extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统'>
-                多选框标题
-            </Radio>
-            <Radio value={3} extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统'>
-                多选框标题
-            </Radio>
-        </RadioGroup>
-        <br />
-        <br />
-        <div>设置了width=180</div>
-        <RadioGroup type='card' defaultValue={1}>
-            <Radio value={1} extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统' style={{ width: 180 }}>
-                多选框标题
-            </Radio>
-            <Radio value={2} extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统' style={{ width: 180 }}>
-                多选框标题
-            </Radio>
-            <Radio value={3} extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统' style={{ width: 180 }}>
-                多选框标题
-            </Radio>
-        </RadioGroup>
-        <br />
-        <br />
-        <div>没有extra,width=180</div>
-        <RadioGroup type='card' defaultValue={1}>
-            <Radio value={1} style={{ width: 180 }}>
-                多选框标题
-            </Radio>
-            <Radio value={2} style={{ width: 180 }}>
-                多选框标题
-            </Radio>
-            <Radio value={3} style={{ width: 180 }}>
-                多选框标题
-            </Radio>
-        </RadioGroup>
-        <br />
-        <br />
-        <div>没有标题,width=380</div>
-        <RadioGroup type='card' defaultValue={1}>
-            <Radio value={1} extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统' style={{ width: 380 }}>
-            </Radio>
-            <Radio value={2} extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统' style={{ width: 380 }}>
-            </Radio>
-            <Radio value={3} extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统' style={{ width: 380 }}>
-            </Radio>
-        </RadioGroup>
-        <br />
-        <br />
-        <hr />
-        <div>下面是垂直的情况:</div>
-        <div>常见情况</div>
-        <RadioGroup direction='vertical' type='card' defaultValue={1}>
-            <Radio value={1} extra='Semi Design' style={{ width: 280 }}>
-                多选框标题
-            </Radio>
-            <Radio value={2} extra='Semi Design' style={{ width: 280 }}>
-                多选框标题
-            </Radio>
-            <Radio value={3} extra='Semi Design' style={{ width: 280 }}>
-                多选框标题
-            </Radio>
+export const RadioGroupButtonStyle = () => {
+  const Demo = () => {
+    const [value1, setValue1] = useState(1);
+    const [value2, setValue2] = useState(2);
+    const [value3, setValue3] = useState(3);
+    const onChange1 = e => {
+      setValue1(e.target.value);
+    };
+    const onChange2 = e => {
+      setValue2(e.target.value);
+    };
+    const onChange3 = e => {
+      setValue3(e.target.value);
+    };
+    return (
+      <Space vertical spacing="loose" align="start">
+        <RadioGroup type="button" buttonSize="small" onChange={onChange1} value={value1}>
+          <Radio value={1}>semi</Radio>
+          <Radio value={2}>pipixia</Radio>
+          <Radio value={3}>hotsoon</Radio>
+          <Radio value={4}>toutiao</Radio>
         </RadioGroup>
-        <br />
-        <br />
-        <div>没有设置宽度</div>
-        <RadioGroup direction='vertical' type='card' defaultValue={1}>
-            <Radio value={1} extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统'>
-                多选框标题
-            </Radio>
-            <Radio value={2} extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统'>
-                多选框标题
-            </Radio>
-            <Radio value={3} extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统'>
-                多选框标题
-            </Radio>
+        <RadioGroup type="button" buttonSize="middle" onChange={onChange2} value={value2}>
+          <Radio value={1}>semi</Radio>
+          <Radio value={2}>pipixia</Radio>
+          <Radio value={3}>hotsoon</Radio>
+          <Radio value={4}>toutiao</Radio>
         </RadioGroup>
-        <br />
-        <br />
-        <div>设置了width=380</div>
-        <RadioGroup direction='vertical' type='card' defaultValue={1}>
-            <Radio value={1} extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统' style={{ width: 380 }}>
-                多选框标题
-            </Radio>
-            <Radio value={2} extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统' style={{ width: 380 }}>
-                多选框标题
-            </Radio>
-            <Radio value={3} extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统' style={{ width: 380 }}>
-                多选框标题
-            </Radio>
+        <RadioGroup type="button" buttonSize="large" onChange={onChange3} value={value3}>
+          <Radio value={1}>semi</Radio>
+          <Radio value={2}>pipixia</Radio>
+          <Radio value={3}>hotsoon</Radio>
+          <Radio value={4}>toutiao</Radio>
         </RadioGroup>
-    </>
-));
+      </Space>
+    );
+  };
 
-stories.add(`radioGroup pureCard style`, () => (
-    <>
-        <div>常见情况</div>
-        <RadioGroup type='pureCard' defaultValue={1}>
-            <Radio value={1} extra='Semi Design' style={{ width: 280 }}>
-                多选框标题
-            </Radio>
-            <Radio value={2} extra='Semi Design' style={{ width: 280 }}>
-                多选框标题
-            </Radio>
-            <Radio value={3} extra='Semi Design' style={{ width: 280 }}>
-                多选框标题
-            </Radio>
-        </RadioGroup>
-        <br />
-        <br />
-        <div>radio disabled</div>
-        <RadioGroup type='pureCard' defaultValue={1}>
-            <Radio value={1} disabled extra='Semi Design' style={{ width: 280 }}>
-                多选框标题
-            </Radio>
-            <Radio value={2} extra='Semi Design' style={{ width: 280 }}>
-                多选框标题
-            </Radio>
-            <Radio value={3} extra='Semi Design' style={{ width: 280 }}>
-                多选框标题
-            </Radio>
-        </RadioGroup>
-        <br />
-        <br />
-        <div>radioGroup disabled</div>
-        <RadioGroup type='pureCard' disabled defaultValue={1}>
-            <Radio value={1} extra='Semi Design' style={{ width: 280 }}>
-                多选框标题
-            </Radio>
-            <Radio value={2} extra='Semi Design' style={{ width: 280 }}>
-                多选框标题
-            </Radio>
-            <Radio value={3} extra='Semi Design' style={{ width: 280 }}>
-                多选框标题
-            </Radio>
-        </RadioGroup>
-        <br />
-        <br />
-        <div>文字很长,并且没有设置宽度,因此换行显示</div>
-        <RadioGroup type='pureCard' defaultValue={1}>
-            <Radio value={1} extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统'>
-                多选框标题
-            </Radio>
-            <Radio value={2} extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统'>
-                多选框标题
-            </Radio>
-            <Radio value={3} extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统'>
-                多选框标题
-            </Radio>
-        </RadioGroup>
-        <br />
-        <br />
-        <div>设置了width=180</div>
-        <RadioGroup type='pureCard' defaultValue={1}>
-            <Radio value={1} extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统' style={{ width: 180 }}>
-                多选框标题
-            </Radio>
-            <Radio value={2} extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统' style={{ width: 180 }}>
-                多选框标题
-            </Radio>
-            <Radio value={3} extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统' style={{ width: 180 }}>
-                多选框标题
-            </Radio>
-        </RadioGroup>
-        <br />
-        <br />
-        <div>没有extra,width=180</div>
-        <RadioGroup type='pureCard' defaultValue={1}>
-            <Radio value={1} style={{ width: 180 }}>
-                多选框标题
-            </Radio>
-            <Radio value={2} style={{ width: 180 }}>
-                多选框标题
-            </Radio>
-            <Radio value={3} style={{ width: 180 }}>
-                多选框标题
-            </Radio>
-        </RadioGroup>
-        <br />
-        <br />
-        <div>没有标题,width=380</div>
-        <RadioGroup type='pureCard' defaultValue={1}>
-            <Radio value={1} extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统' style={{ width: 380 }}>
-            </Radio>
-            <Radio value={2} extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统' style={{ width: 380 }}>
-            </Radio>
-            <Radio value={3} extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统' style={{ width: 380 }}>
-            </Radio>
-        </RadioGroup>
-        <br />
-        <br />
-        <hr />
-        <div>下面是垂直的情况:</div>
-        <div>常见情况</div>
-        <RadioGroup direction='vertical' type='pureCard' defaultValue={1}>
-            <Radio value={1} extra='Semi Design' style={{ width: 280 }}>
-                多选框标题
-            </Radio>
-            <Radio value={2} extra='Semi Design' style={{ width: 280 }}>
-                多选框标题
-            </Radio>
-            <Radio value={3} extra='Semi Design' style={{ width: 280 }}>
-                多选框标题
-            </Radio>
-        </RadioGroup>
-        <br />
-        <br />
-        <div>没有设置宽度</div>
-        <RadioGroup direction='vertical' type='pureCard' defaultValue={1}>
-            <Radio value={1} extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统'>
-                多选框标题
-            </Radio>
-            <Radio value={2} extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统'>
-                多选框标题
-            </Radio>
-            <Radio value={3} extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统'>
-                多选框标题
-            </Radio>
-        </RadioGroup>
-        <br />
-        <br />
-        <div>设置了width=380</div>
-        <RadioGroup direction='vertical' type='pureCard' defaultValue={1}>
-            <Radio value={1} extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统' style={{ width: 380 }}>
-                多选框标题
-            </Radio>
-            <Radio value={2} extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统' style={{ width: 380 }}>
-                多选框标题
-            </Radio>
-            <Radio value={3} extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统' style={{ width: 380 }}>
-                多选框标题
-            </Radio>
-        </RadioGroup>
-    </>
-));
+  return <Demo />;
+};
+RadioGroupButtonStyle.story = {
+  name: 'radioGroup button style'
+};
+
+
+export const RadioGroupCardStyle = () => (
+  <>
+    <div>常见情况</div>
+    <RadioGroup type="card" defaultValue={1}>
+      <Radio value={1} extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Radio>
+      <Radio value={2} extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Radio>
+      <Radio value={3} extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Radio>
+    </RadioGroup>
+    <br />
+    <br />
+    <div>radio disabled</div>
+    <RadioGroup type="card" defaultValue={1}>
+      <Radio value={1} disabled extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Radio>
+      <Radio value={2} extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Radio>
+      <Radio value={3} extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Radio>
+    </RadioGroup>
+    <br />
+    <br />
+    <div>radioGroup disabled</div>
+    <RadioGroup type="card" disabled defaultValue={1}>
+      <Radio value={1} extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Radio>
+      <Radio value={2} extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Radio>
+      <Radio value={3} extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Radio>
+    </RadioGroup>
+    <br />
+    <br />
+    <div>文字很长,并且没有设置宽度,因此换行显示</div>
+    <RadioGroup type="card" defaultValue={1}>
+      <Radio
+        value={1}
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+      >
+        多选框标题
+      </Radio>
+      <Radio
+        value={2}
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+      >
+        多选框标题
+      </Radio>
+      <Radio
+        value={3}
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+      >
+        多选框标题
+      </Radio>
+    </RadioGroup>
+    <br />
+    <br />
+    <div>设置了width=180</div>
+    <RadioGroup type="card" defaultValue={1}>
+      <Radio
+        value={1}
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+        style={{ width: 180 }}
+      >
+        多选框标题
+      </Radio>
+      <Radio
+        value={2}
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+        style={{ width: 180 }}
+      >
+        多选框标题
+      </Radio>
+      <Radio
+        value={3}
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+        style={{ width: 180 }}
+      >
+        多选框标题
+      </Radio>
+    </RadioGroup>
+    <br />
+    <br />
+    <div>没有extra,width=180</div>
+    <RadioGroup type="card" defaultValue={1}>
+      <Radio value={1} style={{ width: 180 }}>
+        多选框标题
+      </Radio>
+      <Radio value={2} style={{ width: 180 }}>
+        多选框标题
+      </Radio>
+      <Radio value={3} style={{ width: 180 }}>
+        多选框标题
+      </Radio>
+    </RadioGroup>
+    <br />
+    <br />
+    <div>没有标题,width=380</div>
+    <RadioGroup type="card" defaultValue={1}>
+      <Radio
+        value={1}
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+        style={{ width: 380 }}
+      ></Radio>
+      <Radio
+        value={2}
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+        style={{ width: 380 }}
+      ></Radio>
+      <Radio
+        value={3}
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+        style={{ width: 380 }}
+      ></Radio>
+    </RadioGroup>
+    <br />
+    <br />
+    <hr />
+    <div>下面是垂直的情况:</div>
+    <div>常见情况</div>
+    <RadioGroup direction="vertical" type="card" defaultValue={1}>
+      <Radio value={1} extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Radio>
+      <Radio value={2} extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Radio>
+      <Radio value={3} extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Radio>
+    </RadioGroup>
+    <br />
+    <br />
+    <div>没有设置宽度</div>
+    <RadioGroup direction="vertical" type="card" defaultValue={1}>
+      <Radio
+        value={1}
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+      >
+        多选框标题
+      </Radio>
+      <Radio
+        value={2}
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+      >
+        多选框标题
+      </Radio>
+      <Radio
+        value={3}
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+      >
+        多选框标题
+      </Radio>
+    </RadioGroup>
+    <br />
+    <br />
+    <div>设置了width=380</div>
+    <RadioGroup direction="vertical" type="card" defaultValue={1}>
+      <Radio
+        value={1}
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+        style={{ width: 380 }}
+      >
+        多选框标题
+      </Radio>
+      <Radio
+        value={2}
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+        style={{ width: 380 }}
+      >
+        多选框标题
+      </Radio>
+      <Radio
+        value={3}
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+        style={{ width: 380 }}
+      >
+        多选框标题
+      </Radio>
+    </RadioGroup>
+  </>
+);
+
+RadioGroupCardStyle.story = {
+  name: 'radioGroup card style'
+}
+
+export const RadioGroupPureCardStyle = () => (
+  <>
+    <div>常见情况</div>
+    <RadioGroup type="pureCard" defaultValue={1}>
+      <Radio value={1} extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Radio>
+      <Radio value={2} extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Radio>
+      <Radio value={3} extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Radio>
+    </RadioGroup>
+    <br />
+    <br />
+    <div>radio disabled</div>
+    <RadioGroup type="pureCard" defaultValue={1}>
+      <Radio value={1} disabled extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Radio>
+      <Radio value={2} extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Radio>
+      <Radio value={3} extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Radio>
+    </RadioGroup>
+    <br />
+    <br />
+    <div>radioGroup disabled</div>
+    <RadioGroup type="pureCard" disabled defaultValue={1}>
+      <Radio value={1} extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Radio>
+      <Radio value={2} extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Radio>
+      <Radio value={3} extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Radio>
+    </RadioGroup>
+    <br />
+    <br />
+    <div>文字很长,并且没有设置宽度,因此换行显示</div>
+    <RadioGroup type="pureCard" defaultValue={1}>
+      <Radio
+        value={1}
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+      >
+        多选框标题
+      </Radio>
+      <Radio
+        value={2}
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+      >
+        多选框标题
+      </Radio>
+      <Radio
+        value={3}
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+      >
+        多选框标题
+      </Radio>
+    </RadioGroup>
+    <br />
+    <br />
+    <div>设置了width=180</div>
+    <RadioGroup type="pureCard" defaultValue={1}>
+      <Radio
+        value={1}
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+        style={{ width: 180 }}
+      >
+        多选框标题
+      </Radio>
+      <Radio
+        value={2}
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+        style={{ width: 180 }}
+      >
+        多选框标题
+      </Radio>
+      <Radio
+        value={3}
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+        style={{ width: 180 }}
+      >
+        多选框标题
+      </Radio>
+    </RadioGroup>
+    <br />
+    <br />
+    <div>没有extra,width=180</div>
+    <RadioGroup type="pureCard" defaultValue={1}>
+      <Radio value={1} style={{ width: 180 }}>
+        多选框标题
+      </Radio>
+      <Radio value={2} style={{ width: 180 }}>
+        多选框标题
+      </Radio>
+      <Radio value={3} style={{ width: 180 }}>
+        多选框标题
+      </Radio>
+    </RadioGroup>
+    <br />
+    <br />
+    <div>没有标题,width=380</div>
+    <RadioGroup type="pureCard" defaultValue={1}>
+      <Radio
+        value={1}
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+        style={{ width: 380 }}
+      ></Radio>
+      <Radio
+        value={2}
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+        style={{ width: 380 }}
+      ></Radio>
+      <Radio
+        value={3}
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+        style={{ width: 380 }}
+      ></Radio>
+    </RadioGroup>
+    <br />
+    <br />
+    <hr />
+    <div>下面是垂直的情况:</div>
+    <div>常见情况</div>
+    <RadioGroup direction="vertical" type="pureCard" defaultValue={1}>
+      <Radio value={1} extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Radio>
+      <Radio value={2} extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Radio>
+      <Radio value={3} extra="Semi Design" style={{ width: 280 }}>
+        多选框标题
+      </Radio>
+    </RadioGroup>
+    <br />
+    <br />
+    <div>没有设置宽度</div>
+    <RadioGroup direction="vertical" type="pureCard" defaultValue={1}>
+      <Radio
+        value={1}
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+      >
+        多选框标题
+      </Radio>
+      <Radio
+        value={2}
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+      >
+        多选框标题
+      </Radio>
+      <Radio
+        value={3}
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+      >
+        多选框标题
+      </Radio>
+    </RadioGroup>
+    <br />
+    <br />
+    <div>设置了width=380</div>
+    <RadioGroup direction="vertical" type="pureCard" defaultValue={1}>
+      <Radio
+        value={1}
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+        style={{ width: 380 }}
+      >
+        多选框标题
+      </Radio>
+      <Radio
+        value={2}
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+        style={{ width: 380 }}
+      >
+        多选框标题
+      </Radio>
+      <Radio
+        value={3}
+        extra="Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统"
+        style={{ width: 380 }}
+      >
+        多选框标题
+      </Radio>
+    </RadioGroup>
+  </>
+);
+RadioGroupPureCardStyle.story = {
+  name: 'radioGroup pureCard style'
+}

+ 83 - 69
packages/semi-ui/rating/_story/rating.stories.js

@@ -1,83 +1,97 @@
 import React from 'react';
-import { storiesOf } from '@storybook/react'; // import { withKnobs, text, boolean } from '@storybook/addon-knobs';
-
-import withPropsCombinations from 'react-storybook-addon-props-combinations';
 import Rating from '../index';
-import Icon from '../../icons';
 import { IconLikeHeart } from '@douyinfe/semi-icons';
-const stories = storiesOf('Rating', module); // stories.addDecorator(withKnobs);;
 
-stories.add('Rating', () => (
-    <div style={{display: 'flex'}}>
-        <div style={{ width: '50%' }}>
-            <h5>default</h5>
-            <Rating />
-            <br />
-            <h5>allowHalf</h5>
-            <Rating allowHalf />
-            <br />
-            <h5>disabled</h5>
-            <Rating disabled defaultValue={4} />
-            <br />
-            <h5>allowClear = false</h5>
-            <Rating allowClear={false} />
-            <br />
-            <h5>character</h5>
-            <Rating character={<IconLikeHeart />} />
-            <br />
-            <Rating character={'好'} defaultValue={2} disabled />
-        </div>
-        <div style={{ width: '50%' }}>
-            <br />
-            <h5>tooltips</h5>
-            <Rating tooltips={['terrible', 'bad', 'normal', 'good', 'wonderful']} />
-            <br />
-            <h5>defaultValue</h5>
-            <Rating defaultValue={2} />
-            <h5>value</h5>
-            <Rating value={3} />
-            <br />
-            <h5>onHoverChange</h5>
-            <Rating onHoverChange={e => console.log(e)} />
-            <h5>size</h5>
-            <Rating size='small' defaultValue={2} />
-            <Rating size='large' defaultValue={2} />
-        </div>
+export default {
+  title: 'Rating',
+  parameters: {
+    chromatic: { disableSnapshot: true },
+  },
+}
+
+export const _Rating = () => (
+  <div style={{ display: 'flex' }}>
+    <div style={{ width: '50%' }}>
+      <h5>default</h5>
+      <Rating />
+      <br />
+      <h5>allowHalf</h5>
+      <Rating allowHalf />
+      <br />
+      <h5>disabled</h5>
+      <Rating disabled defaultValue={4} />
+      <br />
+      <h5>allowClear = false</h5>
+      <Rating allowClear={false} />
+      <br />
+      <h5>character</h5>
+      <Rating character={<IconLikeHeart />} />
+      <br />
+      <Rating character={'好'} defaultValue={2} disabled />
+    </div>
+    <div style={{ width: '50%' }}>
+      <br />
+      <h5>tooltips</h5>
+      <Rating tooltips={['terrible', 'bad', 'normal', 'good', 'wonderful']} />
+      <br />
+      <h5>defaultValue</h5>
+      <Rating defaultValue={2} />
+      <h5>value</h5>
+      <Rating value={3} />
+      <br />
+      <h5>onHoverChange</h5>
+      <Rating onHoverChange={e => console.log(e)} />
+      <h5>size</h5>
+      <Rating size="small" defaultValue={2} />
+      <Rating size="large" defaultValue={2} />
     </div>
-));
+  </div>
+);
+
+_Rating.parameters = {
+  chromatic: { disableSnapshot: false },
+};
 
 class Demo extends React.Component {
-    constructor(props) {
-        super();
-        this.state = {
-            value: 0,
-        };
-        this.handleChange = this.handleChange.bind(this);
-    }
+  constructor(props) {
+    super();
+    this.state = {
+      value: 0,
+    };
+    this.handleChange = this.handleChange.bind(this);
+  }
 
-    handleChange(value) {
-        this.setState({
-            value,
-        });
-    }
+  handleChange(value) {
+    this.setState({
+      value,
+    });
+  }
 
-    render() {
-        const { value } = this.state;
-        const desc = ['terrible', 'bad', 'normal', 'good', 'wonderful'];
-        return (
-            <div>
-                <span>How was the help you received: {value ? <span>{desc[value - 1]}</span> : ''}</span>
-                <br />
-                <Rating tooltips={desc} onChange={this.handleChange} value={value} />
-            </div>
-        );
-    }
+  render() {
+    const { value } = this.state;
+    const desc = ['terrible', 'bad', 'normal', 'good', 'wonderful'];
+    return (
+      <div>
+        <span>How was the help you received: {value ? <span>{desc[value - 1]}</span> : ''}</span>
+        <br />
+        <Rating tooltips={desc} onChange={this.handleChange} value={value} />
+      </div>
+    );
+  }
 }
 
-stories.add('tooltip Rating', () => <Demo />);
+export const TooltipRating = () => <Demo />;
+
+TooltipRating.story = {
+  name: 'tooltip Rating',
+};
 
 const KeyDownDemo = () => {
-    return <Rating onKeyDown={event => console.log(event) }/>
-}
+  return <Rating onKeyDown={event => console.log(event)} />;
+};
+
+export const Keydown = () => <KeyDownDemo />;
 
-stories.add('keydown', () => <KeyDownDemo />);
+Keydown.story = {
+  name: 'keydown',
+};

+ 20 - 9
packages/semi-ui/scrollList/_story/scrolllist.stories.js

@@ -1,15 +1,26 @@
 import React from 'react';
-import { storiesOf } from '@storybook/react';
-import ScrollList from '../index';
-import ScrollItem from '../scrollItem';
-import Button from '../../button';
 import WheelListDemo from './WheelList';
 import ScrollListDemo from './ScrollList';
 
-const stories = storiesOf('scrollList', module);
 
-stories.add('ScrollList simple', () => {
-    return <ScrollListDemo />;
-});
+export default {
+  title: 'ScrollList'
+}
 
-stories.add('wheel list demo', () => <WheelListDemo />);
+export const ScrollListSimple = () => {
+  return <ScrollListDemo />;
+};
+
+ScrollListSimple.story = {
+  name: 'ScrollList simple',
+};
+
+ScrollListSimple.parameters = {
+  chromatic: { disableSnapshot: true },
+}
+
+export const _WheelListDemo = () => <WheelListDemo />;
+
+_WheelListDemo.story = {
+  name: 'wheel list demo',
+};

+ 2620 - 2418
packages/semi-ui/select/_story/select.stories.js

@@ -1,7 +1,5 @@
-import React, { useState, useRef } from 'react';
-import { storiesOf } from '@storybook/react'; // import { withKnobs, text, boolean } from '@storybook/addon-knobs';
+import React, { useState, useRef, useEffect } from 'react';
 
-import withPropsCombinations from 'react-storybook-addon-props-combinations';
 import './select.scss';
 import { Input, Select, Button, Icon, Avatar, Checkbox, Form, withField, Space } from '../../index';
 import CustomTrigger from './CustomTrigger';
@@ -9,2648 +7,2852 @@ import classNames from 'classnames';
 import { getHighLightTextHTML } from '../../_utils/index';
 const Option = Select.Option;
 import { IconSearch, IconGift } from '@douyinfe/semi-icons';
-const stories = storiesOf('Select', module); // stories.addDecorator(withKnobs);;
 
-let Test = () => {
-    let [options, setOptions] = useState([1, 2, 3, 4]);
-
-    function add() {
-        let newOptions = Array.from(
-            {
-                length: Math.floor(Math.random() * 10),
-            },
-            (v, i) => i + 1
-        );
-        setOptions(newOptions);
-    }
+export default {
+  title: 'Select',
+  parameters: {
+    chromatic: { disableSnapshot: true },
+  },
+}
 
-    let style = {
-        width: 150,
-        margin: 20,
-    };
-    let slotStyle = {
-        backgroundColor: 'whitesmoke',
-        height: '40px',
-        display: 'flex',
-        justifyContent: 'center',
-        alignItems: 'center',
-        borderRadius: '0 0 6px 6px',
-    };
-    let outSlotStyle = {
-        backgroundColor: 'whitesmoke',
-        height: '29px',
-        display: 'flex',
-        justifyContent: 'center',
-        alignItems: 'center',
-        cursor: 'pointer',
-    };
+let Test = () => {
+  let [options, setOptions] = useState([1, 2, 3, 4]);
+
+  function add() {
+    let newOptions = Array.from(
+      {
+        length: Math.floor(Math.random() * 10),
+      },
+      (v, i) => i + 1
+    );
+    setOptions(newOptions);
+  }
+
+  let style = {
+    width: 150,
+    margin: 20,
+  };
+  let slotStyle = {
+    backgroundColor: 'whitesmoke',
+    height: '40px',
+    display: 'flex',
+    justifyContent: 'center',
+    alignItems: 'center',
+    borderRadius: '0 0 6px 6px',
+  };
+  let outSlotStyle = {
+    backgroundColor: 'whitesmoke',
+    height: '29px',
+    display: 'flex',
+    justifyContent: 'center',
+    alignItems: 'center',
+    cursor: 'pointer',
+  };
 
-    const click = e => {};
+  const click = e => {};
 
-    let outSlotNode = (
-        <div onClick={e => click(e)}>
-            <Checkbox>sendLarkNotification</Checkbox>
-            <div>
-                <Button theme="solid">confirm</Button>
-            </div>
-        </div>
-    );
-    return (
-        <>
-            <Select
-                style={style}
-                dropdownClassName="test-dropdown"
-                dropdownStyle={{
-                    width: 150,
-                }}
-                filter
-                placeholder="fefe"
-                position="rightTop"
-                innerBottomSlot={
-                    <div style={slotStyle}>
-                        <Button
-                            size="small"
-                            style={{
-                                margin: 0,
-                            }}
-                        >
-                            申请其他地区权限
-                        </Button>
-                    </div>
-                }
-            >
-                {options.map(option => (
-                    <Option value={option} key={option} className="fefe">
-                        {option}
-                    </Option>
-                ))}
-            </Select>
-            <Select
-                style={{
-                    marginTop: 20,
-                    width: 200,
-                }}
-                dropdownClassName="test-dropdown"
-                dropdownStyle={{
-                    width: 150,
-                }}
-                filter
-                placeholder="fefe"
-                position="rightTop"
-                outerBottomSlot={outSlotNode}
+  let outSlotNode = (
+    <div onClick={e => click(e)}>
+      <Checkbox>sendLarkNotification</Checkbox>
+      <div>
+        <Button theme="solid">confirm</Button>
+      </div>
+    </div>
+  );
+  return (
+    <>
+      <Select
+        style={style}
+        dropdownClassName="test-dropdown"
+        dropdownStyle={{
+          width: 150,
+        }}
+        filter
+        placeholder="fefe"
+        position="rightTop"
+        innerBottomSlot={
+          <div style={slotStyle}>
+            <Button
+              size="small"
+              style={{
+                margin: 0,
+              }}
             >
-                {options.map(option => (
-                    <Option value={option} key={option} className="fefe">
-                        {option}
-                    </Option>
-                ))}
-            </Select>
-        </>
-    );
+              申请其他地区权限
+            </Button>
+          </div>
+        }
+      >
+        {options.map(option => (
+          <Option value={option} key={option} className="fefe">
+            {option}
+          </Option>
+        ))}
+      </Select>
+      <Select
+        style={{
+          marginTop: 20,
+          width: 200,
+        }}
+        dropdownClassName="test-dropdown"
+        dropdownStyle={{
+          width: 150,
+        }}
+        filter
+        placeholder="fefe"
+        position="rightTop"
+        outerBottomSlot={outSlotNode}
+      >
+        {options.map(option => (
+          <Option value={option} key={option} className="fefe">
+            {option}
+          </Option>
+        ))}
+      </Select>
+    </>
+  );
 };
 
 const AutoFocusDemo = () => {
-    return (
-        <>
-            <Select
-                autoFocus
-                style={{
-                    width: 200,
-                }}
-                onFocus={() => console.log('onFocus')}
-                onBlur={() => console.log('onBlur')}
-            >
-                <Option value="abc">抖音</Option>
-                <Option value="hotsoon">火山</Option>
-                <Option value="pipixia">皮皮虾</Option>
-                <Option value="duoshan">多闪</Option>
-                <Option value="xigua">西瓜视频</Option>
-            </Select>
-            <div className="test-div">test-div</div>
-        </>
-    );
+  return (
+    <>
+      <Select
+        autoFocus
+        style={{
+          width: 200,
+        }}
+        onFocus={() => console.log('onFocus')}
+        onBlur={() => console.log('onBlur')}
+      >
+        <Option value="abc">抖音</Option>
+        <Option value="hotsoon">火山</Option>
+        <Option value="pipixia">皮皮虾</Option>
+        <Option value="duoshan">多闪</Option>
+        <Option value="xigua">西瓜视频</Option>
+      </Select>
+      <div className="test-div">test-div</div>
+    </>
+  );
 };
 
-stories.add('autoFocus', () => <AutoFocusDemo />);
-stories.add('innerBottommSlot / outerBottomSlot', () => <Test />);
-stories.add('innerTopSlot / outerTopSlot', () => {
-    const slot = <div>未找到应用?</div>;
-    return (
-        <div>
-            innerTopSlot
-            <div>
-                <Select
-                    innerTopSlot={slot}
-                    style={{
-                        width: 250,
-                    }}
-                    maxHeight={150}
-                >
-                    <Option value="abc">抖音</Option>
-                    <Option value="hotsoon">火山</Option>
-                    <Option value="pipixia">皮皮虾</Option>
-                    <Option value="duoshan">多闪</Option>
-                    <Option value="xigua">西瓜视频</Option>
-                </Select>
-            </div>
-            outerTopSlot
-            <div>
-                <Select
-                    outerTopSlot={slot}
-                    style={{
-                        width: 250,
-                    }}
-                    maxHeight={150}
-                >
-                    <Option value="abc">抖音</Option>
-                    <Option value="hotsoon">火山</Option>
-                    <Option value="pipixia">皮皮虾</Option>
-                    <Option value="duoshan">多闪</Option>
-                    <Option value="xigua">西瓜视频</Option>
-                </Select>
-            </div>
-        </div>
-    );
-});
-stories.add('一个Option,其他数组', () => (
-    <Select
-        defaultValue={'all'}
-        style={{
+export const AutoFocus = () => <AutoFocusDemo />;
+
+AutoFocus.story = {
+  name: 'autoFocus',
+};
+
+export const InnerBottomSlotOuterBottomSlot = () => <Test />;
+
+InnerBottomSlotOuterBottomSlot.story = {
+  name: 'innerBottomSlot / outerBottomSlot',
+};
+
+export const InnerTopSlotOuterTopSlot = () => {
+  const slot = <div>未找到应用?</div>;
+  return (
+    <div>
+      innerTopSlot
+      <div>
+        <Select
+          innerTopSlot={slot}
+          style={{
             width: 250,
-        }}
-    >
-        <Option value="all" key="all">
-            all
-        </Option>
-        {[1, 2, 3].map(item => (
-            <Option value={`type${item}`} key={item}>{`type${item}`}</Option>
-        ))}
-    </Select>
-));
+          }}
+          maxHeight={150}
+        >
+          <Option value="abc">抖音</Option>
+          <Option value="hotsoon">火山</Option>
+          <Option value="pipixia">皮皮虾</Option>
+          <Option value="duoshan">多闪</Option>
+          <Option value="xigua">西瓜视频</Option>
+        </Select>
+      </div>
+      outerTopSlot
+      <div>
+        <Select
+          outerTopSlot={slot}
+          style={{
+            width: 250,
+          }}
+          maxHeight={150}
+        >
+          <Option value="abc">抖音</Option>
+          <Option value="hotsoon">火山</Option>
+          <Option value="pipixia">皮皮虾</Option>
+          <Option value="duoshan">多闪</Option>
+          <Option value="xigua">西瓜视频</Option>
+        </Select>
+      </div>
+    </div>
+  );
+};
+
+InnerTopSlotOuterTopSlot.story = {
+  name: 'innerTopSlot / outerTopSlot',
+};
+
+export const OneOptionJsxWithOtherOptionArray = () => (
+  <Select
+    defaultValue={'all'}
+    style={{
+      width: 250,
+    }}
+  >
+    <Option value="all" key="all">
+      all
+    </Option>
+    {[1, 2, 3].map(item => (
+      <Option value={`type${item}`} key={item}>{`type${item}`}</Option>
+    ))}
+  </Select>
+);
+
+OneOptionJsxWithOtherOptionArray.story = {
+  name: 'one option jsx with other option array',
+};
+
 let options = [
-    {
-        value: 'all',
-        label: '全部',
-        otherKey: 'all semi',
-    },
-    {
-        value: 'abc',
-        label: '抖音',
-        otherKey: 'abc semi',
-    },
-    {
-        value: 'hotsoon',
-        label: '火山小视频',
-        otherKey: 'hostsoom semi',
-    },
-    {
-        value: 'pipixia',
-        label: '皮皮虾',
-        otherKey: 'pif',
-    },
-    {
-        value: 'toutiao',
-        label: '今日头条',
-        otherKey: 'toutiao semi',
-    },
-    {
-        value: 'rd',
-        label: 'rd',
-        otherKey: 'semi rd',
-    },
-    {
-        value: 'ued',
-        label: 'ued',
-        otherKey: 'semi ued',
-    },
-    {
-        value: 'ued',
-        label: 'japan',
-        otherKey: 'semi ued',
-    },
-    {
-        value: '+86',
-        label: '+86',
-        otherKey: 'semi',
-    },
+  {
+    value: 'all',
+    label: '全部',
+    otherKey: 'all semi',
+  },
+  {
+    value: 'abc',
+    label: '抖音',
+    otherKey: 'abc semi',
+  },
+  {
+    value: 'hotsoon',
+    label: '火山小视频',
+    otherKey: 'hostsoom semi',
+  },
+  {
+    value: 'pipixia',
+    label: '皮皮虾',
+    otherKey: 'pif',
+  },
+  {
+    value: 'toutiao',
+    label: '今日头条',
+    otherKey: 'toutiao semi',
+  },
+  {
+    value: 'rd',
+    label: 'rd',
+    otherKey: 'semi rd',
+  },
+  {
+    value: 'ued',
+    label: 'ued',
+    otherKey: 'semi ued',
+  },
+  {
+    value: 'ued',
+    label: 'japan',
+    otherKey: 'semi ued',
+  },
+  {
+    value: '+86',
+    label: '+86',
+    otherKey: 'semi',
+  },
 ];
 let longOptions = options.concat({
-    value: 'long',
-    label: 'Semi Design 是一个设计系统,它定义了一套中后台设计与前端基础组',
+  value: 'long',
+  label: 'Semi Design 是一个设计系统,它定义了一套中后台设计与前端基础组',
 });
-stories.add('select size', () => (
+
+export const SelectSize = () => (
+  <div
+    style={{
+      margin: 20,
+    }}
+  >
+    <h4>
+      使用方不设width时,下拉菜单根据内容自动适配宽度(不推荐这样使用,select的宽度会动态变化)
+    </h4>
+    <Select
+      defaultValue={'all'}
+      optionList={options}
+      style={{
+        margin: 10,
+      }}
+    ></Select>
+    <Select
+      defaultValue={'long'}
+      optionList={longOptions}
+      style={{
+        margin: 10,
+      }}
+    ></Select>
+    <Select
+      defaultValue={'abc'}
+      size="large"
+      optionList={options}
+      style={{
+        margin: 10,
+      }}
+    ></Select>
+    {/* <Select defaultValue={'+86'} size="large" optionList={options}  style={{margin: 10}}>
+    </Select> */}
+    <h4>通过style设width的</h4>
+    90px:{' '}
+    <Select
+      defaultValue={'all'}
+      style={{
+        width: 90,
+        marign: 10,
+      }}
+      optionList={options}
+    ></Select>
+    120px:{' '}
+    <Select
+      defaultValue={'all'}
+      style={{
+        width: 120,
+        margin: 10,
+      }}
+      optionList={options}
+    ></Select>
+    400px:{' '}
+    <Select
+      defaultValue={'all'}
+      style={{
+        width: 400,
+        margin: 10,
+      }}
+      optionList={options}
+    ></Select>
+    <br />
+    100%:{' '}
+    <Select
+      defaultValue={'all'}
+      style={{
+        width: '100%',
+        margin: 10,
+      }}
+      optionList={options}
+    ></Select>
+    <br />
+    <h4>通过css设width的</h4>
+    <Select defaultValue={'all'} className="test-width" optionList={options}></Select>
+    <br />
+    <h4>dropdownMatchSelectWidth</h4>
+    <p>当该项设为true时,下拉菜单最小宽度会等于Select宽度(默认为true)</p>
     <div
+      style={{
+        margin: 10,
+      }}
+    >
+      style方式指定90px:
+      <Select
+        defaultValue={'all'}
+        optionList={options}
+        dropdownMatchSelectWidth={true}
         style={{
-            margin: 20,
+          width: 90,
         }}
+      />
+    </div>
+    <div
+      style={{
+        margin: 10,
+      }}
     >
-        <h4>使用方不设width时,下拉菜单根据内容自动适配宽度(不推荐这样使用,select的宽度会动态变化)</h4>
-        <Select
-            defaultValue={'all'}
-            optionList={options}
-            style={{
-                margin: 10,
-            }}
-        ></Select>
-        <Select
-            defaultValue={'long'}
-            optionList={longOptions}
-            style={{
-                margin: 10,
-            }}
-        ></Select>
-        <Select
-            defaultValue={'abc'}
-            size="large"
-            optionList={options}
-            style={{
-                margin: 10,
-            }}
-        ></Select>
-        {/* <Select defaultValue={'+86'} size="large" optionList={options}  style={{margin: 10}}>
-    </Select> */}
-        <h4>通过style设width的</h4>
-        90px:{' '}
-        <Select
-            defaultValue={'all'}
-            style={{
-                width: 90,
-                marign: 10,
-            }}
-            optionList={options}
-        ></Select>
-        120px:{' '}
-        <Select
-            defaultValue={'all'}
-            style={{
-                width: 120,
-                margin: 10,
-            }}
-            optionList={options}
-        ></Select>
-        400px:{' '}
-        <Select
-            defaultValue={'all'}
-            style={{
-                width: 400,
-                margin: 10,
-            }}
-            optionList={options}
-        ></Select>
-        <br />
-        100%:{' '}
-        <Select
-            defaultValue={'all'}
-            style={{
-                width: '100%',
-                margin: 10,
-            }}
-            optionList={options}
-        ></Select>
-        <br />
-        <h4>通过css设width的</h4>
-        <Select defaultValue={'all'} className="test-width" optionList={options}></Select>
-        <br />
-        <h4>dropdownMatchSelectWidth</h4>
-        <p>当该项设为true时,下拉菜单最小宽度会等于Select宽度(默认为true)</p>
-        <div
-            style={{
-                margin: 10,
-            }}
-        >
-            style方式指定90px:
-            <Select
-                defaultValue={'all'}
-                optionList={options}
-                dropdownMatchSelectWidth={true}
-                style={{
-                    width: 90,
-                }}
-            />
-        </div>
-        <div
-            style={{
-                margin: 10,
-            }}
-        >
-            css方式声明130px:
-            <Select
-                defaultValue={'all'}
-                className="test-width"
-                optionList={options}
-                dropdownMatchSelectWidth={true}
-            ></Select>
-        </div>
-        <div>
-            <h4>需要强制下拉菜单与select同宽的时候</h4>
-            <p>通过dropdownStyle覆盖min-width,将其设成与select的width同样的值</p>
-            <Select
-                defaultValue={'all'}
-                style={{
-                    width: 300,
-                    margin: 10,
-                }}
-                dropdownStyle={{
-                    width: 300,
-                }}
-                optionList={options}
-            />
-        </div>
+      css方式声明130px:
+      <Select
+        defaultValue={'all'}
+        className="test-width"
+        optionList={options}
+        dropdownMatchSelectWidth={true}
+      ></Select>
     </div>
-));
-stories.add('with prefix / suffix / insetLabel, showClear, showArrow', () => (
-    <>
-        <h4>prefix & suffix</h4>
-        <Select
-            style={{
-                width: '250px',
-            }}
-            optionList={options}
-            prefix={<IconSearch />}
-            suffix={<IconGift></IconGift>}
-        ></Select>
-        <h4>insetLabel</h4>
-        <Select
-            style={{
-                width: '250px',
-            }}
-            optionList={options}
-            insetLabel={'业务线'}
-        ></Select>
-        <h4>showClear</h4>
-        <Select
-            style={{
-                width: '250px',
-            }}
-            optionList={options}
-            showClear
-        ></Select>
-        <h4>showArrow = false</h4>
-        <Select
-            style={{
-                width: '250px',
-            }}
-            optionList={options}
-            showArrow={false}
-        ></Select>
-
-        <h4>defaultValue是不存在的值</h4>
-        <Select
-            style={{
-                width: '250px',
-            }}
-            optionList={options}
-            defaultValue="+85"
-        ></Select>
-    </>
-));
-stories.add('with default selected', () => (
-    <Select
+    <div>
+      <h4>需要强制下拉菜单与select同宽的时候</h4>
+      <p>通过dropdownStyle覆盖min-width,将其设成与select的width同样的值</p>
+      <Select
+        defaultValue={'all'}
         style={{
-            width: '250px',
+          width: 300,
+          margin: 10,
         }}
-        defaultValue={1}
-    >
-        <Option value={1}>opt1</Option>
-        <Option value={2}>opt2</Option>
-        <Option value={3}>opt3</Option>
-        <Option value="4">opt4</Option>
-    </Select>
-));
-stories.add('with scrollbar', () => (
-    <Select
-        style={{
-            width: '250px',
+        dropdownStyle={{
+          width: 300,
         }}
-        defaultValue={1}
-    >
-        <Option value={1}>opt1</Option>
-        <Option value={2}>opt2</Option>
-        <Option value={3}>opt3</Option>
-        <Option value="4">opt4</Option>
-        <Option value={5}>opt5</Option>
-        <Option value={6}>opt6</Option>
-        <Option value={7}>opt7</Option>
-        <Option value="8">opt8</Option>
-        <Option value={9}>opt9</Option>
-        <Option value={10}>opt10dfsdfsdfdsfdsfsdf</Option>
-        <Option value={11}>opt11</Option>
-        <Option value="12">opt12jfldsjflsdjlfldjslfjhifsdfdsfdsffdsodsjlfhjl</Option>
-    </Select>
-));
+        optionList={options}
+      />
+    </div>
+  </div>
+);
 
-class Link extends React.Component {
-    get provinces() {
-        return ['Sichuan', 'Guangdong'];
-    }
+SelectSize.story = {
+  name: 'select size',
+};
 
-    get maps() {
-        return {
-            Sichuan: ['Chengdu', 'Dujiangyan'],
-            Guangdong: ['Guangzhou', 'Shenzhen', 'Dongguan'],
-        };
-    }
+export const WithPrefixSuffixInsetLabelShowClearShowArrow = () => (
+  <>
+    <h4>prefix & suffix</h4>
+    <Select
+      style={{
+        width: '250px',
+      }}
+      optionList={options}
+      prefix={<IconSearch />}
+      suffix={<IconGift></IconGift>}
+    ></Select>
+    <h4>insetLabel</h4>
+    <Select
+      style={{
+        width: '250px',
+      }}
+      optionList={options}
+      insetLabel={'业务线'}
+    ></Select>
+    <h4>showClear</h4>
+    <Select
+      style={{
+        width: '250px',
+      }}
+      optionList={options}
+      showClear
+    ></Select>
+    <h4>showArrow = false</h4>
+    <Select
+      style={{
+        width: '250px',
+      }}
+      optionList={options}
+      showArrow={false}
+    ></Select>
 
-    constructor() {
-        super();
-        this.state = {
-            provinces: this.provinces,
-            maps: this.maps,
-            citys: this.maps[this.provinces[0]],
-            city: this.maps[this.provinces[0]][0],
-        };
-        this.provinceChange = this.provinceChange.bind(this);
-        this.cityChange = this.cityChange.bind(this);
-    }
+    <h4>defaultValue是不存在的值</h4>
+    <Select
+      style={{
+        width: '250px',
+      }}
+      optionList={options}
+      defaultValue="+85"
+    ></Select>
+  </>
+);
 
-    provinceChange(newProvince) {
-        const { maps } = this.state;
-        this.setState({
-            citys: maps[newProvince],
-            city: maps[newProvince][0],
-        });
-    }
+WithPrefixSuffixInsetLabelShowClearShowArrow.story = {
+  name: 'with prefix / suffix / insetLabel, showClear, showArrow',
+};
+WithPrefixSuffixInsetLabelShowClearShowArrow.parameters = {
+  chromatic: { disableSnapshot: false },
+};
 
-    cityChange(city) {
-        this.setState({
-            city,
-        });
-    }
+export const WithDefaultSelected = () => (
+  <Select
+    style={{
+      width: '250px',
+    }}
+    defaultValue={1}
+  >
+    <Option value={1}>opt1</Option>
+    <Option value={2}>opt2</Option>
+    <Option value={3}>opt3</Option>
+    <Option value="4">opt4</Option>
+  </Select>
+);
+
+WithDefaultSelected.story = {
+  name: 'with default selected',
+};
 
-    render() {
-        const { provinces, citys, city } = this.state;
-        return (
-            <React.Fragment>
-                <Select
-                    style={{
-                        width: '150px',
-                        margin: '10px',
-                    }}
-                    onChange={this.provinceChange}
-                    defaultValue={provinces[0]}
-                >
-                    {provinces.map(pro => (
-                        <Option value={pro} key={pro}>
-                            {pro}
-                        </Option>
-                    ))}
-                </Select>
-                <Select
-                    style={{
-                        width: '150px',
-                        margin: '10px',
-                    }}
-                    value={city}
-                    onChange={this.cityChange}
-                >
-                    {citys.map(c => (
-                        <Option value={c} key={c}>
-                            {c}
-                        </Option>
-                    ))}
-                </Select>
-            </React.Fragment>
-        );
-    }
-}
+export const WithScrollbar = () => (
+  <Select
+    style={{
+      width: '250px',
+    }}
+    defaultValue={1}
+  >
+    <Option value={1}>opt1</Option>
+    <Option value={2}>opt2</Option>
+    <Option value={3}>opt3</Option>
+    <Option value="4">opt4</Option>
+    <Option value={5}>opt5</Option>
+    <Option value={6}>opt6</Option>
+    <Option value={7}>opt7</Option>
+    <Option value="8">opt8</Option>
+    <Option value={9}>opt9</Option>
+    <Option value={10}>opt10dfsdfsdfdsfdsfsdf</Option>
+    <Option value={11}>opt11</Option>
+    <Option value="12">opt12jfldsjflsdjlfldjslfjhifsdfdsfdsffdsodsjlfhjl</Option>
+  </Select>
+);
+
+WithScrollbar.story = {
+  name: 'with scrollbar',
+};
 
-stories.add('select 联动', () => <Link />);
-stories.add('select multiple', () => (
-    <>
-        <Select
-            multiple={true}
-            max={10}
-            style={{
-                width: '180px',
-            }}
-            placeholder="fefe"
-        >
-            <Option value={1}>opt1</Option>
-            <Option value={2}>opt2</Option>
-            <Option value={3}>opt3</Option>
-            <Option value="4">opt4</Option>
-            <Option value={5}>opt5</Option>
-            <Option value={6}>opt6</Option>
-            <Option value={7}>opt7</Option>
-            <Option value={8}>opt8</Option>
-        </Select>
-        <br />
-        <br />
-        <Select
-            multiple={true}
-            style={{
-                width: '300px',
-            }}
-            defaultValue={[1, 2, 3]}
-            placeholder="fefe"
-        >
-            <Option value={1}>opt1</Option>
-            <Option value={2}>opt2</Option>
-            <Option value={3}>opt3</Option>
-            <Option value="4">opt4</Option>
-            <Option value={5}>opt5</Option>
-            <Option value={6}>opt6</Option>
-            <Option value={7}>opt7</Option>
-            <Option value={8}>opt8</Option>
-        </Select>
-        <br />
-        <br />
-        <Select
-            multiple={true}
-            style={{
-                width: '300px',
-            }}
-            defaultValue={[1, 2, 3]}
-            placeholder="fefe"
-            disabled
-            onSelect={(...res) => console.log(res)}
-            onDeselect={(...res) => console.log(res)}
-        >
-            <Option value={1}>opt1</Option>
-            <Option value={2}>opt2</Option>
-            <Option value={3}>opt3</Option>
-            <Option value="4">opt4</Option>
-            <Option value={5}>opt5</Option>
-            <Option value={6}>opt6</Option>
-            <Option value={7}>opt7</Option>
-            <Option value={8}>opt8</Option>
-        </Select>
-        <br />
-        <br />
-        maxTagCount = 3
+class Link extends React.Component {
+  get provinces() {
+    return ['Sichuan', 'Guangdong'];
+  }
+
+  get maps() {
+    return {
+      Sichuan: ['Chengdu', 'Dujiangyan'],
+      Guangdong: ['Guangzhou', 'Shenzhen', 'Dongguan'],
+    };
+  }
+
+  constructor() {
+    super();
+    this.state = {
+      provinces: this.provinces,
+      maps: this.maps,
+      citys: this.maps[this.provinces[0]],
+      city: this.maps[this.provinces[0]][0],
+    };
+    this.provinceChange = this.provinceChange.bind(this);
+    this.cityChange = this.cityChange.bind(this);
+  }
+
+  provinceChange(newProvince) {
+    const { maps } = this.state;
+    this.setState({
+      citys: maps[newProvince],
+      city: maps[newProvince][0],
+    });
+  }
+
+  cityChange(city) {
+    this.setState({
+      city,
+    });
+  }
+
+  render() {
+    const { provinces, citys, city } = this.state;
+    return (
+      <React.Fragment>
         <Select
-            multiple={true}
-            maxTagCount={3}
-            style={{
-                width: '350px',
-            }}
-            defaultValue={[1, 2, 3]}
-            placeholder="fefe"
-            insetLabel="标签"
-            onSelect={(...res) => console.log(res)}
-            onDeselect={(...res) => console.log(res)}
+          style={{
+            width: '150px',
+            margin: '10px',
+          }}
+          onChange={this.provinceChange}
+          defaultValue={provinces[0]}
         >
-            <Option value={1}>opt1</Option>
-            <Option value={2}>opt2</Option>
-            <Option value={3}>opt3</Option>
-            <Option value="4">opt4</Option>
-            <Option value={5}>opt5</Option>
-            <Option value={6}>opt6</Option>
-            <Option value={7}>opt7</Option>
-            <Option value={8}>opt8</Option>
+          {provinces.map(pro => (
+            <Option value={pro} key={pro}>
+              {pro}
+            </Option>
+          ))}
         </Select>
-        <br />
-        <br />
-        maxTagCount = 3, max=5
         <Select
-            multiple={true}
-            maxTagCount={3}
-            max={5}
-            style={{
-                width: '350px',
-            }}
-            defaultValue={[1, 2, 3]}
-            placeholder="fefe"
-            insetLabel="标签"
-            onSelect={(...res) => console.log(res)}
-            onDeselect={(...res) => console.log(res)}
+          style={{
+            width: '150px',
+            margin: '10px',
+          }}
+          value={city}
+          onChange={this.cityChange}
         >
-            <Option value={1}>opt1</Option>
-            <Option value={2}>opt2</Option>
-            <Option value={3}>opt3</Option>
-            <Option value="4">opt4</Option>
-            <Option value={5}>opt5</Option>
-            <Option value={6}>opt6</Option>
-            <Option value={7}>opt7</Option>
-            <Option value={8}>opt8</Option>
+          {citys.map(c => (
+            <Option value={c} key={c}>
+              {c}
+            </Option>
+          ))}
         </Select>
-    </>
-));
-stories.add('select disabled', () => (
+      </React.Fragment>
+    );
+  }
+}
+
+export const TwoSelectChangeAtTheSameTime = () => <Link />;
+
+TwoSelectChangeAtTheSameTime.story = {
+  name: 'two select change at the same time',
+};
+
+export const SelectMultiple = () => (
+  <>
     <Select
-        disabled
-        multiple={true}
-        max={10}
-        style={{
-            width: '250px',
-        }}
+      multiple={true}
+      max={10}
+      style={{
+        width: '180px',
+      }}
+      placeholder="fefe"
     >
-        <Option value={1}>opt1</Option>
-        <Option value={2} disabled>
-            opt2
-        </Option>
-        <Option value={3}>opt3</Option>
-        <Option value="4">opt4</Option>
+      <Option value={1}>opt1</Option>
+      <Option value={2}>opt2</Option>
+      <Option value={3}>opt3</Option>
+      <Option value="4">opt4</Option>
+      <Option value={5}>opt5</Option>
+      <Option value={6}>opt6</Option>
+      <Option value={7}>opt7</Option>
+      <Option value={8}>opt8</Option>
+    </Select>
+    <br />
+    <br />
+    <Select
+      multiple={true}
+      style={{
+        width: '300px',
+      }}
+      defaultValue={[1, 2, 3]}
+      placeholder="fefe"
+    >
+      <Option value={1}>opt1</Option>
+      <Option value={2}>opt2</Option>
+      <Option value={3}>opt3</Option>
+      <Option value="4">opt4</Option>
+      <Option value={5}>opt5</Option>
+      <Option value={6}>opt6</Option>
+      <Option value={7}>opt7</Option>
+      <Option value={8}>opt8</Option>
     </Select>
-));
+    <br />
+    <br />
+    <Select
+      multiple={true}
+      style={{
+        width: '300px',
+      }}
+      defaultValue={[1, 2, 3]}
+      placeholder="fefe"
+      disabled
+      onSelect={(...res) => console.log(res)}
+      onDeselect={(...res) => console.log(res)}
+    >
+      <Option value={1}>opt1</Option>
+      <Option value={2}>opt2</Option>
+      <Option value={3}>opt3</Option>
+      <Option value="4">opt4</Option>
+      <Option value={5}>opt5</Option>
+      <Option value={6}>opt6</Option>
+      <Option value={7}>opt7</Option>
+      <Option value={8}>opt8</Option>
+    </Select>
+    <br />
+    <br />
+    maxTagCount = 3
+    <Select
+      multiple={true}
+      maxTagCount={3}
+      style={{
+        width: '350px',
+      }}
+      defaultValue={[1, 2, 3]}
+      placeholder="fefe"
+      insetLabel="标签"
+      onSelect={(...res) => console.log(res)}
+      onDeselect={(...res) => console.log(res)}
+    >
+      <Option value={1}>opt1</Option>
+      <Option value={2}>opt2</Option>
+      <Option value={3}>opt3</Option>
+      <Option value="4">opt4</Option>
+      <Option value={5}>opt5</Option>
+      <Option value={6}>opt6</Option>
+      <Option value={7}>opt7</Option>
+      <Option value={8}>opt8</Option>
+    </Select>
+    <br />
+    <br />
+    maxTagCount = 3, max=5
+    <Select
+      multiple={true}
+      maxTagCount={3}
+      max={5}
+      style={{
+        width: '350px',
+      }}
+      defaultValue={[1, 2, 3]}
+      placeholder="fefe"
+      insetLabel="标签"
+      onSelect={(...res) => console.log(res)}
+      onDeselect={(...res) => console.log(res)}
+    >
+      <Option value={1}>opt1</Option>
+      <Option value={2}>opt2</Option>
+      <Option value={3}>opt3</Option>
+      <Option value="4">opt4</Option>
+      <Option value={5}>opt5</Option>
+      <Option value={6}>opt6</Option>
+      <Option value={7}>opt7</Option>
+      <Option value={8}>opt8</Option>
+    </Select>
+  </>
+);
+
+SelectMultiple.story = {
+  name: 'select multiple',
+};
+SelectMultiple.parameters =  {
+  chromatic: { disableSnapshot: false },
+};
+
+export const SelectDisabled = () => (
+  <Select
+    disabled
+    multiple={true}
+    max={10}
+    style={{
+      width: '250px',
+    }}
+  >
+    <Option value={1}>opt1</Option>
+    <Option value={2} disabled>
+      opt2
+    </Option>
+    <Option value={3}>opt3</Option>
+    <Option value="4">opt4</Option>
+  </Select>
+);
+
+SelectDisabled.story = {
+  name: 'select disabled',
+};
 
 function filter(input, option) {
-    console.log(option);
-    return option.label.includes(input);
+  console.log(option);
+  return option.label.includes(input);
 }
 
 const spanStyle = {
-    display: 'inline-block',
-    marginRight: '8px',
-    width: '16px',
-    height: '16px',
-    borderRadius: '50%',
-    border: '1px solid var(--semi-color-bg-1)',
+  display: 'inline-block',
+  marginRight: '8px',
+  width: '16px',
+  height: '16px',
+  borderRadius: '50%',
+  border: '1px solid var(--semi-color-bg-1)',
 };
 const colorOptions = [
-    {
-        value: 'grey-1',
-        spanStyle: { ...spanStyle, backgroundColor: 'rgb(107, 116, 117)' },
-    },
-    {
-        value: 'purple-5',
-        spanStyle: { ...spanStyle, backgroundColor: 'rgb(158, 40, 179)' },
-    },
-    {
-        value: 'pink-2',
-        spanStyle: { ...spanStyle, backgroundColor: 'rgb(233, 30, 99)' },
-    },
-    {
-        value: 'blue-3',
-        spanStyle: { ...spanStyle, backgroundColor: 'rgb(0, 119, 250)' },
-    },
+  {
+    value: 'grey-1',
+    spanStyle: { ...spanStyle, backgroundColor: 'rgb(107, 116, 117)' },
+  },
+  {
+    value: 'purple-5',
+    spanStyle: { ...spanStyle, backgroundColor: 'rgb(158, 40, 179)' },
+  },
+  {
+    value: 'pink-2',
+    spanStyle: { ...spanStyle, backgroundColor: 'rgb(233, 30, 99)' },
+  },
+  {
+    value: 'blue-3',
+    spanStyle: { ...spanStyle, backgroundColor: 'rgb(0, 119, 250)' },
+  },
 ];
 const alignStyle = {
-    display: 'flex',
-    alignItems: 'center',
+  display: 'flex',
+  alignItems: 'center',
 };
 
 const customFilter = (input, option) => {
-    return option.value.includes(input);
+  return option.value.includes(input);
 };
 
-stories.add('select filter single', () => (
-    <div>
-        <h5>默认筛选</h5>
-        <Select
-            filter
+export const SelectFilterSingle = () => (
+  <div>
+    <h5>默认筛选</h5>
+    <Select
+      filter
+      style={{
+        width: '250px',
+        margin: 10,
+      }}
+      autoFocus
+      onFocus={() => console.log('onFocus')}
+      onBlur={() => console.log('onBlur')}
+    >
+      <Option value={1}>opt1</Option>
+      <Option value={2} disabled>
+        disabled
+      </Option>
+      <Option value={3}>Lucy</Option>
+      <Option value="4">bay</Option>
+      <Option value="5">sert</Option>
+      <Option value="6">wym</Option>
+      <Option value="7" disabled>
+        meno
+      </Option>
+      <Option value="8">opts</Option>
+    </Select>
+    <h5>自定义筛选函数</h5>
+    <Select
+      style={{
+        width: '250px',
+        margin: 10,
+      }}
+      filter={filter}
+      onBlur={() => console.log('onBlur')}
+      onFocus={() => console.log('onFocus')}
+    >
+      <Option value={1}>opt1(value:1)</Option>
+      <Option value={2}>mike(value:2)</Option>
+      <Option value={3}>Lucy(value:3)</Option>
+      <Option value={4}>bay(value:4)</Option>
+    </Select>
+    <h5>filter为true,但option label为node时</h5>
+    <Select
+      style={{
+        width: '250px',
+        margin: 10,
+      }}
+      filter={customFilter}
+      onChange={v => console.log(v)}
+      insetLabel="insetLabel"
+      onFocus={() => console.log('onFocus')}
+      onBlur={() => console.log('onBlur')}
+    >
+      {colorOptions.map(option => (
+        <Option value={option.value} key={option.value}>
+          <div style={alignStyle}>
+            <span style={option.spanStyle}></span>
+            {option.value}
+          </div>
+        </Option>
+      ))}
+    </Select>
+  </div>
+);
+
+SelectFilterSingle.story = {
+  name: 'select filter single',
+};
+
+export const SelectFilterMultiple = () => (
+  <>
+    <Select
+      filter
+      multiple={true}
+      style={{
+        width: '250px',
+      }}
+      placeholder="fefe"
+    >
+      <Option value={1}>opt1</Option>
+      <Option value={2}>opt2</Option>
+      <Option value={3}>opt22</Option>
+      <Option value={3}>opt3</Option>
+      <Option value={4}>opt4</Option>
+      <Option value={5}>opt5</Option>
+      <Option value={6}>opt6</Option>
+      <Option value={7}>opt7</Option>
+      <Option value={8}>opt8</Option>
+    </Select>
+    <Select
+      filter
+      multiple={true}
+      maxTagCount={3}
+      style={{
+        width: '270px',
+      }}
+      placeholder="fefe"
+    >
+      <Option value={1}>opt1</Option>
+      <Option value={2}>opt2</Option>
+      <Option value={3}>opt22</Option>
+      <Option value={3}>opt3</Option>
+      <Option value={4}>opt4</Option>
+      <Option value={5}>opt5</Option>
+      <Option value={6}>opt6</Option>
+      <Option value={7}>opt7</Option>
+      <Option value={8}>opt8</Option>
+    </Select>
+  </>
+);
+
+SelectFilterMultiple.story = {
+  name: 'select filter multiple',
+};
+
+const OptionLabelProp = () => {
+  const [value, setValue] = useState(1);
+  return (
+    <>
+      设置optionLabelProp属性(默认为'children')为'value'时,回填到选择框中的文本会是Option.value
+      <br></br>
+      <Select
+        style={{
+          width: '250px',
+        }}
+        defaultValue={1}
+        optionLabelProp="value"
+      >
+        <Option value={1}>opt1</Option>
+        <Option value={2}>opt2</Option>
+        <Option value={3}>
+          <span
             style={{
-                width: '250px',
-                margin: 10,
+              color: 'pink',
             }}
-            autoFocus
-            onFocus={() => console.log('onFocus')}
-            onBlur={() => console.log('onBlur')}
-        >
-            <Option value={1}>opt1</Option>
-            <Option value={2} disabled>
-                disabled
-            </Option>
-            <Option value={3}>Lucy</Option>
-            <Option value="4">bay</Option>
-            <Option value="5">sert</Option>
-            <Option value="6">wym</Option>
-            <Option value="7" disabled>
-                meno
-            </Option>
-            <Option value="8">opts</Option>
-        </Select>
-        <h5>自定义筛选函数</h5>
-        <Select
+          >
+            opt3 Node
+          </span>
+        </Option>
+        <Option value="4">
+          <span
+            style={{
+              color: 'red',
+            }}
+          >
+            testNode
+          </span>
+        </Option>
+      </Select>
+      <br />
+      <br />
+      <Select
+        style={{
+          width: '250px',
+        }}
+        value={value}
+        optionLabelProp="value"
+        onChange={setValue}
+      >
+        <Option value={1}>opt1</Option>
+        <Option value={2}>opt2</Option>
+        <Option value={3}>
+          <span
+            style={{
+              color: 'pink',
+            }}
+          >
+            opt3 Node
+          </span>
+        </Option>
+        <Option value="4">
+          <span
             style={{
-                width: '250px',
-                margin: 10,
+              color: 'red',
             }}
-            filter={filter}
-            onBlur={() => console.log('onBlur')}
-            onFocus={() => console.log('onFocus')}
+          >
+            testNode
+          </span>
+        </Option>
+      </Select>
+      <br />
+      <br />
+      <Select
+        style={{
+          width: '250px',
+        }}
+        defaultValue={1}
+      >
+        <Option value={1}>children Label Text 1</Option>
+        <Option value={2}>opt2</Option>
+        <Option value={3}>opt3</Option>
+        <Option value="4">
+          <span
+            style={{
+              color: 'red',
+            }}
+          >
+            testNode
+          </span>
+        </Option>
+      </Select>
+      <Select
+        style={{
+          width: '250px',
+        }}
+        defaultValue={1}
+        filter
+        optionLabelProp="value"
+      >
+        <Option value={1}>children Label Text 1</Option>
+        <Option value={2}>opt2</Option>
+        <Option value={3}>opt3</Option>
+        <Option value="4">
+          <span
+            style={{
+              color: 'red',
+            }}
+          >
+            testNode
+          </span>
+        </Option>
+      </Select>
+      <br />
+      <br />
+      多选
+      <Select
+        style={{
+          width: '250px',
+        }}
+        multiple
+        filter
+        optionLabelProp="value"
+      >
+        <Option value={1}>children Label Text 1</Option>
+        <Option value={2}>opt2</Option>
+        <Option value={3}>opt3</Option>
+        <Option value="4">
+          <span
+            style={{
+              color: 'red',
+            }}
+          >
+            testNode
+          </span>
+        </Option>
+      </Select>
+    </>
+  );
+};
+
+class CustomRender extends React.Component {
+  constructor() {
+    super();
+    this.state = {
+      list: [
+        {
+          name: '夏可漫',
+          email: '[email protected]',
+          abbr: 'XK',
+          color: 'amber',
+        },
+        {
+          name: '申悦',
+          email: '[email protected]',
+          abbr: 'SY',
+          color: 'indigo',
+        },
+        {
+          name: '曲晨一',
+          email: '[email protected]',
+          abbr: 'CY',
+          color: 'blue',
+        },
+        {
+          name: '文嘉茂',
+          email: '[email protected]',
+          abbr: 'JM',
+          color: 'cyan',
+        },
+      ],
+    };
+  }
+
+  renderCustomOption(item) {
+    let optionStyle = {
+      display: 'flex',
+    };
+    return (
+      <Option value={item.name} style={optionStyle} showTick={false} {...item}>
+        <Avatar color={item.color} size="small">
+          {item.abbr}
+        </Avatar>
+        <div
+          style={{
+            marginLeft: 4,
+          }}
         >
-            <Option value={1}>opt1(value:1)</Option>
-            <Option value={2}>mike(value:2)</Option>
-            <Option value={3}>Lucy(value:3)</Option>
-            <Option value={4}>bay(value:4)</Option>
-        </Select>
-        <h5>filter为true,但option label为node时</h5>
-        <Select
+          <p
+            style={{
+              fontSize: 14,
+              margin: 4,
+            }}
+          >
+            {item.name}
+          </p>
+          <p
             style={{
-                width: '250px',
-                margin: 10,
+              margin: 4,
             }}
-            filter={customFilter}
-            onChange={v => console.log(v)}
-            insetLabel="insetLabel"
-            onFocus={() => console.log('onFocus')}
-            onBlur={() => console.log('onBlur')}
+          >
+            {item.email}
+          </p>
+        </div>
+      </Option>
+    );
+  }
+
+  renderSelectedItem(optionNode) {
+    return (
+      <div>
+        <Avatar color={optionNode.color} size="small">
+          {optionNode.abbr}
+        </Avatar>
+        <span
+          style={{
+            margin: 8,
+          }}
         >
-            {colorOptions.map(option => (
-                <Option value={option.value} key={option.value}>
-                    <div style={alignStyle}>
-                        <span style={option.spanStyle}></span>
-                        {option.value}
-                    </div>
-                </Option>
-            ))}
+          {optionNode.email}
+        </span>
+      </div>
+    );
+  }
+
+  renderMultipleSelectedItem(optionNode) {
+    let content = (
+      <div>
+        <Avatar color={optionNode.color} size="small">
+          {optionNode.abbr}
+        </Avatar>
+      </div>
+    );
+    return {
+      isRenderInTag: true,
+      content,
+    };
+  }
+
+  renderMultipleWithoutTag(optionNode, { onClose, index }) {
+    let content = (
+      <div>
+        <Avatar color={optionNode.color} size="small">
+          {optionNode.abbr}
+        </Avatar>
+      </div>
+    );
+    return {
+      isRenderInTag: false,
+      content,
+    };
+  }
+
+  render() {
+    const { list } = this.state;
+    return (
+      <React.Fragment>
+        <Select
+          style={{
+            width: 300,
+            height: 40,
+          }}
+          onChange={this.provinceChange}
+          defaultValue={'夏可漫'}
+          renderSelectedItem={this.renderSelectedItem}
+        >
+          {list.map(item => this.renderCustomOption(item))}
         </Select>
-    </div>
-));
-stories.add('select filter multiple', () => (
-    <>
         <Select
-            filter
-            multiple={true}
-            style={{
-                width: '250px',
-            }}
-            placeholder="fefe"
+          style={{
+            width: 360,
+            height: 60,
+            marginTop: 20,
+          }}
+          onChange={this.provinceChange}
+          defaultValue={['夏可漫', '申悦']}
+          multiple
+          renderSelectedItem={this.renderMultipleSelectedItem}
         >
-            <Option value={1}>opt1</Option>
-            <Option value={2}>opt2</Option>
-            <Option value={3}>opt22</Option>
-            <Option value={3}>opt3</Option>
-            <Option value={4}>opt4</Option>
-            <Option value={5}>opt5</Option>
-            <Option value={6}>opt6</Option>
-            <Option value={7}>opt7</Option>
-            <Option value={8}>opt8</Option>
+          {list.map(item => this.renderCustomOption(item))}
         </Select>
         <Select
-            filter
-            multiple={true}
-            maxTagCount={3}
-            style={{
-                width: '270px',
-            }}
-            placeholder="fefe"
+          style={{
+            width: 360,
+            height: 60,
+            marginTop: 20,
+          }}
+          onChange={this.provinceChange}
+          defaultValue={['夏可漫', '申悦']}
+          multiple
+          renderSelectedItem={this.renderMultipleWithoutTag}
         >
-            <Option value={1}>opt1</Option>
-            <Option value={2}>opt2</Option>
-            <Option value={3}>opt22</Option>
-            <Option value={3}>opt3</Option>
-            <Option value={4}>opt4</Option>
-            <Option value={5}>opt5</Option>
-            <Option value={6}>opt6</Option>
-            <Option value={7}>opt7</Option>
-            <Option value={8}>opt8</Option>
+          {list.map(item => this.renderCustomOption(item))}
         </Select>
-    </>
-));
-
-const OptionLabelProp = () => {
-    const [value, setValue] = useState(1);
-    return (
-        <>
-            设置optionLabelProp属性(默认为'children')为'value'时,回填到选择框中的文本会是Option.value
-            <br></br>
-            <Select
-                style={{
-                    width: '250px',
-                }}
-                defaultValue={1}
-                optionLabelProp="value"
-            >
-                <Option value={1}>opt1</Option>
-                <Option value={2}>opt2</Option>
-                <Option value={3}>
-                    <span
-                        style={{
-                            color: 'pink',
-                        }}
-                    >
-                        opt3 Node
-                    </span>
-                </Option>
-                <Option value="4">
-                    <span
-                        style={{
-                            color: 'red',
-                        }}
-                    >
-                        testNode
-                    </span>
-                </Option>
-            </Select>
-            <br />
-            <br />
-            <Select
-                style={{
-                    width: '250px',
-                }}
-                value={value}
-                optionLabelProp="value"
-                onChange={setValue}
-            >
-                <Option value={1}>opt1</Option>
-                <Option value={2}>opt2</Option>
-                <Option value={3}>
-                    <span
-                        style={{
-                            color: 'pink',
-                        }}
-                    >
-                        opt3 Node
-                    </span>
-                </Option>
-                <Option value="4">
-                    <span
-                        style={{
-                            color: 'red',
-                        }}
-                    >
-                        testNode
-                    </span>
-                </Option>
-            </Select>
-            <br />
-            <br />
-            <Select
-                style={{
-                    width: '250px',
-                }}
-                defaultValue={1}
-            >
-                <Option value={1}>children Label Text 1</Option>
-                <Option value={2}>opt2</Option>
-                <Option value={3}>opt3</Option>
-                <Option value="4">
-                    <span
-                        style={{
-                            color: 'red',
-                        }}
-                    >
-                        testNode
-                    </span>
-                </Option>
-            </Select>
-            <Select
-                style={{
-                    width: '250px',
-                }}
-                defaultValue={1}
-                filter
-                optionLabelProp="value"
-            >
-                <Option value={1}>children Label Text 1</Option>
-                <Option value={2}>opt2</Option>
-                <Option value={3}>opt3</Option>
-                <Option value="4">
-                    <span
-                        style={{
-                            color: 'red',
-                        }}
-                    >
-                        testNode
-                    </span>
-                </Option>
-            </Select>
-            <br />
-            <br />
-            多选
-            <Select
-                style={{
-                    width: '250px',
-                }}
-                multiple
-                filter
-                optionLabelProp="value"
-            >
-                <Option value={1}>children Label Text 1</Option>
-                <Option value={2}>opt2</Option>
-                <Option value={3}>opt3</Option>
-                <Option value="4">
-                    <span
-                        style={{
-                            color: 'red',
-                        }}
-                    >
-                        testNode
-                    </span>
-                </Option>
-            </Select>
-        </>
+      </React.Fragment>
     );
-};
+  }
+}
 
-class CustomRender extends React.Component {
-    constructor() {
-        super();
-        this.state = {
-            list: [
-                {
-                    name: '夏可漫',
-                    email: '[email protected]',
-                    abbr: 'XK',
-                    color: 'amber',
-                },
-                {
-                    name: '申悦',
-                    email: '[email protected]',
-                    abbr: 'SY',
-                    color: 'indigo',
-                },
-                {
-                    name: '曲晨一',
-                    email: '[email protected]',
-                    abbr: 'CY',
-                    color: 'blue',
-                },
-                {
-                    name: '文嘉茂',
-                    email: '[email protected]',
-                    abbr: 'JM',
-                    color: 'cyan',
-                },
-            ],
-        };
-    }
+export const RenderSelectedItem = () => (
+  <>
+    renderSelectedItem
+    <CustomRender />
+    <br />
+    <br />
+    OptionLabelProp
+    <OptionLabelProp />
+  </>
+);
+
+RenderSelectedItem.story = {
+  name: 'renderSelectedItem',
+};
 
-    renderCustomOption(item) {
-        let optionStyle = {
-            display: 'flex',
-        };
-        return (
-            <Option value={item.name} style={optionStyle} showTick={false} {...item}>
-                <Avatar color={item.color} size="small">
-                    {item.abbr}
-                </Avatar>
-                <div
-                    style={{
-                        marginLeft: 4,
-                    }}
-                >
-                    <p
-                        style={{
-                            fontSize: 14,
-                            margin: 4,
-                        }}
-                    >
-                        {item.name}
-                    </p>
-                    <p
-                        style={{
-                            margin: 4,
-                        }}
-                    >
-                        {item.email}
-                    </p>
-                </div>
-            </Option>
-        );
-    }
+RenderSelectedItem.parameters =  {
+  chromatic: { disableSnapshot: false },
+};
 
-    renderSelectedItem(optionNode) {
-        return (
-            <div>
-                <Avatar color={optionNode.color} size="small">
-                    {optionNode.abbr}
-                </Avatar>
-                <span
-                    style={{
-                        margin: 8,
-                    }}
-                >
-                    {optionNode.email}
-                </span>
+const ControledSelect = () => {
+  const [value, setValue] = useState('nick');
+  const [value2, setValue2] = useState('jerry');
+  const [value3, setValue3] = useState();
+  const [value4, setValue4] = useState(['nick']);
+  const [value5, setValue5] = useState();
+  return (
+    <>
+      <span>value + onChange</span>
+      <Select
+        value={value}
+        onChange={setValue}
+        style={{
+          width: 200,
+        }}
+      >
+        <Option value="nick">nick</Option>
+        <Option value="jerry">jerry</Option>
+        <Option value="mark">mark</Option>
+      </Select>
+
+      <br />
+      <br />
+      <span>只传value,不传onChange</span>
+      <Select
+        value={value2}
+        style={{
+          width: 200,
+        }}
+      >
+        <Option value="nick">nick</Option>
+        <Option value="jerry">jerry</Option>
+        <Option value="mark">mark</Option>
+      </Select>
+      <br />
+      <br />
+
+      <span>value + onChange , 多选</span>
+      <Select
+        value={value3}
+        onChange={setValue3}
+        multiple
+        style={{
+          width: 200,
+        }}
+      >
+        <Option value="nick">nick</Option>
+        <Option value="jerry">jerry</Option>
+        <Option value="mark">mark</Option>
+        <Option value="nick2">nick2</Option>
+        <Option value="jerry2">jerry2</Option>
+        <Option value="mark2">mark2</Option>
+      </Select>
+      <br />
+      <br />
+
+      <span>value, 多选</span>
+      <Select
+        value={value4}
+        multiple
+        style={{
+          width: 200,
+        }}
+      >
+        <Option value="nick">nick</Option>
+        <Option value="jerry">jerry</Option>
+        <Option value="mark">mark</Option>
+      </Select>
+
+      <br />
+      <h5>filter为true,但option label为node时</h5>
+      <Select
+        style={{
+          width: '250px',
+        }}
+        filter={customFilter}
+        onChange={v => console.log(v)}
+        insetLabel="insetLabel"
+        value={value5}
+        onChange={setValue5}
+      >
+        {colorOptions.map(option => (
+          <Option value={option.value} key={option.value}>
+            <div style={alignStyle}>
+              <span style={option.spanStyle}></span>
+              {option.value}
             </div>
-        );
-    }
+          </Option>
+        ))}
+      </Select>
+    </>
+  );
+};
 
-    renderMultipleSelectedItem(optionNode) {
-        let content = (
-            <div>
-                <Avatar color={optionNode.color} size="small">
-                    {optionNode.abbr}
-                </Avatar>
-            </div>
-        );
-        return {
-            isRenderInTag: true,
-            content,
-        };
-    }
+export const Controlled = () => <ControledSelect></ControledSelect>;
 
-    renderMultipleWithoutTag(optionNode, { onClose, index }) {
-        let content = (
-            <div>
-                <Avatar color={optionNode.color} size="small">
-                    {optionNode.abbr}
-                </Avatar>
-            </div>
-        );
-        return {
-            isRenderInTag: false,
-            content,
-        };
-    }
+Controlled.story = {
+  name: 'controlled',
+};
 
-    render() {
-        const { list } = this.state;
-        return (
-            <React.Fragment>
-                <Select
-                    style={{
-                        width: 300,
-                        height: 40,
-                    }}
-                    onChange={this.provinceChange}
-                    defaultValue={'夏可漫'}
-                    renderSelectedItem={this.renderSelectedItem}
-                >
-                    {list.map(item => this.renderCustomOption(item))}
-                </Select>
-                <Select
-                    style={{
-                        width: 360,
-                        height: 60,
-                        marginTop: 20,
-                    }}
-                    onChange={this.provinceChange}
-                    defaultValue={['夏可漫', '申悦']}
-                    multiple
-                    renderSelectedItem={this.renderMultipleSelectedItem}
-                >
-                    {list.map(item => this.renderCustomOption(item))}
-                </Select>
-                <Select
-                    style={{
-                        width: 360,
-                        height: 60,
-                        marginTop: 20,
-                    }}
-                    onChange={this.provinceChange}
-                    defaultValue={['夏可漫', '申悦']}
-                    multiple
-                    renderSelectedItem={this.renderMultipleWithoutTag}
-                >
-                    {list.map(item => this.renderCustomOption(item))}
-                </Select>
-            </React.Fragment>
-        );
-    }
-}
+const UnControledSelect = () => {
+  const onChange = value => {
+    console.log(value);
+  };
 
-stories.add('自定义已选标签渲染', () => (
+  return (
     <>
-        renderSelectedItem
-        <CustomRender />
-        <br />
-        <br />
-        OptionLabelProp
-        <OptionLabelProp />
+      <h5>defaultValue在list中不存在</h5>
+      <Select
+        defaultValue={90}
+        onChange={onChange}
+        style={{
+          width: 200,
+        }}
+      >
+        <Option value={20}>nick</Option>
+        <Option value={10}>jerry</Option>
+        <Option value={5}>mark</Option>
+      </Select>
+      <h5>defaultValue在list中存在</h5>
+      <Select
+        defaultValue={10}
+        onChange={onChange}
+        style={{
+          width: 200,
+        }}
+      >
+        <Option value={20}>nick</Option>
+        <Option value={10}>jerry</Option>
+        <Option value={5}>mark</Option>
+      </Select>
     </>
-));
+  );
+};
+
+export { UnControledSelect };
+UnControledSelect.story = {
+  name: '非受控组件'
+};
+
+export const TestScroll = () => (
+  <div
+    style={{
+      marginTop: '600px',
+      marginBottom: '50px',
+    }}
+  >
+    <Select
+      style={{
+        width: '150px',
+      }}
+    >
+      <Option value="tony">IronMan</Option>
+      <Option value="Thor" disabled>
+        Thor
+      </Option>
+      <Option value="steve">Caption</Option>
+      <Option value="peter">SpiderBoy</Option>
+    </Select>
+  </div>
+);
+
+TestScroll.story = {
+  name: 'test scroll',
+};
+
+let optionList = [
+  {
+    value: 'tony',
+    label: 'Ironman',
+  },
+  {
+    value: 'Thor',
+    label: 'Thor',
+  },
+  {
+    value: 'steve',
+    label: 'Caption',
+  },
+  {
+    value: 'peter',
+    label: 'SpiderBoy',
+  },
+];
+
+export const OptionList = () => (
+  <Select
+    style={{
+      width: '100px',
+    }}
+    optionList={optionList}
+  ></Select>
+);
+
+OptionList.story = {
+  name: 'optionList',
+};
+
+export const InsetLabel = () => (
+  <>
+    <Select
+      style={{
+        width: 300,
+      }}
+      insetLabel="主播类型"
+      placeholder="请选择"
+      optionList={optionList}
+    ></Select>
+    <Select
+      style={{
+        width: 300,
+      }}
+      multiple
+      insetLabel="主播类型"
+      optionList={optionList}
+    ></Select>
+    <Select
+      style={{
+        width: 300,
+      }}
+      filter
+      insetLabel="主播类型"
+      optionList={optionList}
+    ></Select>
+    <Select
+      style={{
+        width: 300,
+      }}
+      filter
+      multiple
+      insetLabel="主播类型"
+      optionList={optionList}
+    ></Select>
+  </>
+);
 
-const ControledSelect = () => {
-    const [value, setValue] = useState('nick');
-    const [value2, setValue2] = useState('jerry');
-    const [value3, setValue3] = useState();
-    const [value4, setValue4] = useState(['nick']);
-    const [value5, setValue5] = useState();
-    return (
-        <>
-            <span>value + onChange</span>
-            <Select
-                value={value}
-                onChange={setValue}
-                style={{
-                    width: 200,
-                }}
-            >
-                <Option value="nick">nick</Option>
-                <Option value="jerry">jerry</Option>
-                <Option value="mark">mark</Option>
-            </Select>
-
-            <br />
-            <br />
-            <span>只传value,不传onChange</span>
-            <Select
-                value={value2}
-                style={{
-                    width: 200,
-                }}
-            >
-                <Option value="nick">nick</Option>
-                <Option value="jerry">jerry</Option>
-                <Option value="mark">mark</Option>
-            </Select>
-            <br />
-            <br />
-
-            <span>value + onChange , 多选</span>
-            <Select
-                value={value3}
-                onChange={setValue3}
-                multiple
-                style={{
-                    width: 200,
-                }}
-            >
-                <Option value="nick">nick</Option>
-                <Option value="jerry">jerry</Option>
-                <Option value="mark">mark</Option>
-                <Option value="nick2">nick2</Option>
-                <Option value="jerry2">jerry2</Option>
-                <Option value="mark2">mark2</Option>
-            </Select>
-            <br />
-            <br />
-
-            <span>value, 多选</span>
-            <Select
-                value={value4}
-                multiple
-                style={{
-                    width: 200,
-                }}
-            >
-                <Option value="nick">nick</Option>
-                <Option value="jerry">jerry</Option>
-                <Option value="mark">mark</Option>
-            </Select>
-
-            <br />
-            <h5>filter为true,但option label为node时</h5>
-            <Select
-                style={{
-                    width: '250px',
-                }}
-                filter={customFilter}
-                onChange={v => console.log(v)}
-                insetLabel="insetLabel"
-                value={value5}
-                onChange={setValue5}
-            >
-                {colorOptions.map(option => (
-                    <Option value={option.value} key={option.value}>
-                        <div style={alignStyle}>
-                            <span style={option.spanStyle}></span>
-                            {option.value}
-                        </div>
-                    </Option>
-                ))}
-            </Select>
-        </>
-    );
+InsetLabel.story = {
+  name: 'insetLabel',
 };
 
-stories.add('受控组件', () => <ControledSelect></ControledSelect>);
+export const ChangeOptionDynamic = () => {
+  function App() {
+    let [options, setOptions] = useState([]);
+    let [index, setIndex] = useState(0);
+
+    const addOption = () => {
+      const randomItem = optionList[index];
+      index = index + 1;
+      setIndex(index);
+      options = [...options, { ...randomItem }];
+      setOptions(options);
+    };
 
-const UnControledSelect = () => {
-    const onChange = value => {
-        console.log(value);
+    const reset = () => {
+      setOptions([]);
+      setIndex(0);
     };
 
     return (
-        <>
-            <h5>defaultValue在list中不存在</h5>
-            <Select
-                defaultValue={90}
-                onChange={onChange}
-                style={{
-                    width: 200,
-                }}
-            >
-                <Option value={20}>nick</Option>
-                <Option value={10}>jerry</Option>
-                <Option value={5}>mark</Option>
-            </Select>
-            <h5>defaultValue在list中存在</h5>
-            <Select
-                defaultValue={10}
-                onChange={onChange}
-                style={{
-                    width: 200,
-                }}
-            >
-                <Option value={20}>nick</Option>
-                <Option value={10}>jerry</Option>
-                <Option value={5}>mark</Option>
-            </Select>
-        </>
-    );
-};
-
-stories.add('非受控组件', () => <UnControledSelect></UnControledSelect>);
-stories.add('test scroll', () => (
-    <div
-        style={{
-            marginTop: '600px',
-            marginBottom: '50px',
-        }}
-    >
+      <div>
         <Select
-            style={{
-                width: '150px',
-            }}
+          style={{
+            width: '150px',
+          }}
+          defaultValue="tony"
         >
-            <Option value="tony">IronMan</Option>
-            <Option value="Thor" disabled>
-                Thor
-            </Option>
-            <Option value="steve">Caption</Option>
-            <Option value="peter">SpiderBoy</Option>
+          {options.map((option, idx) => (
+            <Select.Option key={option.key || idx} value={option.value}>
+              {option.label}
+            </Select.Option>
+          ))}
         </Select>
-    </div>
-));
-let optionList = [
-    {
-        value: 'tony',
-        label: 'Ironman',
-    },
-    {
-        value: 'Thor',
-        label: 'Thor',
-    },
-    {
-        value: 'steve',
-        label: 'Caption',
-    },
-    {
-        value: 'peter',
-        label: 'SpiderBoy',
-    },
-];
-stories.add('optionList方式传入', () => (
-    <Select
-        style={{
-            width: '100px',
-        }}
-        optionList={optionList}
-    ></Select>
-));
-stories.add('insetLabel', () => (
-    <>
-        <Select
-            style={{
-                width: 300,
-            }}
-            insetLabel="主播类型"
-            placeholder="请选择"
-            optionList={optionList}
-        ></Select>
-        <Select
-            style={{
-                width: 300,
-            }}
-            multiple
-            insetLabel="主播类型"
-            optionList={optionList}
-        ></Select>
-        <Select
-            style={{
-                width: 300,
-            }}
-            filter
-            insetLabel="主播类型"
-            optionList={optionList}
-        ></Select>
+        <h4>多选</h4>
         <Select
-            style={{
-                width: 300,
-            }}
-            filter
-            multiple
-            insetLabel="主播类型"
-            optionList={optionList}
-        ></Select>
-    </>
-));
-stories.add('change option dynamic', () => {
-    function App() {
-        let [options, setOptions] = useState([]);
-        let [index, setIndex] = useState(0);
-
-        const addOption = () => {
-            const randomItem = optionList[index];
-            index = index + 1;
-            setIndex(index);
-            options = [...options, { ...randomItem }];
-            setOptions(options);
-        };
+          style={{
+            width: '150px',
+          }}
+          multiple
+          defaultValue={['tony']}
+        >
+          {options.map((option, idx) => (
+            <Select.Option key={option.key || idx} value={option.value}>
+              {option.label}
+            </Select.Option>
+          ))}
+        </Select>
+        <button onClick={addOption}>add option</button>
+        <button onClick={reset}>reset</button>
+      </div>
+    );
+  }
 
-        const reset = () => {
-            setOptions([]);
-            setIndex(0);
-        };
+  return <App />;
+};
 
-        return (
-            <div>
-                <Select
-                    style={{
-                        width: '150px',
-                    }}
-                    defaultValue="tony"
-                >
-                    {options.map((option, idx) => (
-                        <Select.Option key={option.key || idx} value={option.value}>
-                            {option.label}
-                        </Select.Option>
-                    ))}
-                </Select>
-                <h4>多选</h4>
-                <Select
-                    style={{
-                        width: '150px',
-                    }}
-                    multiple
-                    defaultValue={['tony']}
-                >
-                    {options.map((option, idx) => (
-                        <Select.Option key={option.key || idx} value={option.value}>
-                            {option.label}
-                        </Select.Option>
-                    ))}
-                </Select>
-                <button onClick={addOption}>add option</button>
-                <button onClick={reset}>reset</button>
-            </div>
-        );
-    }
+ChangeOptionDynamic.story = {
+  name: 'change option dynamic',
+};
 
-    return <App />;
-});
 let list = [
-    {
-        value: 'tony',
-        label: 'Ironman',
-        otherKey: {
-            role: 1,
-        },
+  {
+    value: 'tony',
+    label: 'Ironman',
+    otherKey: {
+      role: 1,
     },
-    {
-        value: 'Thor',
-        label: 'Thor',
-        otherKey: {
-            role: 2,
-        },
+  },
+  {
+    value: 'Thor',
+    label: 'Thor',
+    otherKey: {
+      role: 2,
     },
-    {
-        value: 'steve',
-        label: 'Caption',
-        otherKey: {
-            role: 3,
-        },
+  },
+  {
+    value: 'steve',
+    label: 'Caption',
+    otherKey: {
+      role: 3,
     },
-    {
-        value: 'peter',
-        label: 'SpiderBoy',
-        otherKey: {
-            role: 4,
-        },
+  },
+  {
+    value: 'peter',
+    label: 'SpiderBoy',
+    otherKey: {
+      role: 4,
     },
+  },
 ];
 
 const SearchDemo1 = () => {
-    const [optionList, setOptionList] = useState(list);
-    const [loading, setLoading] = useState(false);
-
-    const handleSearch = value => {
-        setLoading(true);
-        let length = Math.ceil(Math.random() * 10);
-        let result = Array.from(
-            {
-                length,
-            },
-            (v, i) => {
-                return {
-                    value: value + i,
-                    label: value + i,
-                    otherKey: {
-                        role: i,
-                    },
-                };
-            }
-        );
-        setTimeout(() => {
-            setOptionList(result);
-            setLoading(false);
-        }, 1000);
-    };
-
-    const [value, setValue] = useState(optionList[0].value);
-
-    const onChange = value => {
-        console.log(value);
-        setValue(value);
-    };
-
-    return (
-        <div>
-            受控:
-            <Select
-                filter
-                style={{
-                    width: '150px',
-                }}
-                onSearch={v => handleSearch(v)}
-                optionList={optionList}
-                value={value}
-                loading={loading}
-                onChange={onChange}
-            ></Select>
-            非受控:
-            <Select
-                style={{
-                    width: '150px',
-                }}
-                filter
-                onSearch={v => handleSearch(v)}
-                optionList={optionList}
-                loading={loading}
-                onChange={onChange}
-            ></Select>
-            多选非受控
-            <Select
-                style={{
-                    width: '150px',
-                }}
-                filter
-                multiple
-                onSearch={v => handleSearch(v)}
-                optionList={optionList}
-                loading={loading}
-                onChange={onChange}
-            ></Select>
-        </div>
-    );
-};
-
-import debounce from 'lodash/debounce';
-
-class SearchDemo2 extends React.Component {
-    constructor() {
-        super();
-        this.state = {
-            loading: false,
-            optionList: [
-                {
-                    value: 'abc',
-                    label: '抖音',
-                    type: 1,
-                },
-                {
-                    value: 'hotsoon',
-                    label: '火山小视频',
-                    type: 2,
-                },
-                {
-                    value: 'pipixia',
-                    label: '皮皮虾',
-                    type: 3,
-                },
-                {
-                    value: 'toutiao',
-                    label: '今日头条',
-                    type: 4,
-                },
-            ],
-            value: [],
+  const [optionList, setOptionList] = useState(list);
+  const [loading, setLoading] = useState(false);
+
+  const handleSearch = value => {
+    setLoading(true);
+    let length = Math.ceil(Math.random() * 10);
+    let result = Array.from(
+      {
+        length,
+      },
+      (v, i) => {
+        return {
+          value: value + i,
+          label: value + i,
+          otherKey: {
+            role: i,
+          },
         };
-        this.handleSearch = debounce(this.handleSearch, 800).bind(this);
-        this.onChange = this.onChange.bind(this);
-        this.customRender = this.customRender.bind(this);
-    }
-
-    handleSearch(inputValue) {
-        this.setState({
-            loading: true,
-        });
-        let length = Math.ceil(Math.random() * 100);
-        let result = Array.from(
-            {
-                length,
-            },
-            (v, i) => {
-                return {
-                    value: inputValue + i,
-                    label: 'label' + i,
-                    type: i + 1,
-                };
-            }
-        );
-        setTimeout(() => {
-            this.setState({
-                optionList: result,
-                loading: false,
-            });
-        }, 2000);
-    }
-
-    onChange(value) {
-        this.setState({
-            value,
-        });
-        console.log(value);
-    }
-
-    customRender(optionNode) {
-        return optionNode.value + optionNode.label;
-    }
-
-    render() {
-        const { loading, optionList, value } = this.state;
-        return (
-            <div>
-                <Select
-                    style={{
-                        width: 150,
-                    }}
-                    filter
-                    labelInValue
-                    onSearch={this.handleSearch}
-                    optionList={optionList}
-                    loading={loading}
-                    onChange={this.onChange}
-                    placeholder="请选择"
-                ></Select>
-                <br />
-                <br />
-                <Select
-                    style={{
-                        width: 180,
-                    }}
-                    filter // labelInValue
-                    multiple
-                    value={value}
-                    renderSelectedItem={this.customRender}
-                    onSearch={this.handleSearch}
-                    optionList={optionList}
-                    loading={loading}
-                    onChange={this.onChange}
-                    placeholder="请选择"
-                ></Select>
-            </div>
-        );
-    }
-}
-
-stories.add('搜索', () => (
-    <>
-        <SearchDemo1 />
-        <SearchDemo2 />
-    </>
-));
-export const IncomeDetail = ({ config }) => {
-    const [detailList, setDetailList] = useState([]);
-    const [hasMore, setHasMore] = useState(true);
-    const [loading, setLoading] = useState();
-
-    const fetchData = (outParams = {}) => {
-        if (lock) {
-            return;
-        }
-
-        setLoading(true); // 参数
-        // 请求
-
-        fetch({
-            url: URL.user_profit,
-            method: 'get',
-            baseURL: config.webcast_host,
-            params,
-        })
-            .then(res => {
-                lock = false;
-                setLoading(false);
-                console.log('++++', data);
-            })
-            .catch(() => {
-                setLoading(false);
-                Toast.show('网络异常,请稍后重试');
-            });
-    };
+      }
+    );
+    setTimeout(() => {
+      setOptionList(result);
+      setLoading(false);
+    }, 1000);
+  };
 
-    useEffect(fetchData, []); // 监听滚动设置吸顶 以及加载更多
+  const [value, setValue] = useState(optionList[0].value);
 
-    useEffect(() => {
-        window.addEventListener('scroll', function() {
-            // 加载更多
-            const scrollY = window.scrollY;
-            const scrollHeight = document.documentElement.scrollHeight;
-            const screenHeight = screen.height;
+  const onChange = value => {
+    console.log(value);
+    setValue(value);
+  };
 
-            if (!loading && hasMore && scrollY + screenHeight + 300 > scrollHeight) {
-                fetchData();
-            }
-        });
-    }, [detailList.length]);
-    return (
-        <div>
-            <Select></Select>
-        </div>
-    );
-};
-stories.add('allowCreate', () => (
-    <Select
+  return (
+    <div>
+      受控:
+      <Select
+        filter
         style={{
-            width: 500,
+          width: '150px',
         }}
+        onSearch={v => handleSearch(v)}
         optionList={optionList}
-        allowCreate={true}
-        multiple={true}
-        filter={true}
-        onChange={v => console.log(v)}
-    ></Select>
-));
-stories.add('allowCreate custom render', () => (
-    <Select
+        value={value}
+        loading={loading}
+        onChange={onChange}
+      ></Select>
+      非受控:
+      <Select
         style={{
-            width: 500,
+          width: '150px',
         }}
+        filter
+        onSearch={v => handleSearch(v)}
         optionList={optionList}
-        allowCreate={true}
-        multiple={true}
-        filter={true}
-        onChange={v => console.log(v)}
-        renderCreateItem={v => `semi: ${v}`}
-    ></Select>
-));
+        loading={loading}
+        onChange={onChange}
+      ></Select>
+      多选非受控
+      <Select
+        style={{
+          width: '150px',
+        }}
+        filter
+        multiple
+        onSearch={v => handleSearch(v)}
+        optionList={optionList}
+        loading={loading}
+        onChange={onChange}
+      ></Select>
+    </div>
+  );
+};
 
-let AllowCreateControledDemo = () => {
-    let [value, setValue] = useState();
-    const optionList = [
+import debounce from 'lodash/debounce';
+
+class SearchDemo2 extends React.Component {
+  constructor() {
+    super();
+    this.state = {
+      loading: false,
+      optionList: [
         {
-            value: 'abc',
-            label: '抖音',
+          value: 'abc',
+          label: '抖音',
+          type: 1,
         },
         {
-            value: 'hotsoon',
-            label: '火山小视频',
+          value: 'hotsoon',
+          label: '火山小视频',
+          type: 2,
         },
         {
-            value: 'pipixia',
-            label: '皮皮虾',
+          value: 'pipixia',
+          label: '皮皮虾',
+          type: 3,
         },
         {
-            value: 'toutiao',
-            label: '今日头条',
+          value: 'toutiao',
+          label: '今日头条',
+          type: 4,
         },
-    ];
-    const [list, setList] = useState(optionList);
-
-    const handleSelect = v => {
-        var lastOne = v[v.length - 1];
-
-        if (lastOne && list.findIndex(item => item.value === lastOne) == -1) {
-            list.push({
-                value: lastOne,
-                label: lastOne,
-            });
-        }
-
-        setList(list);
-        setValue(v);
+      ],
+      value: [],
     };
+    this.handleSearch = debounce(this.handleSearch, 800).bind(this);
+    this.onChange = this.onChange.bind(this);
+    this.customRender = this.customRender.bind(this);
+  }
+
+  handleSearch(inputValue) {
+    this.setState({
+      loading: true,
+    });
+    let length = Math.ceil(Math.random() * 100);
+    let result = Array.from(
+      {
+        length,
+      },
+      (v, i) => {
+        return {
+          value: inputValue + i,
+          label: 'label' + i,
+          type: i + 1,
+        };
+      }
+    );
+    setTimeout(() => {
+      this.setState({
+        optionList: result,
+        loading: false,
+      });
+    }, 2000);
+  }
+
+  onChange(value) {
+    this.setState({
+      value,
+    });
+    console.log(value);
+  }
 
+  customRender(optionNode) {
+    return optionNode.value + optionNode.label;
+  }
+
+  render() {
+    const { loading, optionList, value } = this.state;
     return (
+      <div>
         <Select
-            style={{
-                width: 400,
-            }}
-            optionList={list}
-            allowCreate={true}
-            multiple={true}
-            filter={true}
-            value={value}
-            onChange={handleSelect}
+          style={{
+            width: 150,
+          }}
+          filter
+          labelInValue
+          onSearch={this.handleSearch}
+          optionList={optionList}
+          loading={loading}
+          onChange={this.onChange}
+          placeholder="请选择"
+        ></Select>
+        <br />
+        <br />
+        <Select
+          style={{
+            width: 180,
+          }}
+          filter // labelInValue
+          multiple
+          value={value}
+          renderSelectedItem={this.customRender}
+          onSearch={this.handleSearch}
+          optionList={optionList}
+          loading={loading}
+          onChange={this.onChange}
+          placeholder="请选择"
         ></Select>
+      </div>
     );
+  }
+}
+
+export const Search = () => (
+  <>
+    <SearchDemo1 />
+    <SearchDemo2 />
+  </>
+);
+
+Search.story = {
+  name: 'search',
 };
 
-const AllowCreateDemo = () => {
-    let [value, setValue] = useState();
-    const optionList = [
-        {
-            value: 'abc',
-            label: '抖音',
-        },
-        {
-            value: 'hotsoon',
-            label: '火山小视频',
-        },
-        {
-            value: 'pipixia',
-            label: '皮皮虾',
-        },
-        {
-            value: 'toutiao',
-            label: '今日头条',
-        },
-    ];
-    const [list, setList] = useState(optionList);
+export const IncomeDetail = ({ config = {}, params = {} }) => {
+  const [detailList, setDetailList] = useState([]);
+  const [hasMore, setHasMore] = useState(true);
+  const [loading, setLoading] = useState();
+  let lock;
 
-    const handleSelect = v => {
-        var lastOne = v[v.length - 1];
+  const fetchData = (outParams = {}) => {
+    if (lock) {
+      return;
+    }
 
-        if (lastOne && list.findIndex(item => item.value === lastOne) == -1) {
-            list.push({
-                value: lastOne,
-                label: lastOne,
-            });
-        }
+    setLoading(true); // 参数
+    // 请求
+
+    fetch({
+      url: URL.user_profit,
+      method: 'get',
+      baseURL: config.webcast_host,
+      params,
+    })
+      .then(res => {
+        lock = false;
+        setLoading(false);
+        console.log('++++', data);
+      })
+      .catch(() => {
+        setLoading(false);
+        Toast.show('网络异常,请稍后重试');
+      });
+  };
+
+  useEffect(fetchData, []); // 监听滚动设置吸顶 以及加载更多
+
+  useEffect(() => {
+    window.addEventListener('scroll', function() {
+      // 加载更多
+      const scrollY = window.scrollY;
+      const scrollHeight = document.documentElement.scrollHeight;
+      const screenHeight = screen.height;
+
+      if (!loading && hasMore && scrollY + screenHeight + 300 > scrollHeight) {
+        fetchData();
+      }
+    });
+  }, [detailList.length]);
+  return (
+    <div>
+      <Select></Select>
+    </div>
+  );
+};
 
-        setList(list); // setValue(v)
-    };
+export const AllowCreate = () => (
+  <Select
+    style={{
+      width: 500,
+    }}
+    optionList={optionList}
+    allowCreate={true}
+    multiple={true}
+    filter={true}
+    onChange={v => console.log(v)}
+  ></Select>
+);
+
+AllowCreate.story = {
+  name: 'allowCreate',
+};
 
-    return (
-        <Select
-            style={{
-                width: 400,
-            }}
-            optionList={list}
-            defaultValue={['abc', 'hotsoon']}
-            allowCreate={true}
-            multiple={true}
-            filter={true}
-            onChange={handleSelect}
-        ></Select>
-    );
+export const AllowCreateCustomRender = () => (
+  <Select
+    style={{
+      width: 500,
+    }}
+    optionList={optionList}
+    allowCreate={true}
+    multiple={true}
+    filter={true}
+    onChange={v => console.log(v)}
+    renderCreateItem={v => `semi: ${v}`}
+  ></Select>
+);
+
+AllowCreateCustomRender.story = {
+  name: 'allowCreate custom render',
 };
 
-stories.add('allowCreate 带默认值', () => <AllowCreateDemo />);
+let AllowCreateControledDemo = () => {
+  let [value, setValue] = useState();
+  const optionList = [
+    {
+      value: 'abc',
+      label: '抖音',
+    },
+    {
+      value: 'hotsoon',
+      label: '火山小视频',
+    },
+    {
+      value: 'pipixia',
+      label: '皮皮虾',
+    },
+    {
+      value: 'toutiao',
+      label: '今日头条',
+    },
+  ];
+  const [list, setList] = useState(optionList);
 
-class HideDemo extends React.Component {
-    constructor(props) {
-        super(props);
-        this.state = {
-            optionList: [
-                {
-                    value: 'abc',
-                    label: '抖音',
-                },
-                {
-                    value: 'hotsoon',
-                    label: '火山小视频',
-                },
-                {
-                    value: 'pipixia',
-                    label: '皮皮虾',
-                },
-                {
-                    value: 'toutiao',
-                    label: '今日头条',
-                },
-            ],
-            selectedItems: [],
-        };
-        this.onChange = this.onChange.bind(this);
-    }
+  const handleSelect = v => {
+    var lastOne = v[v.length - 1];
 
-    onChange(selectedItems) {
-        this.setState({
-            selectedItems,
-        });
+    if (lastOne && list.findIndex(item => item.value === lastOne) == -1) {
+      list.push({
+        value: lastOne,
+        label: lastOne,
+      });
     }
 
-    render() {
-        let { optionList, selectedItems } = this.state;
-        let filterOptions = optionList.filter(option => !selectedItems.includes(option.value));
-        return (
-            <Select
-                value={selectedItems}
-                multiple
-                style={{
-                    width: 300,
-                }}
-                onChange={this.onChange}
-                optionList={filterOptions}
-            ></Select>
-        );
-    }
-}
+    setList(list);
+    setValue(v);
+  };
 
-stories.add('自动隐藏已选项', () => <HideDemo></HideDemo>);
+  return (
+    <Select
+      style={{
+        width: 400,
+      }}
+      optionList={list}
+      allowCreate={true}
+      multiple={true}
+      filter={true}
+      value={value}
+      onChange={handleSelect}
+    ></Select>
+  );
+};
 
-class CustomCreate extends React.Component {
-    constructor(props) {
-        super(props);
-        this.state = {
-            optionList: [
-                {
-                    value: 'abc',
-                    label: '抖音',
-                },
-                {
-                    value: 'hotsoon',
-                    label: '火山小视频',
-                },
-                {
-                    value: 'pipixia',
-                    label: '皮皮虾',
-                },
-                {
-                    value: 'toutiao',
-                    label: '今日头条',
-                },
-                {
-                    value: 0,
-                    label: 0,
-                },
-            ],
-            selectedItems: ['fefe'],
-        };
-        this.onChange = this.onChange.bind(this);
-        this.customRender = this.customRender.bind(this);
-        this.search = this.search.bind(this);
-    }
+const AllowCreateDemo = () => {
+  let [value, setValue] = useState();
+  const optionList = [
+    {
+      value: 'abc',
+      label: '抖音',
+    },
+    {
+      value: 'hotsoon',
+      label: '火山小视频',
+    },
+    {
+      value: 'pipixia',
+      label: '皮皮虾',
+    },
+    {
+      value: 'toutiao',
+      label: '今日头条',
+    },
+  ];
+  const [list, setList] = useState(optionList);
 
-    onChange(selectedItems) {
-        console.log(selectedItems); // this.setState({ selectedItems, optionList: [] });
+  const handleSelect = v => {
+    var lastOne = v[v.length - 1];
 
-        this.setState({
-            selectedItems,
-        }); // this.setState({ optionList: [] });
+    if (lastOne && list.findIndex(item => item.value === lastOne) == -1) {
+      list.push({
+        value: lastOne,
+        label: lastOne,
+      });
     }
 
-    customRender(v) {
-        return (
-            <>
-                <span>label:{v.label}</span>
-                <span>value:{v.value}</span>
-            </>
-        );
-    }
+    setList(list); // setValue(v)
+  };
 
-    customCreate(inputValue, isFocus) {
-        let style = {
-            padding: 12,
-            cursor: 'pointer',
-            backgroundColor: isFocus ? 'var(--semi-color-fill-0)' : '#FFF',
-        };
-        return <div style={style}>{'create' + inputValue}</div>;
-    }
+  return (
+    <Select
+      style={{
+        width: 400,
+      }}
+      optionList={list}
+      defaultValue={['abc', 'hotsoon']}
+      allowCreate={true}
+      multiple={true}
+      filter={true}
+      onChange={handleSelect}
+    ></Select>
+  );
+};
 
-    search(inputValue) {
-        let length = Math.ceil(Math.random() * 10);
-        let result = Array.from(
-            {
-                length,
-            },
-            (v, i) => {
-                return {
-                    value: inputValue + i,
-                    label: inputValue + i,
-                    type: i + 1,
-                };
-            }
-        );
-        console.log(result); // result = result.concat(selectedOption);
-
-        this.setState({
-            optionList: result,
-        });
-    }
+export const AllowCreateWithDefaultValue = () => <AllowCreateDemo />;
 
-    render() {
-        let { optionList, selectedItems } = this.state;
-        return (
-            <>
-                <Select
-                    defaultValue={['abc']}
-                    filter
-                    style={{
-                        width: 300,
-                    }}
-                    multiple
-                    optionList={optionList}
-                    onSearch={this.search}
-                    onChange={this.onChange}
-                    emptyContent={null} // onChangeWithObject
-                ></Select>
-            </>
-        );
-    }
+AllowCreateWithDefaultValue.story = {
+  name: 'allowCreate with defaultValue',
+};
+
+class HideDemo extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      optionList: [
+        {
+          value: 'abc',
+          label: '抖音',
+        },
+        {
+          value: 'hotsoon',
+          label: '火山小视频',
+        },
+        {
+          value: 'pipixia',
+          label: '皮皮虾',
+        },
+        {
+          value: 'toutiao',
+          label: '今日头条',
+        },
+      ],
+      selectedItems: [],
+    };
+    this.onChange = this.onChange.bind(this);
+  }
+
+  onChange(selectedItems) {
+    this.setState({
+      selectedItems,
+    });
+  }
+
+  render() {
+    let { optionList, selectedItems } = this.state;
+    let filterOptions = optionList.filter(option => !selectedItems.includes(option.value));
+    return (
+      <Select
+        value={selectedItems}
+        multiple
+        style={{
+          width: 300,
+        }}
+        onChange={this.onChange}
+        optionList={filterOptions}
+      ></Select>
+    );
+  }
 }
 
-stories.add('CustomCreate', () => <CustomCreate></CustomCreate>);
+export const AutoHiddenSelectedItem = () => <HideDemo></HideDemo>;
 
-class OptionGroupDemo extends React.Component {
-    constructor(props) {
-        super(props);
-        this.handleSearch = this.handleSearch.bind(this);
-        this.state = {
-            groups: [
-                {
-                    label: 'Asia',
-                    children: [
-                        {
-                            label: 'China',
-                            value: 'zhongguo',
-                        },
-                        {
-                            label: 'Koera',
-                            value: 'hanguo',
-                        },
-                    ],
-                },
-                {
-                    label: 'Europe',
-                    children: [
-                        {
-                            label: 'Germany',
-                            value: 'deguo',
-                        },
-                        {
-                            label: 'France',
-                            value: 'faguo',
-                        },
-                    ],
-                },
-                {
-                    label: 'Other',
-                    children: [
-                        {
-                            label: 'vf',
-                            value: 'Sourth',
-                        },
-                    ],
-                },
-            ],
-        };
-    }
+AutoHiddenSelectedItem.story = {
+  name: 'auto hidden selected item',
+};
 
-    handleSearch(input) {
-        let groups = [1, 2, 3].map(i => {
-            return {
-                label: i,
-                // label: Math.random(),
-                children: [10, 20].map(j => {
-                    return {
-                        label: Math.random(),
-                        value: Math.random(),
-                    };
-                }),
-            };
-        });
-        this.setState({
-            groups,
-        });
-    }
+class CustomCreate extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      optionList: [
+        {
+          value: 'abc',
+          label: '抖音',
+        },
+        {
+          value: 'hotsoon',
+          label: '火山小视频',
+        },
+        {
+          value: 'pipixia',
+          label: '皮皮虾',
+        },
+        {
+          value: 'toutiao',
+          label: '今日头条',
+        },
+        {
+          value: 0,
+          label: 0,
+        },
+      ],
+      selectedItems: ['fefe'],
+    };
+    this.onChange = this.onChange.bind(this);
+    this.customRender = this.customRender.bind(this);
+    this.search = this.search.bind(this);
+  }
 
-    renderGroup(group) {
-        let options = group.children.map(option => (
-            <Select.Option value={option.value} label={option.label} key={option.label}></Select.Option>
-        ));
-        return <Select.OptGroup label={group.label}>{options}</Select.OptGroup>;
-    }
+  onChange(selectedItems) {
+    console.log(selectedItems); // this.setState({ selectedItems, optionList: [] });
 
-    render() {
-        let { groups } = this.state;
-        return (
-            <>
-                <Select
-                    placeholder=""
-                    style={{
-                        width: 180,
-                    }}
-                    filter
-                    onSearch={this.handleSearch}
-                    remote
-                >
-                    {groups.map(group => this.renderGroup(group))}
-                </Select>
-            </>
-        );
-    }
-}
+    this.setState({
+      selectedItems,
+    }); // this.setState({ optionList: [] });
+  }
 
-stories.add('Select OptionGroup', () => <OptionGroupDemo></OptionGroupDemo>);
+  customRender(v) {
+    return (
+      <>
+        <span>label:{v.label}</span>
+        <span>value:{v.value}</span>
+      </>
+    );
+  }
 
-const BlurDemo = () => {
-    const onBlur = (value, e) => {
-        console.log(value);
-        console.log(e);
+  customCreate(inputValue, isFocus) {
+    let style = {
+      padding: 12,
+      cursor: 'pointer',
+      backgroundColor: isFocus ? 'var(--semi-color-fill-0)' : '#FFF',
     };
+    return <div style={style}>{'create' + inputValue}</div>;
+  }
+
+  search(inputValue) {
+    let length = Math.ceil(Math.random() * 10);
+    let result = Array.from(
+      {
+        length,
+      },
+      (v, i) => {
+        return {
+          value: inputValue + i,
+          label: inputValue + i,
+          type: i + 1,
+        };
+      }
+    );
+    console.log(result); // result = result.concat(selectedOption);
 
-    const onFocus = (value, e) => {
-        console.log(value);
-        console.log(e);
-    };
+    this.setState({
+      optionList: result,
+    });
+  }
 
+  render() {
+    let { optionList, selectedItems } = this.state;
     return (
-        <>
-            <Select
-                filter
-                placeholder=""
-                style={{
-                    width: 180,
-                }}
-                onBlur={onBlur}
-                onFocus={onFocus}
-            >
-                <Select.Option value="zhongguo">China</Select.Option>
-                <Select.Option value="hanguo">Koera</Select.Option>
-                <Select.Option value="deguo">Germany</Select.Option>
-                <Select.Option value="faguo">France</Select.Option>
-            </Select>
-        </>
+      <>
+        <Select
+          defaultValue={['abc']}
+          filter
+          style={{
+            width: 300,
+          }}
+          multiple
+          optionList={optionList}
+          onSearch={this.search}
+          onChange={this.onChange}
+          emptyContent={null} // onChangeWithObject
+        ></Select>
+      </>
     );
-};
+  }
+}
 
-stories.add('Select onBlur/onFocus', () => <BlurDemo></BlurDemo>); // stories.add('BugDemo', () => <BugDemo></BugDemo>);
+export const _CustomCreate = () => <CustomCreate></CustomCreate>;
 
-const AutoAdjustOverflowDemo = () => {
-    const [list, setList] = useState([
-        {
-            value: 'abc',
-            label: '1111',
-        },
+_CustomCreate.story = {
+  name: 'CustomCreate',
+};
+
+class OptionGroupDemo extends React.Component {
+  constructor(props) {
+    super(props);
+    this.handleSearch = this.handleSearch.bind(this);
+    this.state = {
+      groups: [
         {
-            value: 'hotsoon',
-            label: '1112',
+          label: 'Asia',
+          children: [
+            {
+              label: 'China',
+              value: 'zhongguo',
+            },
+            {
+              label: 'Koera',
+              value: 'hanguo',
+            },
+          ],
         },
         {
-            value: 'pipixia',
-            label: '1113',
+          label: 'Europe',
+          children: [
+            {
+              label: 'Germany',
+              value: 'deguo',
+            },
+            {
+              label: 'France',
+              value: 'faguo',
+            },
+          ],
         },
         {
-            value: 'toutiao',
-            label: '1114',
-        },
-    ]);
-
-    const onSearch = () => {
-        let newList = Array.from(
+          label: 'Other',
+          children: [
             {
-                length: Math.floor(Math.random() * 10),
+              label: 'vf',
+              value: 'Sourth',
             },
-            (v, i) => {
-                return {
-                    value: i,
-                    label: i,
-                };
-            }
-        );
-        setList(newList);
-        console.log(newList);
+          ],
+        },
+      ],
     };
+  }
+
+  handleSearch(input) {
+    let groups = [1, 2, 3].map(i => {
+      return {
+        label: i,
+        // label: Math.random(),
+        children: [10, 20].map(j => {
+          return {
+            label: Math.random(),
+            value: Math.random(),
+          };
+        }),
+      };
+    });
+    this.setState({
+      groups,
+    });
+  }
 
+  renderGroup(group) {
+    let options = group.children.map(option => (
+      <Select.Option value={option.value} label={option.label} key={option.label}></Select.Option>
+    ));
+    return <Select.OptGroup label={group.label}>{options}</Select.OptGroup>;
+  }
+
+  render() {
+    let { groups } = this.state;
     return (
-        <div
-            style={{
-                height: 180,
-                margin: 250,
-                border: '1px solid pink',
-            }}
+      <>
+        <Select
+          placeholder=""
+          style={{
+            width: 180,
+          }}
+          filter
+          onSearch={this.handleSearch}
+          remote
         >
-            <Select
-                optionList={list}
-                filter={true}
-                remote={true}
-                onSearch={onSearch}
-                style={{
-                    width: 200,
-                }}
-                multiple
-            />
-        </div>
+          {groups.map(group => this.renderGroup(group))}
+        </Select>
+      </>
     );
+  }
+}
+
+export const SelectOptionGroup = () => <OptionGroupDemo></OptionGroupDemo>;
+
+SelectOptionGroup.story = {
+  name: 'Select OptionGroup',
 };
 
-stories.add('autoAdjustOverflow', () => <AutoAdjustOverflowDemo></AutoAdjustOverflowDemo>);
+const BlurDemo = () => {
+  const onBlur = (value, e) => {
+    console.log(value);
+    console.log(e);
+  };
 
-const AllowCreateWithFilter = () => {
-    const [list, setList] = useState([
-        {
-            value: 'abc',
-            label: 'abc',
-            otherKey: 'abc',
-        },
-        {
-            value: 'hotsoon',
-            label: 'hotsoon',
-            otherKey: 'efg',
-        },
-        {
-            value: 'pipixia',
-            label: 'pipixia',
-            otherKey: 'hij',
-        },
-        {
-            value: 'toutiao',
-            label: 'toutiao',
-            otherKey: 'klm',
-        },
-    ]);
+  const onFocus = (value, e) => {
+    console.log(value);
+    console.log(e);
+  };
 
-    const filter = (sugInput, option) => {
-        let compareKey = option.otherKey ? option.otherKey.toUpperCase() : '';
-        let sug = sugInput.toUpperCase();
-        return compareKey.includes(sug);
-    };
+  return (
+    <>
+      <Select
+        filter
+        placeholder=""
+        style={{
+          width: 180,
+        }}
+        onBlur={onBlur}
+        onFocus={onFocus}
+      >
+        <Select.Option value="zhongguo">China</Select.Option>
+        <Select.Option value="hanguo">Koera</Select.Option>
+        <Select.Option value="deguo">Germany</Select.Option>
+        <Select.Option value="faguo">France</Select.Option>
+      </Select>
+    </>
+  );
+};
 
-    return (
-        <div
-            style={{
-                height: 180,
-                margin: 250,
-            }}
-        >
-            <Select
-                optionList={list}
-                multiple
-                filter={filter}
-                style={{
-                    width: 200,
-                }}
-                allowCreate
-            />
-        </div>
+export const SelectOnBlurOnFocus = () => <BlurDemo></BlurDemo>;
+
+SelectOnBlurOnFocus.story = {
+  name: 'Select onBlur/onFocus',
+};
+
+const AutoAdjustOverflowDemo = () => {
+  const [list, setList] = useState([
+    {
+      value: 'abc',
+      label: '1111',
+    },
+    {
+      value: 'hotsoon',
+      label: '1112',
+    },
+    {
+      value: 'pipixia',
+      label: '1113',
+    },
+    {
+      value: 'toutiao',
+      label: '1114',
+    },
+  ]);
+
+  const onSearch = () => {
+    let newList = Array.from(
+      {
+        length: Math.floor(Math.random() * 10),
+      },
+      (v, i) => {
+        return {
+          value: i,
+          label: i,
+        };
+      }
     );
+    setList(newList);
+    console.log(newList);
+  };
+
+  return (
+    <div
+      style={{
+        height: 180,
+        margin: 250,
+        border: '1px solid pink',
+      }}
+    >
+      <Select
+        optionList={list}
+        filter={true}
+        remote={true}
+        onSearch={onSearch}
+        style={{
+          width: 200,
+        }}
+        multiple
+      />
+    </div>
+  );
+};
+
+export const AutoAdjustOverflow = () => <AutoAdjustOverflowDemo></AutoAdjustOverflowDemo>;
+
+AutoAdjustOverflow.story = {
+  name: 'autoAdjustOverflow',
+};
+
+const AllowCreateWithFilter = () => {
+  const [list, setList] = useState([
+    {
+      value: 'abc',
+      label: 'abc',
+      otherKey: 'abc',
+    },
+    {
+      value: 'hotsoon',
+      label: 'hotsoon',
+      otherKey: 'efg',
+    },
+    {
+      value: 'pipixia',
+      label: 'pipixia',
+      otherKey: 'hij',
+    },
+    {
+      value: 'toutiao',
+      label: 'toutiao',
+      otherKey: 'klm',
+    },
+  ]);
+
+  const filter = (sugInput, option) => {
+    let compareKey = option.otherKey ? option.otherKey.toUpperCase() : '';
+    let sug = sugInput.toUpperCase();
+    return compareKey.includes(sug);
+  };
+
+  return (
+    <div
+      style={{
+        height: 180,
+        margin: 250,
+      }}
+    >
+      <Select
+        optionList={list}
+        multiple
+        filter={filter}
+        style={{
+          width: 200,
+        }}
+        allowCreate
+      />
+    </div>
+  );
 };
 
-stories.add('Filter + allowCreate', () => <AllowCreateWithFilter></AllowCreateWithFilter>);
+export const FilterAllowCreate = () => <AllowCreateWithFilter></AllowCreateWithFilter>;
+
+FilterAllowCreate.story = {
+  name: 'Filter + allowCreate',
+};
 
 const SelectRefDemo = () => {
-    const ref = useRef();
-    const secondRef = useRef();
-    const [open, setOpen] = useState(false);
-    const list = [
-        {
-            value: 'abc',
-            label: 'Abc',
-        },
-        {
-            value: 'hotsoon',
-            label: 'Hotsoon',
-        },
-        {
-            value: 'pipixia',
-            label: 'Pipixia',
-        },
-        {
-            value: 'toutiao',
-            label: 'TooBuzz',
-        },
-    ];
-
-    const change = () => {
-        if (!open) {
-            ref.current.open();
-            setOpen(true);
-        } else {
-            ref.current.close();
-            setOpen(false);
-        }
-    };
+  const ref = useRef();
+  const secondRef = useRef();
+  const [open, setOpen] = useState(false);
+  const list = [
+    {
+      value: 'abc',
+      label: 'Abc',
+    },
+    {
+      value: 'hotsoon',
+      label: 'Hotsoon',
+    },
+    {
+      value: 'pipixia',
+      label: 'Pipixia',
+    },
+    {
+      value: 'toutiao',
+      label: 'TooBuzz',
+    },
+  ];
+
+  const change = () => {
+    if (!open) {
+      ref.current.open();
+      setOpen(true);
+    } else {
+      ref.current.close();
+      setOpen(false);
+    }
+  };
 
-    const focus = () => {
-        ref.current.focus();
-    };
+  const focus = () => {
+    ref.current.focus();
+  };
 
-    const clearInput = () => {
-        ref.current.clearInput();
-    };
+  const clearInput = () => {
+    ref.current.clearInput();
+  };
 
-    const deselectAll = () => {
-        ref.current.deselectAll();
-    };
+  const deselectAll = () => {
+    ref.current.deselectAll();
+  };
 
-    const selectAll = () => {
-        ref.current.selectAll();
-    };
+  const selectAll = () => {
+    ref.current.selectAll();
+  };
 
-    return (
-        <>
-            <h4>onChangeWithObject = false</h4>
-            <Select
-                innerBottomSlot={
-                    <div>
-                        <Space>
-                            <Button onClick={change}>close</Button>
-                            <Button onClick={clearInput}>clearInput</Button>
-                            <Button onClick={deselectAll}>deselectAll</Button>
-                            <Button onClick={selectAll}>selectAll</Button>
-                        </Space>
-                    </div>
-                }
-                ref={ref}
-                onChange={e => console.log(e)}
-                placeholder="Business line"
-                style={{
-                    width: 180,
-                }}
-                optionList={list}
-                filter
-                multiple
-            ></Select>
-            <Space>
-                <Button onClick={change}>open</Button>
-                <Button onClick={focus}>focus</Button>
-                <Button onClick={clearInput}>clearInput</Button>
-                <Button onClick={deselectAll}>deselectAll</Button>
-                <Button onClick={selectAll}>selectAll</Button>
-            </Space>
-            <h4
-                style={{
-                    marginTop: 20,
-                }}
-            >
-                onChangeWithObject = true
-            </h4>
-            <Select
-                innerBottomSlot={
-                    <div>
-                        <Space></Space>
-                    </div>
-                }
-                onChange={e => console.log(e)}
-                onChangeWithObject
-                ref={secondRef}
-                placeholder="Business line"
-                style={{
-                    width: 180,
-                }}
-                optionList={list}
-                filter
-                multiple
-            ></Select>
+  return (
+    <>
+      <h4>onChangeWithObject = false</h4>
+      <Select
+        innerBottomSlot={
+          <div>
             <Space>
-                <Button onClick={() => secondRef.current.deselectAll()}>deselectAll</Button>
-                <Button onClick={() => secondRef.current.selectAll()}>selectAll</Button>
+              <Button onClick={change}>close</Button>
+              <Button onClick={clearInput}>clearInput</Button>
+              <Button onClick={deselectAll}>deselectAll</Button>
+              <Button onClick={selectAll}>selectAll</Button>
             </Space>
-        </>
-    );
+          </div>
+        }
+        ref={ref}
+        onChange={e => console.log(e)}
+        placeholder="Business line"
+        style={{
+          width: 180,
+        }}
+        optionList={list}
+        filter
+        multiple
+      ></Select>
+      <Space>
+        <Button onClick={change}>open</Button>
+        <Button onClick={focus}>focus</Button>
+        <Button onClick={clearInput}>clearInput</Button>
+        <Button onClick={deselectAll}>deselectAll</Button>
+        <Button onClick={selectAll}>selectAll</Button>
+      </Space>
+      <h4
+        style={{
+          marginTop: 20,
+        }}
+      >
+        onChangeWithObject = true
+      </h4>
+      <Select
+        innerBottomSlot={
+          <div>
+            <Space></Space>
+          </div>
+        }
+        onChange={e => console.log(e)}
+        onChangeWithObject
+        ref={secondRef}
+        placeholder="Business line"
+        style={{
+          width: 180,
+        }}
+        optionList={list}
+        filter
+        multiple
+      ></Select>
+      <Space>
+        <Button onClick={() => secondRef.current.deselectAll()}>deselectAll</Button>
+        <Button onClick={() => secondRef.current.selectAll()}>selectAll</Button>
+      </Space>
+    </>
+  );
 };
 
-stories.add('ref', () => <SelectRefDemo />);
-stories.add(`custom trigger`, () => <CustomTrigger />); 
+export const Ref = () => <SelectRefDemo />;
 
-class VirtualizeDemo extends React.Component {
-    constructor(props) {
-        super(props);
-        // this.handleSearch = this.handleSearch.bind(this);
-        let newOptions = Array.from({ length: 1000 }, (v, i) => ({ label: `option-${i}`, value: i }));
-        this.state = {
-            optionList: newOptions,
-        };
-    }
-    render() {
-        let { groups, optionList } = this.state;
-        let virtualize = {
-            height: 300,
-            widht: '100%',
-            itemSize: 36,
-        };
-        return (
-            <>
-                <Select
-                    placeholder=""
-                    style={{ width: 180 }}
-                    filter
-                    onSearch={this.handleSearch}
-                    virtualize={virtualize}
-                    optionList={optionList}
-                ></Select>
-            </>
-        );
-    }
+Ref.story = {
+  name: 'ref',
+};
+
+export const CustomTriggerDemo = () => <CustomTrigger />;
+CustomTriggerDemo.story = {
+  name: 'custom trigger'
 }
-stories.add(`virtualize select`, () => <VirtualizeDemo />);
 
-const SelectPosition = () => {
+class VirtualizeClassDemo extends React.Component {
+  constructor(props) {
+    super(props);
+    // this.handleSearch = this.handleSearch.bind(this);
+    let newOptions = Array.from({ length: 1000 }, (v, i) => ({ label: `option-${i}`, value: i }));
+    this.state = {
+      optionList: newOptions,
+    };
+  }
+  render() {
+    let { groups, optionList } = this.state;
+    let virtualize = {
+      height: 300,
+      widht: '100%',
+      itemSize: 36,
+    };
     return (
-        <div
-            style={{
-                height: 500,
-                border: '1px solid red',
-                overflow: 'auto',
-            }}
-        >
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <Select
-                defaultValue="abc"
-                style={{
-                    width: 120,
-                }}
-            >
-                <Option value="abc">抖音</Option>
-                <Option value="hotsoon">火山</Option>
-                <Option value="pipixia" disabled>
-                    皮皮虾
-                </Option>
-                <Option value="xigua">西瓜视频</Option>
-            </Select>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-            <p>p</p>
-        </div>
+      <>
+        <Select
+          placeholder=""
+          style={{ width: 180 }}
+          filter
+          onSearch={this.handleSearch}
+          virtualize={virtualize}
+          optionList={optionList}
+        ></Select>
+      </>
     );
+  }
+}
+
+export const VirtualizeDemo = () => <VirtualizeClassDemo />;
+
+VirtualizeDemo.story = {
+  name: 'virtualize select'
+}
+
+
+const SelectPosition = () => {
+  return (
+    <div
+      style={{
+        height: 500,
+        border: '1px solid red',
+        overflow: 'auto',
+      }}
+    >
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <Select
+        defaultValue="abc"
+        style={{
+          width: 120,
+        }}
+      >
+        <Option value="abc">抖音</Option>
+        <Option value="hotsoon">火山</Option>
+        <Option value="pipixia" disabled>
+          皮皮虾
+        </Option>
+        <Option value="xigua">西瓜视频</Option>
+      </Select>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+      <p>p</p>
+    </div>
+  );
 };
 
-stories.add(`Select position problem`, () => <SelectPosition />);
+export { SelectPosition };
+SelectPosition.story = {
+  name: 'Select position problem'
+}
 
 const RenderOptionDemo = () => {
-    const renderOptionItem = renderProps => {
-        const {
-            disabled,
-            selected,
-            label,
-            value,
-            focused,
-            className,
-            style,
-            onMouseEnter,
-            onClick,
-            empty,
-            emptyContent,
-            ...rest
-        } = renderProps;
-        const optionCls = classNames({
-            ['custom-option-render']: true,
-            ['custom-option-render-focused']: focused,
-            ['custom-option-render-disabled']: disabled,
-            ['custom-option-render-selected']: selected,
-        }); // Notice:
-        // 1.props传入的style需在wrapper dom上进行消费,否则在虚拟化场景下会无法正常使用
-        // 2.选中(selected)、聚焦(focused)、禁用(disabled)等状态的样式需自行加上,你可以从props中获取到相对的boolean值
-        // 3.onMouseEnter需在wrapper dom上绑定,否则上下键盘操作时显示会有问题
-
-        return (
-            <div style={style} className={optionCls} onClick={() => onClick()} onMouseEnter={e => onMouseEnter()}>
-                <Checkbox checked={selected} />
-                <div className="option-right">{label}</div>
-            </div>
-        );
-    };
+  const renderOptionItem = renderProps => {
+    const {
+      disabled,
+      selected,
+      label,
+      value,
+      focused,
+      className,
+      style,
+      onMouseEnter,
+      onClick,
+      empty,
+      emptyContent,
+      ...rest
+    } = renderProps;
+    const optionCls = classNames({
+      ['custom-option-render']: true,
+      ['custom-option-render-focused']: focused,
+      ['custom-option-render-disabled']: disabled,
+      ['custom-option-render-selected']: selected,
+    }); // Notice:
+    // 1.props传入的style需在wrapper dom上进行消费,否则在虚拟化场景下会无法正常使用
+    // 2.选中(selected)、聚焦(focused)、禁用(disabled)等状态的样式需自行加上,你可以从props中获取到相对的boolean值
+    // 3.onMouseEnter需在wrapper dom上绑定,否则上下键盘操作时显示会有问题
 
     return (
-        <>
-            <Select
-                filter
-                dropdownClassName="components-select-demo-renderOptionItem"
-                optionList={optionList}
-                style={{
-                    width: 300,
-                }}
-                renderOptionItem={renderOptionItem}
-            />
-            <br />
-            <br />
-            <Select
-                filter
-                multiple
-                dropdownClassName="components-select-demo-renderOptionItem"
-                optionList={optionList}
-                style={{
-                    width: 450,
-                }}
-                renderOptionItem={renderOptionItem}
-            />
-        </>
+      <div
+        style={style}
+        className={optionCls}
+        onClick={() => onClick()}
+        onMouseEnter={e => onMouseEnter()}
+      >
+        <Checkbox checked={selected} />
+        <div className="option-right">{label}</div>
+      </div>
     );
+  };
+
+  return (
+    <>
+      <Select
+        filter
+        dropdownClassName="components-select-demo-renderOptionItem"
+        optionList={optionList}
+        style={{
+          width: 300,
+        }}
+        renderOptionItem={renderOptionItem}
+      />
+      <br />
+      <br />
+      <Select
+        filter
+        multiple
+        dropdownClassName="components-select-demo-renderOptionItem"
+        optionList={optionList}
+        style={{
+          width: 450,
+        }}
+        renderOptionItem={renderOptionItem}
+      />
+    </>
+  );
 };
 
-stories.add('renderOptionItem', () => <RenderOptionDemo />);
+export const RenderOptionItem = () => <RenderOptionDemo />;
+
+RenderOptionItem.story = {
+  name: 'renderOptionItem',
+};
 
 const FilterDefaultOpen = () => {
-    const [value1, setValue1] = useState('a-1');
-    return (
-        <>
-            <Select
-                placeholder=""
-                style={{
-                    width: 180,
-                }}
-                filter
-                defaultOpen
-            >
-                <Select.OptGroup label="Asia">
-                    <Select.Option value="a-1">China</Select.Option>
-                    <Select.Option value="a-2">Koera</Select.Option>
-                </Select.OptGroup>
-                <Select.OptGroup label="Europe">
-                    <Select.Option value="b-1">Germany</Select.Option>
-                    <Select.Option value="b-2">France</Select.Option>
-                </Select.OptGroup>
-                <Select.OptGroup label="South America">
-                    <Select.Option value="c-1">Peru</Select.Option>
-                </Select.OptGroup>
-            </Select>
-            <Select
-                placeholder=""
-                style={{
-                    width: 180,
-                    marginLeft: 20,
-                }}
-                filter
-                defaultOpen
-                defaultValue="a-2"
-            >
-                <Select.OptGroup label="Asia">
-                    <Select.Option value="a-1">China</Select.Option>
-                    <Select.Option value="a-2">Koera</Select.Option>
-                </Select.OptGroup>
-                <Select.OptGroup label="Europe">
-                    <Select.Option value="b-1">Germany</Select.Option>
-                    <Select.Option value="b-2">France</Select.Option>
-                </Select.OptGroup>
-                <Select.OptGroup label="South America">
-                    <Select.Option value="c-1">Peru</Select.Option>
-                </Select.OptGroup>
-            </Select>
-            <Select
-                placeholder=""
-                style={{
-                    width: 180,
-                    marginLeft: 20,
-                }}
-                filter
-                defaultOpen
-                value={value1}
-                onChange={val => setValue1(val)}
-            >
-                <Select.Option value="a-1">China</Select.Option>
-                <Select.Option value="a-2">Koera</Select.Option>
-                <Select.Option value="b-1">Germany</Select.Option>
-                <Select.Option value="b-2">France</Select.Option>
-                <Select.Option value="c-1">Peru</Select.Option>
-            </Select>
-        </>
-    );
+  const [value1, setValue1] = useState('a-1');
+  return (
+    <>
+      <Select
+        placeholder=""
+        style={{
+          width: 180,
+        }}
+        filter
+        defaultOpen
+      >
+        <Select.OptGroup label="Asia">
+          <Select.Option value="a-1">China</Select.Option>
+          <Select.Option value="a-2">Koera</Select.Option>
+        </Select.OptGroup>
+        <Select.OptGroup label="Europe">
+          <Select.Option value="b-1">Germany</Select.Option>
+          <Select.Option value="b-2">France</Select.Option>
+        </Select.OptGroup>
+        <Select.OptGroup label="South America">
+          <Select.Option value="c-1">Peru</Select.Option>
+        </Select.OptGroup>
+      </Select>
+      <Select
+        placeholder=""
+        style={{
+          width: 180,
+          marginLeft: 20,
+        }}
+        filter
+        defaultOpen
+        defaultValue="a-2"
+      >
+        <Select.OptGroup label="Asia">
+          <Select.Option value="a-1">China</Select.Option>
+          <Select.Option value="a-2">Koera</Select.Option>
+        </Select.OptGroup>
+        <Select.OptGroup label="Europe">
+          <Select.Option value="b-1">Germany</Select.Option>
+          <Select.Option value="b-2">France</Select.Option>
+        </Select.OptGroup>
+        <Select.OptGroup label="South America">
+          <Select.Option value="c-1">Peru</Select.Option>
+        </Select.OptGroup>
+      </Select>
+      <Select
+        placeholder=""
+        style={{
+          width: 180,
+          marginLeft: 20,
+        }}
+        filter
+        defaultOpen
+        value={value1}
+        onChange={val => setValue1(val)}
+      >
+        <Select.Option value="a-1">China</Select.Option>
+        <Select.Option value="a-2">Koera</Select.Option>
+        <Select.Option value="b-1">Germany</Select.Option>
+        <Select.Option value="b-2">France</Select.Option>
+        <Select.Option value="c-1">Peru</Select.Option>
+      </Select>
+    </>
+  );
 };
 
-stories.add(`Filter + defaultOpen`, () => <FilterDefaultOpen />); // const CustomSelect = React.forwardRef((props, ref) => {
-//     const { fieldRef, ...rest } = props;
-//     return <Select {...rest} ref={fieldRef} />
-// });
+export { FilterDefaultOpen };
+FilterDefaultOpen.story = {
+  name: 'Filter + defaultOpen'
+};
 
 const CustomSelect = props => {
-    const { fieldRef, ...rest } = props;
-    return <Select {...rest} ref={fieldRef} />;
+  const { fieldRef, ...rest } = props;
+  return <Select {...rest} ref={fieldRef} />;
 };
 
 const CustomFieldSelect = withField(CustomSelect);
 
 const RefDemo = () => {
-    const fieldRef = useRef(null);
+  const fieldRef = useRef(null);
+
+  const onChange = () => {
+    console.log(fieldRef);
+    fieldRef.current.open();
+    debugger;
+  };
+
+  return (
+    <Form>
+      <CustomFieldSelect field="test" initValue="se" fieldRef={fieldRef}></CustomFieldSelect>
+      <Button onClick={onChange}>change</Button>
+    </Form>
+  );
+};
 
-    const onChange = () => {
-        console.log(fieldRef);
-        fieldRef.current.open();
-        debugger;
-    };
+export const RefFieldDemo = () => <RefDemo />;
 
-    return (
-        <Form>
-            <CustomFieldSelect field="test" initValue="se" fieldRef={fieldRef}></CustomFieldSelect>
-            <Button onClick={onChange}>change</Button>
-        </Form>
-    );
+RefFieldDemo.story = {
+  name: 'Ref field demo',
 };
 
-stories.add('Ref field demo', () => <RefDemo />);
-
 const ValueZeroDemo = () => {
-    const list = [
-        {
-            value: 6,
-            label: '抖音小视频',
-            otherKey: 0,
-        },
-        {
-            value: 1,
-            label: '火山小视频',
-            disabled: true,
-            otherKey: 1,
-        },
-        {
-            value: 'pipixia',
-            label: '皮皮虾',
-            otherKey: 2,
-        },
-        {
-            value: 'toutiao',
-            label: '今日头条',
-            otherKey: 3,
-        },
-    ];
-    return (
-        <Select
-            placeholder="请选择业务线"
-            style={{
-                width: 180,
-            }}
-            optionList={list}
-            value={0}
-            renderSelectedItem={option => option.label + 1}
-        ></Select>
-    );
+  const list = [
+    {
+      value: 6,
+      label: '抖音小视频',
+      otherKey: 0,
+    },
+    {
+      value: 1,
+      label: '火山小视频',
+      disabled: true,
+      otherKey: 1,
+    },
+    {
+      value: 'pipixia',
+      label: '皮皮虾',
+      otherKey: 2,
+    },
+    {
+      value: 'toutiao',
+      label: '今日头条',
+      otherKey: 3,
+    },
+  ];
+  return (
+    <Select
+      placeholder="请选择业务线"
+      style={{
+        width: 180,
+      }}
+      optionList={list}
+      value={0}
+      renderSelectedItem={option => option.label + 1}
+    ></Select>
+  );
 };
 
-stories.add('value=0', () => <ValueZeroDemo />);
+export const Value0 = () => <ValueZeroDemo />;
+
+Value0.story = {
+  name: 'value=0',
+};
 
 const Highlight = () => {
-    const searchWords = ['do', 'dollar'];
-    const sourceString = 'aaa do dollar aaa';
-    const result = getHighLightTextHTML({
-        searchWords,
-        sourceString,
-    });
-    const result2 = getHighLightTextHTML({
-        searchWords: ['z'],
-        sourceString: 'aaazaaazaaa',
-    });
-    return result2;
+  const searchWords = ['do', 'dollar'];
+  const sourceString = 'aaa do dollar aaa';
+  const result = getHighLightTextHTML({
+    searchWords,
+    sourceString,
+  });
+  const result2 = getHighLightTextHTML({
+    searchWords: ['z'],
+    sourceString: 'aaazaaazaaa',
+  });
+  return result2;
 };
 
-stories.add('highlight', () => <Highlight />);
+export const _Highlight = () => <Highlight />;
 
-stories.add('scroll into view', () => (
-    <>
-        <div>
-            <p>single selection</p>
-            <Select defaultValue='option-11' defaultOpen style={{ marginBottom: 300, width: 120 }}>
-                {new Array(50).fill(null).map((item, idx) => (
-                    <Option value={`${idx}`} key={idx}>{`option-${idx}`}</Option>
-                ))}
-            </Select>
-            <p>single selection with no selected item</p>
-            <Select style={{ marginBottom: 300, width: 120 }}>
-                {new Array(50).fill(null).map((item, idx) => (
-                    <Option value={`${idx}`} key={idx}>{`option-${idx}`}</Option>
-                ))}
-            </Select>
-            <p>The selected node is the last</p>
-            <Select defaultValue='option-49' defaultOpen style={{ marginBottom: 300, width: 120 }}>
-                {new Array(50).fill(null).map((item, idx) => (
-                    <Option value={`${idx}`} key={idx}>{`option-${idx}`}</Option>
-                ))}
-            </Select>
-            <p>The selected node is the first</p>
-            <Select defaultValue='option-0' style={{ marginBottom: 300, width: 120 }}>
-                {new Array(50).fill(null).map((item, idx) => (
-                    <Option value={`${idx}`} key={idx}>{`option-${idx}`}</Option>
-                ))}
-            </Select>
-            <p>multiple selection</p>
-            <Select defaultValue={['option-25', 'option-9']} multiple style={{ marginBottom: 300, width: 220 }}>
-                {new Array(30).fill(null).map((item, idx) => (
-                    <Option value={`${idx}`} key={idx}>{`option-${idx}`}</Option>
-                ))}
-            </Select>
-            <p>multiple selection with no selected item</p>
-            <Select multiple style={{ marginBottom: 300, width: 220 }}>
-                {new Array(30).fill(null).map((item, idx) => (
-                    <Option value={`${idx}`} key={idx}>{`option-${idx}`}</Option>
-                ))}
-            </Select>
-        </div>
-    </>
-));
+_Highlight.story = {
+  name: 'highlight',
+};
+
+export const ScrollIntoView = () => (
+  <>
+    <div>
+      <p>single selection</p>
+      <Select defaultValue="option-11" defaultOpen style={{ marginBottom: 300, width: 120 }}>
+        {new Array(50).fill(null).map((item, idx) => (
+          <Option value={`${idx}`} key={idx}>{`option-${idx}`}</Option>
+        ))}
+      </Select>
+      <p>single selection with no selected item</p>
+      <Select style={{ marginBottom: 300, width: 120 }}>
+        {new Array(50).fill(null).map((item, idx) => (
+          <Option value={`${idx}`} key={idx}>{`option-${idx}`}</Option>
+        ))}
+      </Select>
+      <p>The selected node is the last</p>
+      <Select defaultValue="option-49" defaultOpen style={{ marginBottom: 300, width: 120 }}>
+        {new Array(50).fill(null).map((item, idx) => (
+          <Option value={`${idx}`} key={idx}>{`option-${idx}`}</Option>
+        ))}
+      </Select>
+      <p>The selected node is the first</p>
+      <Select defaultValue="option-0" style={{ marginBottom: 300, width: 120 }}>
+        {new Array(50).fill(null).map((item, idx) => (
+          <Option value={`${idx}`} key={idx}>{`option-${idx}`}</Option>
+        ))}
+      </Select>
+      <p>multiple selection</p>
+      <Select
+        defaultValue={['option-25', 'option-9']}
+        multiple
+        style={{ marginBottom: 300, width: 220 }}
+      >
+        {new Array(30).fill(null).map((item, idx) => (
+          <Option value={`${idx}`} key={idx}>{`option-${idx}`}</Option>
+        ))}
+      </Select>
+      <p>multiple selection with no selected item</p>
+      <Select multiple style={{ marginBottom: 300, width: 220 }}>
+        {new Array(30).fill(null).map((item, idx) => (
+          <Option value={`${idx}`} key={idx}>{`option-${idx}`}</Option>
+        ))}
+      </Select>
+    </div>
+  </>
+);
+
+ScrollIntoView.story = {
+  name: 'scroll into view',
+};

+ 336 - 311
packages/semi-ui/sideSheet/_story/sideSheet.stories.js

@@ -1,354 +1,379 @@
 import React, { useState } from 'react';
-import { storiesOf } from '@storybook/react';
 
 import SideSheet from '../index';
-import {
-    Select,
-    Button,
-    Tooltip,
-    RadioGroup,
-    Radio,
-} from '../../index';
+import { Select, Button, Tooltip, RadioGroup, Radio } from '../../index';
 
-
-const stories = storiesOf('SideSheet', module);
-
-// stories.addDecorator(withKnobs);;
+export default {
+  title: 'SideSheet',
+  parameters: {
+    chromatic: { disableSnapshot: true },
+  },
+}
 
 const BasicSide = props => {
-    const [visible, setVisible] = useState(false);
-
-    const handleCancel = e => {
-        console.log('cancelling')
-        setVisible(false);
-    };
-
-    return (
-        <React.Fragment>
-            <Button onClick={() => setVisible(true)}>show sideSheet</Button>
-            <SideSheet visible={visible} onCancel={handleCancel}>12333</SideSheet>
-        </React.Fragment>
-    );
+  const [visible, setVisible] = useState(false);
+
+  const handleCancel = e => {
+    console.log('cancelling');
+    setVisible(false);
+  };
+
+  return (
+    <React.Fragment>
+      <Button onClick={() => setVisible(true)}>show sideSheet</Button>
+      <SideSheet visible={visible} onCancel={handleCancel}>
+        12333
+      </SideSheet>
+    </React.Fragment>
+  );
 };
 
-stories.add('side sheet left', () => <BasicSide />);
+export const SideSheetLeft = () => <BasicSide />;
+
+SideSheetLeft.story = {
+  name: 'side sheet left',
+};
 
 const PosBasicSide = props => {
-    const [visible, setVisible] = useState(false);
-
-    const handleCancel = e => {
-        setVisible(false);
-    };
-
-    return (
-        <React.Fragment>
-            <Button onClick={() => setVisible(true)}>show sideSheet</Button>
-            <SideSheet visible={visible} placement={'bottom'} onCancel={handleCancel}>12333</SideSheet>
-        </React.Fragment>
-    );
+  const [visible, setVisible] = useState(false);
+
+  const handleCancel = e => {
+    setVisible(false);
+  };
+
+  return (
+    <React.Fragment>
+      <Button onClick={() => setVisible(true)}>show sideSheet</Button>
+      <SideSheet visible={visible} placement={'bottom'} onCancel={handleCancel}>
+        12333
+      </SideSheet>
+    </React.Fragment>
+  );
 };
 
-stories.add('side sheet', () => <PosBasicSide />);
+export const _SideSheet = () => <PosBasicSide />;
+
+_SideSheet.story = {
+  name: 'side sheet',
+};
 
 const SideMask = props => {
-    const [visible, setVisible] = useState(false);
-
-    const handleCancel = e => {
-        setVisible(false);
-    };
-
-    return (
-        <React.Fragment>
-            <Button onClick={() => setVisible(true)}>show sideSheet</Button>
-            <SideSheet
-                visible={visible}
-                placement={'bottom'}
-                onCancel={handleCancel}
-                maskClosable={false}
-            >
-                12333
-            </SideSheet>
-        </React.Fragment>
-    );
+  const [visible, setVisible] = useState(false);
+
+  const handleCancel = e => {
+    setVisible(false);
+  };
+
+  return (
+    <React.Fragment>
+      <Button onClick={() => setVisible(true)}>show sideSheet</Button>
+      <SideSheet
+        visible={visible}
+        placement={'bottom'}
+        onCancel={handleCancel}
+        maskClosable={false}
+      >
+        12333
+      </SideSheet>
+    </React.Fragment>
+  );
 };
 
-stories.add('side sheet mask', () => <SideMask />);
+export const SideSheetMask = () => <SideMask />;
 
+SideSheetMask.story = {
+  name: 'side sheet mask',
+};
 
 const Test2 = () => {
-    const [visible, setVisible] = useState(false);
-    const [visible2, setVisible2] = useState(false);
-    const handleCancel = e => {
-        setVisible(false);
-    };
-
-    const handleCancel2 = e => {
-        setVisible2(false);
-    };
-
-    return (
-        <>
-            <Button onClick={() => setVisible(true)} > show sideSheet </Button>
-            <SideSheet
-                visible={visible}
-                placement={'bottom'}
-                onCancel={handleCancel}
-            >
-                <Button onClick={() => setVisible2(true)}>show sideSheet2 </Button>
-                <SideSheet
-                    visible={visible2}
-                    placement={'bottom'}
-                    onCancel={handleCancel2}
-                    height='200px'
-                />
-            </SideSheet>
-        </>
-    );
+  const [visible, setVisible] = useState(false);
+  const [visible2, setVisible2] = useState(false);
+  const handleCancel = e => {
+    setVisible(false);
+  };
+
+  const handleCancel2 = e => {
+    setVisible2(false);
+  };
+
+  return (
+    <>
+      <Button onClick={() => setVisible(true)}> show sideSheet </Button>
+      <SideSheet visible={visible} placement={'bottom'} onCancel={handleCancel}>
+        <Button onClick={() => setVisible2(true)}>show sideSheet2 </Button>
+        <SideSheet
+          visible={visible2}
+          placement={'bottom'}
+          onCancel={handleCancel2}
+          height="200px"
+        />
+      </SideSheet>
+    </>
+  );
 };
 
-stories.add('sidesheet in sidesheet', () => < Test2 />);
+export const SidesheetInSidesheet = () => <Test2 />;
+
+SidesheetInSidesheet.story = {
+  name: 'sidesheet in sidesheet',
+};
 
 const Blocking = () => {
-    const [visible, setVisible] = useState(false);
-    const [placement, setPlacement] = useState('right');
-    const handleCancel = e => {
-        setVisible(false);
-    };
-    const show = () => {
-        setVisible(true);
-    }
-
-    const onSelect = e => {
-        setPlacement(e.target.value)
-    }
-    return (
-        <>
-            <RadioGroup onChange={(e) => onSelect(e)} value={placement}>
-                <Radio value={'right'}>right</Radio>
-                <Radio value={'left'}>left</Radio>
-                <Radio value={'top'}>top</Radio>
-                <Radio value={'bottom'}>bottom</Radio>
-            </RadioGroup>
-            <p>
-                jklasjdkfljaskljdfklajksdljfkl;ajklsdjfk;lajksldjfklajskdlfjajsdlf;jaklsjdfkljaklsdjflajsdfjakljsdkl;fja;sd
-            </p>
-            <br />
-            <br />
-            <Button onClick={() => show()}>Open SideSheet</Button>
-            <SideSheet
-                title="自定义位置的侧边栏"
-                visible={visible}
-                placement={placement}
-                onCancel={() => handleCancel()}
-                mask={false}
-            >
-                <p>This is the content of a basic sidesheet.</p>
-                <p>Here is more content...</p>
-            </SideSheet>
-        </>
-    );
-}
+  const [visible, setVisible] = useState(false);
+  const [placement, setPlacement] = useState('right');
+  const handleCancel = e => {
+    setVisible(false);
+  };
+  const show = () => {
+    setVisible(true);
+  };
+
+  const onSelect = e => {
+    setPlacement(e.target.value);
+  };
+  return (
+    <>
+      <RadioGroup onChange={e => onSelect(e)} value={placement}>
+        <Radio value={'right'}>right</Radio>
+        <Radio value={'left'}>left</Radio>
+        <Radio value={'top'}>top</Radio>
+        <Radio value={'bottom'}>bottom</Radio>
+      </RadioGroup>
+      <p>
+        jklasjdkfljaskljdfklajksdljfkl;ajklsdjfk;lajksldjfklajskdlfjajsdlf;jaklsjdfkljaklsdjflajsdfjakljsdkl;fja;sd
+      </p>
+      <br />
+      <br />
+      <Button onClick={() => show()}>Open SideSheet</Button>
+      <SideSheet
+        title="自定义位置的侧边栏"
+        visible={visible}
+        placement={placement}
+        onCancel={() => handleCancel()}
+        mask={false}
+      >
+        <p>This is the content of a basic sidesheet.</p>
+        <p>Here is more content...</p>
+      </SideSheet>
+    </>
+  );
+};
 
-stories.add('sidesheet non-blocking', () => <Blocking />);
+export const SidesheetNonBlocking = () => <Blocking />;
 
+SidesheetNonBlocking.story = {
+  name: 'sidesheet non-blocking',
+};
 
 const Popup = () => {
-    const [visible, setVisible] = useState(false);
-    const [placement, setPlacement] = useState('right');
-    const handleCancel = e => {
-        setVisible(false);
-    };
-
-    const onSelect = e => {
-        setPlacement(e.target.value)
-    }
-    return (
-        <div
-            style={{
-                height: 200,
-                overflow: 'hidden',
-                position: 'relative',
-                border: '1px solid #ebedf0',
-                borderRadius: 2,
-                padding: 48,
-                textAlign: 'center',
-                background: '#fafafa',
-            }}
-            className='sidesheet-container'
-        >
-            Render in this
-            <div style={{ marginTop: 16 }}>
-                <Button onClick={() => setVisible(true)} > show sideSheet </Button>
-                <RadioGroup onChange={(e) => onSelect(e)} value={placement}>
-                    <Radio value={'right'}>right</Radio>
-                    <Radio value={'left'}>left</Radio>
-                    <Radio value={'top'}>top</Radio>
-                    <Radio value={'bottom'}>bottom</Radio>
-                </RadioGroup>
-            </div>
-            <SideSheet
-                visible={visible}
-                title='sideSheet'
-                height='100px'
-                placement={'right'}
-                onCancel={handleCancel}
-                placement={placement}
-                getPopupContainer={() => document.querySelector('.sidesheet-container')}
-            >
-                <p>Some contents...</p>
-                <p>Some contents...</p>
-                <p>Some contents...</p>
-                <p>Some contents...</p>
-                <p>Some contents...</p>
-                <p>Some contents...</p>
-                <p>Some contents...</p>
-                <p>Some contents...</p>
-                <p>Some contents...</p>
-                <p>Some contents...</p>
-                <p>Some contents...</p>
-                <p>Some contents...</p>
-                <p>Some contents...</p>
-                <p>Some contents...</p>
-                <p>Some contents...</p>
-                <p>Some contents...</p>
-            </SideSheet>
-        </div>
-
-    );
+  const [visible, setVisible] = useState(false);
+  const [placement, setPlacement] = useState('right');
+  const handleCancel = e => {
+    setVisible(false);
+  };
+
+  const onSelect = e => {
+    setPlacement(e.target.value);
+  };
+  return (
+    <div
+      style={{
+        height: 200,
+        overflow: 'hidden',
+        position: 'relative',
+        border: '1px solid #ebedf0',
+        borderRadius: 2,
+        padding: 48,
+        textAlign: 'center',
+        background: '#fafafa',
+      }}
+      className="sidesheet-container"
+    >
+      Render in this
+      <div style={{ marginTop: 16 }}>
+        <Button onClick={() => setVisible(true)}> show sideSheet </Button>
+        <RadioGroup onChange={e => onSelect(e)} value={placement}>
+          <Radio value={'right'}>right</Radio>
+          <Radio value={'left'}>left</Radio>
+          <Radio value={'top'}>top</Radio>
+          <Radio value={'bottom'}>bottom</Radio>
+        </RadioGroup>
+      </div>
+      <SideSheet
+        visible={visible}
+        title="sideSheet"
+        height="100px"
+        placement={'right'}
+        onCancel={handleCancel}
+        placement={placement}
+        getPopupContainer={() => document.querySelector('.sidesheet-container')}
+      >
+        <p>Some contents...</p>
+        <p>Some contents...</p>
+        <p>Some contents...</p>
+        <p>Some contents...</p>
+        <p>Some contents...</p>
+        <p>Some contents...</p>
+        <p>Some contents...</p>
+        <p>Some contents...</p>
+        <p>Some contents...</p>
+        <p>Some contents...</p>
+        <p>Some contents...</p>
+        <p>Some contents...</p>
+        <p>Some contents...</p>
+        <p>Some contents...</p>
+        <p>Some contents...</p>
+        <p>Some contents...</p>
+      </SideSheet>
+    </div>
+  );
 };
 
-stories.add('sidesheet getpopupcontanier', () => <Popup />);
+export const SidesheetGetpopupcontanier = () => <Popup />;
 
+SidesheetGetpopupcontanier.story = {
+  name: 'sidesheet getpopupcontanier',
+};
 
 const Combox = () => {
-    const [visible, setVisible] = useState(false);
-    const [placement, setPlacement] = useState('right');
-    const handleCancel = e => {
-        setVisible(false);
-    };
-
-    const onSelect = e => {
-        setPlacement(e.target.value)
-    }
-    return (
-        <div
-            style={{
-                height: 200,
-                overflow: 'hidden',
-                position: 'relative',
-                border: '1px solid #ebedf0',
-                borderRadius: 2,
-                padding: 48,
-                textAlign: 'center',
-                background: '#fafafa',
-            }}
-            className='sidesheet-container'
-        >
-            Render in this
-            <div style={{ marginTop: 16 }}>
-                <Button onClick={() => setVisible(true)} > show sideSheet </Button>
-                <RadioGroup onChange={(e) => onSelect(e)} value={placement}>
-                    <Radio value={'right'}>right</Radio>
-                    <Radio value={'left'}>left</Radio>
-                    <Radio value={'top'}>top</Radio>
-                    <Radio value={'bottom'}>bottom</Radio>
-                </RadioGroup>
-            </div>
-            <SideSheet
-                visible={visible}
-                title='sideSheet'
-                height='100px'
-                placement={'right'}
-                onCancel={handleCancel}
-                placement={placement}
-                mask={false}
-                bodyStyle={{ overflow: 'auto', height: 200 }}
-                getPopupContainer={() => document.querySelector('.sidesheet-container')}
-            >
-                <p>Some contents...</p>
-                <p>Some contents...</p>
-                <p>Some contents...</p>
-                <p>Some contents...</p>
-                <p>Some contents...</p>
-                <p>Some contents...</p>
-                <p>Some contents...</p>
-                <p>Some contents...</p>
-                <p>Some contents...</p>
-                <p>Some contents...</p>
-                <p>Some contents...</p>
-                <p>Some contents...</p>
-                <p>Some contents...</p>
-                <p>Some contents...</p>
-                <p>Some contents...</p>
-                <p>Some contents...</p>
-            </SideSheet>
-        </div>
-
-    );
+  const [visible, setVisible] = useState(false);
+  const [placement, setPlacement] = useState('right');
+  const handleCancel = e => {
+    setVisible(false);
+  };
+
+  const onSelect = e => {
+    setPlacement(e.target.value);
+  };
+  return (
+    <div
+      style={{
+        height: 200,
+        overflow: 'hidden',
+        position: 'relative',
+        border: '1px solid #ebedf0',
+        borderRadius: 2,
+        padding: 48,
+        textAlign: 'center',
+        background: '#fafafa',
+      }}
+      className="sidesheet-container"
+    >
+      Render in this
+      <div style={{ marginTop: 16 }}>
+        <Button onClick={() => setVisible(true)}> show sideSheet </Button>
+        <RadioGroup onChange={e => onSelect(e)} value={placement}>
+          <Radio value={'right'}>right</Radio>
+          <Radio value={'left'}>left</Radio>
+          <Radio value={'top'}>top</Radio>
+          <Radio value={'bottom'}>bottom</Radio>
+        </RadioGroup>
+      </div>
+      <SideSheet
+        visible={visible}
+        title="sideSheet"
+        height="100px"
+        placement={'right'}
+        onCancel={handleCancel}
+        placement={placement}
+        mask={false}
+        bodyStyle={{ overflow: 'auto', height: 200 }}
+        getPopupContainer={() => document.querySelector('.sidesheet-container')}
+      >
+        <p>Some contents...</p>
+        <p>Some contents...</p>
+        <p>Some contents...</p>
+        <p>Some contents...</p>
+        <p>Some contents...</p>
+        <p>Some contents...</p>
+        <p>Some contents...</p>
+        <p>Some contents...</p>
+        <p>Some contents...</p>
+        <p>Some contents...</p>
+        <p>Some contents...</p>
+        <p>Some contents...</p>
+        <p>Some contents...</p>
+        <p>Some contents...</p>
+        <p>Some contents...</p>
+        <p>Some contents...</p>
+      </SideSheet>
+    </div>
+  );
 };
 
-stories.add('sidesheet getpopupcontanier and non-blocking', () => <Combox />);
+export const SidesheetGetpopupcontanierAndNonBlocking = () => <Combox />;
+
+SidesheetGetpopupcontanierAndNonBlocking.story = {
+  name: 'sidesheet getpopupcontanier and non-blocking',
+};
 
 const WithFooter = () => {
-    const [visible, setVisible] = useState(false);
-    const handleCancel = e => {
-        setVisible(false);
-    };
-    const show = () => {
-        setVisible(true);
-    }
-
-    return (
-        <div>
-            <Button onClick={() => show()}>Open SideSheet</Button>
-            <SideSheet
-                visible={visible}
-                title='sideSheet'
-                footer={<div>1234</div>}
-                placement={'right'}
-                onCancel={handleCancel}
-            // bodyStyle={{ overflow: 'auto', height: 200 }}
-            >
-                <p>Some contents...</p>
-                <p>Some contents...</p>
-                <p>Some contents...</p>
-                <p>Some contents...</p>
-                <p>Some contents...</p>
-                <p>Some contents...</p>
-            </SideSheet>
-        </div>
-    );
+  const [visible, setVisible] = useState(false);
+  const handleCancel = e => {
+    setVisible(false);
+  };
+  const show = () => {
+    setVisible(true);
+  };
+
+  return (
+    <div>
+      <Button onClick={() => show()}>Open SideSheet</Button>
+      <SideSheet
+        visible={visible}
+        title="sideSheet"
+        footer={<div>1234</div>}
+        placement={'right'}
+        onCancel={handleCancel}
+        // bodyStyle={{ overflow: 'auto', height: 200 }}
+      >
+        <p>Some contents...</p>
+        <p>Some contents...</p>
+        <p>Some contents...</p>
+        <p>Some contents...</p>
+        <p>Some contents...</p>
+        <p>Some contents...</p>
+      </SideSheet>
+    </div>
+  );
 };
 
-stories.add('WithFooter', () => <WithFooter />);
+export const _WithFooter = () => <WithFooter />;
 
+_WithFooter.story = {
+  name: 'WithFooter',
+};
 
 const MaskFalseDemo = () => {
-    const [visible, setVisible] = useState(false);
-    const handleCancel = e => {
-        setVisible(false);
-    };
-    const show = () => {
-        setVisible(true);
-    }
-
-    return (
-        <div>
-            <Button onClick={() => show()}>Open SideSheet</Button>
-            <SideSheet
-                mask={false}
-                width="90%"
-                visible={visible}
-                placement={'right'}
-                onCancel={handleCancel}
-            >
-                <p>Some contents...</p>
-                <p>Some contents...</p>
-                <p>Some contents...</p>
-                <p>Some contents...</p>
-            </SideSheet>
-        </div>
-    );
+  const [visible, setVisible] = useState(false);
+  const handleCancel = e => {
+    setVisible(false);
+  };
+  const show = () => {
+    setVisible(true);
+  };
+
+  return (
+    <div>
+      <Button onClick={() => show()}>Open SideSheet</Button>
+      <SideSheet
+        mask={false}
+        width="90%"
+        visible={visible}
+        placement={'right'}
+        onCancel={handleCancel}
+      >
+        <p>Some contents...</p>
+        <p>Some contents...</p>
+        <p>Some contents...</p>
+        <p>Some contents...</p>
+      </SideSheet>
+    </div>
+  );
 };
 
-stories.add('width percent & mask=false', () => <MaskFalseDemo />);
+export const WidthPercentMaskFalse = () => <MaskFalseDemo />;
+
+WidthPercentMaskFalse.story = {
+  name: 'width percent & mask=false',
+};

+ 67 - 58
packages/semi-ui/skeleton/_story/skeleton.stories.js

@@ -1,5 +1,4 @@
 import React, { useMemo } from 'react';
-import { storiesOf } from '@storybook/react';
 // import { withKnobs, text, boolean } from '@storybook/addon-knobs';
 import withPropsCombinations from 'react-storybook-addon-props-combinations';
 
@@ -8,66 +7,76 @@ import { Table } from '@douyinfe/semi-ui/';
 import Skeleton from '../index';
 import Avatar from '../../avatar';
 
-const stories = storiesOf('Skeleton', module);
+export default {
+  title: 'Skeleton'
+}
 
-// stories.addDecorator(withKnobs);;
+export const _Skeleton = () => (
+  <div>
+    <Skeleton placeholder={<Skeleton.Avatar />} loading={true}>
+      <Avatar>U</Avatar>
+    </Skeleton>
+    <Skeleton placeholder={<Skeleton.Image />} loading={true}>
+      <Avatar>U</Avatar>
+    </Skeleton>
+    <Skeleton placeholder={<Skeleton.Paragraph row={6} />} loading={true}>
+      <Avatar>U</Avatar>
+    </Skeleton>
+    <Skeleton placeholder={<Skeleton.Button />} loading={true}>
+      <Avatar>U</Avatar>
+    </Skeleton>
+    <Skeleton placeholder={<Skeleton.Title />} loading={true}>
+      <Avatar>U</Avatar>
+    </Skeleton>
+  </div>
+);
 
-stories.add('Skeleton', () => (
-    <div>
-        <Skeleton placeholder={<Skeleton.Avatar />} loading={true}>
-            <Avatar>U</Avatar>
-        </Skeleton>
-        <Skeleton placeholder={<Skeleton.Image />} loading={true}>
-            <Avatar>U</Avatar>
-        </Skeleton>
-        <Skeleton placeholder={<Skeleton.Paragraph row={6} />} loading={true}>
-            <Avatar>U</Avatar>
-        </Skeleton>
-        <Skeleton placeholder={<Skeleton.Button />} loading={true}>
-            <Avatar>U</Avatar>
-        </Skeleton>
-        <Skeleton placeholder={<Skeleton.Title />} loading={true}>
-            <Avatar>U</Avatar>
-        </Skeleton>
-    </div>
-));
+export const _Table = () => {
+  const Demo = () => {
+    const phArray = [1, 2, 1, 1, 1, 1, 2, 1];
+    const columns = useMemo(
+      () =>
+        phArray.map((key, idx) => {
+          const item = {};
+          item.title = <Skeleton.Title style={{ width: '0' }} />;
+          item.dataIndex = key;
+          item.key = idx;
+          return item;
+        }),
+      phArray
+    );
+    const dataSource = useMemo(
+      () =>
+        [1, 2, 3, 4, 5].map(key => {
+          const item = {};
+          item.key = key;
+          phArray.forEach(i => {
+            const width = 50 * i;
+            item[i] = <Skeleton.Paragraph style={{ width }} rows={1} />;
+          });
+          return item;
+        }),
+      []
+    );
 
-// avatar, image, paragraph, title, button
+    const placeholder = (
+      <div style={{ position: 'relative' }}>
+        <Table
+          style={{ backgroundColor: 'var(--semi-color-bg-1)' }}
+          columns={columns}
+          dataSource={dataSource}
+          pagination={false}
+        />
+        <div style={{ position: 'absolute', left: 0, right: 0, top: 0, bottom: 0 }} />
+      </div>
+    );
 
-stories.add('table', () => {
-    const Demo = () => {
-        const phArray = [1, 2, 1, 1, 1, 1, 2, 1];
-        const columns = useMemo(() => phArray.map((key, idx) => {
-            const item = {};
-            item.title = <Skeleton.Title style={{ width: '0' }} />;
-            item.dataIndex = key;
-            item.key = idx;
-            return item;
-        }), phArray);
-        const dataSource = useMemo(() => [1, 2, 3, 4, 5].map(key => {
-            const item = {};
-            item.key = key;
-            phArray.forEach(i => {
-                const width = 50 * i;
-                item[i] = <Skeleton.Paragraph style={{ width }} rows={1} />;
-            });
-            return item;
-        }), []);
+    return <Skeleton placeholder={placeholder} loading={true} />;
+  };
 
-        const placeholder = (
-            <div style={{ position: 'relative' }}>
-                <Table
-                    style={{ backgroundColor: 'var(--semi-color-bg-1)' }}
-                    columns={columns}
-                    dataSource={dataSource}
-                    pagination={false}
-                />
-                <div style={{ position: 'absolute', left: 0, right: 0, top: 0, bottom: 0 }} />
-            </div>
-        );
+  return <Demo />;
+};
 
-        return <Skeleton placeholder={placeholder} loading={true} />;
-    };
-
-    return <Demo />;
-});
+_Table.story = {
+  name: 'table',
+};

+ 365 - 246
packages/semi-ui/slider/_story/slider.stories.js

@@ -1,285 +1,404 @@
 import React, { Component } from 'react';
-import { storiesOf } from '@storybook/react';
-// import { withKnobs, text, boolean } from '@storybook/addon-knobs';
-import withPropsCombinations from 'react-storybook-addon-props-combinations';
 import Slider from '../index';
-// import Button from '../../button/index';
 import Input from '../../input/index';
 import { Modal, Button, Form, Row, Col } from '@douyinfe/semi-ui/';
 
-const stories = storiesOf('Slider', module);
-
-// stories.addDecorator(withKnobs);;
+export default {
+  title: 'Slider'
+}
 
 function formatter(value) {
-    return `${value}自定义`;
+  return `${value}自定义`;
 }
 let divStyle = {
-    width: 800,
-    marginLeft: 20,
-    marginTop: 40,
-    paddingBottom: 30
-}
-stories.add('horizontal slider', () => (
-    <div>
-        <div style={divStyle}>
-            <div>default</div>
-            <Slider showBoundary={true} onChange={(value) => { console.log('value改变了' + value) }}></Slider>
-        </div>
-        <div style={divStyle}>
-            <div>min, max</div>
-            <Slider showBoundary={true} min={10} max={50} onChange={(value) => { console.log('value改变了' + value) }}></Slider>
-        </div>
-        <div style={divStyle}>
-            <div>range</div>
-            <Slider
-                defaultValue={[20, 60]}
-                range
-                // step={0.01}
-                onChange={(value) => { console.log('value改变了啊啊啊啊啊啊' + value) }}
-                onAfterChange={(value) => { console.log('value结束于' + value) }}
-            ></Slider>
-        </div>
-        <div style={divStyle}>
-            <div>组合输入框</div>
-            <InputSlider />
-        </div>
-        <div style={divStyle}>
-            <div>格式化tooltip</div>
-            <Slider tipFormatter={formatter} onChange={(value) => { console.log('value改变了' + value) }}></Slider>
-        </div>
-        <div style={divStyle}>
-            <div>tooltip=null</div>
-            <Slider tipFormatter={null} onChange={(value) => { console.log('value改变了' + value) }}></Slider>
-        </div>
-        <div style={divStyle}>
-            <div>tooltipVisible=true始终显示tooltip</div>
-            <Slider tooltipVisible={true} onChange={(value) => { console.log('value改变了' + value) }}></Slider>
-        </div>
-        <div style={divStyle}>
-            <div>step=10</div>
-            <Slider step={10} marks={{ 10: '10', 20: '20', 30: '30', 40: '40', 50: '50' }} defaultValue={[10, 100]} range={true} onChange={(value) => { console.log('value改变了' + value) }}></Slider>
-        </div>
-        <div style={divStyle}>
-            <div>step=0.1</div>
-            <Slider step={0.1} marks={{ 0.1: '0.1', 0.2: '0.2', 0.3: '0.3', 0.4: '0.4', 0.5: '0.5' }} min={0} max={1} defaultValue={[0.1, 0.5]} range={true} onChange={(value) => { console.log('value改变了' + value) }}></Slider>
-        </div>
-        <div style={divStyle}>
-            <div>marks</div>
-            <Slider marks={{ 20: '20c', 40: '40c' }} defaultValue={[0, 100]} range={true} onChange={(value) => { console.log('value改变了' + value) }}></Slider>
-        </div>
-        <div style={divStyle}>
-            <div>inclued</div>
-            <Slider marks={{ 20: '20c', 40: '40c' }} included={false} defaultValue={[0, 100]} range={true} onChange={(value) => { console.log('value改变了' + value) }}></Slider>
-        </div>
+  width: 800,
+  marginLeft: 20,
+  marginTop: 40,
+  paddingBottom: 30,
+};
+
+export const HorizontalSlider = () => (
+  <div>
+    <div style={divStyle}>
+      <div>default</div>
+      <Slider
+        showBoundary={true}
+        onChange={value => {
+          console.log('value改变了' + value);
+        }}
+      ></Slider>
+    </div>
+    <div style={divStyle}>
+      <div>min, max</div>
+      <Slider
+        showBoundary={true}
+        min={10}
+        max={50}
+        onChange={value => {
+          console.log('value改变了' + value);
+        }}
+      ></Slider>
+    </div>
+    <div style={divStyle}>
+      <div>range</div>
+      <Slider
+        defaultValue={[20, 60]}
+        range
+        // step={0.01}
+        onChange={value => {
+          console.log('value改变了啊啊啊啊啊啊' + value);
+        }}
+        onAfterChange={value => {
+          console.log('value结束于' + value);
+        }}
+      ></Slider>
+    </div>
+    <div style={divStyle}>
+      <div>组合输入框</div>
+      <InputSlider />
+    </div>
+    <div style={divStyle}>
+      <div>格式化tooltip</div>
+      <Slider
+        tipFormatter={formatter}
+        onChange={value => {
+          console.log('value改变了' + value);
+        }}
+      ></Slider>
+    </div>
+    <div style={divStyle}>
+      <div>tooltip=null</div>
+      <Slider
+        tipFormatter={null}
+        onChange={value => {
+          console.log('value改变了' + value);
+        }}
+      ></Slider>
+    </div>
+    <div style={divStyle}>
+      <div>tooltipVisible=true始终显示tooltip</div>
+      <Slider
+        tooltipVisible={true}
+        onChange={value => {
+          console.log('value改变了' + value);
+        }}
+      ></Slider>
     </div>
-));
+    <div style={divStyle}>
+      <div>step=10</div>
+      <Slider
+        step={10}
+        marks={{ 10: '10', 20: '20', 30: '30', 40: '40', 50: '50' }}
+        defaultValue={[10, 100]}
+        range={true}
+        onChange={value => {
+          console.log('value改变了' + value);
+        }}
+      ></Slider>
+    </div>
+    <div style={divStyle}>
+      <div>step=0.1</div>
+      <Slider
+        step={0.1}
+        marks={{ 0.1: '0.1', 0.2: '0.2', 0.3: '0.3', 0.4: '0.4', 0.5: '0.5' }}
+        min={0}
+        max={1}
+        defaultValue={[0.1, 0.5]}
+        range={true}
+        onChange={value => {
+          console.log('value改变了' + value);
+        }}
+      ></Slider>
+    </div>
+    <div style={divStyle}>
+      <div>marks</div>
+      <Slider
+        marks={{ 20: '20c', 40: '40c' }}
+        defaultValue={[0, 100]}
+        range={true}
+        onChange={value => {
+          console.log('value改变了' + value);
+        }}
+      ></Slider>
+    </div>
+    <div style={divStyle}>
+      <div>inclued</div>
+      <Slider
+        marks={{ 20: '20c', 40: '40c' }}
+        included={false}
+        defaultValue={[0, 100]}
+        range={true}
+        onChange={value => {
+          console.log('value改变了' + value);
+        }}
+      ></Slider>
+    </div>
+  </div>
+);
+
+HorizontalSlider.story = {
+  name: 'horizontal slider',
+};
 
 class InputSlider extends Component {
-    state = {
-        value: 10
-    }
+  state = {
+    value: 10,
+  };
 
-    getSliderValue = (value) => {
-        this.setState({ value: value / 1 });
-    }
+  getSliderValue = value => {
+    this.setState({ value: value / 1 });
+  };
 
-    render() {
-        const { value } = this.state
-        return (
-            <div style={{ display: 'flex', width: 800 }}>
-                <div style={{ width: 500 }}>
-                    <Slider step={0.1} value={value} onChange={(value) => (this.getSliderValue(value))}></Slider>
-                </div>
-                <Input onChange={(v) => this.getSliderValue(v)} style={{ flex: 1 }} value={value} />
-            </div>
-            // <div>
-            // <div style={{display:'inlineBlock'}}>
-            //     <Slider step={0.1} onChange={(value) => (this.getSliderValue(value))}></Slider>
-            //     <Input  value={value} />
-            // </div>
-            //  </div>
-        );
-    }
+  render() {
+    const { value } = this.state;
+    return (
+      <div style={{ display: 'flex', width: 800 }}>
+        <div style={{ width: 500 }}>
+          <Slider step={0.1} value={value} onChange={value => this.getSliderValue(value)}></Slider>
+        </div>
+        <Input onChange={v => this.getSliderValue(v)} style={{ flex: 1 }} value={value} />
+      </div>
+    );
+  }
 }
 
 let divStyle1 = {
-    height: 400,
-    marginLeft: 20,
-    marginTop: 40,
-    paddingRight: 30,
-    display: 'inline-block'
-}
+  height: 400,
+  marginLeft: 20,
+  marginTop: 40,
+  paddingRight: 30,
+  display: 'inline-block',
+};
 
-stories.add('vertical slider', () => (
-    <div>
-        <div style={divStyle1}>
-            <Slider vertical range defaultValue={[20, 60]}></Slider>
-        </div>
-        {/* <div style={divStyle1}>
-            <Slider vertical onChange={(value) => { }}></Slider>
-        </div>
-        <div style={divStyle1}>
-            <Slider vertical range defaultValue={[20, 60]} onChange={(value) => { console.log('value改变了' + value) }}></Slider>
-        </div>
-        <div style={divStyle1}>
-            <Slider vertical range marks={{ 20: '20c', 40: '40c' }} step={10} defaultValue={[20, 60]} onChange={(value) => { console.log('value改变了' + value) }}></Slider>
-        </div> */}
+export const VerticalSlider = () => (
+  <div>
+    <div style={divStyle1}>
+      <Slider vertical range defaultValue={[20, 60]}></Slider>
     </div>
-));
+  </div>
+);
 
-stories.add('在滚动容器中的vertical slider', () => (
-    <div style={{ height: '300px', overflow: 'scroll' }}>
-        <div style={{ height: '600px', marginTop: '30px' }}>
-            <div style={divStyle1}>
-                <Slider vertical onChange={(value) => { }}></Slider>
-            </div>
-            <div style={divStyle1}>
-                <Slider vertical range defaultValue={[20, 60]} onChange={(value) => { console.log('value改变了' + value) }}></Slider>
-            </div>
-            <div style={divStyle1}>
-                <Slider vertical range marks={{ 20: '20c', 40: '40c' }} step={10} defaultValue={[20, 60]} onChange={(value) => { console.log('value改变了' + value) }}></Slider>
-            </div>
-        </div>
+VerticalSlider.story = {
+  name: 'vertical slider',
+};
+
+export const VerticalSliderInScrollContainer = () => (
+  <div style={{ height: '300px', overflow: 'scroll' }}>
+    <div style={{ height: '600px', marginTop: '30px' }}>
+      <div style={divStyle1}>
+        <Slider vertical onChange={value => {}}></Slider>
+      </div>
+      <div style={divStyle1}>
+        <Slider
+          vertical
+          range
+          defaultValue={[20, 60]}
+          onChange={value => {
+            console.log('value改变了' + value);
+          }}
+        ></Slider>
+      </div>
+      <div style={divStyle1}>
+        <Slider
+          vertical
+          range
+          marks={{ 20: '20c', 40: '40c' }}
+          step={10}
+          defaultValue={[20, 60]}
+          onChange={value => {
+            console.log('value改变了' + value);
+          }}
+        ></Slider>
+      </div>
     </div>
-));
+  </div>
+);
 
-stories.add('在滚动容器中的slider', () => (
-    <div style={{ width: '300px', overflow: 'scroll' }}>
-        <div style={{ width: '500px', marginTop: '10px' }}>
-            <div style={divStyle}>
-                <Slider onChange={(value) => { }}></Slider>
-            </div>
-            <div style={divStyle}>
-                <Slider range defaultValue={[20, 60]} onChange={(value) => { console.log('value改变了' + value) }}></Slider>
-            </div>
-            <div style={divStyle}>
-                <Slider range marks={{ 20: '20c', 40: '40c' }} step={10} defaultValue={[20, 60]} onChange={(value) => { console.log('value改变了' + value) }}></Slider>
-            </div>
-        </div>
+VerticalSliderInScrollContainer.story = {
+  name: '在滚动容器中的vertical slider',
+};
+
+export const SliderInScrollContainer = () => (
+  <div style={{ width: '300px', overflow: 'scroll' }}>
+    <div style={{ width: '500px', marginTop: '10px' }}>
+      <div style={divStyle}>
+        <Slider onChange={value => {}}></Slider>
+      </div>
+      <div style={divStyle}>
+        <Slider
+          range
+          defaultValue={[20, 60]}
+          onChange={value => {
+            console.log('value改变了' + value);
+          }}
+        ></Slider>
+      </div>
+      <div style={divStyle}>
+        <Slider
+          range
+          marks={{ 20: '20c', 40: '40c' }}
+          step={10}
+          defaultValue={[20, 60]}
+          onChange={value => {
+            console.log('value改变了' + value);
+          }}
+        ></Slider>
+      </div>
     </div>
-));
+  </div>
+);
 
+SliderInScrollContainer.story = {
+  name: '在滚动容器中的slider'
+}
 
-class ControllSlider extends Component {
-    state = {
-        value: 50,
-        rangeValue: undefined
-    }
-    changeValue = () => {
-        this.setState({ value: this.state.value + 10 });
-    }
-    changeRangeValue = rangeValue => {
-        console.log('rangeValue' + rangeValue);
-        this.setState({ rangeValue: rangeValue });
-    }
-    render() {
-        const { value, rangeValue } = this.state;
-        return (
-            <div>
-                <Button onClick={() => this.changeValue()}>点击改变value</Button>
-                <div style={{ width: 800, marginLeft: 20, marginTop: 40 }}>
-                    <Slider value={value} onChange={(value) => { console.log('value改变了' + value) }}></Slider>
-                </div>
-                <div style={{ width: 800, marginLeft: 20, marginTop: 40 }}>
-                    <Slider value={rangeValue} onChange={(rangeValue) => this.changeRangeValue(rangeValue)} range></Slider>
-                </div>
-            </div>
-        );
-    }
+class ControlledSlider extends Component {
+  state = {
+    value: 50,
+    rangeValue: undefined,
+  };
+  changeValue = () => {
+    this.setState({ value: this.state.value + 10 });
+  };
+  changeRangeValue = rangeValue => {
+    console.log('rangeValue' + rangeValue);
+    this.setState({ rangeValue: rangeValue });
+  };
+  render() {
+    const { value, rangeValue } = this.state;
+    return (
+      <div>
+        <Button onClick={() => this.changeValue()}>点击改变value</Button>
+        <div style={{ width: 800, marginLeft: 20, marginTop: 40 }}>
+          <Slider
+            value={value}
+            onChange={value => {
+              console.log('value改变了' + value);
+            }}
+          ></Slider>
+        </div>
+        <div style={{ width: 800, marginLeft: 20, marginTop: 40 }}>
+          <Slider
+            value={rangeValue}
+            onChange={rangeValue => this.changeRangeValue(rangeValue)}
+            range
+          ></Slider>
+        </div>
+      </div>
+    );
+  }
 }
 
-stories.add('受控slider', () => <ControllSlider />);
+export const ControlledSliderDemo = () => <ControlledSlider />;
+ControlledSliderDemo.story = {
+  name: '受控slider'
+}
 
 class DisableSlider extends Component {
-    state = {
-        disabled: false
-    }
-    changeValue = () => {
-        this.setState({ disabled: !this.state.disabled });
-    }
-    render() {
-        const { disabled } = this.state
-        return (
-            <div>
-                <Button onClick={() => this.changeValue()}>toggle disable slider</Button>
-                <div style={{ width: 800, marginLeft: 20, marginTop: 40 }}>
-                    <Slider disabled={disabled} defaultValue={10} onChange={(value) => { console.log('value改变了' + value) }}></Slider>
-                </div>
-            </div>
-        );
-    }
+  state = {
+    disabled: false,
+  };
+  changeValue = () => {
+    this.setState({ disabled: !this.state.disabled });
+  };
+  render() {
+    const { disabled } = this.state;
+    return (
+      <div>
+        <Button onClick={() => this.changeValue()}>toggle disable slider</Button>
+        <div style={{ width: 800, marginLeft: 20, marginTop: 40 }}>
+          <Slider
+            disabled={disabled}
+            defaultValue={10}
+            onChange={value => {
+              console.log('value改变了' + value);
+            }}
+          ></Slider>
+        </div>
+      </div>
+    );
+  }
 }
 
-stories.add('disable slider', () => <DisableSlider />);
+export const _DisableSlider = () => <DisableSlider />;
 
+_DisableSlider.story = {
+  name: 'disable slider',
+};
 
 class TestDemo extends React.Component {
-    constructor() {
-        super();
-        this.state = {
-            visible: false
-        };
-        this.showDialog = this.showDialog.bind(this);
-        this.getFormApi = this.getFormApi.bind(this);
-        this.handleOk = this.handleOk.bind(this);
-        this.handleCancel = this.handleCancel.bind(this);
-    }
-    getFormApi(formApi) { this.formApi = formApi }
-    showDialog() {
-        this.setState({
-            visible: true
-        });
-    }
-    handleOk(e) {
-        this.setState({
-            visible: false
-        });
-    }
-    handleCancel(e) {
-        this.setState({
-            visible: false,
-        });
-    }
-    render() {
-        const { Slider, Switch } = Form;
-        return (
-            <>
-                <Button onClick={this.showDialog}>打开弹窗</Button>
-                <Modal
-                    title="基本对话框"
-                    visible={this.state.visible}
-                    onOk={this.handleOk}
-                    onCancel={this.handleCancel}
-                >
-                    <Form
-                        style={{ padding: 10, width: '100%' }}
-                        onValueChange={(v) => console.log(v)}
-                    >
-                        <Row>
-                            <Col span={12}>
-                                <Slider field="range" range initValue={[10, 100]} style={{ width: '90%' }} />
-                            </Col>
-                            <Col span={12}>
-                                <Switch field='switch' />
-                            </Col>
-                        </Row>
-                    </Form>
-                </Modal>
-            </>
-        );
-    }
+  constructor() {
+    super();
+    this.state = {
+      visible: false,
+    };
+    this.showDialog = this.showDialog.bind(this);
+    this.getFormApi = this.getFormApi.bind(this);
+    this.handleOk = this.handleOk.bind(this);
+    this.handleCancel = this.handleCancel.bind(this);
+  }
+  getFormApi(formApi) {
+    this.formApi = formApi;
+  }
+  showDialog() {
+    this.setState({
+      visible: true,
+    });
+  }
+  handleOk(e) {
+    this.setState({
+      visible: false,
+    });
+  }
+  handleCancel(e) {
+    this.setState({
+      visible: false,
+    });
+  }
+  render() {
+    const { Slider, Switch } = Form;
+    return (
+      <>
+        <Button onClick={this.showDialog}>打开弹窗</Button>
+        <Modal
+          title="基本对话框"
+          visible={this.state.visible}
+          onOk={this.handleOk}
+          onCancel={this.handleCancel}
+        >
+          <Form style={{ padding: 10, width: '100%' }} onValueChange={v => console.log(v)}>
+            <Row>
+              <Col span={12}>
+                <Slider field="range" range initValue={[10, 100]} style={{ width: '90%' }} />
+              </Col>
+              <Col span={12}>
+                <Switch field="switch" />
+              </Col>
+            </Row>
+          </Form>
+        </Modal>
+      </>
+    );
+  }
 }
 
-stories.add('slider in modal', () => <TestDemo />);
+export const SliderInModal = () => <TestDemo />;
 
-stories.add('range min slider', () => (
-    <Slider
-        defaultValue={[20, 60]}
-        range
-        // step={0.01}
-        min={10}
+SliderInModal.story = {
+  name: 'slider in modal',
+};
+
+export const RangeMinSlider = () => (
+  <Slider
+    defaultValue={[20, 60]}
+    range
+    // step={0.01}
+    min={10}
     // onChange={(value) => { console.log('value改变了啊啊啊啊啊啊' + value) }}
     // onAfterChange={(value) => { console.log('value结束于' + value) }}
-    />
-));
+  />
+);
+
+RangeMinSlider.story = {
+  name: 'range min slider',
+};

+ 3 - 2
packages/semi-ui/slider/index.tsx

@@ -194,7 +194,7 @@ export default class Slider extends BaseComponent<SliderProps, SliderState> {
                 this._addEventListener(document.body, 'mouseup', this.foundation.onHandleUp, false);
                 this._addEventListener(document.body, 'touchmove', this.foundation.onHandleTouchMove, false);
             },
-            onHandleMove: (mousePos: number, isMin: boolean, stateChangeCallback = noop): boolean | void => {
+            onHandleMove: (mousePos: number, isMin: boolean, stateChangeCallback = noop, clickTrack = false): boolean | void => {
 
                 const sliderDOMIsInRenderTree = this.foundation.checkAndUpdateIsInRenderTreeState();
                 if (!sliderDOMIsInRenderTree) {
@@ -211,7 +211,8 @@ export default class Slider extends BaseComponent<SliderProps, SliderState> {
                 const { currentValue } = this.state;
                 if (!isEqual(this.foundation.outPutValue(currentValue), outPutValue)) {
                     onChange(outPutValue);
-                    if (this.foundation.valueFormatIsCorrect(value)) {
+                    if (!clickTrack && this.foundation.valueFormatIsCorrect(value)) {
+                        // still require afterChangeCallback when click on the track directly, need skip here
                         return false;
                     }
                     this.setState({

+ 242 - 214
packages/semi-ui/space/_story/space.stories.js

@@ -1,226 +1,254 @@
 import React from 'react';
-import { storiesOf } from '@storybook/react';
 import { Button, Tag } from '@douyinfe/semi-ui/';
 import Space from '../index';
 
-const stories = storiesOf('Space', module);
+export default {
+  title: 'Space'
+}
 
 const divStyle = {
-    width: 100,
-    height: 100,
-    backgroundColor:'lightblue',
-    display: 'flex',
-    alignItems: 'center'
-}
-stories.add('Space default', () => (
-    <>
-        <Space align='baseline'>
-            <Button onClick={()=>{alert('button')}}>按钮</Button>
-            <Button>按钮</Button>
-            <Tag> default tag </Tag>
-            <div style={divStyle}>div</div>
-        </Space>
-    </>
-));
+  width: 100,
+  height: 100,
+  backgroundColor: 'lightblue',
+  display: 'flex',
+  alignItems: 'center',
+};
+
+export const SpaceDefault = () => (
+  <>
+    <Space align="baseline">
+      <Button
+        onClick={() => {
+          alert('button');
+        }}
+      >
+        按钮
+      </Button>
+      <Button>按钮</Button>
+      <Tag> default tag </Tag>
+      <div style={divStyle}>div</div>
+    </Space>
+  </>
+);
+
+SpaceDefault.story = {
+  name: 'Space default',
+};
+
+export const SpaceAlign = () => (
+  <>
+    <Space align="center">
+      <span>horizontal:align-center</span>
+      <Button>按钮</Button>
+      <Button>按钮</Button>
+      <Tag> default tag </Tag>
+      <div style={divStyle}>div</div>
+    </Space>
+    <br />
+    <Space align="start">
+      <span>horizontal:align-start</span>
+      <Button>按钮</Button>
+      <Button>按钮</Button>
+      <Tag> default tag </Tag>
+      <div style={divStyle}>div</div>
+    </Space>
+    <br />
+    <Space align="end">
+      <span>horizontal:align-end</span>
+      <Button>按钮</Button>
+      <Button>按钮</Button>
+      <Tag> default tag </Tag>
+      <div style={divStyle}>div</div>
+    </Space>
+    <br />
+    <Space align="baseline">
+      <span>horizontal:align-baseline</span>
+      <Button>按钮</Button>
+      <Button>按钮</Button>
+      <Tag> default tag </Tag>
+      <div style={divStyle}>div</div>
+    </Space>
+    <hr />
+    <br />
+    <Space vertical align="center">
+      <span>vertical:align-center</span>
+      <Button>按钮</Button>
+      <Button>按钮</Button>
+      <Tag> default tag </Tag>
+      <div style={divStyle}>div</div>
+    </Space>
+    <br />
+    <Space vertical align="start">
+      <span>vertical:align-start</span>
+      <Button>按钮</Button>
+      <Button>按钮</Button>
+      <Tag> default tag </Tag>
+      <div style={divStyle}>div</div>
+    </Space>
+    <br />
+    <Space vertical align="end">
+      <span>vertical:align-end</span>
+      <Button>按钮</Button>
+      <Button>按钮</Button>
+      <Tag> default tag </Tag>
+      <div style={divStyle}>div</div>
+    </Space>
+    <br />
+    <Space vertical align="baseline">
+      <span>vertical:align-baseline</span>
+      <Button>按钮</Button>
+      <Button>按钮</Button>
+      <Tag> default tag </Tag>
+      <div style={divStyle}>div</div>
+    </Space>
+  </>
+);
+
+SpaceAlign.story = {
+  name: 'Space align',
+};
 
-stories.add('Space align', () => (
-    <>
-        <Space align='center'>
-            <span>horizontal:align-center</span>
-            <Button>按钮</Button>
-            <Button>按钮</Button>
-            <Tag> default tag </Tag>
-            <div style={divStyle}>div</div>
-        </Space>
-        <br />
-        <Space align='start'>
-            <span>horizontal:align-start</span>
-            <Button>按钮</Button>
-            <Button>按钮</Button>
-            <Tag> default tag </Tag>
-            <div style={divStyle}>div</div>
-        </Space>
-        <br />
-        <Space align='end'>
-            <span>horizontal:align-end</span>
-            <Button>按钮</Button>
-            <Button>按钮</Button>
-            <Tag> default tag </Tag>
-            <div style={divStyle}>div</div>
-        </Space>
-        <br />
-        <Space align='baseline'>
-            <span>horizontal:align-baseline</span>
-            <Button>按钮</Button>
-            <Button>按钮</Button>
-            <Tag> default tag </Tag>
-            <div style={divStyle}>div</div>
-        </Space>
-        <hr />
-        <br />
-        <Space vertical align='center'>
-            <span>vertical:align-center</span>
-            <Button>按钮</Button>
-            <Button>按钮</Button>
-            <Tag> default tag </Tag>
-            <div style={divStyle}>div</div>
-        </Space>
-        <br />
-        <Space vertical align='start'>
-            <span>vertical:align-start</span>
-            <Button>按钮</Button>
-            <Button>按钮</Button>
-            <Tag> default tag </Tag>
-            <div style={divStyle}>div</div>
-        </Space>
-        <br />
-        <Space vertical align='end'>
-            <span>vertical:align-end</span>
-            <Button>按钮</Button>
-            <Button>按钮</Button>
-            <Tag> default tag </Tag>
-            <div style={divStyle}>div</div>
-        </Space>
-        <br />
-        <Space vertical align='baseline'>
-            <span>vertical:align-baseline</span>
-            <Button>按钮</Button>
-            <Button>按钮</Button>
-            <Tag> default tag </Tag>
-            <div style={divStyle}>div</div>
-        </Space>
-    </>
-));
+export const SpaceVertical = () => (
+  <>
+    <Space direction="horizontal">
+      <Button>主要按钮</Button>
+      <Button type="secondary">次要按钮</Button>
+      <Button type="tertiary">第三按钮</Button>
+      <Button type="warning">警告按钮</Button>
+      <Button type="danger">危险按钮</Button>
+    </Space>
+    <br />
+    <Space vertical>
+      <Button>主要按钮</Button>
+      <Button type="secondary">次要按钮</Button>
+      <Button type="tertiary">第三按钮</Button>
+      <Button type="warning">警告按钮</Button>
+      <Button type="danger">危险按钮</Button>
+    </Space>
+  </>
+);
 
+SpaceVertical.story = {
+  name: 'Space vertical',
+};
 
-stories.add('Space vertical', () => (
-    <>
-        <Space direction='horizontal'>
-            <Button>主要按钮</Button>
-            <Button type="secondary">次要按钮</Button>
-            <Button type="tertiary">第三按钮</Button>
-            <Button type="warning">警告按钮</Button>
-            <Button type="danger">危险按钮</Button>
-        </Space>
-        <br />
-        <Space vertical>
-            <Button>主要按钮</Button>
-            <Button type="secondary">次要按钮</Button>
-            <Button type="tertiary">第三按钮</Button>
-            <Button type="warning">警告按钮</Button>
-            <Button type="danger">危险按钮</Button>
-        </Space>
-    </>
-));
+export const SpaceSpacing = () => (
+  <>
+    <Space spacing="loose">
+      <span>spacing-loose</span>
+      <Button>主要按钮</Button>
+      <Button type="secondary">次要按钮</Button>
+      <Button type="tertiary">第三按钮</Button>
+      <Button type="warning">警告按钮</Button>
+      <Button type="danger">危险按钮</Button>
+    </Space>
+    <br />
+    <Space spacing="medium">
+      <span>spacing-medium</span>
+      <Button>主要按钮</Button>
+      <Button type="secondary">次要按钮</Button>
+      <Button type="tertiary">第三按钮</Button>
+      <Button type="warning">警告按钮</Button>
+      <Button type="danger">危险按钮</Button>
+    </Space>
+    <br />
+    <Space spacing="tight">
+      <span>spacing-tight</span>
+      <Button>主要按钮</Button>
+      <Button type="secondary">次要按钮</Button>
+      <Button type="tertiary">第三按钮</Button>
+      <Button type="warning">警告按钮</Button>
+      <Button type="danger">危险按钮</Button>
+    </Space>
+    <br />
+    <Space spacing={30}>
+      <span>spacing-number-30</span>
+      <Button>主要按钮</Button>
+      <Button type="secondary">次要按钮</Button>
+      <Button type="tertiary">第三按钮</Button>
+      <Button type="warning">警告按钮</Button>
+      <Button type="danger">危险按钮</Button>
+    </Space>
+    <br />
+    <Space spacing={[20, 20]}>
+      <span>spacing-array-[20,20]</span>
+      <Button>主要按钮</Button>
+      <Button type="secondary">次要按钮</Button>
+      <Button type="tertiary">第三按钮</Button>
+      <Button type="warning">警告按钮</Button>
+      <Button type="danger">危险按钮</Button>
+    </Space>
+    <br />
+    <Space spacing={['medium', 'loose']}>
+      <span>spacing-array-['medium','loose']</span>
+      <Button>主要按钮</Button>
+      <Button type="secondary">次要按钮</Button>
+      <Button type="tertiary">第三按钮</Button>
+      <Button type="warning">警告按钮</Button>
+      <Button type="danger">危险按钮</Button>
+    </Space>
+    <br />
+    <Space spacing={['medium', 20]}>
+      <span>spacing-array-['medium',20]</span>
+      <Button>主要按钮</Button>
+      <Button type="secondary">次要按钮</Button>
+      <Button type="tertiary">第三按钮</Button>
+      <Button type="warning">警告按钮</Button>
+      <Button type="danger">危险按钮</Button>
+    </Space>
+    <br />
+    <Space wrap spacing="loose">
+      <span>spacing-loose,wrap=true</span>
+      <Button>主要按钮</Button>
+      <Button type="secondary">次要按钮</Button>
+      <Button type="tertiary">第三按钮</Button>
+      <Button type="warning">警告按钮</Button>
+      <Button type="danger">危险按钮</Button>
+    </Space>
+    <br />
+    <Space wrap spacing="medium">
+      <span>spacing-medium,wrap=true</span>
+      <Button>主要按钮</Button>
+      <Button type="secondary">次要按钮</Button>
+      <Button type="tertiary">第三按钮</Button>
+      <Button type="warning">警告按钮</Button>
+      <Button type="danger">危险按钮</Button>
+    </Space>
+    <br />
+    <Space wrap spacing="tight">
+      <span>spacing-tight,wrap=true</span>
+      <Button>主要按钮</Button>
+      <Button type="secondary">次要按钮</Button>
+      <Button type="tertiary">第三按钮</Button>
+      <Button type="warning">警告按钮</Button>
+      <Button type="danger">危险按钮</Button>
+    </Space>
+    <br />
+  </>
+);
 
-stories.add('Space spacing', () => (
-    <>
-        <Space spacing='loose'>
-            <span>spacing-loose</span>
-            <Button>主要按钮</Button>
-            <Button type="secondary">次要按钮</Button>
-            <Button type="tertiary">第三按钮</Button>
-            <Button type="warning">警告按钮</Button>
-            <Button type="danger">危险按钮</Button>
-        </Space>
-        <br />
-        <Space spacing='medium'>
-            <span>spacing-medium</span>
-            <Button>主要按钮</Button>
-            <Button type="secondary">次要按钮</Button>
-            <Button type="tertiary">第三按钮</Button>
-            <Button type="warning">警告按钮</Button>
-            <Button type="danger">危险按钮</Button>
-        </Space>
-        <br />
-        <Space spacing='tight'>
-            <span>spacing-tight</span>
-            <Button>主要按钮</Button>
-            <Button type="secondary">次要按钮</Button>
-            <Button type="tertiary">第三按钮</Button>
-            <Button type="warning">警告按钮</Button>
-            <Button type="danger">危险按钮</Button>
-        </Space>
-        <br />
-        <Space spacing={30}>
-            <span>spacing-number-30</span>
-            <Button>主要按钮</Button>
-            <Button type="secondary">次要按钮</Button>
-            <Button type="tertiary">第三按钮</Button>
-            <Button type="warning">警告按钮</Button>
-            <Button type="danger">危险按钮</Button>
-        </Space>
-        <br />
-        <Space spacing={[20, 20]}>
-            <span>spacing-array-[20,20]</span>
-            <Button>主要按钮</Button>
-            <Button type="secondary">次要按钮</Button>
-            <Button type="tertiary">第三按钮</Button>
-            <Button type="warning">警告按钮</Button>
-            <Button type="danger">危险按钮</Button>
-        </Space>
-        <br />
-        <Space spacing={['medium', 'loose']}>
-            <span>spacing-array-['medium','loose']</span>
-            <Button>主要按钮</Button>
-            <Button type="secondary">次要按钮</Button>
-            <Button type="tertiary">第三按钮</Button>
-            <Button type="warning">警告按钮</Button>
-            <Button type="danger">危险按钮</Button>
-        </Space>
-        <br />
-        <Space spacing={['medium', 20]}>
-            <span>spacing-array-['medium',20]</span>
-            <Button>主要按钮</Button>
-            <Button type="secondary">次要按钮</Button>
-            <Button type="tertiary">第三按钮</Button>
-            <Button type="warning">警告按钮</Button>
-            <Button type="danger">危险按钮</Button>
-        </Space>
-        <br />
-        <Space wrap spacing='loose'>
-            <span>spacing-loose,wrap=true</span>
-            <Button>主要按钮</Button>
-            <Button type="secondary">次要按钮</Button>
-            <Button type="tertiary">第三按钮</Button>
-            <Button type="warning">警告按钮</Button>
-            <Button type="danger">危险按钮</Button>
-        </Space>
-        <br />
-        <Space wrap spacing='medium'>
-            <span>spacing-medium,wrap=true</span>
-            <Button>主要按钮</Button>
-            <Button type="secondary">次要按钮</Button>
-            <Button type="tertiary">第三按钮</Button>
-            <Button type="warning">警告按钮</Button>
-            <Button type="danger">危险按钮</Button>
-        </Space>
-        <br />
-        <Space wrap spacing='tight'>
-            <span>spacing-tight,wrap=true</span>
-            <Button>主要按钮</Button>
-            <Button type="secondary">次要按钮</Button>
-            <Button type="tertiary">第三按钮</Button>
-            <Button type="warning">警告按钮</Button>
-            <Button type="danger">危险按钮</Button>
-        </Space>
-        <br />
-    </>
-));
-stories.add('Space wrap', () => (
-    <>
-        <Space wrap={false}>
-            {new Array(30).fill(null).map((item, idex) => (
-                <Button key={idex}>按钮</Button>
-            ))}
-        </Space>
-        <br />
-        <Space wrap={true}>
-            {new Array(30).fill(null).map((item, idex) => (
-                <Button theme='solid' type='secondary' key={idex}>按钮</Button>
-            ))}
-        </Space>
-    </>
-));
+SpaceSpacing.story = {
+  name: 'Space spacing',
+};
 
+export const SpaceWrap = () => (
+  <>
+    <Space wrap={false}>
+      {new Array(30).fill(null).map((item, idex) => (
+        <Button key={idex}>按钮</Button>
+      ))}
+    </Space>
+    <br />
+    <Space wrap={true}>
+      {new Array(30).fill(null).map((item, idex) => (
+        <Button theme="solid" type="secondary" key={idex}>
+          按钮
+        </Button>
+      ))}
+    </Space>
+  </>
+);
 
+SpaceWrap.story = {
+  name: 'Space wrap',
+};

+ 76 - 52
packages/semi-ui/spin/_story/spin.stories.js

@@ -1,68 +1,92 @@
 import React, { useState } from 'react';
-import { storiesOf } from '@storybook/react';
-// import { withKnobs, text, boolean } from '@storybook/addon-knobs';
 import Button from '../../button/index';
 import Spin from '../index';
 
-const stories = storiesOf('Spin', module);
-
-// stories.addDecorator(withKnobs);;
+export default {
+  title: 'Spin'
+}
 
 const Example1 = () => (
-    <div style={{marginLeft: 30}}>
-        <div style={{ marginTop: 20 }}>size:small</div>
-        <Spin size="small" />
-        <div style={{ marginTop: 20 }}>size:middle</div>
-        <Spin size="middle" />
-        <div style={{ marginTop: 20 }}>size:large</div>
-        <Spin size="large" />
-    </div>
+  <div style={{ marginLeft: 30 }}>
+    <div style={{ marginTop: 20 }}>size:small</div>
+    <Spin size="small" />
+    <div style={{ marginTop: 20 }}>size:middle</div>
+    <Spin size="middle" />
+    <div style={{ marginTop: 20 }}>size:large</div>
+    <Spin size="large" />
+  </div>
 );
 
-stories.add('spin default', () => <Example1 />);
+export const SpinDefault = () => <Example1 />;
 
-const Example2 = () => {
-    const [visible, setVisible] = useState(true);
-    return (
-        <div>
-            <Spin spinning={visible} tip='loading'>
-                <div style={{ 'background-color': '#e6f7ff', 'border': '1px solid #91d5ff' }}>
-                    <p>yoyoyoyoyo</p>
-                    <p>yoyoyoyoyo</p>
-                    <p>yoyoyoyoyo</p>
-                </div>
-            </Spin>
-            <div style={{marginTop:30}}>
-                    <Button onClick={()=>{setVisible(!visible)}} style={{ marginRight:20 }}>受控</Button>
-            </div>   
-        </div>        
-    )
+SpinDefault.story = {
+  name: 'spin default',
+};
 
-}
+const Example2 = () => {
+  const [visible, setVisible] = useState(true);
+  return (
+    <div>
+      <Spin spinning={visible} tip="loading">
+        <div style={{ 'background-color': '#e6f7ff', border: '1px solid #91d5ff' }}>
+          <p>yoyoyoyoyo</p>
+          <p>yoyoyoyoyo</p>
+          <p>yoyoyoyoyo</p>
+        </div>
+      </Spin>
+      <div style={{ marginTop: 30 }}>
+        <Button
+          onClick={() => {
+            setVisible(!visible);
+          }}
+          style={{ marginRight: 20 }}
+        >
+          受控
+        </Button>
+      </div>
+    </div>
+  );
+};
 
-stories.add('spin has text', () => <Example2 />);
+export const SpinHasText = () => <Example2 />;
 
+SpinHasText.story = {
+  name: 'spin has text',
+};
 
 const Example3 = () => {
-    const [visible1, setVisible1] = useState(false);
-    const [visible2, setVisible2] = useState(false);
-    return (
-        <div style={{marginLeft:30}}>
-            <div style={{marginTop:30}}>
-                <Button onClick={()=>{setVisible1(!visible1)}} style={{ marginRight:20 }}>延迟显示spin</Button>
-                <Spin delay={1000} spinning={visible1}>
-                </Spin>
-            </div> 
-            <div style={{marginTop:30}}>
-                    <Button onClick={()=>{setVisible2(!visible2)}} style={{ marginRight:20 }}>受控显示spin</Button>
-                    <Spin spinning={visible2}>
-                    </Spin>
-            </div>            
-        </div>
-       
-    )
-
-}
+  const [visible1, setVisible1] = useState(false);
+  const [visible2, setVisible2] = useState(false);
+  return (
+    <div style={{ marginLeft: 30 }}>
+      <div style={{ marginTop: 30 }}>
+        <Button
+          onClick={() => {
+            setVisible1(!visible1);
+          }}
+          style={{ marginRight: 20 }}
+        >
+          延迟显示spin
+        </Button>
+        <Spin delay={1000} spinning={visible1}></Spin>
+      </div>
+      <div style={{ marginTop: 30 }}>
+        <Button
+          onClick={() => {
+            setVisible2(!visible2);
+          }}
+          style={{ marginRight: 20 }}
+        >
+          受控显示spin
+        </Button>
+        <Spin spinning={visible2}></Spin>
+      </div>
+    </div>
+  );
+};
 
+export const SpinHasDelay = () => <Example3 />;
 
-stories.add('spin has delay', () => <Example3 />);
+SpinHasDelay.story = {
+  name: 'spin has delay',
+};

+ 2 - 2
packages/semi-ui/spin/index.tsx

@@ -16,7 +16,7 @@ export interface SpinProps {
     spinning?: boolean;
     indicator?: React.ReactNode;
     delay?: number;
-    tip?: string;
+    tip?: React.ReactNode;
     wrapperClassName?: string;
     style?: React.CSSProperties;
     childStyle?: React.CSSProperties;
@@ -34,7 +34,7 @@ class Spin extends BaseComponent<SpinProps, SpinState> {
         children: PropTypes.node,
         indicator: PropTypes.node,
         delay: PropTypes.number,
-        tip: PropTypes.string,
+        tip: PropTypes.node,
         wrapperClassName: PropTypes.string,
         childStyle: PropTypes.object,
         style: PropTypes.object,

+ 258 - 214
packages/semi-ui/steps/_story/steps.stories.js

@@ -1,5 +1,4 @@
 import React, { useState } from 'react';
-import { storiesOf } from '@storybook/react'; // import { withKnobs, text, boolean } from '@storybook/addon-knobs';
 
 import { Form } from '../../form';
 import Radio from '../../radio';
@@ -9,254 +8,299 @@ import Icon from '../../icons';
 import Button from '../../button';
 import { IconTriangleDown, IconClear, IconTick, IconClose, IconBell } from '@douyinfe/semi-icons';
 
-const stories = storiesOf('Steps', module);
+export default {
+  title: 'Steps'
+}
 const sizes = ['default', 'small'];
 
 const AllSteps = () => {
-    const [stepProps, setProps] = useState({
-        type: 'basic',
-        size: 'small',
-        current: 0,
-        hasLine: true,
-        direction: 'horizontal',
-        initial: 0,
-        status: 'finish',
-    });
-    return (
-        <>
-            <Form layout="vertical" labelPosition="left" onValueChange={v => setProps({ ...v })} initValues={stepProps}>
-                <Form.RadioGroup field="type">
-                    <Radio value="fill">fill</Radio>
-                    <Radio value="basic">basic</Radio>
-                    <Radio value="nav">nav</Radio>
-                </Form.RadioGroup>
-                <Form.RadioGroup field="size">
-                    <Radio value="small">small</Radio>
-                    <Radio value="default">default</Radio>
-                </Form.RadioGroup>
-                <Form.RadioGroup field="hasLine">
-                    <Radio value={true}>true</Radio>
-                    <Radio value={false}>false</Radio>
-                </Form.RadioGroup>
-                <Form.InputNumber field="current"></Form.InputNumber>
-                <Form.RadioGroup field="direction">
-                    <Radio value="horizontal">horizontal</Radio>
-                    <Radio value="vertical">vertical</Radio>
-                </Form.RadioGroup>
-                <Form.InputNumber field="initial"></Form.InputNumber>
-                <Form.RadioGroup field="status">
-                    <Radio value="wait">wait</Radio>
-                    <Radio value="process">process</Radio>
-                    <Radio value="finish">finish</Radio>
-                    <Radio value="error">error</Radio>
-                    <Radio value="warning">warning</Radio>
-                </Form.RadioGroup>
-            </Form>
-            <Steps type="basic" {...stepProps}>
-                <Step
-                    title="Step.1"
-                    icon={<IconBell />}
-                    description="This is a long descriptionThis is a long descriptionThis is a long descriptionThis is a long descriptionThis is a long descriptionThis is a long description"
-                ></Step>
-                <Step title="Step.2" description="This is some description"></Step>
-                <Step title="Step.3"></Step>
-                <Step title="Step.4" description="This is some description"></Step>
-            </Steps>
-        </>
-    );
+  const [stepProps, setProps] = useState({
+    type: 'basic',
+    size: 'small',
+    current: 0,
+    hasLine: true,
+    direction: 'horizontal',
+    initial: 0,
+    status: 'finish',
+  });
+  return (
+    <>
+      <Form
+        layout="vertical"
+        labelPosition="left"
+        onValueChange={v => setProps({ ...v })}
+        initValues={stepProps}
+      >
+        <Form.RadioGroup field="type">
+          <Radio value="fill">fill</Radio>
+          <Radio value="basic">basic</Radio>
+          <Radio value="nav">nav</Radio>
+        </Form.RadioGroup>
+        <Form.RadioGroup field="size">
+          <Radio value="small">small</Radio>
+          <Radio value="default">default</Radio>
+        </Form.RadioGroup>
+        <Form.RadioGroup field="hasLine">
+          <Radio value={true}>true</Radio>
+          <Radio value={false}>false</Radio>
+        </Form.RadioGroup>
+        <Form.InputNumber field="current"></Form.InputNumber>
+        <Form.RadioGroup field="direction">
+          <Radio value="horizontal">horizontal</Radio>
+          <Radio value="vertical">vertical</Radio>
+        </Form.RadioGroup>
+        <Form.InputNumber field="initial"></Form.InputNumber>
+        <Form.RadioGroup field="status">
+          <Radio value="wait">wait</Radio>
+          <Radio value="process">process</Radio>
+          <Radio value="finish">finish</Radio>
+          <Radio value="error">error</Radio>
+          <Radio value="warning">warning</Radio>
+        </Form.RadioGroup>
+      </Form>
+      <Steps type="basic" {...stepProps}>
+        <Step
+          title="Step.1"
+          icon={<IconBell />}
+          description="This is a long descriptionThis is a long descriptionThis is a long descriptionThis is a long descriptionThis is a long descriptionThis is a long description"
+        ></Step>
+        <Step title="Step.2" description="This is some description"></Step>
+        <Step title="Step.3"></Step>
+        <Step title="Step.4" description="This is some description"></Step>
+      </Steps>
+    </>
+  );
 };
 
-stories.add('all steps', () => <AllSteps></AllSteps>);
+export const _AllSteps = () => <AllSteps></AllSteps>;
+
+_AllSteps.story = {
+  name: 'all steps',
+};
 
 const FillStep = () => {
-    return sizes.map(s => (
-        <Steps key={s} size={s} current={1}>
-            <Step title="中文" description="This is a description." />
-            <Step title="In Progress" description="This is a description." />
-            <Step title="Waiting" description="This is a description." />
-        </Steps>
-    ));
+  return sizes.map(s => (
+    <Steps key={s} size={s} current={1}>
+      <Step title="中文" description="This is a description." />
+      <Step title="In Progress" description="This is a description." />
+      <Step title="Waiting" description="This is a description." />
+    </Steps>
+  ));
 };
 
-stories.add('steps default fill', () => <FillStep />);
+export const StepsDefaultFill = () => <FillStep />;
+
+StepsDefaultFill.story = {
+  name: 'steps default fill',
+};
 
 const BasicStep = () => {
-    return sizes.map(s => (
-        <Steps key={s} size={s} type="basic" current={1}>
-            <Step title="Step.1" description="This is a description.This is a description." />
-            <Step title="Step.2" description="This is a description.This is a description." />
-            <Step title="Step.3" description="This is a description.This is a description." />
-        </Steps>
-    ));
+  return sizes.map(s => (
+    <Steps key={s} size={s} type="basic" current={1}>
+      <Step title="Step.1" description="This is a description.This is a description." />
+      <Step title="Step.2" description="This is a description.This is a description." />
+      <Step title="Step.3" description="This is a description.This is a description." />
+    </Steps>
+  ));
+};
+
+export const StepsBasic = () => <BasicStep />;
+
+StepsBasic.story = {
+  name: 'steps basic',
+};
+
+export const StepsWithIcon = () => {
+  return (
+    <Steps>
+      <Step status="finish" title="Login" icon={<IconTriangleDown />} />
+      <Step status="finish" title="Verification" icon={<IconClear />} />
+      <Step status="process" title="Pay" icon={<IconTick />} />
+      <Step status="wait" title="Done" icon={<IconClose />} />
+    </Steps>
+  );
+};
+
+StepsWithIcon.story = {
+  name: 'steps with icon',
 };
 
-stories.add('steps basic', () => <BasicStep />);
-stories.add('steps with icon', () => {
+const steps = [
+  {
+    title: 'First',
+    content: 'First-content',
+  },
+  {
+    title: 'Second',
+    content: 'Second-content',
+  },
+  {
+    title: 'Last',
+    content: 'Last-content',
+  },
+];
+
+class StepsDemo extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      current: 0,
+    };
+  }
+
+  next() {
+    const current = this.state.current + 1;
+    this.setState({
+      current,
+    });
+  }
+
+  prev() {
+    const current = this.state.current - 1;
+    this.setState({
+      current,
+    });
+  }
+
+  render() {
+    const { current } = this.state;
     return (
-        <Steps>
-            <Step status="finish" title="Login" icon={<IconTriangleDown />} />
-            <Step status="finish" title="Verification" icon={<IconClear />} />
-            <Step status="process" title="Pay" icon={<IconTick />} />
-            <Step status="wait" title="Done" icon={<IconClose />} />
+      <div>
+        <Steps current={current}>
+          {steps.map(item => (
+            <Step key={item.title} title={item.title} />
+          ))}
         </Steps>
+        <div className="steps-content">{steps[current].content}</div>
+        <div className="steps-action">
+          {current < steps.length - 1 && (
+            <Button type="primary" onClick={() => this.next()}>
+              Next
+            </Button>
+          )}
+          {current === steps.length - 1 && (
+            <Button type="primary" onClick={() => console.log('Processing complete!')}>
+              Done
+            </Button>
+          )}
+          {current > 0 && (
+            <Button
+              style={{
+                marginLeft: 8,
+              }}
+              onClick={() => this.prev()}
+            >
+              Previous
+            </Button>
+          )}
+        </div>
+      </div>
     );
-});
-const steps = [
-    {
+  }
+}
+
+export const StepsWithControled = () => {
+  return <StepsDemo></StepsDemo>;
+};
+
+StepsWithControled.story = {
+  name: 'steps with controled',
+};
+
+class StepsWithonChange extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      current: 1,
+    };
+  }
+
+  onChange(current) {
+    this.setState({ current });
+  }
+
+  render() {
+    const { current } = this.state;
+    const { Step } = Steps;
+    const steps = [
+      {
         title: 'First',
         content: 'First-content',
-    },
-    {
+      },
+      {
         title: 'Second',
         content: 'Second-content',
-    },
-    {
+      },
+      {
         title: 'Last',
         content: 'Last-content',
-    },
-];
+      },
+    ];
 
-class StepsDemo extends React.Component {
-    constructor(props) {
-        super(props);
-        this.state = {
-            current: 0,
-        };
-    }
-
-    next() {
-        const current = this.state.current + 1;
-        this.setState({
-            current,
-        });
-    }
-
-    prev() {
-        const current = this.state.current - 1;
-        this.setState({
-            current,
-        });
-    }
-
-    render() {
-        const { current } = this.state;
-        return (
-            <div>
-                <Steps current={current}>
-                    {steps.map(item => (
-                        <Step key={item.title} title={item.title} />
-                    ))}
-                </Steps>
-                <div className="steps-content">{steps[current].content}</div>
-                <div className="steps-action">
-                    {current < steps.length - 1 && (
-                        <Button type="primary" onClick={() => this.next()}>
-                            Next
-                        </Button>
-                    )}
-                    {current === steps.length - 1 && (
-                        <Button type="primary" onClick={() => console.log('Processing complete!')}>
-                            Done
-                        </Button>
-                    )}
-                    {current > 0 && (
-                        <Button
-                            style={{
-                                marginLeft: 8,
-                            }}
-                            onClick={() => this.prev()}
-                        >
-                            Previous
-                        </Button>
-                    )}
-                </div>
-            </div>
-        );
-    }
+    return (
+      <div>
+        <Steps type="basic" current={current} onChange={current => this.onChange(current)}>
+          {steps.map(item => (
+            <Step key={item.title} title={item.title} />
+          ))}
+        </Steps>
+      </div>
+    );
+  }
 }
 
-stories.add('steps with controled', () => {
-    return <StepsDemo></StepsDemo>;
-});
-
-class StepsWithonChange extends React.Component {
-    constructor(props) {
-        super(props);
-        this.state = {
-            current: 1,
-        };
-    }
-
-    onChange(current) {
-        this.setState({ current });
-    }
-
-    render() {
-        const { current } = this.state;
-        const { Step } = Steps;
-        const steps = [
-            {
-                title: 'First',
-                content: 'First-content',
-            },
-            {
-                title: 'Second',
-                content: 'Second-content',
-            },
-            {
-                title: 'Last',
-                content: 'Last-content',
-            },
-        ];
-
-        return (
-            <div>
-                <Steps type="basic" current={current} onChange={current => this.onChange(current)}>
-                    {steps.map(item => (
-                        <Step key={item.title} title={item.title} />
-                    ))}
-                </Steps>
-            </div>
-        );
-    }
-}
+export const StepsWithOnChange = () => {
+  return <StepsWithonChange />;
+};
 
-stories.add('steps with onChange', () => {
-    return <StepsWithonChange/>;
-});
+StepsWithOnChange.story = {
+  name: 'steps with onChange',
+};
 
 const StatusStep = () => {
-    return sizes.map(s => (
-        <Steps key={s} size={s} current={1} status="error">
-            <Step title="Finished" description="This is a description" />
-            <Step title="In Process" description="This is a description" />
-            <Step title="Waiting" description="This is a description" />
-        </Steps>
-    ));
+  return sizes.map(s => (
+    <Steps key={s} size={s} current={1} status="error">
+      <Step title="Finished" description="This is a description" />
+      <Step title="In Process" description="This is a description" />
+      <Step title="Waiting" description="This is a description" />
+    </Steps>
+  ));
 };
 
-stories.add('steps with status', () => <StatusStep />);
+export const StepsWithStatus = () => <StatusStep />;
+
+StepsWithStatus.story = {
+  name: 'steps with status',
+};
 
 const VerticalStep = () => {
-    return sizes.map(s => (
-        <Steps key={s} size={s} current={1} status="error" direction="vertical">
-            <Step title="Finished" description="This is a description" />
-            <Step title="In Process" description="This is a description" />
-            <Step title="Waiting" description="This is a description" />
-        </Steps>
-    ));
+  return sizes.map(s => (
+    <Steps key={s} size={s} current={1} status="error" direction="vertical">
+      <Step title="Finished" description="This is a description" />
+      <Step title="In Process" description="This is a description" />
+      <Step title="Waiting" description="This is a description" />
+    </Steps>
+  ));
 };
 
-stories.add('steps vertical', () => <VerticalStep />);
+export const StepsVertical = () => <VerticalStep />;
+
+StepsVertical.story = {
+  name: 'steps vertical',
+};
 
 const LineStep = () => {
-    return sizes.map(s => (
-        <Steps key={s} size={s} hasLine={false} current={1} status="error">
-            <Step title="Finished" description="This is a description" />
-            <Step title="In Process" description="This is a description" />
-            <Step title="Waiting" description="This is a description" />
-        </Steps>
-    ));
+  return sizes.map(s => (
+    <Steps key={s} size={s} hasLine={false} current={1} status="error">
+      <Step title="Finished" description="This is a description" />
+      <Step title="In Process" description="This is a description" />
+      <Step title="Waiting" description="This is a description" />
+    </Steps>
+  ));
 };
 
-stories.add('steps without line', () => <LineStep></LineStep>);
+export const StepsWithoutLine = () => <LineStep></LineStep>;
+
+StepsWithoutLine.story = {
+  name: 'steps without line',
+};

+ 144 - 108
packages/semi-ui/switch/_story/switch.stories.js

@@ -1,124 +1,160 @@
 import React, { useState } from 'react';
-import { Button } from '@douyinfe/semi-ui/';
-import {
-    storiesOf
-} from '@storybook/react';
-// import { withKnobs, text, boolean } from '@storybook/addon-knobs';
 
+import { Button } from '@douyinfe/semi-ui/';
 import { Switch } from '../../index';
 
-const stories = storiesOf('Switch', module);
-
-// stories.addDecorator(withKnobs);;
-
-stories.add('switch', () => (
-    <div>
-        <Switch onChange={(v, e) => console.log(v)}>
-        </Switch>
-        <Switch defaultChecked={true} onChange={(v, e) => console.log(v)}>
-        </Switch>
-    </div>
-));
-
-
-stories.add('switch size', () => (
-    <div>
-        <Switch onChange={(v, e) => console.log(v)}></Switch>
-        <Switch onChange={(v, e) => console.log(v)} size='small'></Switch>
-        <Switch onChange={(v, e) => console.log(v)} size='large'></Switch>
-    </div>
-));
-
-stories.add('switch checkedText &  uncheckedText', () => (
-    <div>
-        <Switch defaultChecked checkedText='开' uncheckedText='关' />
-        <Switch checkedText={'|'} uncheckedText='〇' />
-        <br/><br/>
-        <Switch checkedText='开' uncheckedText='关' />
-        <Switch defaultChecked checkedText='|' uncheckedText='〇' />
-        <br/><br/>
-        <Switch checkedText='开' uncheckedText='关' size='large' />
-        <Switch checkedText='|' uncheckedText='〇' size='large' />
-        <br/><br/>
-        <Switch defaultChecked checkedText='开' uncheckedText='关' size='large' />
-        <Switch defaultChecked checkedText='|' uncheckedText='〇' size='large' />
-    </div>
-));
-
-stories.add('switch disabled', () => (
-    <>
-        <Switch disabled>
-            disabled
-        </Switch>
+export default {
+  title: 'Switch'
+}
 
-        <Switch disabled checked={true} onChange={(v, e) => console.log(v)}>
-        </Switch>
-    </>
-));
+export const _Switch = () => (
+  <div>
+    <Switch onChange={(v, e) => console.log(v)}></Switch>
+    <Switch defaultChecked={true} onChange={(v, e) => console.log(v)}></Switch>
+  </div>
+);
+
+_Switch.story = {
+  name: 'switch',
+};
+
+export const SwitchSize = () => (
+  <div>
+    <Switch onChange={(v, e) => console.log(v)}></Switch>
+    <Switch onChange={(v, e) => console.log(v)} size="small"></Switch>
+    <Switch onChange={(v, e) => console.log(v)} size="large"></Switch>
+  </div>
+);
 
+SwitchSize.story = {
+  name: 'switch size',
+};
+
+export const SwitchCheckedTextUncheckedText = () => (
+  <div>
+    <Switch defaultChecked checkedText="开" uncheckedText="关" />
+    <Switch checkedText={'|'} uncheckedText="〇" />
+    <br />
+    <br />
+    <Switch checkedText="开" uncheckedText="关" />
+    <Switch defaultChecked checkedText="|" uncheckedText="〇" />
+    <br />
+    <br />
+    <Switch checkedText="开" uncheckedText="关" size="large" />
+    <Switch checkedText="|" uncheckedText="〇" size="large" />
+    <br />
+    <br />
+    <Switch defaultChecked checkedText="开" uncheckedText="关" size="large" />
+    <Switch defaultChecked checkedText="|" uncheckedText="〇" size="large" />
+  </div>
+);
+
+SwitchCheckedTextUncheckedText.story = {
+  name: 'switch checkedText &  uncheckedText',
+};
+
+export const SwitchDisabled = () => (
+  <>
+    <Switch disabled>disabled</Switch>
+
+    <Switch disabled checked={true} onChange={(v, e) => console.log(v)}></Switch>
+  </>
+);
+
+SwitchDisabled.story = {
+  name: 'switch disabled',
+};
 
 const ControledSwitch = () => {
-    const [checked, onChange] = useState(true);
-    return (
-        <Switch checked={checked} onChange={(v, e) => onChange(v)} />
-    );
+  const [checked, onChange] = useState(true);
+  return <Switch checked={checked} onChange={(v, e) => onChange(v)} />;
+};
+export const SwitchCheckedOnChange = () => <ControledSwitch />;
+
+SwitchCheckedOnChange.story = {
+  name: 'switch checked + onChange',
 };
-stories.add('switch checked + onChange', () => <ControledSwitch/>);
 
 const UnControledSwitch = () => {
-    const onChange = checked => {
-        console.log(checked);
-    };
-    return (
-        <>
-            {/* <Switch onChange={onChange} defaultChecked={false}/> */}
-            <Switch onChange={onChange} defaultChecked={true}/>
-        </>
-    );
+  const onChange = checked => {
+    console.log(checked);
+  };
+  return (
+    <>
+      {/* <Switch onChange={onChange} defaultChecked={false}/> */}
+      <Switch onChange={onChange} defaultChecked={true} />
+    </>
+  );
+};
+export const SwitchDefaultCheckedOnChange = () => <UnControledSwitch />;
+
+SwitchDefaultCheckedOnChange.story = {
+  name: 'switch defaultChecked + onChange',
 };
-stories.add('switch defaultChecked + onChange', () => <UnControledSwitch/>);
 
 class LoadingDemo extends React.Component {
-    constructor() {
-        super()
-        this.state = {
-            checked: true,
-            loading:false
-        }
-        this.onChange = this.onChange.bind(this);
-    }
-    onChange(checked) {
-        this.setState({ checked });
-    }
-    render() {
-        return (
-            <>
-                <Button onClick={() => { this.setState({ checked: true }); }}>
-                    checked
-                </Button>
-                <br /><br />
-                <Button onClick={() => { this.setState({ checked: false }); }}>
-                    unchecked
-                </Button>
-                <br /><br />
-                <Button onClick={() => { this.setState({ loading: !this.state.loading }); }}>
-                    loading
-                </Button>
-                <br /><br />
-                <Switch
-                    checked={this.state.checked}
-                    onChange={this.onChange}
-                    loading={this.state.loading}>
-                </Switch>
-                <br /><br />
-                <hr />
-                <Switch loading disabled/>
-                <br /><br />
-                <Switch loading disabled defaultChecked/>
-                <br /><br />
-            </>
-        )
-    }
+  constructor() {
+    super();
+    this.state = {
+      checked: true,
+      loading: false,
+    };
+    this.onChange = this.onChange.bind(this);
+  }
+  onChange(checked) {
+    this.setState({ checked });
+  }
+  render() {
+    return (
+      <>
+        <Button
+          onClick={() => {
+            this.setState({ checked: true });
+          }}
+        >
+          checked
+        </Button>
+        <br />
+        <br />
+        <Button
+          onClick={() => {
+            this.setState({ checked: false });
+          }}
+        >
+          unchecked
+        </Button>
+        <br />
+        <br />
+        <Button
+          onClick={() => {
+            this.setState({ loading: !this.state.loading });
+          }}
+        >
+          loading
+        </Button>
+        <br />
+        <br />
+        <Switch
+          checked={this.state.checked}
+          onChange={this.onChange}
+          loading={this.state.loading}
+        ></Switch>
+        <br />
+        <br />
+        <hr />
+        <Switch loading disabled />
+        <br />
+        <br />
+        <Switch loading disabled defaultChecked />
+        <br />
+        <br />
+      </>
+    );
+  }
 }
 
-stories.add('loading', () => <LoadingDemo/>);
+export const Loading = () => <LoadingDemo />;
+
+Loading.story = {
+  name: 'loading',
+};

+ 25 - 17
packages/semi-ui/table/Body/index.tsx

@@ -22,7 +22,7 @@ import { strings } from '@douyinfe/semi-foundation/table/constants';
 import Store from '@douyinfe/semi-foundation/utils/Store';
 
 import BaseComponent, { BaseProps } from '../../_base/baseComponent';
-import { measureScrollbar, logger } from '../utils';
+import { logger } from '../utils';
 import ColGroup from '../ColGroup';
 import BaseRow from './BaseRow';
 import ExpandedRow from './ExpandedRow';
@@ -126,6 +126,7 @@ class Body extends BaseComponent<BodyProps, BodyState> {
     ref: React.MutableRefObject<any>;
     listRef: React.MutableRefObject<any>;
     observer: ResizeObserver;
+    foundation: BodyFoundation;
     constructor(props: BodyProps, context: BodyContext) {
         super(props);
         this.ref = React.createRef();
@@ -159,7 +160,7 @@ class Body extends BaseComponent<BodyProps, BodyState> {
             setVirtualizedData: (virtualizedData, cb) => this.setState({ virtualizedData }, cb),
             setCachedExpandBtnShouldInRow: cachedExpandBtnShouldInRow => this.setState({ cachedExpandBtnShouldInRow }),
             setCachedExpandRelatedProps: cachedExpandRelatedProps => this.setState({ cachedExpandRelatedProps }),
-            observeBodyResize: bodyWrapDOM => {
+            observeBodyResize: (bodyWrapDOM: HTMLDivElement) => {
                 const { setBodyHasScrollbar } = this.context;
 
                 // Callback when the size of the body dom content changes, notifying Table.jsx whether the bodyHasScrollBar exists
@@ -176,11 +177,12 @@ class Body extends BaseComponent<BodyProps, BodyState> {
                 // Monitor body dom resize
                 if (bodyWrapDOM) {
                     if (get(window, 'ResizeObserver')) {
-                        // no need to observe many times when ref update
-                        if (!this.observer) {
-                            this.observer = new ResizeObserver(resizeCallback);
-                            this.observer.observe(bodyWrapDOM);
+                        if (this.observer) {
+                            this.observer.unobserve(bodyWrapDOM);
+                            this.observer = null;
                         }
+                        this.observer = new ResizeObserver(resizeCallback);
+                        this.observer.observe(bodyWrapDOM);
                     } else {
                         logger.warn(
                             'The current browser does not support ResizeObserver,' +
@@ -194,17 +196,19 @@ class Body extends BaseComponent<BodyProps, BodyState> {
                 const bodyWrapDOM = this.ref.current;
                 if (this.observer) {
                     this.observer.unobserve(bodyWrapDOM);
+                    this.observer = null;
                 }
             }
         };
     }
 
     componentDidUpdate(prevProps: BodyProps, prevState: BodyState) {
-        if (this.props.virtualized) {
+        const { virtualized, dataSource, expandedRowKeys, columns, scroll  } = this.props;
+        if (virtualized) {
             if (
-                prevProps.dataSource !== this.props.dataSource ||
-                prevProps.expandedRowKeys !== this.props.expandedRowKeys ||
-                prevProps.columns !== this.props.columns
+                prevProps.dataSource !== dataSource ||
+                prevProps.expandedRowKeys !== expandedRowKeys ||
+                prevProps.columns !== columns
             ) {
                 this.foundation.initVirtualizedData();
             }
@@ -215,6 +219,12 @@ class Body extends BaseComponent<BodyProps, BodyState> {
         if (!isEqual(newExpandRelatedProps, prevState.cachedExpandRelatedProps)) {
             this.foundation.initExpandBtnShouldInRow(newExpandRelatedProps);
         }
+
+        const scrollY = get(scroll, 'y');
+        const bodyWrapDOM = this.ref.current;
+        if (scrollY && scrollY !== get(prevProps, 'scroll.y')) {
+            this.foundation.observeBodyResize(bodyWrapDOM);
+        }
     }
 
     forwardRef = (node: HTMLDivElement) => {
@@ -289,12 +299,11 @@ class Body extends BaseComponent<BodyProps, BodyState> {
 
     getVirtualizedRowWidth = () => {
         const { getCellWidths } = this.context;
-        const { columns, anyColumnFixed } = this.props;
+        const { columns } = this.props;
         const cellWidths = getCellWidths(columns);
-        const measuredScrollbarWidth = measureScrollbar('vertical');
         const rowWidth = arrayAdd(cellWidths, 0, size(columns));
 
-        return !anyColumnFixed && measuredScrollbarWidth ? rowWidth - measuredScrollbarWidth : rowWidth;
+        return rowWidth;
     };
 
     renderVirtualizedRow = (options: { index?: number; style?: React.CSSProperties; isScrolling?: boolean }) => {
@@ -396,8 +405,6 @@ class Body extends BaseComponent<BodyProps, BodyState> {
             return null;
         }
 
-        const measuredScrollbarWidth = measureScrollbar('vertical');
-
         const rawY = get(scroll, 'y');
         const yIsNumber = typeof rawY === 'number';
         const y = yIsNumber ? rawY : 600;
@@ -409,8 +416,8 @@ class Body extends BaseComponent<BodyProps, BodyState> {
         const listStyle = {
             width: '100%',
             height: y,
-            overflowX: anyColumnFixed ? 'scroll' : 'auto',
-            overflowY: measuredScrollbarWidth ? 'scroll' : 'auto',
+            overflowX: 'auto',
+            overflowY: 'auto',
         } as const;
 
         const wrapCls = classnames(`${prefixCls}-body`);
@@ -433,6 +440,7 @@ class Body extends BaseComponent<BodyProps, BodyState> {
                 innerElementType={this.renderTbody}
                 outerElementType={this.renderOuter}
                 style={{ ...listStyle, direction }}
+                direction={direction}
             >
                 {this.renderVirtualizedRow}
             </List>

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä