Browse Source

chore: merge release to main

zhangyumei.0319 3 years ago
parent
commit
07467f6b0a
51 changed files with 951 additions and 113 deletions
  1. 2 0
      content/input/checkbox/index-en-US.md
  2. 2 0
      content/input/checkbox/index.md
  3. 1 1
      content/input/datepicker/index-en-US.md
  4. 1 1
      content/input/datepicker/index.md
  5. 2 0
      content/input/radio/index-en-US.md
  6. 2 0
      content/input/radio/index.md
  7. 2 2
      content/show/tag/index-en-US.md
  8. 6 6
      content/show/tag/index.md
  9. 1 0
      content/show/tooltip/index-en-US.md
  10. 1 0
      content/show/tooltip/index.md
  11. 16 0
      content/start/changelog/index-en-US.md
  12. 15 0
      content/start/changelog/index.md
  13. 271 1
      cypress/integration/datePicker.spec.js
  14. 1 1
      lerna.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. 11 2
      packages/semi-foundation/checkbox/checkboxFoundation.ts
  19. 21 0
      packages/semi-foundation/datePicker/_utils/parser.ts
  20. 144 20
      packages/semi-foundation/datePicker/foundation.ts
  21. 49 3
      packages/semi-foundation/datePicker/inputFoundation.ts
  22. 2 2
      packages/semi-foundation/datePicker/monthsGridFoundation.ts
  23. 2 2
      packages/semi-foundation/package.json
  24. 11 0
      packages/semi-foundation/radio/radioFoundation.ts
  25. 5 0
      packages/semi-foundation/tooltip/foundation.ts
  26. 2 2
      packages/semi-icons/package.json
  27. 1 1
      packages/semi-illustrations/package.json
  28. 2 2
      packages/semi-next/package.json
  29. 1 1
      packages/semi-scss-compile/package.json
  30. 1 1
      packages/semi-theme-default/package.json
  31. 16 6
      packages/semi-ui/checkbox/checkbox.tsx
  32. 48 1
      packages/semi-ui/datePicker/_story/datePicker.stories.js
  33. 37 0
      packages/semi-ui/datePicker/_story/v2/AutoFillTime.jsx
  34. 29 0
      packages/semi-ui/datePicker/_story/v2/InputFormat.jsx
  35. 44 0
      packages/semi-ui/datePicker/_story/v2/InputFormatConfirm.jsx
  36. 27 0
      packages/semi-ui/datePicker/_story/v2/InputFormatDisabled.jsx
  37. 4 0
      packages/semi-ui/datePicker/_story/v2/index.js
  38. 7 0
      packages/semi-ui/datePicker/dateInput.tsx
  39. 7 11
      packages/semi-ui/datePicker/datePicker.tsx
  40. 2 1
      packages/semi-ui/datePicker/monthsGrid.tsx
  41. 6 6
      packages/semi-ui/modal/Modal.tsx
  42. 10 11
      packages/semi-ui/modal/confirm.tsx
  43. 9 1
      packages/semi-ui/modal/useModal/index.tsx
  44. 8 8
      packages/semi-ui/package.json
  45. 17 7
      packages/semi-ui/radio/radio.tsx
  46. 1 1
      packages/semi-ui/select/index.tsx
  47. 4 4
      packages/semi-ui/tag/group.tsx
  48. 5 1
      packages/semi-ui/tooltip/index.tsx
  49. 1 1
      packages/semi-ui/treeSelect/index.tsx
  50. 1 1
      packages/semi-webpack/package.json
  51. 88 0
      yarn.lock

+ 2 - 0
content/input/checkbox/index-en-US.md

@@ -399,11 +399,13 @@ import { CheckboxGroup, Checkbox, Row, Col } from '@douyinfe/semi-ui';
 
 | PROPERTIES     | Instructions                                                 | type               | Default |
 | -------------- | ------------------------------------------------------------ | ------------------ | ------- |
+| addonId | id of addon node, aria-labelledby refers to this id, if not set, it will generate an id randomly  **provided after v2.11.0**                                 | string            |       |
 | aria-label     | Define label of the Checkbox  | string | - |
 | checked        | Specify whether the current Checkbox is selected (it is invalid when used in Group)                     | boolean            | false   |
 | defaultChecked | Whether Checked by default (it is invalid when used in Group)                                           | boolean            | false   |
 | disabled       | Disabled state                                               | boolean            | false   |
 | extra          | Provide extra information <br/>**>= v0.25.0**                | ReactNode          | -       |
+| extraId        | id of extra node. aria-describedby refers to this id, if not set, it will randomly generate an id <br/>**provided after v2.11.0**                     | ReactNode         | -      |
 | value          | The value that the checkbox represents in the CheckboxGroup  | any | - |
 | indeterminate  | Set to indeterminate state, style control only               | boolean            | false   |
 | onChange       | Callback function when change                                | function(e: Event) | -       |

+ 2 - 0
content/input/checkbox/index.md

@@ -381,11 +381,13 @@ import { Checkbox, CheckboxGroup, Row, Col } from '@douyinfe/semi-ui';
 
 | 参数 | 说明 | 类型 | 默认值 |
 | --- | --- | --- | --- |
+| addonId | addon 节点 id,aria-labelledby 指向这个 id,若无设置会随机生成一个 id  **v2.11.0 后提供**                                 | string            |       |
 | aria-label | 定义 Checkbox 的作用 | string | - |
 | checked | 指定当前Checkbox是否选中(在Group中使用时无效) | boolean | false |
 | defaultChecked | 初始是否选中(在Group中使用时无效) | boolean | false |
 | disabled | 失效状态 | boolean | false |
 | extra | 副文本<br/>__v0.25.0后提供__ | ReactNode | - |
+| extraId        | 副文本的 id,aria-describedby 指向这个 id,若无设置会随机生成一个 id <br/>**v2.11.0 后提供**                     | ReactNode         | -      |
 | value | 该checkbox在CheckboxGroup中代表的value | any | - |
 | indeterminate | 设置 indeterminate 状态,只负责样式控制 | boolean | false |
 | onChange | 变化时回调函数 | function(e:Event) | - |

+ 1 - 1
content/input/datepicker/index-en-US.md

@@ -784,7 +784,7 @@ function Demo() {
 |--------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------|---------|------------|
 | autoAdjustOverflow | Whether the floating layer automatically adjusts its direction when it is blocked                                                                                                         | boolean                                          | true    | **0.34.0** |
 | autoFocus          | Automatic access to focus                                                                                                                                                                 | boolean                                          | false   | **1.10.0** |
-| autoSwitchDate     | When false is passed in, the date will not be automatically switched when the year and year are changed through the left and right buttons on the top of the panel and the drop-down menu | boolean                                          | true    | **1.13.0** |
+| autoSwitchDate     | When the year and month are changed through the left and right buttons and the drop-down menu at the top of the panel, the date is automatically switched. Only valid for `date` type. | boolean                                          | true    | **1.13.0** |
 | bottomSlot         | Render the bottom extra area                                                                                                                                                              | ReactNode                                        |         | **1.22.0** |
 | className          | Class name                                                                                                                                                                                | string                                           | -       |            |
 | defaultOpen        | Panel displays or hides by default                                                                                                                                                        | boolean                                          | false   |            |

+ 1 - 1
content/input/datepicker/index.md

@@ -746,7 +746,7 @@ function Demo() {
 | --- | --- | --- | --- | --- |
 | autoAdjustOverflow | 浮层被遮挡时是否自动调整方向 | boolean | true | **0.34.0** |
 | autoFocus | 自动获取焦点 | boolean | false | **1.10.0** |
-| autoSwitchDate | 传入 false 时,通过面板上方左右按钮、下拉菜单更改年月时,不会自动切换日期 | boolean | true | **1.13.0** |
+| autoSwitchDate | 通过面板上方左右按钮、下拉菜单更改年月时,自动切换日期。仅对 date type 生效。 | boolean | true | **1.13.0** |
 | bottomSlot | 渲染底部额外区域 | ReactNode |  | **1.22.0** |
 | className | 类名 | string | - |  |
 | defaultOpen | 面板默认显示或隐藏 | boolean | false |  |

+ 2 - 0
content/input/radio/index-en-US.md

@@ -358,6 +358,7 @@ class App extends React.Component {
 | PROPERTIES | Instructions | Type | Default |
 | --- | --- | --- | --- |
 | addonClassName | classname of content wrapper<br/>**provided after v1.16.0** | string |  |
+| addonId | id of addon node, aria-labelledby refers to this id, if not set, it will generate an id randomly  **provided after v2.11.0**                                 | string            |       |
 | addonStyle | inline style of content wrapper<br/>**provided after v1.16.0** | object |  |
 | aria-label      | Label of Radio                                                            | string           | -  |
 | autoFocus | Automatically focus the form control when the page is loaded | boolean | false |
@@ -366,6 +367,7 @@ class App extends React.Component {
 | defaultChecked | Checked by default | boolean | false |
 | disabled | Disable the radio | boolean | false |
 | extra | Extra information displayed <br/>**provided after v0.25.0** | ReactNode | - |
+| extraId        | id of extra node. aria-describedby refers to this id, if not set, it will randomly generate an id <br/>**provided after v2.11.0**                     | ReactNode         | -      |
 | mode | In advanced mode, options can be clicked to uncheck, one of `advanced` | string | - |
 | style | Inline style | CSSProperties |  |
 | value | Compared based on value to determine whether the option is selected | string \| number | - |

+ 2 - 0
content/input/radio/index.md

@@ -318,6 +318,7 @@ class App extends React.Component {
 | 属性           | 说明                                                                   | 类型              | 默认值  |
 |----------------|-----------------------------------------------------------------------|------------------|--------|
 | addonClassName | 包裹内容容器的样式类名  **v1.16.0 后提供**                                 | string            |       |
+| addonId | addon 节点 id,aria-labelledby 指向这个 id,若无设置会随机生成一个 id  **v2.11.0 后提供**                                 | string            |       |
 | addonStyle     | 包裹内容容器的内联样式  **v1.16.0 后提供**                                 | CSSProperties     |       |
 | aria-label      | Radio 的 label                                                            | string           | -  |
 | autoFocus      | 自动获取焦点                                                            | boolean           | false  |
@@ -326,6 +327,7 @@ class App extends React.Component {
 | defaultChecked | 初始是否选中                                                             | boolean           | false  |
 | disabled       | 禁选单选框                                                              |boolean            | false    |
 | extra          | 副文本,只对type='default'生效<br/>**v0.25.0 后提供**                     | ReactNode         | -      |
+| extraId        | 副文本的 id,aria-describedby 指向这个 id,若无设置会随机生成一个 id <br/>**v2.11.0 后提供**                     | ReactNode         | -      |
 | mode           | 高级和普通模式,高级模式可以在 checked 时点击变成 unchecked,可选值 advanced   | string            | -      |
 | style          | 内联样式                                                                 | CSSProperties    |        |
 | value          | 根据 value 进行比较,判断是否选中                                          | string \| number               | -      |

+ 2 - 2
content/show/tag/index-en-US.md

@@ -263,7 +263,7 @@ import { TagGroup } from '@douyinfe/semi-ui';
 ### TagGroup
 
 | Properties | Instructions | type | Default | Version |
-| --- | --- | --- | --- | --- |
+| --- | --- | --- | -- | --- |
 | avatarShape | Shape of avatar tag, one of `square` and `circle` | string | `square` | 1.6.0 |
 | className | Class name | string |  |  |
 | maxTagCount | Cap number to display, shown as + N when exceeded | number |  |  |
@@ -271,7 +271,7 @@ import { TagGroup } from '@douyinfe/semi-ui';
 | showPopover | When hover to + N, whether to display the remaining content through Popover | boolean | false |  |
 | size | Size, one of `small`, `large` | string | `small` |  |
 | style | Inline style | CSSProperties |  |  |
-| tagList | Label Group data | (TagProps \| React.ReactNode)[] |  |  |
+| tagList | Label Group data | (TagProps)[] |  |  |
 
 ## Design Tokens
 

+ 6 - 6
content/show/tag/index.md

@@ -226,15 +226,15 @@ import { TagGroup } from '@douyinfe/semi-ui';
 ### TagGroup
 
 | 属性  | 说明        | 类型   | 默认值 | 版本 |
-|-------|-------------|-----------------|--------|--------|
+|-------|-------------|--------------|----|--------|
 | avatarShape | 头像 Tag 形状,可选 `square` 和 `circle` | string |  `square` | 1.6.0 |
-| className | 类名 | string |     | |
-| maxTagCount | 最大数量限制,超出后显示为 +N | number |     | |
+| className | 类名 | string |    | |
+| maxTagCount | 最大数量限制,超出后显示为 +N | number |    | |
 | popoverProps | popover 的配置属性,可以控制 direction, zIndex, trigger 等,具体参考 [Popover](/zh-CN/show/popover#API_参考) | PopoverProps | {} | |
 | showPopover | hover 到 +N 时,是否通过 Popover 显示剩余内容 | boolean | false | |
 | size | 标签的尺寸,可选 `small`、 `large` | string | `small` | |
-| style | 样式 | CSSProperties |     | |
-| tagList | 标签组  | (TagProps \| React.ReactNode)[] |     | |
+| style | 样式 | CSSProperties |    | |
+| tagList | 标签组  | (TagProps)[] |     | |
 
 ## 设计变量
 <DesignToken/>
@@ -242,4 +242,4 @@ import { TagGroup } from '@douyinfe/semi-ui';
 <!-- ## 相关物料
 ```material
 53
-``` -->
+``` -->

+ 1 - 0
content/show/tooltip/index-en-US.md

@@ -421,6 +421,7 @@ import { Popconfirm, Tooltip, Button } from '@douyinfe/semi-ui';
 | trigger | Timing of triggering display, optional value: `hover`/`focus`/`click`/`custom` | string | 'hover' |  |
 | visible | Whether to show the pop-up layer | boolean |  |  |
 | wrapperClassName | When children are disabled or children are multiple elements, the outer layer will wrap a layer of span elements, and the api is used to set the style class name of this span | string |  | 1.32.0 |
+| wrapperId | The id of the wrapper node of the popup layer. The aria attribute of the trigger points to this id. | string |  | 2.11.0  |
 | zIndex              | Bullet levels.                                                                                                                                                                                                                               | number                      | 1060                |            |
 | onVisibleChange     | A callback triggered when the pop-up layer is displayed/hidden                                                                                                                                                                               | (isVisible: boolean) => void |                     |            |
 | onClickOutSide      | Callback when the pop-up layer is in the display state and the non-Children, non-floating layer inner area is clicked (only valid when trigger is custom, click)                                                                             | (e:event) => void           |                     | **2.1.0** |

+ 1 - 0
content/show/tooltip/index.md

@@ -454,6 +454,7 @@ function Demo() {
 | trigger | 触发展示的时机,可选值:`hover` / `focus` / `click` / `custom` | string | 'hover' |  |
 | visible | 是否展示弹出层 | boolean |  |  |
 | wrapperClassName | 当 children 为 disabled ,或者 children 为多个元素时,外层将会包裹一层 span 元素,该 api 用于设置此 span 的样式类名 | string |  | **1.32.0** |
+| wrapperId | 弹出层 wrapper 节点的 id,trigger 的 aria 属性指向此 id,若不设置组件会随机生成一个 id | string |  | 2.11.0  |
 | zIndex | 弹层层级 | number | 1060 |  |
 | onVisibleChange | 弹出层展示/隐藏时触发的回调 | function(isVisible:boolean) |  |  |
 | onClickOutSide | 当弹出层处于展示状态,点击非Children、非浮层内部区域时的回调(仅trigger为custom、click时有效)| function(e:event) |  | **2.1.0** |

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

@@ -16,11 +16,27 @@ Version:Major.Minor.Patch
 
 ---
 
+#### 🎉 2.11.0-beta.1 (2022-05-20)
+- 【Fix】
+  -  Fixed the issue that DatePicker incorrectly referenced the _utils/parse ts source file, resulting in an error
+
 #### 🎉 2.10.2 (2022-05-20)
 - 【Fix】
     - Fixed  Table onHeaderRow does not take effect when setting scroll prop  [#849](https://github.com/DouyinFE/semi-design/issues/849)
     - Fixed Select aria-controls are inconsistent in SSR scenarios  [#840](https://github.com/DouyinFE/semi-design/issues/840)
 
+#### 🎉 2.11.0-beta.0 (2022-05-18)
+- 【Feat】
+    - After entering the full date in the DatePicker inset input box, the time input box automatically fills the default time  [#294](https://github.com/DouyinFE/semi-design/issues/294)
+    - DatePicker range type supports entering start date or end date, the panel displays the specified date  [#294](https://github.com/DouyinFE/semi-design/issues/294)
+- 【Fix】
+    - Fixed the problem of needConfirm DatePicker that the date will be directly selected without confirmation after entering the date in the inset input box  [#742](https://github.com/DouyinFE/semi-design/issues/742)
+    - Fix the problem that `can't get properties of undefined` is prompted when using Form, Tabs, and Nav components in React 18 createRoot + strictMode strict mode #745  [#795 ](https://github.com/DouyinFE/semi-design/issues/795)
+    - Fix the problem that the upload list file does not meet expectations when the directory and draggable are true for the Upload component  [#827 ](https://github.com/DouyinFE/semi-design/issues/827)
+    - Fixed a warning prompt on the console due to the parameter type problem when using a single Checkbox
+    - Fix Checkbox, Radio, Tooltip ARIA id inconsistency in SSR  [#719](https://github.com/DouyinFE/semi-design/issues/719)
+    - Specification TagGroup tagList props type
+
 #### 🎉 2.10.1 (2022-05-10)
 - 【Fix】
     - Fix the problem that when Select is inside the Popover, clicking Option will cause the outer Popover to be collapsed (the issue affects v2.5-v2.10) [#818](https://github.com/DouyinFE/semi-design/issues/818)

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

@@ -15,11 +15,26 @@ Semi 版本号遵循**Semver**规范(主版本号-次版本号-修订版本号
 
 ---
 
+#### 🎉 2.11.0-beta.1 (2022-05-20)
+- 【Fix】
+  -  修复 DatePicker 错误引用 _utils/parse ts源文件导致报错的问题
+
 #### 🎉 2.10.2 (2022-05-20)
 - 【Fix】
     - 修复 Table onHeaderRow 在配置 scroll 属性时不生效问题  [#849](https://github.com/DouyinFE/semi-design/issues/849)
     - 修复 Select aria-controls 在 SSR 场景不一致问题  [#840](https://github.com/DouyinFE/semi-design/issues/840)
 
+#### 🎉 2.11.0-beta.0 (2022-05-18)
+- 【Feat】
+    - DatePicker 内嵌输入框输入完整日期后,时间输入框自动填充默认时间  [#294](https://github.com/DouyinFE/semi-design/issues/294)
+    - DatePicker 范围选择支持输入开始日期或结束日期后,面板显示指定日期  [#294](https://github.com/DouyinFE/semi-design/issues/294)
+- 【Fix】
+    - 修复内嵌输入框确认日期选择,输入日期后没有确认也会直接选中日期问题  [#742](https://github.com/DouyinFE/semi-design/issues/742)
+    - 修复 React 18 createRoot + strictMode 严格模式下,使用 Form、Tabs、Nav 、SideSheet 、Table 组件时提示 `can't get properties of undefined` 的问题 #745  [#795 ](https://github.com/DouyinFE/semi-design/issues/795)
+    - 修复 Upload 组件在 directory 和 draggable 为true时上传,上传列表文件不符合预期问题  [#827 ](https://github.com/DouyinFE/semi-design/issues/827)
+    - 修复单个 Checkbox使用时因为参数类型问题导致控制台出现warning提示
+    - 修复 Checkbox、Radio、Tooltip ARIA id 在 SSR 时不一致问题  [#719](https://github.com/DouyinFE/semi-design/issues/719)
+    - 规范 TagGroup tagList props 类型
 
 #### 🎉 2.10.1 (2022-05-10)
 - 【Fix】

+ 271 - 1
cypress/integration/datePicker.spec.js

@@ -35,7 +35,7 @@ describe('DatePicker', () => {
         cy.get('[data-cy=1] .semi-input').should('have.value', '2021-12-15 10:37:13');
     });
 
-    it('dateTime needConfirm select+cancel', () => {
+    it('dateTime needConfirm select + cancel', () => {
         cy.visit('http://localhost:6006/iframe.html?id=datepicker--fix-need-confirm&args=&viewMode=story');
         cy.get('[data-cy=1] .semi-input-wrapper').click();
         cy.get('.semi-datepicker-day').contains('15')
@@ -302,4 +302,274 @@ describe('DatePicker', () => {
         cy.get('[data-cy=dateRange] .semi-datepicker-range-input-wrapper-start .semi-input').should('have.value', '2022-07-10');
         cy.get('[data-cy=dateRange] .semi-datepicker-range-input-wrapper-end .semi-input').should('have.value', '2022-10-11');
     });
+
+    // 输入完整日期,面板需要同步变化
+    it('input a valid date + change panel selected date', () => {
+        cy.visit('http://localhost:6006/iframe.html?id=datepicker--input-format&args=&viewMode=story');
+        cy.get('[data-cy=date] .semi-input').first().click();
+        cy.get('[data-cy=date] .semi-input').first().type('2021-03-15');
+        cy.get('[x-type=date] .semi-datepicker-navigation-month').contains("2021年 3月");
+        cy.get('[x-type=date] .semi-datepicker-day-selected').contains("15");
+    });
+
+    // 输入结束日期,面板需要同步变化
+    it('input start + change panel selected date', () => {
+        cy.visit('http://localhost:6006/iframe.html?id=datepicker--input-format&args=&viewMode=story');
+        cy.get('[data-cy=dateRange] .semi-input').eq(1).click();
+        cy.get('[data-cy=dateRange] .semi-input').eq(1).type('2021-03-15');
+        cy.get('[x-type=dateRange] .semi-datepicker-navigation-month').contains("2021年 3月");
+        cy.get('[x-type=dateRange] .semi-datepicker-day-selected-end').contains("15");
+    });
+
+    // 输入开始和结束日期后,通过滚轮修改年月,面板和输入框需要同时发生变化
+    // 暂时去掉了这个需求
+    it.skip('input start + end then change year or month from scroll list', () => {
+        cy.visit('http://localhost:6006/iframe.html?id=datepicker--input-format&args=&viewMode=story');
+        // input date
+        cy.get('[data-cy=dateRange] .semi-input').first().click();
+        cy.get('[data-cy=dateRange] .semi-input').first().type('2021-03-15');
+        cy.get('[x-type=dateRange] .semi-datepicker-navigation-month').first().contains("2021年 3月");
+        cy.get('[x-type=dateRange] .semi-datepicker-day-selected-start').contains("15");
+        cy.get('[data-cy=dateRange] .semi-input').eq(1).click();
+        cy.get('[data-cy=dateRange] .semi-input').eq(1).type('2021-05-15');
+        cy.get('[x-type=dateRange] .semi-datepicker-navigation-month').last().contains("2021年 5月");
+        cy.get('[x-type=dateRange] .semi-datepicker-day-selected-end').contains("15");
+        // click right scroll list
+        cy.get('[x-type=dateRange] .semi-datepicker-navigation-month').last().click();
+        cy.get('.semi-scrolllist-list-outer li').contains('2022').click();
+        cy.get('.semi-datepicker-yam .semi-datepicker-yearmonth-header .semi-button').click();
+        cy.get('[data-cy=dateRange] .semi-input').last().should('have.value', '2022-05-15');
+        cy.get('[x-type=dateRange] .semi-datepicker-navigation-month').last().contains("2022年 5月");
+        // click left scroll list
+        cy.get('[x-type=dateRange] .semi-datepicker-navigation-month').first().click();
+        cy.get('.semi-scrolllist-list-outer li').contains('2022').click();
+        cy.get('.semi-datepicker-yam .semi-datepicker-yearmonth-header .semi-button').click();
+        cy.get('[data-cy=dateRange] .semi-input').first().should('have.value', '2022-03-15');
+        cy.get('[x-type=dateRange] .semi-datepicker-navigation-month').first().contains("2022年 3月");
+    });
+
+    // 输入开始和结束日期后,输入一个不合法的日期,输入框恢复到上次合法日期
+    it('input invalid in date type + blur', () => {
+        cy.visit('http://localhost:6006/iframe.html?id=datepicker--input-format&args=&viewMode=story');
+        cy.get('[data-cy=date] .semi-input').first().click();
+        cy.get('[data-cy=date] .semi-input').first().type('2021-03-15');
+        cy.get('[data-cy=date] .semi-input').first().type('123');
+        // 失焦
+        cy.get('[data-cy=container').click({ force: true });
+        // 恢复到上一次选中时间
+        cy.get('[data-cy=date] .semi-input').first().should('have.value', '2021-03-15');
+    });
+
+    // 输入开始和结束日期后,输入一个不合法的日期,输入框恢复到上次合法日期
+    it('input invalid in dateRange + blur', () => {
+        cy.visit('http://localhost:6006/iframe.html?id=datepicker--input-format&args=&viewMode=story');
+        // input date
+        cy.get('[data-cy=dateRange] .semi-input').first().click();
+        cy.get('[data-cy=dateRange] .semi-input').first().type('2021-03-15');
+        cy.get('[data-cy=dateRange] .semi-input').eq(1).click();
+        cy.get('[data-cy=dateRange] .semi-input').eq(1).type('2021-05-15');
+        // 输入不合法日期
+        cy.get('[data-cy=dateRange] .semi-input').first().click();
+        cy.get('[data-cy=dateRange] .semi-input').first().type('abc');
+        cy.get('[data-cy=dateRange] .semi-input').eq(1).click();
+        cy.get('[data-cy=dateRange] .semi-input').eq(1).type('abc');
+        cy.get('[data-cy=container').click({ force: true });
+        cy.get('[data-cy=dateRange] .semi-input').first().should('have.value', '2021-03-15');
+        cy.get('[data-cy=dateRange] .semi-input').eq(1).should('have.value', '2021-05-15');
+    });
+
+    // 输入开始和结束日期后,输入一个不合法的日期,输入框恢复到上次合法日期
+    it('input invalid in dateTime + blur', () => {
+        cy.visit('http://localhost:6006/iframe.html?id=datepicker--input-format&args=&viewMode=story');
+        // input date
+        cy.get('[data-cy=dateTime] .semi-input').first().click();
+        cy.get('[data-cy=dateTime] .semi-input').first().type('2021-03-15 00:00:00');
+        // 输入不合法日期
+        cy.get('[data-cy=dateTime] .semi-input').first().click();
+        cy.get('[data-cy=dateTime] .semi-input').first().type('abc');
+        cy.get('[data-cy=container').click({ force: true });
+        cy.get('[data-cy=dateTime] .semi-input').first().should('have.value', '2021-03-15 00:00:00');
+    });
+
+    it('input only invalid in date type + blur', () => {
+        cy.visit('http://localhost:6006/iframe.html?id=datepicker--input-format&args=&viewMode=story');
+        cy.get('[data-cy=date] .semi-input').first().click();
+        cy.get('[data-cy=date] .semi-input').first().type('abc');
+        cy.get('[data-cy=container').click({ force: true });
+        cy.get('[data-cy=date] .semi-input').first().should('have.value', '');
+    });
+
+    it('input only invalid in dateRange + blur', () => {
+        cy.visit('http://localhost:6006/iframe.html?id=datepicker--input-format&args=&viewMode=story');
+        cy.get('[data-cy=dateRange] .semi-input').first().click();
+        cy.get('[data-cy=dateRange] .semi-input').first().type('abc');
+        cy.get('[data-cy=dateRange] .semi-input').eq(1).click();
+        cy.get('[data-cy=dateRange] .semi-input').eq(1).type('123');
+        cy.get('[data-cy=container').click({ force: true });
+        cy.get('[data-cy=dateRange] .semi-input').first().should('have.value', '');
+        cy.get('[data-cy=dateRange] .semi-input').eq(1).should('have.value', '');
+    });
+
+    it('input only invalid in dateTime + blur', () => {
+        cy.visit('http://localhost:6006/iframe.html?id=datepicker--input-format&args=&viewMode=story');
+        cy.get('[data-cy=dateTime] .semi-input').first().click();
+        cy.get('[data-cy=dateTime] .semi-input').first().type('123');
+        cy.get('[data-cy=container').click({ force: true });
+        cy.get('[data-cy=dateTime] .semi-input').first().should('have.value', '');
+    });
+
+    // 输入禁用日期,面板不需要同步变化
+    it('input a disabled date + change panel selected date', () => {
+        cy.visit('http://localhost:6006/iframe.html?id=datepicker--input-format-disabled&args=&viewMode=story');
+        cy.get('[data-cy=date] .semi-input').first().click();
+        cy.get('[data-cy=date] .semi-input').first().type('2021-03-15');
+        cy.get('[x-type=date] .semi-datepicker-day-selected').should('not.exist');
+    });
+
+    it('auto fill time + dateTime', () => {
+        cy.visit('http://localhost:6006/iframe.html?id=datepicker--auto-fill-time&viewMode=story');
+        cy.get('[data-cy=dateTime] .semi-input').first().click();
+        cy.get('[x-type=dateTime] .semi-input').first().type('2021-03-15');
+        cy.get('[x-type=dateTime] .semi-input').eq(1).should('have.value', '14:00');
+    });
+
+    it('auto fill time invalid + dateTime', () => {
+        cy.visit('http://localhost:6006/iframe.html?id=datepicker--auto-fill-time&viewMode=story');
+        cy.get('[data-cy=dateTime] .semi-input').first().click();
+        cy.get('[x-type=dateTime] .semi-input').first().type('2021-03-');
+        cy.get('[x-type=dateTime] .semi-input').eq(1).should('have.value', '');
+    });
+
+    it('auto fill time + dateTimeRange', () => {
+        cy.visit('http://localhost:6006/iframe.html?id=datepicker--auto-fill-time&viewMode=story');
+        cy.get('[data-cy=dateTimeRange] .semi-input').first().click();
+        cy.get('[x-type=dateTimeRange] .semi-input').first().type('2021-01-01');
+        cy.get('[x-type=dateTimeRange] .semi-input').eq(1).should('have.value', '00:01');
+        cy.get('[x-type=dateTimeRange] .semi-input').eq(2).type('2021-03-01');
+        cy.get('[x-type=dateTimeRange] .semi-input').eq(3).should('have.value', '23:59');
+    });
+
+    it('input date + needConfirm + cancel', () => {
+        cy.visit('http://localhost:6006/iframe.html?id=datepicker--input-format-confirm&args=&viewMode=story');
+        cy.get('[data-cy=dateTime] .semi-input').first().click();
+        cy.get('[data-cy=dateTime] .semi-input').first().type('2021-03-15 14:00');
+        cy.get('.semi-datepicker-footer .semi-button').first().click();
+        cy.get('[data-cy=dateTime] .semi-input').first().should('have.value', '');
+    });
+
+    it('input date + needConfirm + confirm', () => {
+        cy.visit('http://localhost:6006/iframe.html?id=datepicker--input-format-confirm&args=&viewMode=story');
+        cy.get('[data-cy=dateTime] .semi-input').first().click();
+        cy.get('[data-cy=dateTime] .semi-input').first().type('2021-03-15 14:00');
+        cy.get('.semi-datepicker-footer .semi-button').eq(1).click();
+        cy.get('[data-cy=dateTime] .semi-input').first().should('have.value', '2021-03-15 14:00');
+    });
+
+    it('input date range + needConfirm + cancel', () => {
+        cy.visit('http://localhost:6006/iframe.html?id=datepicker--input-format-confirm&args=&viewMode=story');
+        cy.get('[data-cy=dateTimeRange] .semi-input').first().click().type('2021-03-15 14:00');
+        cy.get('[data-cy=dateTimeRange] .semi-input').eq(1).click().type('2021-03-20 23:59');
+        cy.get('.semi-datepicker-footer .semi-button').eq(0).click();
+        cy.get('[data-cy=dateTimeRange] .semi-input').eq(0).should('have.value', '');
+        cy.get('[data-cy=dateTimeRange] .semi-input').eq(1).should('have.value', '');
+    });
+
+    it('input date range + needConfirm + confirm', () => {
+        cy.visit('http://localhost:6006/iframe.html?id=datepicker--input-format-confirm&args=&viewMode=story');
+        cy.get('[data-cy=dateTimeRange] .semi-input').first().click().type('2021-03-15 14:00');
+        cy.get('[data-cy=dateTimeRange] .semi-input').eq(1).click().type('2021-03-20 23:59');
+        cy.get('.semi-datepicker-footer .semi-button').eq(1).click();
+        cy.get('[data-cy=dateTimeRange] .semi-input').eq(0).should('have.value', '2021-03-15 14:00');
+        cy.get('[data-cy=dateTimeRange] .semi-input').eq(1).should('have.value', '2021-03-20 23:59');
+    });
+
+    it('input date + needConfirm + cancel', () => {
+        cy.visit('http://localhost:6006/iframe.html?id=datepicker--input-format-confirm&args=&viewMode=story');
+        cy.get('[data-cy=inset-switch]').click();
+        cy.get('[data-cy=dateTime] .semi-input').first().click();
+        cy.get('[x-type=dateTime] .semi-input').eq(0).type('2021-03-15');
+        cy.get('.semi-datepicker-footer .semi-button').eq(0).click();
+        cy.get('[data-cy=dateTime] .semi-input').first().should('have.value', '');
+    });
+
+    it('input date + needConfirm + confirm', () => {
+        cy.visit('http://localhost:6006/iframe.html?id=datepicker--input-format-confirm&args=&viewMode=story');
+        cy.get('[data-cy=inset-switch]').click();
+        cy.get('[data-cy=dateTime] .semi-input').first().click();
+        cy.get('[x-type=dateTime] .semi-input').eq(0).type('2021-03-15');
+        cy.get('.semi-datepicker-footer .semi-button').eq(1).click();
+        cy.get('[data-cy=dateTime] .semi-input').first().should('have.value', '2021-03-15 14:00');
+    });
+
+    it('input date range + needConfirm + cancel', () => {
+        cy.visit('http://localhost:6006/iframe.html?id=datepicker--input-format-confirm&args=&viewMode=story');
+        cy.get('[data-cy=inset-switch]').click();
+        cy.get('[data-cy=dateTimeRange] .semi-input').first().click();
+        cy.get('[x-type=dateTimeRange] .semi-input').eq(0).type('2021-03-15');
+        cy.get('[x-type=dateTimeRange] .semi-input').eq(2).type('2021-03-20');
+        cy.get('.semi-datepicker-footer .semi-button').eq(0).click();
+        cy.get('[data-cy=dateTimeRange] .semi-input').eq(0).should('have.value', '');
+        cy.get('[data-cy=dateTimeRange] .semi-input').eq(1).should('have.value', '');
+    });
+
+    it('input date range + needConfirm + confirm', () => {
+        cy.visit('http://localhost:6006/iframe.html?id=datepicker--input-format-confirm&args=&viewMode=story');
+        cy.get('[data-cy=inset-switch]').click();
+        cy.get('[data-cy=dateTimeRange] .semi-input').first().click();
+        cy.get('[x-type=dateTimeRange] .semi-input').eq(0).type('2021-03-15');
+        cy.get('[x-type=dateTimeRange] .semi-input').eq(2).type('2021-03-20');
+        cy.get('.semi-datepicker-footer .semi-button').eq(1).click();
+        cy.get('[data-cy=dateTimeRange] .semi-input').eq(0).should('have.value', '2021-03-15 00:01');
+        cy.get('[data-cy=dateTimeRange] .semi-input').eq(1).should('have.value', '2021-03-20 23:59');
+    });
+
+    it('cashedSelectedValue return to last selected when needConfirm & input invalid', () => {
+        cy.visit('http://localhost:6006/iframe.html?id=datepicker--need-confirm-delete&args=&viewMode=story');
+        cy.get('[data-cy=dateTimeRange] .semi-input').first().click();
+        cy.get('[data-cy=dateTimeRange] .semi-input').eq(0).clear().type('2021-0');
+        cy.get('.semi-datepicker-footer .semi-button').eq(0).click();
+        cy.get('[data-cy=dateTimeRange] .semi-input').first().click();
+        cy.get('.semi-popover .semi-datepicker-day-selected-start').contains('8');
+        cy.get('.semi-popover .semi-datepicker-day-selected-end').contains('9');
+    });
+
+    it('cashedSelectedValue after selected date', () => {
+        cy.visit('http://localhost:6006/iframe.html?id=datepicker--cashed-selected-value&viewMode=story');
+        cy.get('[data-cy=date] .semi-input').first().click();
+        cy.get('.semi-datepicker-day').contains("5").click();
+        cy.get('[data-cy=date] .semi-input').first().click();
+        cy.get('.semi-popover .semi-datepicker-day-selected').contains('5');
+
+        cy.get('[data-cy=dateTime] .semi-input').first().click();
+        cy.get('.semi-datepicker-day').contains("5").click();
+        cy.get('[data-cy=dateTime] .semi-input').first().click();
+        cy.get('.semi-popover .semi-datepicker-day-selected').contains('5');
+
+        cy.get('[data-cy=dateRange] .semi-input').eq(0).click();
+        cy.get('.semi-datepicker-day').contains("5").click();
+        cy.get('[data-cy=dateRange] .semi-input').eq(1).click();
+        cy.get('.semi-datepicker-day').contains("20").click();
+        cy.get('[data-cy=dateRange] .semi-input').eq(0).click();
+        cy.get('.semi-popover .semi-datepicker-day-selected-start').contains('5');
+        cy.get('.semi-popover .semi-datepicker-day-selected-end').contains('20');
+    });
+
+    it('cashedSelectedValue after click outside', () => {
+        cy.visit('http://localhost:6006/iframe.html?id=datepicker--cashed-selected-value&viewMode=story');
+        cy.get('[data-cy=date] .semi-input').first().click();
+        cy.get('[data-cy=date]').click({ force: true });
+        cy.get('[data-cy=date] .semi-input').first().click();
+        cy.get('.semi-popover .semi-datepicker-day-selected').contains('8');
+
+        cy.get('[data-cy=dateTime] .semi-input').first().click();
+        cy.get('[data-cy=dateTime]').click({ force: true });
+        cy.get('[data-cy=dateTime] .semi-input').first().click();
+        cy.get('.semi-popover .semi-datepicker-day-selected').contains('8');
+
+        cy.get('[data-cy=dateRange] .semi-input').first().click();
+        cy.get('[data-cy=dateRange]').click({ force: true });
+        cy.get('[data-cy=dateRange] .semi-input').first().click();
+        cy.get('.semi-popover .semi-datepicker-day-selected-start').contains('8');
+        cy.get('.semi-popover .semi-datepicker-day-selected-end').contains('9');
+    });
 });

+ 1 - 1
lerna.json

@@ -1,5 +1,5 @@
 {
     "useWorkspaces": true,
     "npmClient": "yarn",
-    "version": "2.10.2"
+    "version": "2.11.0-beta.1"
 }

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

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

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

@@ -1,6 +1,6 @@
 {
   "name": "@douyinfe/semi-animation-styled",
-  "version": "2.10.2",
+  "version": "2.11.0-beta.1",
   "description": "semi styled animation",
   "keywords": [
     "semi",

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

@@ -1,6 +1,6 @@
 {
   "name": "@douyinfe/semi-animation",
-  "version": "2.10.2",
+  "version": "2.11.0-beta.1",
   "description": "animation base library for semi-ui",
   "keywords": [
     "animation",

+ 11 - 2
packages/semi-foundation/checkbox/checkboxFoundation.ts

@@ -21,6 +21,8 @@ export interface CheckboxAdapter<P = Record<string, any>, S = Record<string, any
     setNativeControlChecked: (checked: boolean) => void;
     getState: noopFunction;
     notifyChange: (event: BasicCheckboxEvent) => void;
+    setAddonId: () => void;
+    setExtraId: () => void;
 }
 
 class CheckboxFoundation<P = Record<string, any>, S = Record<string, any>> extends BaseFoundation<CheckboxAdapter<P, S>, P, S> {
@@ -29,8 +31,15 @@ class CheckboxFoundation<P = Record<string, any>, S = Record<string, any>> exten
         super({ ...adapter });
     }
 
-    // eslint-disable-next-line @typescript-eslint/no-empty-function
-    init() {}
+    init() {
+        const { children, extra, extraId, addonId } = this.getProps();
+        if (children && !addonId) {
+            this._adapter.setAddonId();
+        }
+        if (extra && !extraId) {
+            this._adapter.setExtraId();
+        }
+    }
 
     getEvent(checked: boolean, e: any) {
         const props = this.getProps();

+ 21 - 0
packages/semi-foundation/datePicker/_utils/parser.ts

@@ -32,3 +32,24 @@ export function compatibleParse(
     }
     return result;
 }
+
+
+/**
+ * whether value can be parsed with date-fns `parse`
+ * 
+ * @example
+ * isValueParseValid({ value: '2021-01-01', formatToken: 'yyyy-MM-dd' }); // true
+ * isValueParseValid({ value: '2021-01-0', formatToken: 'yyyy-MM-dd' }); // false
+ * isValueParseValid({ value: '2021-01', formatToken: 'yyyy-MM-dd' }); // false
+ */
+export function isValueParseValid(options: {
+    value: string;
+    formatToken: string;
+    baseDate?: Date;
+    locale?: Locale;
+}) {
+    const { value, locale, formatToken } = options;
+    const baseDate = options.baseDate || new Date();
+    const result = parse(value, formatToken, baseDate, { locale });
+    return isValid(result);
+}

+ 144 - 20
packages/semi-foundation/datePicker/foundation.ts

@@ -244,10 +244,7 @@ export default class DatePickerFoundation extends BaseFoundation<DatePickerAdapt
         this._adapter.updatePrevTimezone(prevTimeZone);
         this._adapter.updateInputValue(null);
         this._adapter.updateValue(result);
-
-        if (this._adapter.needConfirm()) {
-            this._adapter.updateCachedSelectedValue(result);
-        }
+        this.resetCachedSelectedValue(result);
     }
 
     parseWithTimezone(value: ValueType, timeZone: string | number, prevTimeZone: string | number) {
@@ -370,6 +367,9 @@ export default class DatePickerFoundation extends BaseFoundation<DatePickerAdapt
         }
     }
 
+    /**
+     * call it when change state value or input value
+     */
     resetCachedSelectedValue(willUpdateDates?: Date[]) {
         const { value, cachedSelectedValue } = this._adapter.getStates();
         const newCachedSelectedValue = Array.isArray(willUpdateDates) ? willUpdateDates : value;
@@ -391,8 +391,8 @@ export default class DatePickerFoundation extends BaseFoundation<DatePickerAdapt
      * @param {Date[]} dates
      */
     closePanel(e?: any, inputValue: string = null, dates?: Date[]) {
-        const { value, cachedSelectedValue } = this._adapter.getStates();
-        const willUpdateDates = isNullOrUndefined(dates) ? this._adapter.needConfirm() ? value : cachedSelectedValue : dates;
+        const { value } = this._adapter.getStates();
+        const willUpdateDates = isNullOrUndefined(dates) ? value : dates;
         if (!this._isControlledComponent('open')) {
             this._adapter.togglePanel(false);
             this._adapter.unregisterClickOutSide();
@@ -426,6 +426,7 @@ export default class DatePickerFoundation extends BaseFoundation<DatePickerAdapt
     handleInputChange(input: string, e: any) {
         const result = this._isMultiple() ? this.parseMultipleInput(input) : this.parseInput(input);
         const { value: stateValue } = this.getStates();
+        this._updateCachedSelectedValueFromInput(input);
         // Enter a valid date or empty
         if ((result && result.length) || input === '') {
             // If you click the clear button
@@ -437,9 +438,6 @@ export default class DatePickerFoundation extends BaseFoundation<DatePickerAdapt
             // Updates the selected value when entering a valid date
             const changedDates = this._getChangedDates(result);
             if (!this._someDateDisabled(changedDates)) {
-                if (this._adapter.needConfirm()) {
-                    this._adapter.updateCachedSelectedValue(result);
-                }
                 if (!isEqual(result, stateValue)) {
                     this._notifyChange(result);
                 }
@@ -460,15 +458,13 @@ export default class DatePickerFoundation extends BaseFoundation<DatePickerAdapt
         const _isMultiple = this._isMultiple();
         const result = _isMultiple ? this.parseMultipleInput(insetInputStr, format) : this.parseInput(insetInputStr, format);
         const { value: stateValue } = this.getStates();
+        this._updateCachedSelectedValueFromInput(insetInputStr);
 
         if ((result && result.length)) {
             const changedDates = this._getChangedDates(result);
             if (!this._someDateDisabled(changedDates)) {
-                if (this._adapter.needConfirm()) {
-                    this._adapter.updateCachedSelectedValue(result);
-                }
                 if (!isEqual(result, stateValue)) {
-                    if (!this._isControlledComponent()) {
+                    if (!this._isControlledComponent() && !this._adapter.needConfirm()) {
                         this._adapter.updateValue(result);
                     }
                     this._notifyChange(result);
@@ -480,6 +476,17 @@ export default class DatePickerFoundation extends BaseFoundation<DatePickerAdapt
         this._adapter.updateInsetInputValue(insetInputValue);
     }
 
+    /**
+     * when input change we reset cached selected value
+     */
+    _updateCachedSelectedValueFromInput(input: string) {
+        const looseResult = this.getLooseDateFromInput(input);
+        const changedLooseResult = this._getChangedDates(looseResult);
+        if (!this._someDateDisabled(changedLooseResult)) {
+            this.resetCachedSelectedValue(looseResult);
+        }
+    }
+
     /**
      * Input box blur
      * @param {String} input
@@ -504,6 +511,19 @@ export default class DatePickerFoundation extends BaseFoundation<DatePickerAdapt
         } else {
             this._updateValueAndInput(stateValue);
         }
+
+        /**
+         * 当不是范围类型且不需要确认时,使用 stateValue 重置 cachedSelectedValue
+         * 这样做的目的是,在输入非法值时,使用上次选中的值作为已选值
+         * needConfirm 或者 range type 时,我们在 close panel 时调用 resetCachedSelectedValue,这里不用重复调用
+         * 
+         * Use stateValue to reset cachedSelectedValue when it is not a range type and does not require confirmation
+         * The purpose of this is to use the last selected value as the selected value when an invalid value is entered
+         * When needConfirm or range type, we call resetCachedSelectedValue when close panel, no need to call repeatedly here
+         */
+        if (!this._adapter.needConfirm() && !this._isRangeType()) {
+            this.resetCachedSelectedValue(stateValue);
+        }
     }
 
     /**
@@ -551,9 +571,7 @@ export default class DatePickerFoundation extends BaseFoundation<DatePickerAdapt
         const inputValue = '';
         if (!this._isControlledComponent('value')) {
             this._updateValueAndInput(value, true, inputValue);
-            if (this._adapter.needConfirm()) {
-                this._adapter.updateCachedSelectedValue(value);
-            }
+            this.resetCachedSelectedValue(value);
         }
         this._notifyChange(value);
         this._adapter.notifyClear(e);
@@ -646,6 +664,115 @@ export default class DatePickerFoundation extends BaseFoundation<DatePickerAdapt
         return result;
     }
 
+    /**
+     * get date which may include null from input
+     */
+    getLooseDateFromInput(input: string): Array<Date | null> {
+        const value = this._isMultiple() ? this.parseMultipleInputLoose(input) : this.parseInputLoose(input);
+        return value;
+    }
+
+    /**
+     * parse input into `Array<Date|null>`, loose means return value includes `null`
+     * 
+     * @example
+     * ```javascript
+     * parseInputLoose('2022-03-15 ~ '); // [Date, null]
+     * parseInputLoose(' ~ 2022-03-15 '); // [null, Date]
+     * parseInputLoose(''); // []
+     * parseInputLoose('2022-03- ~ 2022-0'); // [null, null]
+     * ```
+     */
+    parseInputLoose(input = ''): Array<Date | null> {
+        let result: Array<Date | null> = [];
+        const { dateFnsLocale, rangeSeparator, type, format } = this.getProps();
+
+        if (input && input.length) {
+            const formatToken = format || getDefaultFormatTokenByType(type);
+            let parsedResult, formatedInput;
+            const nowDate = new Date();
+            switch (type) {
+                case 'date':
+                case 'dateTime':
+                case 'month':
+                    const _parsedResult = compatibleParse(input, formatToken, nowDate, dateFnsLocale);
+                    if (isValidDate(_parsedResult)) {
+                        formatedInput = this.localeFormat(_parsedResult as Date, formatToken);
+                        if (formatedInput === input) {
+                            parsedResult = _parsedResult;
+                        }
+                    } else {
+                        parsedResult = null;
+                    }
+                    result = [parsedResult];
+                    break;
+                case 'dateRange':
+                case 'dateTimeRange':
+                    const separator = rangeSeparator;
+                    const values = input.split(separator);
+                    parsedResult =
+                        values &&
+                        values.reduce((arr, cur) => {
+                            let parsedVal = null;
+                            const _parsedResult = compatibleParse(cur, formatToken, nowDate, dateFnsLocale);
+                            if (isValidDate(_parsedResult)) {
+                                formatedInput = this.localeFormat(_parsedResult as Date, formatToken);
+                                if (formatedInput === cur) {
+                                    parsedVal = _parsedResult;
+                                }
+                            }
+                            arr.push(parsedVal);
+                            return arr;
+                        }, []);
+                    if (Array.isArray(parsedResult) && parsedResult.every(item => isValid(item))) {
+                        parsedResult.sort((d1, d2) => d1.getTime() - d2.getTime());
+                    }
+                    result = parsedResult;
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * parse multiple into `Array<Date|null>`, loose means return value includes `null`
+     * 
+     * @example
+     * ```javascript
+     * parseMultipleInputLoose('2021-01-01,2021-10-15'); // [Date, Date];
+     * parseMultipleInputLoose('2021-01-01,2021-10-'); // [Date, null];
+     * parseMultipleInputLoose(''); // [];
+     * ```
+     */
+    parseMultipleInputLoose(input = '', separator: string = strings.DEFAULT_SEPARATOR_MULTIPLE, needDedupe = false) {
+        const max = this.getProp('max');
+        const inputArr = input.split(separator);
+        const result: Date[] = [];
+
+        for (const curInput of inputArr) {
+            let tmpParsed = curInput && this.parseInputLoose(curInput);
+            tmpParsed = Array.isArray(tmpParsed) ? tmpParsed : tmpParsed && [tmpParsed];
+            if (tmpParsed && tmpParsed.length) {
+                if (needDedupe) {
+                    !result.filter(r => Boolean(tmpParsed.find(tp => isSameSecond(r, tp)))) && result.push(...tmpParsed);
+                } else {
+                    result.push(...tmpParsed);
+                }
+            } else {
+                return [];
+            }
+
+            if (max && max > 0 && result.length > max) {
+                return [];
+            }
+        }
+
+        return result;
+    }
+
     /**
      * Parses the input when multiple is true, if valid,
      *  returns a list of time objects, otherwise returns an array
@@ -799,15 +926,12 @@ export default class DatePickerFoundation extends BaseFoundation<DatePickerAdapt
          */
         const needCheckFocusRecord = get(options, 'needCheckFocusRecord', true);
 
-        if (this._adapter.needConfirm()) {
-            this._adapter.updateCachedSelectedValue(value);
-        }
-
         const dates = Array.isArray(value) ? [...value] : value ? [value] : [];
         const changedDates = this._getChangedDates(dates);
 
         let inputValue, insetInputValue;
         if (!this._someDateDisabled(changedDates)) {
+            this.resetCachedSelectedValue(dates);
             inputValue = this._isMultiple() ? this.formatMultipleDates(dates) : this.formatDates(dates);
             if (insetInput) {
                 const insetInputFormatToken = getInsetInputFormatToken({ format, type });

+ 49 - 3
packages/semi-foundation/datePicker/inputFoundation.ts

@@ -1,13 +1,17 @@
 /* eslint-disable max-len */
-import { cloneDeep, isObject, set } from 'lodash';
+import { cloneDeep, isObject, set, get } from 'lodash';
+import { format as formatFn } from 'date-fns';
 
 import BaseFoundation, { DefaultAdapter } from '../base/foundation';
-import { BaseValueType, ValidateStatus } from './foundation';
+import { BaseValueType, ValidateStatus, ValueType } from './foundation';
 import { formatDateValues } from './_utils/formatter';
 import { getDefaultFormatTokenByType } from './_utils/getDefaultFormatToken';
 import getInsetInputFormatToken from './_utils/getInsetInputFormatToken';
 import getInsetInputValueFromInsetInputStr from './_utils/getInsetInputValueFromInsetInputStr';
 import { strings } from './constants';
+import getDefaultPickerDate from './_utils/getDefaultPickerDate';
+import { compatibleParse } from './_utils/parser';
+import { isValidDate } from './_utils';
 
 const KEY_CODE_ENTER = 'Enter';
 const KEY_CODE_TAB = 'Tab';
@@ -50,6 +54,7 @@ export interface DateInputFoundationProps extends DateInputElementProps, DateInp
     insetInput?: boolean;
     insetInputValue?: InsetInputValue;
     density?: typeof strings.DENSITY_SET[number];
+    defaultPickerValue?: ValueType;
 }
 
 export interface InsetInputValue {
@@ -175,11 +180,52 @@ export default class InputFoundation extends BaseFoundation<DateInputAdapter> {
         const { value, valuePath, insetInputValue } = options;
         const { format, type } = this._adapter.getProps();
         const insetFormatToken = getInsetInputFormatToken({ type, format });
-        const newInsetInputValue = set(cloneDeep(insetInputValue), valuePath, value);
+        let newInsetInputValue = set(cloneDeep(insetInputValue), valuePath, value);
+        newInsetInputValue = this._autoFillTimeToInsetInputValue({ insetInputValue: newInsetInputValue, valuePath, format: insetFormatToken });
         const newInputValue = this.concatInsetInputValue({ insetInputValue: newInsetInputValue });
         this._adapter.notifyInsetInputChange({ insetInputValue: newInsetInputValue, format: insetFormatToken, insetInputStr: newInputValue });
     }
 
+    _autoFillTimeToInsetInputValue(options: { insetInputValue: InsetInputValue; format: string; valuePath: string;}) {
+        const { valuePath, insetInputValue, format } = options;
+        const { type, defaultPickerValue, dateFnsLocale } = this._adapter.getProps();
+        const insetInputValueWithTime = cloneDeep(insetInputValue);
+        const { nowDate, nextDate } = getDefaultPickerDate({ defaultPickerValue, format, dateFnsLocale  });
+
+        if (type.includes('Time')) {
+            let timeStr = '';
+            const dateFormatToken = get(format.split(' '), '0', strings.FORMAT_FULL_DATE);
+            const timeFormatToken = get(format.split(' '), '1', strings.FORMAT_TIME_PICKER);
+            
+            switch (valuePath) {
+                case 'monthLeft.dateInput':
+                    const dateLeftStr = insetInputValueWithTime.monthLeft.dateInput;
+                    if (!insetInputValueWithTime.monthLeft.timeInput && dateLeftStr.length === dateFormatToken.length) {
+                        const dateLeftParsed = compatibleParse(insetInputValueWithTime.monthLeft.dateInput, dateFormatToken);
+                        if (isValidDate(dateLeftParsed)) {
+                            timeStr = formatFn(nowDate, timeFormatToken);
+                            insetInputValueWithTime.monthLeft.timeInput = timeStr;
+                        }
+                    }
+                    break;
+                case 'monthRight.dateInput':
+                    const dateRightStr = insetInputValueWithTime.monthRight.dateInput;
+                    if (!insetInputValueWithTime.monthRight.timeInput && dateRightStr.length === dateFormatToken.length) {
+                        const dateRightParsed = compatibleParse(dateRightStr, dateFormatToken);
+                        if (isValidDate(dateRightParsed)) {
+                            timeStr = formatFn(nextDate, timeFormatToken);
+                            insetInputValueWithTime.monthRight.timeInput = timeStr;
+                        }
+                    }
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        return insetInputValueWithTime;
+    }
+
     /**
      * 只有传入的 format 符合 formatReg 时,才会使用用户传入的 format
      * 否则会使用默认的 format 作为 placeholder

+ 2 - 2
packages/semi-foundation/datePicker/monthsGridFoundation.ts

@@ -223,10 +223,10 @@ export default class MonthsGridFoundation extends BaseFoundation<MonthsGridAdapt
         this._adapter.updateMonthOnLeft(newMonthLeft);
         const newSelected = new Set<string>();
         if (!this._isMultiple()) {
-            newSelected.add(format(values[0] as Date, strings.FORMAT_FULL_DATE));
+            values[0] && newSelected.add(format(values[0] as Date, strings.FORMAT_FULL_DATE));
         } else {
             values.forEach(date => {
-                newSelected.add(format(date as Date, strings.FORMAT_FULL_DATE));
+                date && newSelected.add(format(date as Date, strings.FORMAT_FULL_DATE));
             });
         }
         if (refreshPicker) {

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

@@ -1,6 +1,6 @@
 {
     "name": "@douyinfe/semi-foundation",
-    "version": "2.10.2",
+    "version": "2.11.0-beta.1",
     "description": "",
     "scripts": {
         "build:lib": "node ./scripts/compileLib.js",
@@ -8,7 +8,7 @@
     },
     "dependencies": {
         "@babel/runtime-corejs3": "^7.15.4",
-        "@douyinfe/semi-animation": "2.10.2",
+        "@douyinfe/semi-animation": "2.11.0-beta.1",
         "async-validator": "^3.5.0",
         "classnames": "^2.2.6",
         "date-fns": "^2.9.0",

+ 11 - 0
packages/semi-foundation/radio/radioFoundation.ts

@@ -2,8 +2,19 @@ import BaseFoundation, { DefaultAdapter } from '../base/foundation';
 
 export interface RadioAdapter extends DefaultAdapter {
     setHover: (hover: boolean) => void;
+    setAddonId: () => void;
+    setExtraId: () => void;
 }
 export default class RadioFoundation extends BaseFoundation<RadioAdapter> {
+    init() {
+        const { children, extra, extraId, addonId } = this._adapter.getProps();
+        if (children && !addonId) {
+            this._adapter.setAddonId();
+        }
+        if (extra && !extraId) {
+            this._adapter.setExtraId();
+        }
+    }
     setHover(hover: boolean) {
         this._adapter.setHover(hover);
     }

+ 5 - 0
packages/semi-foundation/tooltip/foundation.ts

@@ -68,6 +68,7 @@ export interface TooltipAdapter<P = Record<string, any>, S = Record<string, any>
     setInitialFocus(): void;
     notifyEscKeydown(event: any): void;
     getTriggerNode(): any;
+    setId(): void;
 }
 
 export type Position = ArrayElement<typeof strings.POSITION_SET>;
@@ -87,10 +88,14 @@ export default class Tooltip<P = Record<string, any>, S = Record<string, any>> e
     }
 
     init() {
+        const { wrapperId } = this.getProps();
         this._mounted = true;
         this._bindEvent();
         this._shouldShow();
         this._initContainerPosition();
+        if (!wrapperId) {
+            this._adapter.setId();
+        }
     }
 
     destroy() {

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

@@ -1,6 +1,6 @@
 {
   "name": "@douyinfe/semi-icons",
-  "version": "2.10.2",
+  "version": "2.11.0-beta.1",
   "description": "semi icons",
   "keywords": [
     "semi",
@@ -38,7 +38,7 @@
     "@babel/plugin-transform-runtime": "^7.15.8",
     "@babel/preset-env": "^7.15.8",
     "@babel/preset-react": "^7.14.5",
-    "@douyinfe/semi-webpack-plugin": "2.10.2",
+    "@douyinfe/semi-webpack-plugin": "2.11.0-beta.1",
     "babel-loader": "^8.2.2",
     "css-loader": "4.3.0",
     "del": "^6.0.0",

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

@@ -1,6 +1,6 @@
 {
   "name": "@douyinfe/semi-illustrations",
-  "version": "2.10.2",
+  "version": "2.11.0-beta.1",
   "description": "semi illustrations",
   "keywords": [
     "semi",

+ 2 - 2
packages/semi-next/package.json

@@ -1,6 +1,6 @@
 {
     "name": "@douyinfe/semi-next",
-    "version": "2.10.2",
+    "version": "2.11.0-beta.1",
     "description": "Plugin that support Semi Design in Next.js",
     "author": "伍浩威 <[email protected]>",
     "homepage": "",
@@ -23,7 +23,7 @@
         "typescript": "^4"
     },
     "dependencies": {
-        "@douyinfe/semi-webpack-plugin": "2.10.2"
+        "@douyinfe/semi-webpack-plugin": "2.11.0-beta.1"
     },
     "gitHead": "eb34a4f25f002bb4cbcfa51f3df93bed868c831a"
 }

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

@@ -1,6 +1,6 @@
 {
   "name": "@douyinfe/semi-scss-compile",
-  "version": "2.10.2",
+  "version": "2.11.0-beta.1",
   "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.10.2",
+    "version": "2.11.0-beta.1",
     "description": "semi-theme-default",
     "keywords": [
         "semi-theme",

+ 16 - 6
packages/semi-ui/checkbox/checkbox.tsx

@@ -29,9 +29,13 @@ export interface CheckboxProps extends BaseCheckboxProps {
     'aria-label'?: React.AriaAttributes['aria-label'];
     role?: React.HTMLAttributes<HTMLSpanElement>['role']; // a11y: wrapper role
     tabIndex?: number; // a11y: wrapper tabIndex
+    addonId?: string;
+    extraId?: string;
 }
 interface CheckboxState {
     checked: boolean;
+    addonId?: string;
+    extraId?: string;
 }
 class Checkbox extends BaseComponent<CheckboxProps, CheckboxState> {
     static contextType = Context;
@@ -89,7 +93,13 @@ class Checkbox extends BaseComponent<CheckboxProps, CheckboxState> {
             notifyGroupChange: cbContent => {
                 this.context.checkboxGroup.onChange(cbContent);
             },
-            getGroupDisabled: () => (this.context && this.context.checkboxGroup.disabled)
+            getGroupDisabled: () => (this.context && this.context.checkboxGroup.disabled),
+            setAddonId: () => {
+                this.setState({ addonId: getUuidShort({ prefix: 'addon' }) });
+            },
+            setExtraId: () => {
+                this.setState({ extraId: getUuidShort({ prefix: 'extra' }) });
+            }
         };
     }
 
@@ -103,11 +113,11 @@ class Checkbox extends BaseComponent<CheckboxProps, CheckboxState> {
 
         this.state = {
             checked: props.checked || props.defaultChecked || checked,
+            addonId: props.addonId,
+            extraId: props.extraId,
         };
 
         this.checkboxEntity = null;
-        this.addonId = getUuidShort({ prefix: 'addon' });
-        this.extraId = getUuidShort({ prefix: 'extra' });
         this.foundation = new CheckboxFoundation(this.adapter);
     }
 
@@ -153,7 +163,7 @@ class Checkbox extends BaseComponent<CheckboxProps, CheckboxState> {
             tabIndex,
             id
         } = this.props;
-        const { checked } = this.state;
+        const { checked, addonId, extraId } = this.state;
         const props: Record<string, any> = {
             checked,
             disabled,
@@ -195,8 +205,8 @@ class Checkbox extends BaseComponent<CheckboxProps, CheckboxState> {
 
         const renderContent = () => (
             <>
-                {children ? <span id={this.addonId} className={`${prefix}-addon`}>{children}</span> : null}
-                {extra ? <div id={this.extraId} className={extraCls}>{extra}</div> : null}
+                {children ? <span id={addonId} className={`${prefix}-addon`}>{children}</span> : null}
+                {extra ? <div id={extraId} className={extraCls}>{extra}</div> : null}
             </>
         );
         return (

+ 48 - 1
packages/semi-ui/datePicker/_story/datePicker.stories.js

@@ -849,5 +849,52 @@ export const A11yKeyboardDemo = () => {
   );
 };
 
-A11yKeyboardDemo.storyName = "a11y keyboard demo"
+A11yKeyboardDemo.storyName = "a11y keyboard demo";
 
+/**
+ * test with cypress
+ */
+export const NeedConfirmDelete = () => {
+  return (
+    <div data-cy="dateTimeRange">
+      <DatePicker
+        value={[new Date('2022-08-08 00:00'), new Date('2022-08-09 12:00')]}
+        type="dateTimeRange"
+        needConfirm
+      />
+    </div>
+  );
+};
+NeedConfirmDelete.storyName = "cashedSelectedValue return to last selected when needConfirm & input invalid";
+
+/**
+ * test with cypress
+ */
+ export const CashedSelectedValue = () => {
+  return (
+    <Space>
+      <div data-cy="date">
+        <DatePicker
+          defaultValue={new Date('2022-08-08')}
+          type="date"
+          motion={false}
+        />
+      </div>
+      <div data-cy="dateTime">
+        <DatePicker
+          defaultValue={new Date('2022-08-08 19:11:00')}
+          type="dateTime"
+          motion={false}
+        />
+      </div>
+      <div data-cy="dateRange">
+        <DatePicker
+          defaultValue={[new Date('2022-08-08'), new Date('2022-08-09')]}
+          type="dateRange"
+          motion={false}
+        />
+      </div>
+    </Space>
+  );
+};
+CashedSelectedValue.storyName = "cashedSelectedValue";

+ 37 - 0
packages/semi-ui/datePicker/_story/v2/AutoFillTime.jsx

@@ -0,0 +1,37 @@
+import React from 'react';
+import { DatePicker, Space, Button } from '../../../index';
+
+AutoFillTime.storyName = '自动填充时间';
+
+/**
+ * 输入开始日期后,自动填充一个时间
+ */
+export default function AutoFillTime() {
+    const format = 'yyyy-MM-dd HH:mm';
+    const defaultPickerValue = '2021-03-15 14:00';
+    const defaultPickerValue2 = ['2021-01-10 00:01', '2021-03-15 23:59'];
+    
+    const handleChange = (...args) => {
+        console.log('change', ...args);
+    };
+
+    const props = {
+        format,
+        insetInput: true,
+        onChange: handleChange,
+        motion: false,
+    };
+
+    return (
+        <div data-cy="container">
+            <Space>
+                <div data-cy="dateTime">
+                    <DatePicker {...props} type="dateTime" defaultPickerValue={defaultPickerValue} />
+                </div>
+                <div data-cy="dateTimeRange">
+                    <DatePicker {...props} type="dateTimeRange" defaultPickerValue={defaultPickerValue2} />
+                </div>
+            </Space>
+        </div>
+    );
+}

+ 29 - 0
packages/semi-ui/datePicker/_story/v2/InputFormat.jsx

@@ -0,0 +1,29 @@
+import React from 'react';
+import { DatePicker, Space, Button } from '../../../index';
+
+InputFormat.storyName = '输入部分日期,回显在面板上';
+
+/**
+ * 优化 input format
+ */
+export default function InputFormat() {
+    const handleChange = (...args) => {
+        console.log('change', ...args);
+    };
+
+    return (
+        <div data-cy="container">
+            <Space>
+                <div data-cy="date">
+                    <DatePicker onChange={handleChange} />
+                </div>
+                <div data-cy="dateRange">
+                    <DatePicker onChange={handleChange} type="dateRange" />
+                </div>
+                <div data-cy="dateTime">
+                    <DatePicker onChange={handleChange} type="dateTime" />
+                </div>
+            </Space>
+        </div>
+    );
+}

+ 44 - 0
packages/semi-ui/datePicker/_story/v2/InputFormatConfirm.jsx

@@ -0,0 +1,44 @@
+import React from 'react';
+import { DatePicker, Space, Button } from '../../../index';
+
+InputFormatConfirm.storyName = '输入时间 + needConfirm';
+
+export default function InputFormatConfirm() {
+    const [insetInput, setInputInput] = React.useState(false);
+    const format = 'yyyy-MM-dd HH:mm';
+    const defaultPickerValue = '2021-03-15 14:00';
+    const defaultPickerValue2 = ['2021-01-10 00:01', '2021-03-15 23:59'];
+    
+    const handleChange = (...args) => {
+        console.log('change', ...args);
+    };
+        
+    const handleConfirm = (...args) => {
+        console.log('confirm', ...args);
+    };
+
+    const props = {
+        format,
+        onChange: handleChange,
+        onConfirm: handleConfirm,
+        motion: false,
+        needConfirm: true,
+        insetInput
+    };
+
+    return (
+        <div data-cy="container">
+            <Space>
+                <Button data-cy="inset-switch" onClick={() => setInputInput(!insetInput)}>{`insetInput=${insetInput}`}</Button>
+                <Space>
+                    <div data-cy="dateTime">
+                        <DatePicker {...props} type="dateTime" defaultPickerValue={defaultPickerValue} />
+                    </div>
+                    <div data-cy="dateTimeRange">
+                        <DatePicker {...props} type="dateTimeRange" defaultPickerValue={defaultPickerValue2} />
+                    </div>
+                </Space>
+            </Space>
+        </div>
+    );
+}

+ 27 - 0
packages/semi-ui/datePicker/_story/v2/InputFormatDisabled.jsx

@@ -0,0 +1,27 @@
+import React from 'react';
+import { DatePicker, Space, Button } from '../../../index';
+
+InputFormatDisabled.storyName = '输入禁用日期,不回显在面板上';
+
+/**
+ * 优化 input format
+ */
+export default function InputFormatDisabled() {
+    const handleChange = (...args) => {
+        console.log('change', ...args);
+    };
+
+    const disabledDate = (date) => {
+        return date.getDate() === 15;
+    };
+
+    return (
+        <div data-cy="container">
+            <Space>
+                <div data-cy="date">
+                    <DatePicker disabledDate={disabledDate} onChange={handleChange} />
+                </div>
+            </Space>
+        </div>
+    );
+}

+ 4 - 0
packages/semi-ui/datePicker/_story/v2/index.js

@@ -4,3 +4,7 @@ export { default as FixInputRangeFocus } from './FixInputRangeFocus';
 export { default as InsetInput  } from './InsetInput';
 export { default as InsetInputE2E  } from './InsetInputE2E';
 export { default as FixDefaultPickerValue } from './FixDefaultPickerValue';
+export { default as InputFormat  } from './InputFormat';
+export { default as InputFormatDisabled  } from './InputFormatDisabled';
+export { default as AutoFillTime  } from './AutoFillTime';
+export { default as InputFormatConfirm  } from './InputFormatConfirm';

+ 7 - 0
packages/semi-ui/datePicker/dateInput.tsx

@@ -64,6 +64,12 @@ export default class DateInput extends BaseComponent<DateInputProps, {}> {
         rangeSeparator: PropTypes.string,
         insetInput: PropTypes.bool,
         insetInputValue: PropTypes.object,
+        defaultPickerValue: PropTypes.oneOfType([
+            PropTypes.string,
+            PropTypes.number,
+            PropTypes.object,
+            PropTypes.array,
+        ]),
     };
 
     static defaultProps = {
@@ -392,6 +398,7 @@ export default class DateInput extends BaseComponent<DateInputProps, {}> {
             rangeSeparator,
             insetInput,
             insetInputValue,
+            defaultPickerValue,
             ...rest
         } = this.props;
         const dateIcon = <IconCalendar aria-hidden />;

+ 7 - 11
packages/semi-ui/datePicker/datePicker.tsx

@@ -184,7 +184,7 @@ export default class DatePicker extends BaseComponent<DatePickerProps, DatePicke
             isRange: false,
             inputValue: null, // Staging input values
             value: [], // The currently selected date, each date is a Date object
-            cachedSelectedValue: null, // Save last selected date
+            cachedSelectedValue: null, // Save last selected date, maybe include null
             prevTimeZone: null,
             motionEnd: false, // Monitor if popover animation ends
             rangeInputFocus: undefined, // Optional'rangeStart ',' rangeEnd ', false
@@ -415,16 +415,9 @@ export default class DatePicker extends BaseComponent<DatePickerProps, DatePicke
             triggerRender,
             insetInput
         } = this.props;
-        const { value, cachedSelectedValue, motionEnd, rangeInputFocus } = this.state;
-
-        // const cachedSelectedValue = this.adapter.getCache('cachedSelectedValue');
-
-        let defaultValue = value;
-
-        if (this.adapter.needConfirm()) {
-            defaultValue = cachedSelectedValue;
-        }
+        const { cachedSelectedValue, motionEnd, rangeInputFocus } = this.state;
 
+        const defaultValue = cachedSelectedValue;
         return (
             <MonthsGrid
                 ref={this.monthGrid}
@@ -535,6 +528,7 @@ export default class DatePicker extends BaseComponent<DatePickerProps, DatePicke
             inputReadOnly,
             rangeSeparator,
             insetInput,
+            defaultPickerValue
         } = this.props;
         const { value, inputValue, rangeInputFocus, triggerDisabled } = this.state;
         // This class is not needed when triggerRender is function
@@ -555,6 +549,7 @@ export default class DatePicker extends BaseComponent<DatePickerProps, DatePicke
             disabled: inputDisabled,
             inputValue,
             value: value as Date[],
+            defaultPickerValue,
             onChange: this.handleInputChange,
             onEnterPress: this.handleInputComplete,
             // TODO: remove in next major version
@@ -629,7 +624,7 @@ export default class DatePicker extends BaseComponent<DatePickerProps, DatePicke
     };
 
     renderPanel = (locale: Locale['DatePicker'], localeCode: string, dateFnsLocale: Locale['dateFnsLocale']) => {
-        const { dropdownClassName, dropdownStyle, density, topSlot, bottomSlot, insetInput, type, format, rangeSeparator } = this.props;
+        const { dropdownClassName, dropdownStyle, density, topSlot, bottomSlot, insetInput, type, format, rangeSeparator, defaultPickerValue } = this.props;
         const { insetInputValue, value } = this.state;
         const wrapCls = classnames(
             cssClasses.PREFIX,
@@ -653,6 +648,7 @@ export default class DatePicker extends BaseComponent<DatePickerProps, DatePicke
             rangeInputStartRef: this.rangeInputStartRef,
             rangeInputEndRef: this.rangeInputEndRef,
             density,
+            defaultPickerValue
         };
 
         return (

+ 2 - 1
packages/semi-ui/datePicker/monthsGrid.tsx

@@ -168,7 +168,8 @@ export default class MonthsGrid extends BaseComponent<MonthsGridProps, MonthsGri
     componentDidUpdate(prevProps: MonthsGridProps, prevState: MonthsGridState) {
         const { defaultValue, defaultPickerValue, motionEnd } = this.props;
         if (prevProps.defaultValue !== defaultValue) {
-            this.foundation.updateSelectedFromProps(defaultValue, false);
+            // we should always update panel state when value changes
+            this.foundation.updateSelectedFromProps(defaultValue);
         }
 
         if (prevProps.defaultPickerValue !== defaultPickerValue) {

+ 6 - 6
packages/semi-ui/modal/Modal.tsx

@@ -50,7 +50,7 @@ class Modal extends BaseComponent<ModalReactProps, ModalState> {
         centered: PropTypes.bool,
         visible: PropTypes.bool,
         width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
-        height:  PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+        height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
         confirmLoading: PropTypes.bool,
         cancelLoading: PropTypes.bool,
         okText: PropTypes.string,
@@ -193,23 +193,23 @@ class Modal extends BaseComponent<ModalReactProps, ModalState> {
 
 
     static info = function (props: ModalReactProps) {
-        return confirm(withInfo(props));
+        return confirm<ReturnType<typeof withInfo>>(withInfo(props));
     };
 
     static success = function (props: ModalReactProps) {
-        return confirm(withSuccess(props));
+        return confirm<ReturnType<typeof withSuccess>>(withSuccess(props));
     };
 
     static error = function (props: ModalReactProps) {
-        return confirm(withError(props));
+        return confirm<ReturnType<typeof withError>>(withError(props));
     };
 
     static warning = function (props: ModalReactProps) {
-        return confirm(withWarning(props));
+        return confirm<ReturnType<typeof withWarning>>(withWarning(props));
     };
 
     static confirm = function (props: ModalReactProps) {
-        return confirm(withConfirm(props));
+        return confirm<ReturnType<typeof withConfirm>>(withConfirm(props));
     };
 
     static destroyAll = function destroyAllFn() {

+ 10 - 11
packages/semi-ui/modal/confirm.tsx

@@ -5,14 +5,14 @@ import ConfirmModal from './ConfirmModal';
 
 import '@douyinfe/semi-foundation/modal/modal.scss';
 import { get } from 'lodash';
-import { IconAlertTriangle, IconInfoCircle, IconTickCircle, IconHelpCircle, IconAlertCircle } from '@douyinfe/semi-icons';
+import { IconAlertCircle, IconAlertTriangle, IconHelpCircle, IconInfoCircle, IconTickCircle } from '@douyinfe/semi-icons';
 import { Motion } from '../_base/base';
 
-export interface ConfirmProps extends ModalReactProps{
+export interface ConfirmProps extends ModalReactProps {
     type: 'success' | 'info' | 'warning' | 'error' | 'confirm';
 }
 
-export default function confirm(props: ConfirmProps) {
+export default function confirm<T>(props: ConfirmProps) {
     // create a dom in adapter?
     const div = document.createElement('div');
     document.body.appendChild(div);
@@ -51,7 +51,7 @@ export default function confirm(props: ConfirmProps) {
     } : false;
 
     function render(renderProps: ConfirmProps) {
-        ReactDOM.render(<ConfirmModal {...renderProps} motion={mergedMotion} />, div);
+        ReactDOM.render(<ConfirmModal {...renderProps} motion={mergedMotion}/>, div);
     }
 
     function close() {
@@ -62,7 +62,7 @@ export default function confirm(props: ConfirmProps) {
         render(currentConfig);
     }
 
-    function update(newConfig: ConfirmProps) {
+    function update(newConfig: T extends { type: Exclude<ConfirmProps['type'], 'confirm'> } ? ModalReactProps : ConfirmProps) {
         currentConfig = {
             ...currentConfig,
             ...newConfig,
@@ -79,11 +79,10 @@ export default function confirm(props: ConfirmProps) {
 }
 
 
-
 export function withInfo(props: ModalReactProps) {
     return {
         type: 'info' as const,
-        icon: <IconInfoCircle />,
+        icon: <IconInfoCircle/>,
         ...props
     };
 }
@@ -91,7 +90,7 @@ export function withInfo(props: ModalReactProps) {
 export function withSuccess(props: ModalReactProps) {
     return {
         type: 'success' as const,
-        icon: <IconTickCircle />,
+        icon: <IconTickCircle/>,
         ...props
     };
 }
@@ -99,7 +98,7 @@ export function withSuccess(props: ModalReactProps) {
 export function withWarning(props: ModalReactProps) {
     return {
         type: 'warning' as const,
-        icon: <IconAlertTriangle />,
+        icon: <IconAlertTriangle/>,
         ...props
     };
 }
@@ -107,7 +106,7 @@ export function withWarning(props: ModalReactProps) {
 export function withError(props: ModalReactProps) {
     return {
         type: 'error' as const,
-        icon: <IconAlertCircle />,
+        icon: <IconAlertCircle/>,
         ...props
     };
 }
@@ -115,7 +114,7 @@ export function withError(props: ModalReactProps) {
 export function withConfirm(props: ModalReactProps) {
     return {
         type: 'confirm' as const,
-        icon: <IconHelpCircle />,
+        icon: <IconHelpCircle/>,
         ...props
     };
 }

+ 9 - 1
packages/semi-ui/modal/useModal/index.tsx

@@ -19,7 +19,15 @@ function usePatchElement(): ([ReactNode[], (element: ReactNode) => () => void])
     return [elements, patchElement];
 }
 
-export default function useModal() {
+type UseModalReturnHooksType = (config: ModalReactProps) => { destroy: () => void, update: (newConfig: ConfirmProps) => void };
+
+export default function useModal(): [{
+    info: UseModalReturnHooksType,
+    success: UseModalReturnHooksType,
+    error:UseModalReturnHooksType,
+    warning: UseModalReturnHooksType,
+    confirm: UseModalReturnHooksType
+}, ReactNode] {
     const [elements, patchElement] = usePatchElement();
 
     // eslint-disable-next-line max-len

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

@@ -1,6 +1,6 @@
 {
     "name": "@douyinfe/semi-ui",
-    "version": "2.10.2",
+    "version": "2.11.0-beta.1",
     "description": "",
     "main": "lib/cjs/index.js",
     "module": "lib/es/index.js",
@@ -14,12 +14,12 @@
     },
     "dependencies": {
         "@babel/runtime-corejs3": "^7.15.4",
-        "@douyinfe/semi-animation": "2.10.2",
-        "@douyinfe/semi-animation-react": "2.10.2",
-        "@douyinfe/semi-foundation": "2.10.2",
-        "@douyinfe/semi-icons": "2.10.2",
-        "@douyinfe/semi-illustrations": "2.10.2",
-        "@douyinfe/semi-theme-default": "2.10.2",
+        "@douyinfe/semi-animation": "2.11.0-beta.1",
+        "@douyinfe/semi-animation-react": "2.11.0-beta.1",
+        "@douyinfe/semi-foundation": "2.11.0-beta.1",
+        "@douyinfe/semi-icons": "2.11.0-beta.1",
+        "@douyinfe/semi-illustrations": "2.11.0-beta.1",
+        "@douyinfe/semi-theme-default": "2.11.0-beta.1",
         "@types/react-window": "^1.8.2",
         "async-validator": "^3.5.0",
         "classnames": "^2.2.6",
@@ -75,7 +75,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.10.2",
+        "@douyinfe/semi-scss-compile": "2.11.0-beta.1",
         "@storybook/addon-knobs": "^6.3.1",
         "@types/lodash": "^4.14.176",
         "babel-loader": "^8.2.2",

+ 17 - 7
packages/semi-ui/radio/radio.tsx

@@ -41,10 +41,14 @@ export type RadioProps = {
     addonClassName?: string;
     type?: RadioType;
     'aria-label'?: React.AriaAttributes['aria-label'];
+    addonId?: string;
+    extraId?: string;
 };
 
 export interface RadioState {
     hover?: boolean;
+    addonId?: string;
+    extraId?: string;
 }
 
 export { RadioChangeEvent };
@@ -94,11 +98,11 @@ class Radio extends BaseComponent<RadioProps, RadioState> {
         super(props);
         this.state = {
             hover: false,
+            addonId: props.addonId,
+            extraId: props.extraId,
         };
         this.foundation = new RadioFoundation(this.adapter);
         this.radioEntity = null;
-        this.addonId = getUuidShort({ prefix: 'addon' });
-        this.extraId = getUuidShort({ prefix: 'extra' });
     }
 
     get adapter(): RadioAdapter {
@@ -106,6 +110,12 @@ class Radio extends BaseComponent<RadioProps, RadioState> {
             ...super.adapter,
             setHover: (hover: boolean) => {
                 this.setState({ hover });
+            },
+            setAddonId: () => {
+                this.setState({ addonId: getUuidShort({ prefix: 'addon' }) });
+            },
+            setExtraId: () => {
+                this.setState({ extraId: getUuidShort({ prefix: 'extra' }) });
             }
         };
     }
@@ -168,7 +178,7 @@ class Radio extends BaseComponent<RadioProps, RadioState> {
             isButtonRadioComponent,
             buttonSize,
             realPrefixCls;
-        const isHover = this.state.hover;
+        const { hover: isHover, addonId, extraId } = this.state;
         let props = {};
 
         if (this.isInGroup()) {
@@ -218,8 +228,8 @@ class Radio extends BaseComponent<RadioProps, RadioState> {
         }, addonClassName);
         const renderContent = () => (
             <>
-                {children ? <span className={addonCls} style={addonStyle} id={this.addonId}>{children}</span> : null}
-                {extra && !isButtonRadio ? <div className={`${prefix}-extra`} id={this.extraId}>{extra}</div> : null}
+                {children ? <span className={addonCls} style={addonStyle} id={addonId}>{children}</span> : null}
+                {extra && !isButtonRadio ? <div className={`${prefix}-extra`} id={extraId}>{extra}</div> : null}
             </>
         );
         return (
@@ -240,8 +250,8 @@ class Radio extends BaseComponent<RadioProps, RadioState> {
                     ref={(ref: RadioInner) => {
                         this.radioEntity = ref;
                     }}
-                    addonId={children && this.addonId}
-                    extraId={extra && this.extraId}
+                    addonId={children && addonId}
+                    extraId={extra && extraId}
                 />
                 {
                     isCardRadioGroup ?

+ 1 - 1
packages/semi-ui/select/index.tsx

@@ -948,7 +948,7 @@ class Select extends BaseComponent<SelectProps, SelectState> {
 
         const NotOneLine = !maxTagCount; // Multiple lines (that is, do not set maxTagCount), do not use TagGroup, directly traverse with Tag, otherwise Input cannot follow the correct position
 
-        const tagContent = NotOneLine ? tags : <TagGroup tagList={tags} maxTagCount={n} restCount={maxTagCount ? selectedItems.length - maxTagCount : undefined} size="large" mode="custom" />;
+        const tagContent = NotOneLine ? tags : <TagGroup<"custom"> tagList={tags} maxTagCount={n} restCount={maxTagCount ? selectedItems.length - maxTagCount : undefined} size="large" mode="custom" />;
 
         return (
             <>

+ 4 - 4
packages/semi-ui/tag/group.tsx

@@ -10,12 +10,12 @@ const prefixCls = cssClasses.PREFIX;
 const tagSize = strings.TAG_SIZE;
 const avatarShapeSet = strings.AVATAR_SHAPE;
 
-export interface TagGroupProps {
+export interface TagGroupProps<T> {
     style?: React.CSSProperties;
     className?: string;
     maxTagCount?: number;
     restCount?: number;
-    tagList?: (TagProps | React.ReactNode)[];
+    tagList?: (T extends 'custom' ? React.ReactNode : TagProps)[];
     size?: 'small' | 'large';
     showPopover?: boolean;
     popoverProps?: PopoverProps;
@@ -23,7 +23,7 @@ export interface TagGroupProps {
     mode?: string;
 }
 
-export default class TagGroup extends PureComponent<TagGroupProps> {
+export default class TagGroup<T> extends PureComponent<TagGroupProps<T>> {
     static defaultProps = {
         style: {},
         className: '',
@@ -84,7 +84,7 @@ export default class TagGroup extends PureComponent<TagGroupProps> {
         let renderTags: (Tag | React.ReactNode)[] = tags;
 
         const normalTags: (Tag | React.ReactNode)[] = tags.slice(0, maxTagCount);
-        const restTags = tags.slice(maxTagCount) as  React.ReactNode;
+        const restTags = tags.slice(maxTagCount) as React.ReactNode;
         let nTag = null;
         if (n > 0) {
             nTag = this.renderNTag(n, restTags);

+ 5 - 1
packages/semi-ui/tooltip/index.tsx

@@ -75,6 +75,7 @@ export interface TooltipProps extends BaseProps {
     guardFocus?: boolean;
     returnFocusOnClose?: boolean;
     onEscKeyDown?: (e: React.KeyboardEvent) => void;
+    wrapperId?: string;
 }
 interface TooltipState {
     visible: boolean;
@@ -193,7 +194,7 @@ export default class Tooltip extends BaseComponent<TooltipProps, TooltipState> {
             placement: props.position || 'top',
             transitionStyle: {},
             isPositionUpdated: false,
-            id: getUuidShort(), // auto generate id, will be used by children.aria-describedby & content.id, improve a11y
+            id: props.wrapperId, // auto generate id, will be used by children.aria-describedby & content.id, improve a11y
         };
         this.foundation = new TooltipFoundation(this.adapter);
         this.eventManager = new Event();
@@ -428,6 +429,9 @@ export default class Tooltip extends BaseComponent<TooltipProps, TooltipState> {
             },
             notifyEscKeydown: (event: React.KeyboardEvent) => {
                 this.props.onEscKeyDown(event);
+            },
+            setId: () => {
+                this.setState({ id: getUuidShort() });
             }
         };
     }

+ 1 - 1
packages/semi-ui/treeSelect/index.tsx

@@ -826,7 +826,7 @@ class TreeSelect extends BaseComponent<TreeSelectProps, TreeSelectState> {
         const tagList = this.renderTagList();
         // mode=custom to return tagList directly
         return (
-            <TagGroup
+            <TagGroup<'custom'>
                 maxTagCount={maxTagCount}
                 tagList={tagList}
                 size="large"

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

@@ -1,6 +1,6 @@
 {
     "name": "@douyinfe/semi-webpack-plugin",
-    "version": "2.10.2",
+    "version": "2.11.0-beta.1",
     "description": "",
     "author": "伍浩威 <[email protected]>",
     "homepage": "",

+ 88 - 0
yarn.lock

@@ -1460,6 +1460,16 @@
   resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70"
   integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==
 
+"@douyinfe/[email protected]":
+  version "2.10.1"
+  resolved "https://registry.yarnpkg.com/@douyinfe/semi-animation-react/-/semi-animation-react-2.10.1.tgz#c10da6f8833eeeb3530361b815d3c1345c5739c9"
+  integrity sha512-fsF1JWDfsd4NaeFaFlNWiyOwEipadVddtkgqmE2Gj7psx2z0qnwJwyAsUlmJm7stWPjbdTErhk68CqcGiQlxIw==
+  dependencies:
+    "@babel/runtime-corejs3" "^7.15.4"
+    "@douyinfe/semi-animation" "2.10.1"
+    "@douyinfe/semi-animation-styled" "2.10.1"
+    classnames "^2.2.6"
+
 "@douyinfe/[email protected]":
   version "2.9.1"
   resolved "https://registry.yarnpkg.com/@douyinfe/semi-animation-react/-/semi-animation-react-2.9.1.tgz#f2e4c6ef7899729ee6145edf0579598ba195bfdd"
@@ -1470,6 +1480,13 @@
     "@douyinfe/semi-animation-styled" "2.9.1"
     classnames "^2.2.6"
 
+"@douyinfe/[email protected]":
+  version "2.10.1"
+  resolved "https://registry.yarnpkg.com/@douyinfe/semi-animation-styled/-/semi-animation-styled-2.10.1.tgz#b0bffc2d842ea32b7d30b6ce04bbe8e33b493218"
+  integrity sha512-9UU1qs6MwaSdJsZ/V+B56POWN8/YScCxfFLLR0BwLYjuEXepAx11kpEAfPYln2O7quCCiYz9ueWbcBR90cjFbQ==
+  dependencies:
+    "@babel/runtime-corejs3" "^7.15.4"
+
 "@douyinfe/[email protected]":
   version "2.9.1"
   resolved "https://registry.yarnpkg.com/@douyinfe/semi-animation-styled/-/semi-animation-styled-2.9.1.tgz#0a4a3c521626118b209604b2d6447fbcaa4839a4"
@@ -1477,6 +1494,14 @@
   dependencies:
     "@babel/runtime-corejs3" "^7.15.4"
 
+"@douyinfe/[email protected]":
+  version "2.10.1"
+  resolved "https://registry.yarnpkg.com/@douyinfe/semi-animation/-/semi-animation-2.10.1.tgz#615de44754aa995b2dce29dab6eb89281c83ff17"
+  integrity sha512-djHf7K9kAN10DLq7/jS6TigrR5NcV8KG/VsPwC67h/vihlYq2l1uR/A02tHHGGSZZKy8SVlkhFijwySMr+qOMA==
+  dependencies:
+    "@babel/runtime-corejs3" "^7.15.4"
+    bezier-easing "^2.1.0"
+
 "@douyinfe/[email protected]":
   version "2.9.1"
   resolved "https://registry.yarnpkg.com/@douyinfe/semi-animation/-/semi-animation-2.9.1.tgz#4345fd86823b51e7c6fb5e9079d8f5c3ffe608f8"
@@ -1485,6 +1510,21 @@
     "@babel/runtime-corejs3" "^7.15.4"
     bezier-easing "^2.1.0"
 
+"@douyinfe/[email protected]":
+  version "2.10.1"
+  resolved "https://registry.yarnpkg.com/@douyinfe/semi-foundation/-/semi-foundation-2.10.1.tgz#ad78cf042963b4083866024cc9f036d49f3ef026"
+  integrity sha512-xm4QEySLaXJfCQNfsXQxjqOHS6pqjS0k3sHuTm/80KX62VXDq1Z6HR28FbIUhr7y0mSrTiAtljEDCJ9/Y2h4dg==
+  dependencies:
+    "@babel/runtime-corejs3" "^7.15.4"
+    "@douyinfe/semi-animation" "2.10.1"
+    async-validator "^3.5.0"
+    classnames "^2.2.6"
+    date-fns "^2.9.0"
+    date-fns-tz "^1.0.10"
+    lodash "^4.17.21"
+    memoize-one "^5.2.1"
+    scroll-into-view-if-needed "^2.2.24"
+
 "@douyinfe/[email protected]":
   version "2.9.1"
   resolved "https://registry.yarnpkg.com/@douyinfe/semi-foundation/-/semi-foundation-2.9.1.tgz#1300bb97d6ceb92274ca4c9e6c66c5c16dc284ea"
@@ -1500,6 +1540,14 @@
     memoize-one "^5.2.1"
     scroll-into-view-if-needed "^2.2.24"
 
+"@douyinfe/[email protected]", "@douyinfe/semi-icons@^2.0.0":
+  version "2.10.1"
+  resolved "https://registry.yarnpkg.com/@douyinfe/semi-icons/-/semi-icons-2.10.1.tgz#cabca9a13e6464b95cbf00318095610294bb2419"
+  integrity sha512-UWvUbC3l/NkFdxZIjoz9lTY33BOxuHRc5Q9mC+xoz7oY9MVEfMhBQvrziy29tKBEeNwvAbiVwrUI+Zl2Yze07A==
+  dependencies:
+    "@babel/runtime-corejs3" "^7.15.4"
+    classnames "^2.2.6"
+
 "@douyinfe/[email protected]", "@douyinfe/semi-icons@latest":
   version "2.9.1"
   resolved "https://registry.yarnpkg.com/@douyinfe/semi-icons/-/semi-icons-2.9.1.tgz#7a04e1a77070220b04f63e6f65aac30155ed8ddd"
@@ -1508,6 +1556,13 @@
     "@babel/runtime-corejs3" "^7.15.4"
     classnames "^2.2.6"
 
+"@douyinfe/[email protected]":
+  version "2.10.1"
+  resolved "https://registry.yarnpkg.com/@douyinfe/semi-illustrations/-/semi-illustrations-2.10.1.tgz#18e4568b52b0c9d838ce3e0669eef0cf494c0746"
+  integrity sha512-HAOWjDc4TMooESqeRegUQh569DOE++s8VgrD4L3bNPjTx0R8nfRnSA+n78uECkVDQkzSFh+660K20QyKv63mkA==
+  dependencies:
+    "@babel/runtime-corejs3" "^7.15.4"
+
 "@douyinfe/[email protected]":
   version "2.9.1"
   resolved "https://registry.yarnpkg.com/@douyinfe/semi-illustrations/-/semi-illustrations-2.9.1.tgz#1a448d1854ee1beeba57ea612da052b549ea105f"
@@ -1571,6 +1626,13 @@
     monaco-themes "^0.3.3"
     react-live "^2.2.2"
 
+"@douyinfe/[email protected]":
+  version "2.10.1"
+  resolved "https://registry.yarnpkg.com/@douyinfe/semi-theme-default/-/semi-theme-default-2.10.1.tgz#0a48177f5caacd98d01f9642403b13af29bf9fdd"
+  integrity sha512-qf3nd/mOAqR+qUXPt9+IPb42zHeWJubR1bJnr/IuMrWVvoQZU7JdOFLKP6H2I7WDvBB/n10zgS5da0ATS8+Rjw==
+  dependencies:
+    glob "^7.1.6"
+
 "@douyinfe/[email protected]":
   version "2.9.1"
   resolved "https://registry.yarnpkg.com/@douyinfe/semi-theme-default/-/semi-theme-default-2.9.1.tgz#734113e9783ca58b69afe1769005e7e57e5a4da7"
@@ -1578,6 +1640,32 @@
   dependencies:
     glob "^7.1.6"
 
+"@douyinfe/semi-ui@^2.0.0":
+  version "2.10.1"
+  resolved "https://registry.yarnpkg.com/@douyinfe/semi-ui/-/semi-ui-2.10.1.tgz#d2856d6c11989b368a0046cdc0161b26f5fc127d"
+  integrity sha512-oymvFiVOZBUmlNTWffLk8zI1VF97KxyNyZ8cnUMk24fwdg5m2qdQBzOHN4Uz9rXwJxjskV4EobZW51C1L3Ij5w==
+  dependencies:
+    "@babel/runtime-corejs3" "^7.15.4"
+    "@douyinfe/semi-animation" "2.10.1"
+    "@douyinfe/semi-animation-react" "2.10.1"
+    "@douyinfe/semi-foundation" "2.10.1"
+    "@douyinfe/semi-icons" "2.10.1"
+    "@douyinfe/semi-illustrations" "2.10.1"
+    "@douyinfe/semi-theme-default" "2.10.1"
+    "@types/react-window" "^1.8.2"
+    async-validator "^3.5.0"
+    classnames "^2.2.6"
+    copy-text-to-clipboard "^2.1.1"
+    date-fns "^2.9.0"
+    date-fns-tz "^1.0.10"
+    lodash "^4.17.21"
+    react-resizable "^1.8.0"
+    react-sortable-hoc "^2.0.0"
+    react-window "^1.8.2"
+    resize-observer-polyfill "^1.5.1"
+    scroll-into-view-if-needed "^2.2.24"
+    utility-types "^3.10.0"
+
 "@douyinfe/semi-ui@latest":
   version "2.9.1"
   resolved "https://registry.yarnpkg.com/@douyinfe/semi-ui/-/semi-ui-2.9.1.tgz#505d4783ea1fa73d307b75f62091030f1fee9332"