Prechádzať zdrojové kódy

Merge branch 'release' into fix_dropdown_useLevelJudge

pointhalo 1 rok pred
rodič
commit
1d91fc94ad
100 zmenil súbory, kde vykonal 2632 pridanie a 1341 odobranie
  1. 4 1
      .eslintrc.js
  2. 3 1
      CONTRIBUTING.md
  3. 9 6
      content/input/datepicker/index-en-US.md
  4. 9 7
      content/input/datepicker/index.md
  5. 153 4
      content/input/form/index-en-US.md
  6. 152 1
      content/input/form/index.md
  7. 3 0
      content/show/image/index-en-US.md
  8. 3 0
      content/show/image/index.md
  9. 31 22
      content/show/popover/index-en-US.md
  10. 27 23
      content/show/popover/index.md
  11. 1 1
      content/show/tooltip/index-en-US.md
  12. 1 1
      content/show/tooltip/index.md
  13. 75 0
      content/start/changelog/index-en-US.md
  14. 81 6
      content/start/changelog/index.md
  15. 14 0
      cypress/e2e/datePicker.spec.js
  16. 14 1
      cypress/e2e/image.spec.js
  17. 79 0
      cypress/e2e/select.spec.js
  18. 6 0
      cypress/e2e/table.spec.js
  19. 11 0
      cypress/e2e/textarea.spec.js
  20. 33 0
      cypress/e2e/treeSelect.spec.js
  21. 1 1
      lerna.json
  22. 1 1
      package.json
  23. 3 3
      packages/semi-animation-react/package.json
  24. 1 1
      packages/semi-animation-styled/package.json
  25. 1 1
      packages/semi-animation/package.json
  26. 1 1
      packages/semi-eslint-plugin/package.json
  27. 10 6
      packages/semi-foundation/autoComplete/foundation.ts
  28. 4 0
      packages/semi-foundation/breadcrumb/breadcrumb.scss
  29. 3 1
      packages/semi-foundation/cascader/constants.ts
  30. 11 13
      packages/semi-foundation/cascader/foundation.ts
  31. 21 10
      packages/semi-foundation/cascader/util.ts
  32. 7 18
      packages/semi-foundation/datePicker/foundation.ts
  33. 5 1
      packages/semi-foundation/image/constants.ts
  34. 1 4
      packages/semi-foundation/image/previewFooterFoundation.ts
  35. 61 69
      packages/semi-foundation/image/previewImageFoundation.ts
  36. 77 34
      packages/semi-foundation/image/previewInnerFoundation.ts
  37. 33 12
      packages/semi-foundation/input/textareaFoundation.ts
  38. 4 0
      packages/semi-foundation/modal/modalFoundation.ts
  39. 3 3
      packages/semi-foundation/notification/notificationFoundation.ts
  40. 2 2
      packages/semi-foundation/package.json
  41. 5 2
      packages/semi-foundation/select/foundation.ts
  42. 4 0
      packages/semi-foundation/steps/bacisSteps.scss
  43. 2 1
      packages/semi-foundation/table/foundation.ts
  44. 16 0
      packages/semi-foundation/tree/rtl.scss
  45. 6 0
      packages/semi-foundation/tree/tree.scss
  46. 12 8
      packages/semi-foundation/treeSelect/foundation.ts
  47. 1 1
      packages/semi-icons-lab/package.json
  48. 1 1
      packages/semi-icons/package.json
  49. 1 1
      packages/semi-illustrations/package.json
  50. 2 2
      packages/semi-next/package.json
  51. 9 9
      packages/semi-rspack/README.md
  52. 1 1
      packages/semi-rspack/package.json
  53. 1 1
      packages/semi-scss-compile/package.json
  54. 1 1
      packages/semi-theme-default/package.json
  55. 314 291
      packages/semi-ui/autoComplete/_story/autoComplete.stories.jsx
  56. 15 2
      packages/semi-ui/cascader/__test__/cascader.test.js
  57. 140 1
      packages/semi-ui/cascader/_story/cascader.stories.jsx
  58. 18 30
      packages/semi-ui/cascader/index.tsx
  59. 6 1
      packages/semi-ui/datePicker/_story/datePicker.stories.jsx
  60. 22 0
      packages/semi-ui/datePicker/_story/v2/FixNeedConfirmControlled.tsx
  61. 1 0
      packages/semi-ui/datePicker/_story/v2/index.js
  62. 1 5
      packages/semi-ui/datePicker/yearAndMonth.tsx
  63. 1 1
      packages/semi-ui/dropdown/dropdownItem.tsx
  64. 52 1
      packages/semi-ui/image/_story/image.stories.jsx
  65. 1 0
      packages/semi-ui/image/_story/image.stories.tsx
  66. 7 2
      packages/semi-ui/image/image.tsx
  67. 15 5
      packages/semi-ui/image/interface.tsx
  68. 10 1
      packages/semi-ui/image/preview.tsx
  69. 4 9
      packages/semi-ui/image/previewFooter.tsx
  70. 6 6
      packages/semi-ui/image/previewHeader.tsx
  71. 26 80
      packages/semi-ui/image/previewImage.tsx
  72. 147 115
      packages/semi-ui/image/previewInner.tsx
  73. 3 1
      packages/semi-ui/index.ts
  74. 16 0
      packages/semi-ui/input/_story/input.stories.jsx
  75. 56 78
      packages/semi-ui/input/textarea.tsx
  76. 2 0
      packages/semi-ui/modal/Modal.tsx
  77. 8 7
      packages/semi-ui/notification/index.tsx
  78. 1 1
      packages/semi-ui/notification/notice.tsx
  79. 7 7
      packages/semi-ui/package.json
  80. 102 1
      packages/semi-ui/select/_story/select.stories.jsx
  81. 1 1
      packages/semi-ui/select/index.tsx
  82. 47 42
      packages/semi-ui/table/Body/BaseRow.tsx
  83. 27 21
      packages/semi-ui/table/Body/SectionRow.tsx
  84. 6 6
      packages/semi-ui/table/Body/index.tsx
  85. 2 1
      packages/semi-ui/table/_story/table.stories.jsx
  86. 65 0
      packages/semi-ui/table/_story/v2/FixedAllDisabledAndSelected/index.tsx
  87. 1 0
      packages/semi-ui/table/_story/v2/index.js
  88. 1 1
      packages/semi-ui/timePicker/TimePicker.tsx
  89. 1 0
      packages/semi-ui/tree/treeNode.tsx
  90. 93 61
      packages/semi-ui/treeSelect/_story/treeSelect.stories.jsx
  91. 152 50
      packages/semi-ui/treeSelect/index.tsx
  92. 1 1
      packages/semi-webpack/package.json
  93. 190 190
      sitemap.xml
  94. 1 1
      src/sitePages/newHome/components/banner/banner.jsx
  95. 23 23
      src/sitePages/newHome/components/comments/comments.jsx
  96. 8 7
      src/sitePages/newHome/components/feature/feature.jsx
  97. 1 1
      src/sitePages/newHome/components/operateButton/operateButton.jsx
  98. 3 0
      src/sitePages/newHome/components/pro/pro.jsx
  99. 5 5
      src/sitePages/newHome/components/products/products.jsx
  100. 2 2
      src/sitePages/newHome/components/resource/resource.jsx

+ 4 - 1
.eslintrc.js

@@ -43,7 +43,9 @@ module.exports = {
                 'jsx-a11y/mouse-events-have-key-events': ['warn'],
                 'jsx-a11y/mouse-events-have-key-events': ['warn'],
                 'object-curly-spacing': ['error', 'always'],
                 'object-curly-spacing': ['error', 'always'],
                 'space-before-blocks': ['error', 'always'],
                 'space-before-blocks': ['error', 'always'],
-                'max-len': 'off'
+                'max-len': 'off',
+                'react/forbid-foreign-prop-types': ['error', { "allowInPropTypes": true }]
+
             },
             },
             globals: {
             globals: {
                 "sinon": "readonly",
                 "sinon": "readonly",
@@ -130,6 +132,7 @@ module.exports = {
                         }
                         }
                     }
                     }
                 ],
                 ],
+                'react/forbid-foreign-prop-types': ['error', { "allowInPropTypes": true }]
             }
             }
         },
         },
     ],
     ],

+ 3 - 1
CONTRIBUTING.md

@@ -15,6 +15,7 @@ Semi 团队会维护两个常驻分支:`main` 和 `release`,根据我们的[
 Semi Design 团队会认真对待每一个 Pull Request。我们会 review 并合并你的代码。也有可能对你的代码提出一些修改意见。
 Semi Design 团队会认真对待每一个 Pull Request。我们会 review 并合并你的代码。也有可能对你的代码提出一些修改意见。
 
 
 要提交一个 Pull Request,请遵循以下步骤:
 要提交一个 Pull Request,请遵循以下步骤:
+ - Node.js > v16
  - Fork 项目并克隆下来
  - Fork 项目并克隆下来
 ```bash
 ```bash
 git clone https://github.com/<your-username>/semi-design.git
 git clone https://github.com/<your-username>/semi-design.git
@@ -26,7 +27,8 @@ git checkout -b <TOPIC_BRANCH_NAME>
 ```
 ```
 >安装环境前确保本地有 `lerna` 和 `yarn` 的依赖,如果没有则运行:
 >安装环境前确保本地有 `lerna` 和 `yarn` 的依赖,如果没有则运行:
 ```bash
 ```bash
-npm install --global lerna yarn
+corepack enable
+npm install --global lerna
 ```
 ```
  - 完成项目依赖安装
  - 完成项目依赖安装
 ```bash
 ```bash

+ 9 - 6
content/input/datepicker/index-en-US.md

@@ -1030,13 +1030,16 @@ Adopted in the semi-ui component library [date-fns(v2.9.0)](https://date-fns.org
 -   `"m"`: minutes
 -   `"m"`: minutes
 -   `"s"`: seconds
 -   `"s"`: seconds
 
 
-The default date time is formatted to:
+The following uses `new Date('2023-12-09 08:08:00')` or `[new Date('2023-12-09 08:08:00'), new Date('2023-12-10 10 :08:00')]` as `value` to explain the impact of different types and different `format` values on the displayed value:
+
+| type | format | display value |
+| --- | --- | --- |
+| date | yyyy-MM-dd | 2023-12-09 |
+| dateTime | yyyy-MM-dd HH:mm:ss | 2023-12-09 08:08:00 |
+| month | yyyy-MM | 2023-12 |
+| dateRange | yyyy-MM-dd | 2023-12-09 ~ 2023-12-10 |
+| dateTimeRange | yyyy-MM-dd HH:mm:ss | 2023-12-09 08:08 ~ 2023-12-10 10:08 |
 
 
--   `"date"`(date): `"yyyy-mm-dd`
--   `"dateTime"`(date and time)`"yyyy-mm-dd HH:mm:ss"`
--   `"month"`(month): `"yyyy-MM"`
--   `"dateRange"`(Date Range): `"yyyy-mm-dd ~ yyyy-mm-dd"`
--   `"dateTimeRange"`(Date and Time Range): `"yyyy-mm-dd HH:mm:ss ~ yyyy-mm-dd HH:mm:ss"`
 
 
 Multiple dates or times are used by default `","` (English comma) separated.
 Multiple dates or times are used by default `","` (English comma) separated.
 
 

+ 9 - 7
content/input/datepicker/index.md

@@ -1009,13 +1009,15 @@ semi-ui 组件库中采用 [date-fns(v2.9.0)](https://date-fns.org/v2.9.0/docs/G
 -   `"m"` :分钟
 -   `"m"` :分钟
 -   `"s"` :秒
 -   `"s"` :秒
 
 
-默认的日期时间会格式化为:
-
--   `"date"`(日期):`"yyyy-MM-dd"`
--   `"dateTime"`(日期时间):`"yyyy-MM-dd HH:mm:ss"`
--   `"month"`(年月):`"yyyy-MM"`
--   `"dateRange"`(日期范围):`"yyyy-MM-dd ~ yyyy-MM-dd"`
--   `"dateTimeRange"`(日期时间范围):`"yyyy-MM-dd HH:mm:ss ~ yyyy-MM-dd HH:mm:ss"`
+下面以 `new Date('2023-12-09 08:08:00')` 和 `[new Date('2023-12-09 08:08:00'), new Date('2023-12-10 10:08:00')]` 为例说明不同 `format` 值对展示值的影响:
+
+| 类型 | format | 展示值 |  
+| --- | --- |  --- | 
+| date | yyyy-MM-dd | 2023-12-09 |
+| dateTime | yyyy-MM-dd HH:mm:ss | 2023-12-09 08:08:00 |
+| month | yyyy-MM | 2023-12 |
+| dateRange | yyyy-MM-dd | 2023-12-09 ~ 2023-12-10 |
+| dateTimeRange | yyyy-MM-dd HH:mm:ss | 2023-12-09 08:08 ~ 2023-12-10 10:08 |
 
 
 多个日期或时间默认使用 `","` (英文逗号)分隔。
 多个日期或时间默认使用 `","` (英文逗号)分隔。
 
 

+ 153 - 4
content/input/form/index-en-US.md

@@ -1417,13 +1417,13 @@ import { Form, Button } from '@douyinfe/semi-ui';
 );
 );
 ```
 ```
 
 
-#### Add or delete form items dynamically - by use ArrayField
+### ArrayField Usage
 
 
 For array items that are dynamically added or deleted, we provide the `ArrayField` component to simplify the operation of add / remove
 For array items that are dynamically added or deleted, we provide the `ArrayField` component to simplify the operation of add / remove
 
 
 For the detailed API of ArrayField, please refer to [ArrayField Props](#arrayfield-props) below
 For the detailed API of ArrayField, please refer to [ArrayField Props](#arrayfield-props) below
 
 
-Note: The initValue type of ArrayField must be an array
+> Note: The initValue type of ArrayField must be an array
 
 
 ```jsx live=true dir="column"
 ```jsx live=true dir="column"
 import React from 'react';
 import React from 'react';
@@ -1497,6 +1497,155 @@ class ArrayFieldDemo extends React.Component {
 ```
 ```
 
 
 
 
+#### Nesting ArrayField
+
+ArrayField supports multi-level nesting. The following is an example of two-level nesting.
+
+```jsx live=true dir="column" noInline=true
+import { Form, ArrayField, Button, Card, Typography, } from "@douyinfe/semi-ui";
+import { IconPlusCircle, IconMinusCircle } from "@douyinfe/semi-icons";
+import React from "react";
+
+const initValue = {
+    group: [
+        {
+            name: "Email filtering rule 1",
+            rules: [
+                { itemName: "Sender address", type: "include" },
+                { itemName: "Email Title", type: "exclude" },
+            ],
+        },
+        {
+            name: "Email filtering rule 2",
+            rules: [
+                { itemName: "Send time", type: "include" }
+            ],
+        },
+    ]
+};
+
+const NestedField = (props) => {
+    const rowStyle = {
+        marginTop: 12,
+        marginLeft: 12,
+    };
+    return (
+        <ArrayField field={`${props.field}.rules`}>
+            {({ add, arrayFields, addWithInitValue }) => (
+                <React.Fragment>
+                    {arrayFields.map(({ field, key, remove }, i) => (
+                        <div style={{ display: "flex" }} key={key}>
+                            <Form.Input
+                                field={`${field}[itemName]`}
+                                label={`${field}.itemName`}
+                                noLabel
+                                style={{ width: 140, marginRight: 12 }}
+                            ></Form.Input>
+                            <Form.Select
+                                field={`${field}[type]`}
+                                label={`${field}.type`}
+                                noLabel
+                                style={{ width: 140 }}
+                                optionList={[
+                                    { label: "Include", value: "include" },
+                                    { label: "Exclude", value: "exclude" },
+                                ]}
+                            ></Form.Select>
+                            <Button
+                                type="danger"
+                                theme="borderless"
+                                style={rowStyle}
+                                icon={<IconMinusCircle />}
+                                onClick={remove}
+                            />
+                            <Button
+                                icon={<IconPlusCircle />}
+                                style={rowStyle}
+                                disabled={i !== arrayFields.length - 1}
+                                onClick={() => {
+                                    addWithInitValue({
+                                        itemName: `Condition ${arrayFields.length + 1}`,
+                                        type: "include",
+                                    });
+                                }}
+                            />
+                        </div>
+                    ))}
+                </React.Fragment>
+            )}
+        </ArrayField>
+    );
+};
+
+const NestArrayFieldDemo = () => {
+    return (
+        <Form
+            onValueChange={(values) => console.log(values)}
+            initValues={initValue}
+            labelPosition="left"
+            style={{ textAlign: "left" }}
+        >
+            <ArrayField field="group" allowEmpty>
+                {({ add, arrayFields, addWithInitValue }) => (
+                    <React.Fragment>
+                        <Button
+                            icon={<IconPlusCircle />}
+                            theme="solid"
+                            onClick={() => {
+                                addWithInitValue({
+                                    name: "New Rule",
+                                    rules: [
+                                        { itemName: "Main Text", type: "include" },
+                                        { itemName: "Accessory name", type: "include" },
+                                    ],
+                                });
+                            }}
+                        >
+                            Add receiving rules
+                        </Button>
+                        {arrayFields.map(({ field, key, remove }, i) => (
+                            <div
+                                key={key}
+                                style={{ width: 1000, display: "flex", flexWrap: "wrap" }}
+                            >
+                                <Form.Input
+                                    field={`${field}[name]`}
+                                    labelPosition="top"
+                                    label={"RuleName"}
+                                    style={{ width: "600px" }}
+                                ></Form.Input>
+                                <Button
+                                    type="danger"
+                                    theme="borderless"
+                                    style={{ margin: "36px 0 0 12px" }}
+                                    icon={<IconMinusCircle />}
+                                    onClick={remove}
+                                />
+                                <Typography.Text strong style={{ flexBasis: "100%" }}>
+                                    When the mail arrives, the following conditions are met:
+                                </Typography.Text>
+                                <Card
+                                    shadow="hover"
+                                    style={{
+                                        width: 620,
+                                        margin: "12px 0 0 24px",
+                                    }}
+                                >
+                                    <NestedField field={field} />
+                                </Card>
+                            </div>
+                        ))}
+                    </React.Fragment>
+                )}
+            </ArrayField>
+        </Form>
+    );
+};
+
+render(NestArrayFieldDemo);
+```
+
+
 #### Add or delete form items dynamically - by use formApi
 #### Add or delete form items dynamically - by use formApi
 
 
 If you don't use ArrayField, you can use the provided formApi to manually add or delete formState.
 If you don't use ArrayField, you can use the provided formApi to manually add or delete formState.
@@ -1544,12 +1693,12 @@ class ArrayDemo extends React.Component {
     renderItems(formState, values) {
     renderItems(formState, values) {
         return values.effects && values.effects.map((effect, i) => (
         return values.effects && values.effects.map((effect, i) => (
             <div key={effect.key} style={{ width: 1000, display: 'flex' }}>
             <div key={effect.key} style={{ width: 1000, display: 'flex' }}>
-                <Form.Input field={`effects[${i}].name`} style={{ width: 200, marginRight: 16 }}></Form.Input>
+                <Form.Input field={`effects[${i}].name`} style={{ width: 200, marginRight: 12 }}></Form.Input>
                 <Form.Select field={`effects[${i}].type`} style={{ width: 90 }}>
                 <Form.Select field={`effects[${i}].type`} style={{ width: 90 }}>
                     <Form.Select.Option value='2D'>2D</Form.Select.Option>
                     <Form.Select.Option value='2D'>2D</Form.Select.Option>
                     <Form.Select.Option value='3D'>3D</Form.Select.Option>
                     <Form.Select.Option value='3D'>3D</Form.Select.Option>
                 </Form.Select>
                 </Form.Select>
-                <Button type='danger' onClick={() => this.remove(effect.key)} style={{ margin: 16 }}>Remove</Button>
+                <Button type='danger' onClick={() => this.remove(effect.key)} style={{ margin: 12 }}>Remove</Button>
             </div>
             </div>
         ));
         ));
     }
     }

+ 152 - 1
content/input/form/index.md

@@ -1493,7 +1493,7 @@ import { Form, Button } from '@douyinfe/semi-ui';
 );
 );
 ```
 ```
 
 
-#### 数组类动态增删表单项-使用 ArrayField
+### 使用 ArrayField
 
 
 针对动态增删的数组类表单项,我们提供了 ArrayField 作用域来简化 add/remove 的操作  
 针对动态增删的数组类表单项,我们提供了 ArrayField 作用域来简化 add/remove 的操作  
 ArrayField 自带了 add、remove、addWithInitValue 等 api 用来执行新增行,删除行,新增带有初始值的行等操作  
 ArrayField 自带了 add、remove、addWithInitValue 等 api 用来执行新增行,删除行,新增带有初始值的行等操作  
@@ -1570,6 +1570,157 @@ class ArrayFieldDemo extends React.Component {
 }
 }
 ```
 ```
 
 
+
+#### 嵌套 ArrayField
+
+ArrayField 支持多级嵌套,如下是一个两级嵌套的例子
+
+```jsx live=true dir="column" noInline=true
+import { Form, ArrayField, Button, Card, Typography, } from "@douyinfe/semi-ui";
+import { IconPlusCircle, IconMinusCircle } from "@douyinfe/semi-icons";
+import React from "react";
+
+const initValue = {
+    group: [
+        {
+            name: "收信规则1",
+            rules: [
+                { itemName: "发件人地址", type: "include" },
+                { itemName: "邮件主题", type: "exclude" },
+            ],
+        },
+        {
+            name: "收信规则2",
+            rules: [
+                { itemName: "发送时间", type: "include" }
+            ],
+        },
+    ]
+};
+
+const NestedField = (props) => {
+    const rowStyle = {
+        marginTop: 12,
+        marginLeft: 12,
+    };
+    return (
+        <ArrayField field={`${props.field}.rules`}>
+            {({ add, arrayFields, addWithInitValue }) => (
+                <React.Fragment>
+                    {arrayFields.map(({ field, key, remove }, i) => (
+                        <div style={{ display: "flex" }} key={key}>
+                            <Form.Input
+                                field={`${field}[itemName]`}
+                                label={`${field}.itemName`}
+                                noLabel
+                                style={{ width: 100, marginRight: 12 }}
+                            ></Form.Input>
+                            <Form.Select
+                                field={`${field}[type]`}
+                                label={`${field}.type`}
+                                noLabel
+                                style={{ width: 100 }}
+                                optionList={[
+                                    { label: "包含", value: "include" },
+                                    { label: "不包含", value: "exclude" },
+                                ]}
+                            ></Form.Select>
+                            <Button
+                                type="danger"
+                                theme="borderless"
+                                style={rowStyle}
+                                icon={<IconMinusCircle />}
+                                onClick={remove}
+                            />
+                            <Button
+                                icon={<IconPlusCircle />}
+                                style={rowStyle}
+                                disabled={i !== arrayFields.length - 1}
+                                onClick={() => {
+                                    addWithInitValue({
+                                        itemName: `条件${arrayFields.length + 1}`,
+                                        type: "include",
+                                    });
+                                }}
+                            />
+                        </div>
+                    ))}
+                </React.Fragment>
+            )}
+        </ArrayField>
+    );
+};
+
+const NestArrayFieldDemo = () => {
+    return (
+        <Form
+            onValueChange={(values) => console.log(values)}
+            initValues={initValue}
+            labelPosition="left"
+            style={{ textAlign: "left" }}
+        >
+            <ArrayField field="group" allowEmpty>
+                {({ add, arrayFields, addWithInitValue }) => (
+                    <React.Fragment>
+                        <Button
+                            icon={<IconPlusCircle />}
+                            theme="solid"
+                            onClick={() => {
+                                addWithInitValue({
+                                    name: "新规则名称",
+                                    rules: [
+                                        { itemName: "正文", type: "include" },
+                                        { itemName: "附件名称", type: "include" },
+                                    ],
+                                });
+                            }}
+                        >
+                            新增收信规则
+                        </Button>
+                        {arrayFields.map(({ field, key, remove }, i) => (
+                            <div
+                                key={key}
+                                style={{ width: 1000, display: "flex", flexWrap: "wrap" }}
+                            >
+                                <Form.Input
+                                    field={`${field}[name]`}
+                                    labelPosition="top"
+                                    label={"规则名称"}
+                                    style={{ width: "600px" }}
+                                ></Form.Input>
+                                <Button
+                                    type="danger"
+                                    style={{ margin: "36px 0 0 12px" }}
+                                    icon={<IconMinusCircle />}
+                                    onClick={remove}
+                                />
+                                <Typography.Text strong style={{ flexBasis: "100%" }}>
+                                    当邮件到达,满足以下条件时:
+                                </Typography.Text>
+                                <Card
+                                    shadow="hover"
+                                    style={{
+                                        width: 620,
+                                        margin: "12px 0 0 24px",
+                                    }}
+                                >
+                                    <NestedField field={field} />
+                                </Card>
+                            </div>
+                        ))}
+                    </React.Fragment>
+                )}
+            </ArrayField>
+        </Form>
+    );
+};
+
+render(NestArrayFieldDemo);
+```
+
+
+
+
 ### Hooks 的使用
 ### Hooks 的使用
 
 
 我们提供了四个 Hooks,使你在不需要通过 props 传递的情况下,也能在放置于 Form 结构内部的 Functional Component 中也能轻易访问到 Form 内部状态数据,以及调用 Form、Field 的相关 api
 我们提供了四个 Hooks,使你在不需要通过 props 传递的情况下,也能在放置于 Form 结构内部的 Functional Component 中也能轻易访问到 Form 内部状态数据,以及调用 Form、Field 的相关 api

+ 3 - 0
content/show/image/index-en-US.md

@@ -470,6 +470,7 @@ import { Image, ImagePreview } from '@douyinfe/semi-ui';
 | crossOrigin      | Passthrough to the crossorigin of the native img tag | 'anonymous' \| 'use-credentials' |-| |
 | crossOrigin      | Passthrough to the crossorigin of the native img tag | 'anonymous' \| 'use-credentials' |-| |
 | fallback         | Custom loading failed display content | ReactNode  | - | |
 | fallback         | Custom loading failed display content | ReactNode  | - | |
 | height           | Image display height                 | number            | - | |
 | height           | Image display height                 | number            | - | |
+| onClick          | Click callback on image              | (event: Event) => void | - | |
 | onError          | Load error callback                  | (event: Event) => void | - | |
 | onError          | Load error callback                  | (event: Event) => void | - | |
 | onLoad           | Load success callback                | (event: Event) => void | - | |
 | onLoad           | Load success callback                | (event: Event) => void | - | |
 | placeholder      | Placeholder content when the image is not loaded | ReactNode | - | |
 | placeholder      | Placeholder content when the image is not loaded | ReactNode | - | |
@@ -511,6 +512,8 @@ import { Image, ImagePreview } from '@douyinfe/semi-ui';
 | preLoad          | Whether to enable preloading                                                                                                                                             | boolean | true | |
 | preLoad          | Whether to enable preloading                                                                                                                                             | boolean | true | |
 | preLoadGap       | Preloaded step size                                                                                                                                                      | number         | 2 | |
 | preLoadGap       | Preloaded step size                                                                                                                                                      | number         | 2 | |
 | previewTitle     | Custom preview title                                                                                                                                                     | ReactNode      | - | |
 | previewTitle     | Custom preview title                                                                                                                                                     | ReactNode      | - | |
+| previewCls        | Custom preview style class name                                                                                                                                       | string           | - | |
+| previewStyle        | Custom preview style                                                                                                                                       | object           | - | |
 | prevTip          | Previous operation button prompt                                                                                                                                         | string  | "Previous" | |
 | prevTip          | Previous operation button prompt                                                                                                                                         | string  | "Previous" | |
 | renderHeader     | Custom render preview top info                                                                                                                                           |(info: reactNode) => ReactNode  | - | |
 | renderHeader     | Custom render preview top info                                                                                                                                           |(info: reactNode) => ReactNode  | - | |
 | renderPreviewMenu | Custom render preview bottom menu information                                                                                                                            | (props: MenuProps) => ReactNode; | - | |
 | renderPreviewMenu | Custom render preview bottom menu information                                                                                                                            | (props: MenuProps) => ReactNode; | - | |

+ 3 - 0
content/show/image/index.md

@@ -471,6 +471,7 @@ import { Image, ImagePreview } from '@douyinfe/semi-ui';
 | crossOrigin       | 透传给原生 img 标签的 crossorigin         | 'anonymous'|'use-credentials'| - | |
 | crossOrigin       | 透传给原生 img 标签的 crossorigin         | 'anonymous'|'use-credentials'| - | |
 | fallback          | 加载失败容错地址或者自定义加载失败时的显示内容 | ReactNode  | - | |
 | fallback          | 加载失败容错地址或者自定义加载失败时的显示内容 | ReactNode  | - | |
 | height            | 图片显示高度                             | number            | - | |
 | height            | 图片显示高度                             | number            | - | |
+| onClick           | 点击图片的回调                            | (event: any) => void | - | |
 | onError           | 加载错误回调                              | (event: Event) => void | - | |
 | onError           | 加载错误回调                              | (event: Event) => void | - | |
 | onLoad            | 加载成功回调                              | (event: Event) => void | - | |
 | onLoad            | 加载成功回调                              | (event: Event) => void | - | |
 | placeholder       | 图片未加载时候的占位内容                   | ReactNode         | - | |
 | placeholder       | 图片未加载时候的占位内容                   | ReactNode         | - | |
@@ -513,6 +514,8 @@ import { Image, ImagePreview } from '@douyinfe/semi-ui';
 | preLoad           | 是否开启预加载                                                                                                                                          | boolean        | true | |
 | preLoad           | 是否开启预加载                                                                                                                                          | boolean        | true | |
 | preLoadGap        | 预加载的步长                                                                                                                                           | number         | 2 | |
 | preLoadGap        | 预加载的步长                                                                                                                                           | number         | 2 | |
 | previewTitle      | 自定义预览 title                                                                                                                                      | ReactNode      | - | |
 | previewTitle      | 自定义预览 title                                                                                                                                      | ReactNode      | - | |
+| previewCls        | 自定义预览样式类名                                                                                                                                       | string           | - | |
+| previewStyle        | 自定义预览样式                                                                                                                                       | object           | - | |
 | prevTip           | 上一步操作按钮提示                                                                                                                                        | string         | "上一步" | |
 | prevTip           | 上一步操作按钮提示                                                                                                                                        | string         | "上一步" | |
 | renderHeader      | 自定义渲染预览顶部信息                                                                                                                                      | (info: ReactNode) => ReactNode  | - | |
 | renderHeader      | 自定义渲染预览顶部信息                                                                                                                                      | (info: ReactNode) => ReactNode  | - | |
 | renderPreviewMenu | 自定义渲染预览底部菜单信息                                                                                                                                    | (props: MenuProps) => ReactNode;| - | |
 | renderPreviewMenu | 自定义渲染预览底部菜单信息                                                                                                                                    | (props: MenuProps) => ReactNode;| - | |

+ 31 - 22
content/show/popover/index-en-US.md

@@ -474,27 +474,36 @@ import { Popover, Tag } from '@douyinfe/semi-ui';
 
 
 function Demo() {
 function Demo() {
     return (
     return (
-        <Popover
-            content={
-                <article style={{ padding: 4 }}>
-                    Hi ByteDancer, this is a popover.
-                    <br /> We have 2 lines.
-                </article>
-            }
-            trigger="custom"
-            position='right'
-            visible
-            showArrow
-            style={{
-                backgroundColor: 'rgba(var(--semi-blue-4),1)',
-                borderColor: 'rgba(var(--semi-blue-4),1)',
-                color: 'var(--semi-color-white)',
-                borderWidth: 1,
-                borderStyle: 'solid',
-            }}
-        >
-            <Tag>Click here</Tag>
-        </Popover>
+        <div id='popup-parent' style={{ position: 'relative' }}>
+            <Popover
+                content={
+                    <article style={{ padding: 4 }}>
+                        Hi, Semi UI Popover.
+                    </article>
+                }
+                getPopupContainer={() => document.querySelector('#popup-parent')}
+                trigger='custom'
+                visible
+                position='right'
+                showArrow
+                style={{
+                    backgroundColor: 'rgba(var(--semi-blue-4),1)',
+                    borderColor: 'rgba(var(--semi-blue-4),1)',
+                    color: 'var(--semi-color-white)',
+                    borderWidth: 1,
+                    borderStyle: 'solid',
+                }}
+            >
+                <Tag
+                    style={{
+                        backgroundColor: 'rgba(var(--semi-blue-4),1)',
+                        color: 'var(--semi-color-white)'
+                    }}
+                >
+                    Colorful Popover
+                </Tag>
+            </Popover>
+        </div>
     );
     );
 }
 }
 ```
 ```
@@ -549,7 +558,7 @@ Please refer to [Use with Tooltip/Popconfirm](/en-US/show/tooltip#%E6%90%AD%E9%8
 | returnFocusOnClose | After pressing the Esc key, whether the focus returns to the trigger, it only takes effect when the trigger is set to hover, focus, click, etc                                                                                                | boolean | true | **2.8.0** |
 | returnFocusOnClose | After pressing the Esc key, whether the focus returns to the trigger, it only takes effect when the trigger is set to hover, focus, click, etc                                                                                                | boolean | true | **2.8.0** |
 | visible | Display popup or not                                                                                                                                                                                                                          | boolean |  |
 | visible | Display popup or not                                                                                                                                                                                                                          | boolean |  |
 | position | Directions, optional values: `top`, `topLeft`, `topRight`, `left`, `leftTop`, `leftBottom`, `right`, `rightTop`, `rightBottom`, `bottom`, `bottomLeft`, `bottomRight`                                                                         | string | "bottom" |
 | position | Directions, optional values: `top`, `topLeft`, `topRight`, `left`, `leftTop`, `leftBottom`, `right`, `rightTop`, `rightBottom`, `bottom`, `bottomLeft`, `bottomRight`                                                                         | string | "bottom" |
-| spacing | The distance between the out layer and the children element, in px                                                                                                                                                                            | number| <ApiType detail='{ x: number; y: number }'>SpacingObject</ApiType>  | 4(while showArrow=false) 10(while showArrow=true) |  |
+| spacing | The distance between the out layer and the children element, in px. object type props supported after v2.45                                                                                                                                                                            | number| <ApiType detail='{ x: number; y: number }'>SpacingObject</ApiType>  | 4(while showArrow=false) 10(while showArrow=true) |  |
 | showArrow | Display little arrow or not                                                                                                                                                                                                                   | boolean |  |
 | showArrow | Display little arrow or not                                                                                                                                                                                                                   | boolean |  |
 | trigger | Trigger mode, optional value: `hover`, `focus`, `click`, `custom`                                                                                                                                                                             | string | 'hover' |
 | trigger | Trigger mode, optional value: `hover`, `focus`, `click`, `custom`                                                                                                                                                                             | string | 'hover' |
 | stopPropagation | Whether to prevent click events on the bomb layer from bubbling                                                                                                                                                                               | boolean | false | **0.34.0** |
 | stopPropagation | Whether to prevent click events on the bomb layer from bubbling                                                                                                                                                                               | boolean | false | **0.34.0** |

+ 27 - 23
content/show/popover/index.md

@@ -457,34 +457,38 @@ import { Popover, Tag } from '@douyinfe/semi-ui';
 
 
 function Demo() {
 function Demo() {
     return (
     return (
-        <Popover
-            content={
-                <article style={{ padding: 4 }}>
-                    Hi ByteDancer, this is a popover.
-                </article>
-            }
-            position='right'
-            showArrow
-            style={{
-                backgroundColor: 'rgba(var(--semi-blue-4),1)',
-                borderColor: 'rgba(var(--semi-blue-4),1)',
-                color: 'var(--semi-color-white)',
-                borderWidth: 1,
-                borderStyle: 'solid',
-            }}
-        >
-            <Tag
+        <div id='popup-parent' style={{ position: 'relative' }}>
+            <Popover
+                content={
+                    <article style={{ padding: 4 }}>
+                        Hi, Semi UI Popover.
+                    </article>
+                }
+                getPopupContainer={() => document.querySelector('#popup-parent')}
+                trigger='custom'
+                visible
+                position='right'
+                showArrow
                 style={{
                 style={{
                     backgroundColor: 'rgba(var(--semi-blue-4),1)',
                     backgroundColor: 'rgba(var(--semi-blue-4),1)',
-                    color: 'var(--semi-color-white)'
+                    borderColor: 'rgba(var(--semi-blue-4),1)',
+                    color: 'var(--semi-color-white)',
+                    borderWidth: 1,
+                    borderStyle: 'solid',
                 }}
                 }}
             >
             >
-                点击此处
-            </Tag>
-        </Popover>
+                <Tag
+                    style={{
+                        backgroundColor: 'rgba(var(--semi-blue-4),1)',
+                        color: 'var(--semi-color-white)'
+                    }}
+                >
+                    Colorful Popover
+                </Tag>
+            </Popover>
+        </div>
     );
     );
 }
 }
-
 ```
 ```
 
 
 ### 初始化弹出层焦点位置
 ### 初始化弹出层焦点位置
@@ -539,7 +543,7 @@ import { Button, Input, Popover, Space } from '@douyinfe/semi-ui';
 | rePosKey           | 可以更新该项值手动触发弹出层的重新定位                                                                                                         | string\|number             |            |             |
 | rePosKey           | 可以更新该项值手动触发弹出层的重新定位                                                                                                         | string\|number             |            |             |
 | returnFocusOnClose | 按下 Esc 键后,焦点是否回到 trigger 上,设置 trigger 为 hover, focus, click 时生效 | boolean | true  | **2.8.0**  |
 | returnFocusOnClose | 按下 Esc 键后,焦点是否回到 trigger 上,设置 trigger 为 hover, focus, click 时生效 | boolean | true  | **2.8.0**  |
 | position           | 方向,可选值:`top`,`topLeft`,`topRight`,`left`,`leftTop`,`leftBottom`,`right`,`rightTop`,`rightBottom`,`bottom`,`bottomLeft`,`bottomRight` | string                     | "bottom"                                    |            |
 | position           | 方向,可选值:`top`,`topLeft`,`topRight`,`left`,`leftTop`,`leftBottom`,`right`,`rightTop`,`rightBottom`,`bottom`,`bottomLeft`,`bottomRight` | string                     | "bottom"                                    |            |
-| spacing            | 弹出层与 children 元素的距离,单位 px                                                                                                       | number| <ApiType detail='{ x: number; y: number }'>SpacingObject</ApiType>                       | 4(showArrow=false 时) 10(showArrow=true 时) |            |
+| spacing            | 弹出层与 children 元素的距离,单位 px(object类型自 v2.45后支持)                                                                                                       | number| <ApiType detail='{ x: number; y: number }'>SpacingObject</ApiType>                       | 4(showArrow=false 时) 10(showArrow=true 时) |            |
 | showArrow          | 是否显示“小三角”                                                                                                                            | boolean                    |                                             |            |
 | showArrow          | 是否显示“小三角”                                                                                                                            | boolean                    |                                             |            |
 | stopPropagation    | 是否阻止弹出层上的点击事件冒泡                                                                                                              | boolean                    | false                                       | **0.34.0** |
 | stopPropagation    | 是否阻止弹出层上的点击事件冒泡                                                                                                              | boolean                    | false                                       | **0.34.0** |
 | trigger            | 触发方式,可选值:`hover`, `focus`, `click`, `custom`, `contextMenu`(v2.42支持)                                                          | string                     | 'hover'                                     |            |
 | trigger            | 触发方式,可选值:`hover`, `focus`, `click`, `custom`, `contextMenu`(v2.42支持)                                                          | string                     | 'hover'                                     |            |

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

@@ -349,7 +349,7 @@ import { Popconfirm, Tooltip, Button } from '@douyinfe/semi-ui';
 | preventScroll | Indicates whether the browser should scroll the document to display the newly focused element, acting on the focus method inside the component, excluding the component passed in by the user                               | boolean |  |  |
 | preventScroll | Indicates whether the browser should scroll the document to display the newly focused element, acting on the focus method inside the component, excluding the component passed in by the user                               | boolean |  |  |
 | rePosKey | This value can be updated to manually trigger the repositioning of the pop-up layer.                                                                                                                                        | string | number |  |
 | rePosKey | This value can be updated to manually trigger the repositioning of the pop-up layer.                                                                                                                                        | string | number |  |
 | style | Pop-up layer inline style                                                                                                                                                                                                   | object |  |  |
 | style | Pop-up layer inline style                                                                                                                                                                                                   | object |  |  |
-| spacing | The distance between the pop-up layer and the `children` element                                                                                                                                                            | number | <ApiType detail='{ x: number; y: number }'>SpacingObject</ApiType>|  |  |
+| spacing | The distance between the pop-up layer and the `children`. object type props supported after v2.45 element                                                                                                                                                            | number | <ApiType detail='{ x: number; y: number }'>SpacingObject</ApiType>|  |  |
 | showArrow | Does it show an arrow triangle?                                                                                                                                                                                             | boolean | true |  |
 | showArrow | Does it show an arrow triangle?                                                                                                                                                                                             | boolean | true |  |
 | stopPropagation | Whether to prevent click events on the bomb layer from bubbling                                                                                                                                                             | boolean | false | **0.34.0** |
 | stopPropagation | Whether to prevent click events on the bomb layer from bubbling                                                                                                                                                             | boolean | false | **0.34.0** |
 | transformFromCenter | Whether to transform from the horizontal or vertical center of the element of the package, this parameter affects only the `tansform-origin 'of the dynamic effect transformation and generally does not need to be changed | boolean | true |
 | transformFromCenter | Whether to transform from the horizontal or vertical center of the element of the package, this parameter affects only the `tansform-origin 'of the dynamic effect transformation and generally does not need to be changed | boolean | true |

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

@@ -385,7 +385,7 @@ function Demo() {
 | preventScroll | 指示浏览器是否应滚动文档以显示新聚焦的元素,作用于组件内的 focus 方法                                                                                                               | boolean |  |  |
 | preventScroll | 指示浏览器是否应滚动文档以显示新聚焦的元素,作用于组件内的 focus 方法                                                                                                               | boolean |  |  |
 | rePosKey | 可以更新该项值手动触发弹出层的重新定位                                                                                                                                  | string\|number |  |  |
 | rePosKey | 可以更新该项值手动触发弹出层的重新定位                                                                                                                                  | string\|number |  |  |
 | style    | 弹出层的内联样式                                                                                                                                             | object |  |  |
 | style    | 弹出层的内联样式                                                                                                                                             | object |  |  |
-| spacing | 弹出层与 `children` 元素的距离,单位 px                                                                                                                          | number | <ApiType detail='{ x: number; y: number }'>SpacingObject</ApiType>  | 8 |  |
+| spacing | 弹出层与 `children` 元素的距离,单位 px(object类型自 v2.45后支持)                                                                                                                     | number | <ApiType detail='{ x: number; y: number }'>SpacingObject</ApiType>  | 8 |  |
 | showArrow | 是否显示箭头三角形                                                                                                                                            | boolean | true |  |
 | showArrow | 是否显示箭头三角形                                                                                                                                            | boolean | true |  |
 | stopPropagation | 是否阻止弹层上的点击事件冒泡                                                                                                                                       | boolean | false | **0.34.0** |
 | stopPropagation | 是否阻止弹层上的点击事件冒泡                                                                                                                                       | boolean | false | **0.34.0** |
 | transformFromCenter | 是否从包裹的元素水平或垂直中心处变换,该参数仅影响动效变换的 `transform-origin`,一般无需改动                                                                                             | boolean | true |  |
 | transformFromCenter | 是否从包裹的元素水平或垂直中心处变换,该参数仅影响动效变换的 `transform-origin`,一般无需改动                                                                                             | boolean | true |  |

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

@@ -16,6 +16,77 @@ Version:Major.Minor.Patch (follow the **Semver** specification)
 
 
 ---
 ---
 
 
+#### 🎉 2.51.3 (2024-01-19)
+- 【Fix】
+    - Fixed Table propTypes is removed in prod mode
+
+#### 🎉 2.51.2 (2024-01-19)
+- 【Fix】
+    - Fixed TextArea autoSize is not work when textarea resize [#2026](https://github.com/DouyinFE/semi-design/issues/2026)
+    - Fixed controlled DatePicker input value is wrong when type is dateTimeRange and needConfirm is opened [#2024](https://github.com/DouyinFE/semi-design/issues/2024)
+    - Fixed the problem of triggering onClose/onPreview twice when clicking the edge of the close button in the preview state in the ImagePreview component [#2027](https://github.com/DouyinFE/semi-design/pull/2027)
+
+#### 🎉 2.51.1 (2024-01-18)
+- 【Fix】
+    - Unloading the Modal directly when the Modal is not collapsed may cause the page to scroll abnormally. [#2023](https://github.com/DouyinFE/semi-design/pull/2023)
+
+#### 🎉 2.51.0 (2024-01-12)
+- 【Fix】
+    - Fixed the problem that when a TextArea with maxLength is input in Chinese, clicking outside triggers blur, and the echoed content does not comply with the maxLength setting  [#2005](https://github.com/DouyinFE/semi-design/issues/2005)
+    - Fix typeError in Cascader when autoMergeValue is false and value is [] [#2017](https://github.com/DouyinFE/semi-design/pull/2017)
+- 【Style】
+    - The default zIndex value of ImagePreview's preview layer is adjusted from 1000 to 1070
+
+#### 🎉 2.51.0-beta.0 (2024-01-09)
+- 【Feat】
+    - Dropdown.Item supports transparent transmission of data-* attributes to dom
+    - ImagePreview adds previewCls and previewStyle for setting the preview style
+    - Image adds onClick API
+- 【Perf】
+    - Optimize Cascader's stuck problem when thousand-level leaf nodes are selected under multi-selection, leafOnly, searchable, and controlled conditions [#1999](https://github.com/DouyinFE/semi-design/pull/1999)
+- 【Fix】
+    - Fixed the problem that the table header is not selected when all rows of Table are selected and disabled [#2001](https://github.com/DouyinFE/semi-design/issues/2001)
+    - Fixed the issue where the controlled AutoComplete configured with onSelectWithObject reported an error when clicking the clear button [#2013](https://github.com/DouyinFE/semi-design/issues/2013)
+    - Fixed the problem of creating portal DOM node by default when Image is not displayed [#2004](https://github.com/DouyinFE/semi-design/issues/2004)
+    - Fixed the problem that the closable parameter of Image does not take effect
+
+#### 🎉 2.50.1 (2024-01-04)
+- 【Fix】
+    - Fix the indentation error problem when renderingFullLabel after Tree supports showLine(scope of impact: v2.50.0)[#2007](https://github.com/DouyinFE/semi-design/pull/2007)
+    - After Tree supports showLine, the connection line and option text partially overlap in rtl mode (scope of impact: v2.50.0) [#2007](https://github.com/DouyinFE/semi-design/pull/2007)
+- 【Style】
+    - Fix the font-weight error of the active item in BreadCrumb(scope of impact: v2.47-2.50) [#2008](https://github.com/DouyinFE/semi-design/pull/2008)
+
+#### 🎉 2.50.0 (2024-01-02)
+- 【Fix】
+  - When opening a preview in ImagePreview and switching preview images, Zoom changes do not need to be exposed through onZoomIn/onZoomOut
+    callbacks  [#2000 ](https://github.com/DouyinFE/semi-design/issues/2000)
+  - Fixed the issue of unexpected onRotateLeft callback being triggered when switching images during image preview
+
+
+#### 🎉 2.50.0-beta.0 (2023-12-26)
+- 【Feat】
+    - Tree, TreeSelect add showLine api.  [#1801 ](https://github.com/DouyinFE/semi-design/issues/1801) [@Yan-XiaoMing](https://github.com/Yan-XiaoMing)
+    - Table column support sortIcon
+- 【Style】
+    - Modify the CSS implementation of the indentation of each line of the Tree/TreeSelect option. There is no limit to the indentation level greater than 20 levels. [@Yan-XiaoMing](https://github.com/Yan-XiaoMing)
+- 【Fix】
+    - fix the problem that types of Id in Notification is not correct.
+    - 
+#### 🎉 2.49.2 (2023-12-26)
+- 【Fix】
+    - fix the problem of Select failing to select option after clicking outside when the selection is radio (scope of impact v2.49.0)
+    - Fixed the problem that showFilteredOnly does not take effect in TreeSelect controlled expandedKeys  [#1542 ](https://github.com/DouyinFE/semi-design/issues/1542)
+    - fixed the problem that when the DatePicker type is monthRange, the limited date range does not meet the expectations.
+    - Fixed vertical basic step style error when setting box-sizing to border-box globally.  [#1985 ](https://github.com/DouyinFE/semi-design/issues/1985)
+    - Remove the optional type setting of props of triggerRender of TreeSelect/Select  [#532 ](https://github.com/DouyinFE/semi-design/issues/532)
+    - Fixed an issue where `Notification.addNotice()` did not use the global configuration set via `Notification.config()` [@lideming](https://github.com/lideming)
+
+#### 🎉 2.49.0 (2023-12-15)
+- 【Fix】
+    - Image supports zooming via panel and mouse scrolling anywhere on the preview page [#1890](https://github.com/DouyinFE/semi-design/pull/1890)
+    - The initial size of the Image preview has been adjusted. Before adjustment, the initial size of the preview is to fit the width and height of the page; after adjustment, if the width and height of the image are smaller than the width and height of the page, the initial width and height of the preview will be the same as the width and height of the image, otherwise the preview will be scaled to fit the width and height of the page.[#1890](https://github.com/DouyinFE/semi-design/pull/1890)
+    - fixed the problem that after selecting a radio option, clicking outside does not trigger the onblur event [#1977](https://github.com/DouyinFE/semi-design/pull/1977)
 
 
 #### 🎉 2.49.0-beta.0 (2023-12-11)
 #### 🎉 2.49.0-beta.0 (2023-12-11)
 - 【Feat】
 - 【Feat】
@@ -151,6 +222,10 @@ Version:Major.Minor.Patch (follow the **Semver** specification)
     - Fixed an issue where the Item click did not take effect in very few scenarios when nesting Dropdowns.
     - Fixed an issue where the Item click did not take effect in very few scenarios when nesting Dropdowns.
     - fixed resizable table onHeaderCell bug  [#1796](https://github.com/DouyinFE/semi-design/issues/1796)
     - fixed resizable table onHeaderCell bug  [#1796](https://github.com/DouyinFE/semi-design/issues/1796)
 
 
+#### 🎉 2.42.3 (2023-09-01)
+- 【Fix】
+    - Fix: Fix Table baseRow onMouseLeave error [#1794](https://github.com/DouyinFE/semi-design/pull/1794)
+
 #### 🎉 2.42.2 (2023-08-28)
 #### 🎉 2.42.2 (2023-08-28)
 - 【Fix】
 - 【Fix】
     - Fix the problem that when the image file name has a query parameter, the image cannot be opened due to the wrong file name after downloading [@nekocode](https://github.com/nekocode) [#1782](https://github.com/DouyinFE/semi-design/pull/1784)
     - Fix the problem that when the image file name has a query parameter, the image cannot be opened due to the wrong file name after downloading [@nekocode](https://github.com/nekocode) [#1782](https://github.com/DouyinFE/semi-design/pull/1784)

+ 81 - 6
content/start/changelog/index.md

@@ -8,11 +8,82 @@ brief: 关于 Semi Design For React 优化与更新。我们提供了版本间
 ---
 ---
 
 
 Semi 版本号遵循 **Semver** 规范(主版本号-次版本号-修订版本号):
 Semi 版本号遵循 **Semver** 规范(主版本号-次版本号-修订版本号):
--   主版本号(major):重大性能/使用变更,允许做 breaking change
--   次版本号(minor):Semi 固定每两周发布一个 minor 版本,包括以下类型变更:添加了新组件/新 feature,或者样式变更
+-   主版本号(major):大版本更新,一般为重大性能/使用变更,允许做 API 级别的 breaking change
+-   次版本号(minor):Semi 固定每两周发布一个 minor 版本,包括以下类型变更:添加了新组件/新 feature,或者设计规范样式更新,或者不合理交互的变更,但不会对组件 API 做删减或功能变更。
 -   修订版本号(patch):仅会进行 bugfix,发布时间不限
 -   修订版本号(patch):仅会进行 bugfix,发布时间不限
 -   不同版本间的详细关系,可查阅 [FAQ](/zh-CN/start/faq)
 -   不同版本间的详细关系,可查阅 [FAQ](/zh-CN/start/faq)
 
 
+#### 🎉 2.51.3 (2024-01-19)
+- 【Fix】
+    - 修复 Table propTypes 被打包工具移除掉导致报错问题
+
+#### 🎉 2.51.2 (2024-01-19)
+- 【Fix】
+    - 修复 TextArea autosize 未监听文本域宽度变化 [#2026](https://github.com/DouyinFE/semi-design/issues/2026)
+    - 修复受控 DatePicker dateTimeRange + needConfirm 时选择一个日期时输入框回显错误 [#2024](https://github.com/DouyinFE/semi-design/issues/2024)
+    - 修复 ImagePreview 组件在预览时点击关闭按钮边缘时触发 onClose/onPreview 两次问题 [#2027](https://github.com/DouyinFE/semi-design/pull/2027)
+
+#### 🎉 2.51.1 (2024-01-18)
+- 【Fix】
+    - 修复当 Modal 未收起时直接时直接卸载 Modal 导致页面可能滚动异常的问题 [#2023](https://github.com/DouyinFE/semi-design/pull/2023)
+
+#### 🎉 2.51.0 (2024-01-12)
+- 【Fix】
+    - 修复有 maxLength的 TextArea 在中文输入时,点击外部触发 blur,回显内容不符合 maxLength 设置问题  [#2005](https://github.com/DouyinFE/semi-design/issues/2005)
+    - 修复 Cascader 中 autoMergeValue 为 false, value 为 [] 时的 typeError [#2017](https://github.com/DouyinFE/semi-design/pull/2017)
+- 【Style】
+    - ImagePreview 预览层的默认 zIndex 从 1000 调整为 1070
+
+#### 🎉 2.51.0-beta.0 (2024-01-09)
+- 【Feat】
+    - Dropdown.Item 支持透传 data-* 属性到 dom
+    - ImagePreview 增加 previewCls,previewStyle 用于设置预览的样式
+    - Image 增加 onClick API
+- 【Perf】
+    - 优化 Cascader 在多选,leafOnly,可搜索,受控情况下在千级叶子节点量级时被选中出现卡顿问题 [#1999](https://github.com/DouyinFE/semi-design/pull/1999)
+- 【Fix】
+    - 修复 Table 所有行全选且禁用时表头选择未选中问题  [#2001](https://github.com/DouyinFE/semi-design/issues/2001)
+    - 修复配置了 onSelectWithObject 的受控 AutoComplete 在点击 clear 清空按钮时报错的问题 [#2013](https://github.com/DouyinFE/semi-design/issues/2013)
+    - 修复 Image 在未展示时也默认创建 portal DOM节点的问题  [#2004](https://github.com/DouyinFE/semi-design/issues/2004)
+    - 修复 Image 的 closable 参数不生效问题 
+
+
+#### 🎉 2.50.1 (2024-01-04)
+- 【Fix】
+    - 修复 Tree 在支持 showLine 后, renderFullLabel 时缩进错误问题(影响范围:v2.50.0)[#2007](https://github.com/DouyinFE/semi-design/pull/2007)
+    - 修复 Tree 在支持 showLine 后, rtl 模式下连接线和选项文字部分重合问题(影响范围:v2.50.0)[#2007](https://github.com/DouyinFE/semi-design/pull/2007)
+- 【Style】
+    - 修复 BreadCrumb 中 active 项 font-weight 错误问题 (影响范围 v2.47-2.50)[#2008](https://github.com/DouyinFE/semi-design/pull/2008)
+
+#### 🎉 2.50.0 (2024-01-02)
+- 【Fix】
+  - ImagePreview 中打开预览,切换预览图片时,zoom 改变不需要通过 onZoomIn/onZoomOut 回调透出  [#2000](https://github.com/DouyinFE/semi-design/issues/2000)
+  - 修复在图片预览时切换图片触发意外的 onRotateLeft 回调
+
+#### 🎉 2.50.0-beta.0 (2023-12-26)
+- 【Feat】
+    - Tree, TreeSelect 新增 showLine api  [#1801](https://github.com/DouyinFE/semi-design/issues/1801) [@Yan-XiaoMing](https://github.com/Yan-XiaoMing)
+    - Table 列支持自定义排序 icon
+- 【Style】
+    - 修改 Tree/TreeSelect 的选项每行缩进的 CSS 实现,对于缩进层级大于 20层的,不再有限制。 [@Yan-XiaoMing](https://github.com/Yan-XiaoMing)
+- 【Fix】
+    - 修复 Notification 的 Id 类型不正确的问题
+    - 
+#### 🎉 2.49.2 (2023-12-26)
+- 【Fix】
+    - 修复 Select 在单选情况下,点击外部后再次选择选项失败问题(影响范围 v2.49.0)
+    - 修复受控 expandedKeys 的 TreeSelect 中,showFilteredOnly 不生效问题  [#1542 ](https://github.com/DouyinFE/semi-design/issues/1542)
+    - 修复 DatePicker 类型为 monthRange 时,限制日期范围不符合预期问题。
+    - 修复在全局设置box-sizing 为 border-box后,vertical 的basic step 样式错误问题  [#1985 ](https://github.com/DouyinFE/semi-design/issues/1985)
+    - 去除 TreeSelect/Select 的triggerRender的props 的可选类型设置  [#532 ](https://github.com/DouyinFE/semi-design/issues/532)
+    - 修复 `Notification.addNotice()` 未使用通过 `Notification.config()` 设置的全局配置的问题 [@lideming](https://github.com/lideming)
+
+#### 🎉 2.49.0 (2023-12-15)
+- 【Fix】
+    - Image 支持在预览页面的任何位置通过面板和鼠标滚动进行缩放 [#1890](https://github.com/DouyinFE/semi-design/pull/1890)
+    - Image 预览的初始尺寸做了调整。调整前,预览初始尺寸为适应页面的宽高;调整后,如果图片宽高小于适应页面的宽高,则预览初始宽高和图片宽高相同,否则以适应页面宽高进行缩放 [#1890](https://github.com/DouyinFE/semi-design/pull/1890)
+    - 修复 Select 单选选择选项后,点击外部不触发 onblur 事件问题 [#1977](https://github.com/DouyinFE/semi-design/pull/1977)
+
 #### 🎉 2.49.0-beta.0 (2023-12-11)
 #### 🎉 2.49.0-beta.0 (2023-12-11)
 - 【Feat】
 - 【Feat】
     - Table 支持 keepDOM,在折叠时不销毁被折叠的行 [#1969](https://github.com/DouyinFE/semi-design/pull/1969)
     - Table 支持 keepDOM,在折叠时不销毁被折叠的行 [#1969](https://github.com/DouyinFE/semi-design/pull/1969)
@@ -29,7 +100,7 @@ Semi 版本号遵循 **Semver** 规范(主版本号-次版本号-修订版本
 
 
 #### 🎉 2.48.0 (2023-12-01)
 #### 🎉 2.48.0 (2023-12-01)
 - 【Fix】
 - 【Fix】
-    - 修复 TimePicker format 为 HH 时,defaultValue 设置不正确问题。(注意:若原先 default 或 value 传入的值类型不合法,例如数字格式的时间戳以字符串形式传入,将不再尝试进行类型转换)
+    - **修复 TimePicker format 为 HH 时,defaultValue 设置不正确问题。(注意:若原先 default 或 value 传入的值类型不合法,例如数字格式的时间戳以字符串形式传入,将不再尝试进行类型转换)**
 - 【Docs】
 - 【Docs】
     - 增加 @douyinfe/semi-icons-lab 的使用说明
     - 增加 @douyinfe/semi-icons-lab 的使用说明
 
 
@@ -147,6 +218,10 @@ Semi 版本号遵循 **Semver** 规范(主版本号-次版本号-修订版本
     - 修复嵌套 Dropdown 时,Item 的点击在极个别场景不生效的问题。
     - 修复嵌套 Dropdown 时,Item 的点击在极个别场景不生效的问题。
     - 修复 resizable Table onHeaderCell 失效问题 [#1796](https://github.com/DouyinFE/semi-design/issues/1796)
     - 修复 resizable Table onHeaderCell 失效问题 [#1796](https://github.com/DouyinFE/semi-design/issues/1796)
 
 
+#### 🎉 2.42.3 (2023-09-01)
+- 【Fix】
+    - Fix: 修复 Table baseRow onMouseLeave 报错问题 [#1794](https://github.com/DouyinFE/semi-design/pull/1794)
+
 #### 🎉 2.42.2 (2023-08-28)
 #### 🎉 2.42.2 (2023-08-28)
 - 【Fix】
 - 【Fix】
     - 修复当 Image 文件名称带 query 参数时候,图片下载后因文件名错误无法打开问题 [@nekocode](https://github.com/nekocode) [#1782](https://github.com/DouyinFE/semi-design/pull/1784)
     - 修复当 Image 文件名称带 query 参数时候,图片下载后因文件名错误无法打开问题 [@nekocode](https://github.com/nekocode) [#1782](https://github.com/DouyinFE/semi-design/pull/1784)
@@ -570,10 +645,10 @@ Semi 版本号遵循 **Semver** 规范(主版本号-次版本号-修订版本
 
 
 #### 🎉 2.27.1 (2023-01-12)
 #### 🎉 2.27.1 (2023-01-12)
 - 【Fix】
 - 【Fix】
-    - 修复Form Field 级别校验,使用 props.rules 时存在竞态异步,后执行的校验会被前执行的校验覆盖的问题,  [#1375](https://github.com/DouyinFE/semi-design/issues/1375) [@SyMind](https://github.com/SyMind)
-    - 修复Form Field 级别校验,使用 props.validate 时存在竞态异步,后执行的校验会被前执行的校验覆盖的问题,  [#1375 ](https://github.com/DouyinFE/semi-design/issues/1375)
+    - **修复Form Field 级别校验,使用 props.rules 时存在竞态异步,后执行的校验会被前执行的校验覆盖的问题  [#1375](https://github.com/DouyinFE/semi-design/issues/1375) [@SyMind](https://github.com/SyMind) (注意:如果原先存在对单次值修改,触发多次重复校验逻辑。例如本身props.trigger 已配置为change,又在onChange回调中手动调用 formApi.validate 对其进行了校验等,前面执行的校验将会被丢弃,即 promise pending,不再 resolve或 reject)**
+    - 修复Form Field 级别校验,使用 props.validate 时存在竞态异步,后执行的校验会被前执行的校验覆盖的问题  [#1375 ](https://github.com/DouyinFE/semi-design/issues/1375)
 - 【Docs】
 - 【Docs】
-    - 修改 Cascader / TreeSelect / Tree 文档中 treeData API 类型名, 使其和代码一致
+    - 修改 Cascader / TreeSelect / Tree 文档中 treeData API 类型名, 使其和 Ts 代码 interface 一致
 
 
 #### 🎉 2.27.0 (2023-01-06)
 #### 🎉 2.27.0 (2023-01-06)
 - 【Fix】
 - 【Fix】

+ 14 - 0
cypress/e2e/datePicker.spec.js

@@ -802,4 +802,18 @@ describe('DatePicker', () => {
             cy.get('.semi-datepicker-day-selected-end').contains("13");
             cy.get('.semi-datepicker-day-selected-end').contains("13");
         })
         })
     });
     });
+
+    it('test split first inset input + dateTimeRange', () => {
+        cy.visit('http://localhost:6006/iframe.html?id=datepicker--fix-need-confirm-controlled&viewMode=story');
+        cy.get('.semi-input').eq(0).click();
+        cy.get('.semi-datepicker-day').contains('15').trigger('click');
+        cy.get('.semi-input').should('have.value', '2024-02-15 00:00:00');
+        cy.get('button').contains('确定').trigger('click');
+        cy.get('.semi-input').should('have.value', '');
+        cy.get('.semi-input').eq(1).click();
+        cy.get('.semi-datepicker-day').contains('15').trigger('click');
+        cy.get('.semi-input').eq(1).should('have.value', '2024-02-15 00:00:00');
+        cy.get('button').contains('确定').trigger('click');
+        cy.get('.semi-input').eq(1).should('have.value', '');
+    });
 });
 });

+ 14 - 1
cypress/e2e/image.spec.js

@@ -122,7 +122,7 @@ describe('image', () => {
         // 图片拖动策略是图片只能够拖动到图片边缘和容器边缘重合,因此预期top和left都为 0px
         // 图片拖动策略是图片只能够拖动到图片边缘和容器边缘重合,因此预期top和left都为 0px
         cy.get('.semi-image-preview-image-img').trigger('mousedown', { clientX: 0, clientY: 0 });
         cy.get('.semi-image-preview-image-img').trigger('mousedown', { clientX: 0, clientY: 0 });
         cy.wait(200);
         cy.wait(200);
-        cy.get('.semi-image-preview-image-img').trigger('mousemove', { clientX: 200, clientY: 100 }).trigger('mouseup');
+        cy.get('.semi-image-preview-image-img').trigger('mousemove', { clientX: 200, clientY: 100, buttons: 1 });
         cy.wait(200);
         cy.wait(200);
         cy.get('.semi-image-preview-image-img').should('have.css', 'top').and('eq', '0px');
         cy.get('.semi-image-preview-image-img').should('have.css', 'top').and('eq', '0px');
         cy.get('.semi-image-preview-image-img').should('have.css', 'left').and('eq', '0px');
         cy.get('.semi-image-preview-image-img').should('have.css', 'left').and('eq', '0px');
@@ -559,4 +559,17 @@ describe('image', () => {
                     });
                     });
             });
             });
     });
     });
+
+    // API:previewCls, previewStyle,测试 preview 的 className 和 style 是否生效
+    it.only("previewCls & previewStyle", () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?id=image--preview-cls-and-preview-style&args=&viewMode=storyi');
+        cy.wait(4000);
+        cy.get('.semi-image-img-preview').eq(0).click();
+        cy.get('.semi-image-preview').eq(0).should('have.class', 'test-preview');
+        cy.get('.semi-image-preview').eq(0).should('have.attr', 'style').should('contain', 'background: lightblue;');
+        cy.get('.semi-image-preview').click();
+        cy.get('.semi-image-img-preview').eq(1).click();
+        cy.get('.semi-image-preview').eq(0).should('have.class', 'test-imagePreview');
+        cy.get('.semi-image-preview').eq(0).should('have.attr', 'style').should('contain', 'background: lightgreen;');
+    });
 });
 });

+ 79 - 0
cypress/e2e/select.spec.js

@@ -80,6 +80,85 @@ describe('Select', () => {
         cy.get('.semi-select-option').eq(3).should('have.text', 'Xigua');
         cy.get('.semi-select-option').eq(3).should('have.text', 'Xigua');
     });
     });
 
 
+    it('blur trigger by mouse click after select option', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?path=/story/select--all-case-of-blur', {
+            onBeforeLoad(win) {
+                cy.stub(win.console, 'log').as('consoleLog');
+            },
+        });
+
+        cy.viewport(1000, 1000);
+
+        cy.get('.semi-select-selection').eq(0).click();
+        cy.get('.semi-select-option').eq(1).click();
+        cy.root().click('right');
+        cy.get('@consoleLog').should('be.calledWith', 'single autoFocus onBlur');
+        cy.get('@consoleLog').should('be.calledWith', 'single default onBlur');
+
+        cy.get('.semi-select-selection').eq(1).click();
+        cy.get('.semi-select-option').eq(1).click();
+        cy.root().click('right');
+        cy.get('@consoleLog').should('be.calledWith', 'single filter onBlur');
+
+        cy.get('.semi-select-selection').eq(3).click();
+        cy.get('.semi-select-option').eq(1).click();
+        cy.root().click('right');
+        cy.get('@consoleLog').should('be.calledWith', 'single clickToHide onBlur');
+
+        cy.get('.semi-select-selection').eq(4).click();
+        cy.get('.semi-select-option').eq(1).click();
+        cy.root().click('right');
+        cy.get('@consoleLog').should('be.calledWith', 'multiple default onBlur');
+
+        cy.get('.semi-select-selection').eq(5).click();
+        cy.get('.semi-select-option').eq(1).click();
+        cy.root().click('right');
+        cy.get('@consoleLog').should('be.calledWith', 'multiple filter onBlur');
+
+        cy.get('.semi-select-selection').eq(6).click();
+        cy.get('.semi-select-option').eq(1).click();
+        cy.root().click('right');
+        cy.get('@consoleLog').should('be.calledWith', 'multiple clickToHide onBlur');
+       
+    });
+
+    it('blur trigger by mouse click without select option', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?path=/story/select--all-case-of-blur', {
+            onBeforeLoad(win) {
+                cy.stub(win.console, 'log').as('consoleLog');
+            },
+        });
+
+        cy.viewport(1000, 1000);
+
+        cy.get('.semi-select-selection').eq(0).click();
+        cy.root().click('right');
+        cy.get('@consoleLog').should('be.calledWith', 'single autoFocus onBlur');
+        cy.get('@consoleLog').should('be.calledWith', 'single default onBlur');
+
+        cy.get('.semi-select-selection').eq(1).click();
+        cy.root().click('right');
+        cy.get('@consoleLog').should('be.calledWith', 'single filter onBlur');
+
+        cy.get('.semi-select-selection').eq(3).click();
+        cy.root().click('right');
+        cy.get('@consoleLog').should('be.calledWith', 'single clickToHide onBlur');
+
+        cy.get('.semi-select-selection').eq(4).click();
+        cy.get('.semi-select-option').eq(1).click();
+        cy.root().click('right');
+        cy.get('@consoleLog').should('be.calledWith', 'multiple default onBlur');
+
+        cy.get('.semi-select-selection').eq(5).click();
+        cy.root().click('right');
+        cy.get('@consoleLog').should('be.calledWith', 'multiple filter onBlur');
+
+        cy.get('.semi-select-selection').eq(6).click();
+        cy.root().click('right');
+        cy.get('@consoleLog').should('be.calledWith', 'multiple clickToHide onBlur');
+
+    });
+
     // it('ellipsisTrigger', () => {
     // it('ellipsisTrigger', () => {
     //     cy.visit('http://127.0.0.1:6006/iframe.html?path=/story/select--fix-1560');
     //     cy.visit('http://127.0.0.1:6006/iframe.html?path=/story/select--fix-1560');
 
 

+ 6 - 0
cypress/e2e/table.spec.js

@@ -240,4 +240,10 @@ describe('table', () => {
         cy.get('[data-cy=section] .semi-table-expand-icon').eq(0).click({ force: true });
         cy.get('[data-cy=section] .semi-table-expand-icon').eq(0).click({ force: true });
         cy.get('[data-cy=section] .semi-table-row-hidden').should('have.length', 7);
         cy.get('[data-cy=section] .semi-table-row-hidden').should('have.length', 7);
     });
     });
+
+    it('test header selected status when all rows are disabled and selected ', () => {
+        cy.visit('http://localhost:6006/iframe.html?id=table--fixed-all-disabled-and-selected&viewMode=story');
+        cy.get('button').contains('点击全选').click();
+        cy.get('.semi-table-thead .semi-checkbox-checked').should('exist')
+    });
 });
 });

+ 11 - 0
cypress/e2e/textarea.spec.js

@@ -99,4 +99,15 @@ describe('textarea', () => {
             });
             });
         });
         });
     });
     });
+
+    it('autosize + textarea resize', () => {
+        cy.visit('http://localhost:6006/iframe.html?id=input--text-auto-size-resize&viewMode=story');
+        cy.get('button').contains('width=100').trigger('click');
+        cy.wait(100);
+        cy.document().then(document => {
+            const textAreaDOM = document.querySelector(".semi-input-textarea");
+            const { scrollHeight, clientHeight } = textAreaDOM;
+            expect(scrollHeight).eq(clientHeight);
+        });
+    });
 });
 });

+ 33 - 0
cypress/e2e/treeSelect.spec.js

@@ -117,5 +117,38 @@ describe('treeSelect', () => {
         cy.wait(1000);
         cy.wait(1000);
         cy.get('.semi-checkbox').eq(0).get('.semi-checkbox-inner-checked').should("exist");
         cy.get('.semi-checkbox').eq(0).get('.semi-checkbox-inner-checked').should("exist");
     });
     });
+
+    it('expanded controlled + showFilteredOnly', () => {
+        cy.visit('http://127.0.0.1:6006/iframe.html?id=treeselect--issue-1542');
+        cy.get('.semi-tree-select-selection').eq(0).trigger('click');
+        cy.get('.semi-tree-select-inputTrigger').eq(0).children(".semi-input").eq(0).type('b');
+        // showFilteredOnly,因此搜索后的选项应该只有 3 项
+        cy.get('.semi-tree-option').should('have.length', 3);
+        // 清空搜索框,由 state 中的 expandedKeys 决定展示展示项,应该只有两项
+        cy.get('.semi-tree-select-inputTrigger').eq(0).children(".semi-input").eq(0).clear();
+        cy.get('.semi-tree-option').should('have.length', 2);
+        cy.get('.semi-tree-select-inputTrigger').eq(0).children(".semi-input").eq(0).type('s');
+        cy.get('.semi-tree-option').should('have.length', 9);
+        // 搜索状态下,输入框有值,被筛选的选项点击展开按钮行为正常
+        cy.get('.semi-tree-option').eq(1).children('.semi-icon-tree_triangle_down').eq(0).trigger('click');
+        cy.get('.semi-tree-option').should('have.length', 6);
+        cy.get('body').click();
+        // 等待弹出层收起
+        cy.wait(500);
+        cy.get('.semi-tree-select-selection').eq(0).trigger('click');
+        // 等待弹出层展开
+        cy.wait(500);
+        cy.get('.semi-tree-option').should('have.length', 2);
+        cy.get('.semi-tree-select-inputTrigger').eq(0).children(".semi-input").eq(0).type('o');
+        cy.get('.semi-tree-option').should('have.length', 4);
+        cy.get('.semi-tree-option').eq(3).trigger('click');
+        cy.wait(1000);
+        cy.get('.semi-tree-select-selection').eq(0).trigger('click');
+        cy.wait(1000);
+        // 此时展开项目由选中项和原来的 state 中的 expandedKeys 决定
+        cy.get('.semi-tree-option').should('have.length', 4);
+        cy.get('.semi-icon-tree_triangle_down').eq(0).trigger('click');
+        cy.get('.semi-tree-option').should('have.length', 6);
+    });
 });
 });
 
 

+ 1 - 1
lerna.json

@@ -1,5 +1,5 @@
 {
 {
     "useWorkspaces": true,
     "useWorkspaces": true,
     "npmClient": "yarn",
     "npmClient": "yarn",
-    "version": "2.49.0-beta.0"
+    "version": "2.51.3"
 }
 }

+ 1 - 1
package.json

@@ -76,7 +76,6 @@
         "gatsby-source-filesystem": "^2.11.1",
         "gatsby-source-filesystem": "^2.11.1",
         "grapheme-splitter": "^1.0.4",
         "grapheme-splitter": "^1.0.4",
         "immutability-helper": "^3.1.1",
         "immutability-helper": "^3.1.1",
-        "lerna": "4.0.0",
         "lodash-es": "^4.17.21",
         "lodash-es": "^4.17.21",
         "memoize-one": "^5.2.1",
         "memoize-one": "^5.2.1",
         "normalize.css": "^8.0.1",
         "normalize.css": "^8.0.1",
@@ -187,6 +186,7 @@
         "jest-enzyme": "^7.1.2",
         "jest-enzyme": "^7.1.2",
         "jest-mock-random": "^1.1.1",
         "jest-mock-random": "^1.1.1",
         "jsdom": "^15.2.1",
         "jsdom": "^15.2.1",
+        "lerna": "4.0.0",
         "lint-staged": "^10.5.4",
         "lint-staged": "^10.5.4",
         "marked": "^2.1.3",
         "marked": "^2.1.3",
         "mini-css-extract-plugin": "^0.12.0",
         "mini-css-extract-plugin": "^0.12.0",

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

@@ -1,6 +1,6 @@
 {
 {
     "name": "@douyinfe/semi-animation-react",
     "name": "@douyinfe/semi-animation-react",
-    "version": "2.49.0-beta.0",
+    "version": "2.51.3",
     "description": "motion library for semi-ui-react",
     "description": "motion library for semi-ui-react",
     "keywords": [
     "keywords": [
         "motion",
         "motion",
@@ -25,8 +25,8 @@
         "prepublishOnly": "npm run build:lib"
         "prepublishOnly": "npm run build:lib"
     },
     },
     "dependencies": {
     "dependencies": {
-        "@douyinfe/semi-animation": "2.49.0-beta.0",
-        "@douyinfe/semi-animation-styled": "2.49.0-beta.0",
+        "@douyinfe/semi-animation": "2.51.3",
+        "@douyinfe/semi-animation-styled": "2.51.3",
         "classnames": "^2.2.6"
         "classnames": "^2.2.6"
     },
     },
     "devDependencies": {
     "devDependencies": {

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

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

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

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

+ 1 - 1
packages/semi-eslint-plugin/package.json

@@ -1,6 +1,6 @@
 {
 {
     "name": "eslint-plugin-semi-design",
     "name": "eslint-plugin-semi-design",
-    "version": "2.49.0-beta.0",
+    "version": "2.51.3",
     "description": "semi ui eslint plugin",
     "description": "semi ui eslint plugin",
     "keywords": [
     "keywords": [
         "semi",
         "semi",

+ 10 - 6
packages/semi-foundation/autoComplete/foundation.ts

@@ -235,7 +235,7 @@ class AutoCompleteFoundation<P = Record<string, any>, S = Record<string, any>> e
 
 
         const options = this._generateList(data);
         const options = this._generateList(data);
         // Get the option whose value match from options
         // Get the option whose value match from options
-        let selectedOption: StateOptionItem | Array<StateOptionItem> = options.filter(option => renderSelectedItem(option) === selectedValue);
+        let selectedOption: StateOptionItem | Array<StateOptionItem> = options.length ? options.filter(option => renderSelectedItem(option) === selectedValue) : [];
         const canMatchInData = selectedOption.length;
         const canMatchInData = selectedOption.length;
 
 
         const selectedOptionIndex = options.findIndex(option => renderSelectedItem(option) === selectedValue);
         const selectedOptionIndex = options.findIndex(option => renderSelectedItem(option) === selectedValue);
@@ -262,11 +262,13 @@ class AutoCompleteFoundation<P = Record<string, any>, S = Record<string, any>> e
 
 
         let { data, defaultActiveFirstOption } = this.getProps();
         let { data, defaultActiveFirstOption } = this.getProps();
 
 
-        let renderSelectedItem = this._getRenderSelectedItem();
-
-        const options = this._generateList(data);
+        let selectedOptionIndex = -1;
 
 
-        const selectedOptionIndex = options.findIndex(option => renderSelectedItem(option) === searchValue);
+        if (searchValue) {
+            let renderSelectedItem = this._getRenderSelectedItem();
+            const options = this._generateList(data);
+            selectedOptionIndex = options.findIndex(option => renderSelectedItem(option) === searchValue);
+        }
 
 
         if (selectedOptionIndex === -1 && defaultActiveFirstOption) {
         if (selectedOptionIndex === -1 && defaultActiveFirstOption) {
             if (focusIndex !== 0) {
             if (focusIndex !== 0) {
@@ -288,7 +290,9 @@ class AutoCompleteFoundation<P = Record<string, any>, S = Record<string, any>> e
         let { renderSelectedItem } = this.getProps();
         let { renderSelectedItem } = this.getProps();
 
 
         if (typeof renderSelectedItem === 'undefined') {
         if (typeof renderSelectedItem === 'undefined') {
-            renderSelectedItem = (option: any) => option.value;
+            renderSelectedItem = (option: any) => {
+                return option?.value;
+            };
         } else if (renderSelectedItem && typeof renderSelectedItem === 'function') {
         } else if (renderSelectedItem && typeof renderSelectedItem === 'function') {
             // do nothing
             // do nothing
         }
         }

+ 4 - 0
packages/semi-foundation/breadcrumb/breadcrumb.scss

@@ -69,6 +69,10 @@ $module: #{$prefix}-breadcrumb;
             color: $color-breadcrumb_active-text-active;
             color: $color-breadcrumb_active-text-active;
             cursor: default;
             cursor: default;
         }
         }
+
+        .#{$prefix}-typography {
+            font-weight: $font-breadcrumb_active-fontWeight;
+        }
     }
     }
 
 
     &-item-icon {
     &-item-icon {

+ 3 - 1
packages/semi-foundation/cascader/constants.ts

@@ -24,4 +24,6 @@ export {
     cssClasses,
     cssClasses,
     strings,
     strings,
     numbers
     numbers
-};
+};
+
+export const VALUE_SPLIT = '_SEMI_CASCADER_SPLIT_';

+ 11 - 13
packages/semi-foundation/cascader/foundation.ts

@@ -1,4 +1,4 @@
-import { isEqual, get, difference, isUndefined, assign, cloneDeep, isEmpty, isNumber, includes, isFunction } from 'lodash';
+import { isEqual, get, difference, isUndefined, assign, cloneDeep, isEmpty, isNumber, includes, isFunction, isObject } from 'lodash';
 import BaseFoundation, { DefaultAdapter } from '../base/foundation';
 import BaseFoundation, { DefaultAdapter } from '../base/foundation';
 import {
 import {
     filter,
     filter,
@@ -12,10 +12,10 @@ import {
 import { Motion } from '../utils/type';
 import { Motion } from '../utils/type';
 import {
 import {
     convertDataToEntities,
     convertDataToEntities,
-    findKeysForValues,
     normalizedArr,
     normalizedArr,
     isValid,
     isValid,
-    calcMergeType
+    calcMergeType,
+    getKeysByValuePath
 } from './util';
 } from './util';
 import { strings } from './constants';
 import { strings } from './constants';
 import isEnterPress from '../utils/isEnterPress';
 import isEnterPress from '../utils/isEnterPress';
@@ -439,14 +439,14 @@ export default class CascaderFoundation extends BaseFoundation<CascaderAdapter,
         const loadingKeys = this._adapter.getLoadingKeyRefValue();
         const loadingKeys = this._adapter.getLoadingKeyRefValue();
         const filterable = this._isFilterable();
         const filterable = this._isFilterable();
         const loadingActive = [...activeKeys].filter(i => loadingKeys.has(i));
         const loadingActive = [...activeKeys].filter(i => loadingKeys.has(i));
-
-        const valuePath = onChangeWithObject ? normalizedArr(value).map(i => i.value) : normalizedArr(value);
-        const selectedKeys = findKeysForValues(valuePath, keyEntities);
+        const normalizedValue = normalizedArr(value);
+        const valuePath = onChangeWithObject && isObject(normalizedValue[0]) ? normalizedValue.map(i => i.value) : normalizedValue;
+        const selectedKeys = getKeysByValuePath(valuePath);
         let updateStates: Partial<BasicCascaderInnerData> = {};
         let updateStates: Partial<BasicCascaderInnerData> = {};
 
 
-        if (selectedKeys.length) {
-            const selectedKey = selectedKeys[0];
-            const selectedItem = keyEntities[selectedKey];
+        const selectedKey = selectedKeys.length > 0 ? selectedKeys[0] : undefined;
+        const selectedItem = selectedKey ? keyEntities[selectedKey] : undefined;
+        if (selectedItem) {
             /**
             /**
              * When changeOnSelect is turned on, or the target option is a leaf option,
              * When changeOnSelect is turned on, or the target option is a leaf option,
              * the option is considered to be selected, even if the option is disabled
              * the option is considered to be selected, even if the option is disabled
@@ -874,10 +874,8 @@ export default class CascaderFoundation extends BaseFoundation<CascaderAdapter,
         const { keyEntities } = this.getStates();
         const { keyEntities } = this.getStates();
         const values: (string | number)[] = [];
         const values: (string | number)[] = [];
         keys.forEach(key => {
         keys.forEach(key => {
-            if (!isEmpty(keyEntities) && !isEmpty(keyEntities[key])) {
-                const valueItem = keyEntities[key].data.value;
-                values.push(valueItem);
-            }
+            const valueItem = keyEntities[key]?.data?.value;
+            valueItem !== undefined && values.push(valueItem);
         });
         });
         const formatValue: number | string | Array<string | number> = values.length === 1 ?
         const formatValue: number | string | Array<string | number> = values.length === 1 ?
             values[0] :
             values[0] :

+ 21 - 10
packages/semi-foundation/cascader/util.ts

@@ -3,7 +3,7 @@ import {
     isUndefined,
     isUndefined,
     isEqual
     isEqual
 } from 'lodash';
 } from 'lodash';
-import { strings } from './constants';
+import { strings, VALUE_SPLIT } from './constants';
 
 
 function getPosition(level: any, index: any) {
 function getPosition(level: any, index: any) {
     return `${level}-${index}`;
     return `${level}-${index}`;
@@ -30,7 +30,7 @@ function traverseDataNodes(treeNodes: any, callback: any) {
         let item: any = null;
         let item: any = null;
         // Process node if is not root
         // Process node if is not root
         if (node) {
         if (node) {
-            const key = parent ? getPosition(parent.key, ind) : `${ind}`;
+            const key = parent ? `${parent.key}${VALUE_SPLIT}${node.value}` : node.value;
             item = {
             item = {
                 data: { ...node },
                 data: { ...node },
                 ind,
                 ind,
@@ -55,6 +55,25 @@ function traverseDataNodes(treeNodes: any, callback: any) {
     processNode(null);
     processNode(null);
 }
 }
 
 
+export function getKeysByValuePath(valuePath: (string | number)[][] | (string | number)[]) {
+    if (valuePath?.length) {
+        if (Array.isArray(valuePath[0])) {
+            return valuePath.map((item) => getKeyByValuePath(item));
+        } else {
+            return [getKeyByValuePath(valuePath as (string | number)[])];
+        }
+    }
+    return [];
+}
+
+export function getKeyByValuePath(valuePath: (string | number)[]) {
+    return valuePath.join(VALUE_SPLIT);
+}
+
+export function getValuePathByKey(key: string) {
+    return key.split(VALUE_SPLIT);
+}
+
 export function convertDataToEntities(dataNodes: any) {
 export function convertDataToEntities(dataNodes: any) {
     const keyEntities: any = {};
     const keyEntities: any = {};
 
 
@@ -74,14 +93,6 @@ export function convertDataToEntities(dataNodes: any) {
     return keyEntities;
     return keyEntities;
 }
 }
 
 
-export function findKeysForValues(value: any, keyEntities: any) {
-    const valuePath = normalizedArr(value);
-    const res = Object.values(keyEntities)
-        .filter((item: any) => isEqual(item.valuePath, valuePath))
-        .map((item: any) => item.key);
-    return res;
-}
-
 export function calcMergeType(autoMergeValue: boolean, leafOnly: boolean): string {
 export function calcMergeType(autoMergeValue: boolean, leafOnly: boolean): string {
     let mergeType: string;
     let mergeType: string;
     if (leafOnly) {
     if (leafOnly) {

+ 7 - 18
packages/semi-foundation/datePicker/foundation.ts

@@ -994,26 +994,15 @@ export default class DatePickerFoundation extends BaseFoundation<DatePickerAdapt
              * 受控时如果输入不完整,由于没有触发 notifyChange
              * 受控时如果输入不完整,由于没有触发 notifyChange
              * 需要组件内更新一下输入框的值,否则会出现选了一个日期但是输入框没有回显日期的问题 #1357
              * 需要组件内更新一下输入框的值,否则会出现选了一个日期但是输入框没有回显日期的问题 #1357
              */
              */
-            if (!this._adapter.needConfirm() || fromPreset) {
-                if (isRangeTypeAndInputIncomplete) {
-                    // do not change value when selected value is incomplete
-                    this._adapter.updateInputValue(inputValue);
-                    this._adapter.updateInsetInputValue(insetInputValue);
-                    return;
-                } else {
-                    if (!controlled || fromPreset) {
-                        this._updateValueAndInput(dates, true, inputValue);
-                        this._adapter.updateInsetInputValue(insetInputValue);
-                    }
-                }
-            }
-            if (!controlled && this._adapter.needConfirm()) {
-                // select date only change inputValue when needConfirm is true
+            if (isRangeTypeAndInputIncomplete) {
+                // do not change value when selected value is incomplete
                 this._adapter.updateInputValue(inputValue);
                 this._adapter.updateInputValue(inputValue);
                 this._adapter.updateInsetInputValue(insetInputValue);
                 this._adapter.updateInsetInputValue(insetInputValue);
-                // if inputValue is not complete, don't notifyChange
-                if (isRangeTypeAndInputIncomplete) {
-                    return;
+                return;
+            } else {
+                if (!controlled || fromPreset) {
+                    this._updateValueAndInput(dates, true, inputValue);
+                    this._adapter.updateInsetInputValue(insetInputValue);
                 }
                 }
             }
             }
             if (!isEqual(value, stateValue)) {
             if (!isEqual(value, stateValue)) {

+ 5 - 1
packages/semi-foundation/image/constants.ts

@@ -4,4 +4,8 @@ const cssClasses = {
     PREFIX: `${BASE_CLASS_PREFIX}-image`,
     PREFIX: `${BASE_CLASS_PREFIX}-image`,
 } as const;
 } as const;
 
 
-export { cssClasses };
+const numbers = {
+    DEFAULT_Z_INDEX: 1070,
+};
+
+export { cssClasses, numbers };

+ 1 - 4
packages/semi-foundation/image/previewFooterFoundation.ts

@@ -1,8 +1,6 @@
 import BaseFoundation, { DefaultAdapter } from "../base/foundation";
 import BaseFoundation, { DefaultAdapter } from "../base/foundation";
 
 
-export interface PreviewFooterAdapter<P = Record<string, any>, S = Record<string, any>> extends DefaultAdapter<P, S> {
-    setStartMouseOffset: (time: number) => void
-}
+export interface PreviewFooterAdapter<P = Record<string, any>, S = Record<string, any>> extends DefaultAdapter<P, S>{}
 
 
 export default class PreviewFooterFoundation<P = Record<string, any>, S = Record<string, any>> extends BaseFoundation<PreviewFooterAdapter<P, S>, P, S> {
 export default class PreviewFooterFoundation<P = Record<string, any>, S = Record<string, any>> extends BaseFoundation<PreviewFooterAdapter<P, S>, P, S> {
     
     
@@ -24,7 +22,6 @@ export default class PreviewFooterFoundation<P = Record<string, any>, S = Record
         } else {
         } else {
             onZoomOut(Number((value / 100).toFixed(2)));
             onZoomOut(Number((value / 100).toFixed(2)));
         }
         }
-        this._adapter.setStartMouseOffset(value);
     };
     };
 
 
     handleRatioClick = (): void => {
     handleRatioClick = (): void => {

+ 61 - 69
packages/semi-foundation/image/previewImageFoundation.ts

@@ -1,16 +1,8 @@
 import BaseFoundation, { DefaultAdapter } from "../base/foundation";
 import BaseFoundation, { DefaultAdapter } from "../base/foundation";
-import { handlePrevent } from "../utils/a11y";
-import { throttle, isUndefined } from "lodash";
 
 
 export interface PreviewImageAdapter<P = Record<string, any>, S = Record<string, any>> extends DefaultAdapter<P, S> {
 export interface PreviewImageAdapter<P = Record<string, any>, S = Record<string, any>> extends DefaultAdapter<P, S> {
-    getOriginImageSize: () => { originImageWidth: number; originImageHeight: number }; 
-    setOriginImageSize: (size: { originImageWidth: number; originImageHeight: number }) => void;
     getContainer: () => HTMLDivElement;
     getContainer: () => HTMLDivElement;
     getImage: () => HTMLImageElement;
     getImage: () => HTMLImageElement;
-    getMouseMove: () => boolean;
-    setStartMouseMove: (move: boolean) => void;
-    getMouseOffset: () => { x: number; y: number };
-    setStartMouseOffset: (offset: { x: number; y: number }) => void;
     setLoading: (loading: boolean) => void;
     setLoading: (loading: boolean) => void;
     setImageCursor: (canDrag: boolean) => void
     setImageCursor: (canDrag: boolean) => void
 }
 }
@@ -46,6 +38,10 @@ export default class PreviewImageFoundation<P = Record<string, any>, S = Record<
         super({ ...adapter });
         super({ ...adapter });
     }
     }
 
 
+    startMouseOffset = { x: 0, y: 0 };
+    originImageWidth = null;
+    originImageHeight = null;
+
     _isImageVertical = (): boolean => this.getProp("rotation") % 180 !== 0;
     _isImageVertical = (): boolean => this.getProp("rotation") % 180 !== 0;
 
 
     _getImageBounds = (): DOMRect => {
     _getImageBounds = (): DOMRect => {
@@ -77,25 +73,22 @@ export default class PreviewImageFoundation<P = Record<string, any>, S = Record<
     }
     }
 
 
     handleWindowResize = (): void => {
     handleWindowResize = (): void => {
-        const { ratio, setRatio } = this.getProps();
-        const { originImageWidth, originImageHeight } = this._adapter.getOriginImageSize();
-        if (originImageWidth && originImageHeight) {
-            if (ratio !== "adaptation") {
-                setRatio("adaptation");
-            } else {
-                this.handleResizeImage();
-            } 
+        if (this.originImageWidth && this.originImageHeight) {
+            this.handleResizeImage();
         }
         }
     };
     };
 
 
     handleLoad = (e: any): void => {
     handleLoad = (e: any): void => {
         if (e.target) {
         if (e.target) {
-            const { width: w, height: h } = e.target as any;
-            this._adapter.setOriginImageSize({ originImageWidth: w, originImageHeight: h });
+            const { naturalWidth: w, naturalHeight: h } = e.target as any;
+            this.originImageHeight = h;
+            this.originImageWidth = w;
             this.setState({
             this.setState({
                 loading: false,
                 loading: false,
             } as any);
             } as any);
-            this.handleResizeImage();
+            // 图片初次加载,计算 zoom,zoom 改变不需要通过回调透出
+            // When the image is loaded for the first time, zoom is calculated, and zoom changes do not need to be exposed through callbacks.
+            this.handleResizeImage(false);
         }
         }
         const { src, onLoad } = this.getProps();
         const { src, onLoad } = this.getProps();
         onLoad && onLoad(src);
         onLoad && onLoad(src);
@@ -109,21 +102,52 @@ export default class PreviewImageFoundation<P = Record<string, any>, S = Record<
         onError && onError(src);
         onError && onError(src);
     }
     }
 
 
-    handleResizeImage = () => {
+    handleResizeImage = (notify: boolean = true) => {
         const horizontal = !this._isImageVertical();
         const horizontal = !this._isImageVertical();
-        const { originImageWidth, originImageHeight } = this._adapter.getOriginImageSize();
-        const imgWidth = horizontal ? originImageWidth : originImageHeight;
-        const imgHeight = horizontal ? originImageHeight : originImageWidth;
-        const { onZoom } = this.getProps();
+        const { currZoom } = this.getStates();
+        const imgWidth = horizontal ? this.originImageWidth : this.originImageHeight;
+        const imgHeight = horizontal ? this.originImageHeight : this.originImageWidth;
+        const { onZoom, setRatio, ratio } = this.getProps();
         const containerDOM = this._adapter.getContainer();
         const containerDOM = this._adapter.getContainer();
         if (containerDOM) {
         if (containerDOM) {
             const { width: containerWidth, height: containerHeight } = this._getContainerBounds();
             const { width: containerWidth, height: containerHeight } = this._getContainerBounds();
             const reservedWidth = containerWidth - 80;
             const reservedWidth = containerWidth - 80;
             const reservedHeight = containerHeight - 80;
             const reservedHeight = containerHeight - 80;
-            const _zoom = Number(
-                Math.min(reservedWidth / imgWidth, reservedHeight / imgHeight).toFixed(2)
-            );
-            onZoom(_zoom);
+            let _zoom = 1;
+            if (imgWidth > reservedWidth || imgHeight > reservedHeight) {
+                _zoom = Number(
+                    Math.min(reservedWidth / imgWidth, reservedHeight / imgHeight).toFixed(2)
+                );
+            }
+            if (currZoom === _zoom) {
+                this.calculatePreviewImage(_zoom, null);
+            } else {
+                onZoom(_zoom, notify);
+            }
+        }
+    }
+
+    handleRatioChange = () => {
+        if (this.originImageWidth && this.originImageHeight) {
+            const { currZoom } = this.getStates();
+            const { ratio, onZoom } = this.getProps();
+            let _zoom: number;
+            if (ratio === 'adaptation') {
+                const horizontal = !this._isImageVertical();
+                const imgWidth = horizontal ? this.originImageWidth : this.originImageHeight;
+                const imgHeight = horizontal ? this.originImageHeight : this.originImageWidth;
+                const { width: containerWidth, height: containerHeight } = this._getContainerBounds();
+                const reservedWidth = containerWidth - 80;
+                const reservedHeight = containerHeight - 80;
+                _zoom = Number(
+                    Math.min(reservedWidth / imgWidth, reservedHeight / imgHeight).toFixed(2)
+                );
+            } else {
+                _zoom = 1;
+            }
+            if (currZoom !== _zoom) {
+                onZoom(_zoom);
+            }
         }
         }
     }
     }
 
 
@@ -138,33 +162,6 @@ export default class PreviewImageFoundation<P = Record<string, any>, S = Record<
         }
         }
     };
     };
 
 
-    // e: WheelEvent<HTMLImageElement>
-    handleWheel = (e: any) => {
-        this.onWheel(e);
-        handlePrevent(e);
-    }
-
-    // e: WheelEvent<HTMLImageElement>
-    onWheel = throttle((e: any): void => {
-        const { onZoom, zoomStep, maxZoom, minZoom } = this.getProps();
-        const { currZoom } = this.getStates();
-        let _zoom: number;
-        if (e.deltaY < 0) {
-            /* zoom in */
-            if (currZoom + zoomStep <= maxZoom) {
-                _zoom = Number((currZoom + zoomStep).toFixed(2));
-            }
-        } else if (e.deltaY > 0) {
-            /* zoom out */
-            if (currZoom - zoomStep >= minZoom) {
-                _zoom = Number((currZoom - zoomStep).toFixed(2));
-            }
-        }
-        if (!isUndefined(_zoom)) {
-            onZoom(_zoom);
-        }
-    }, 50);
-
     calcCanDragDirection = (): DragDirection => {
     calcCanDragDirection = (): DragDirection => {
         const { width, height } = this.getStates();
         const { width, height } = this.getStates();
         const { rotation } = this.getProps();
         const { rotation } = this.getProps();
@@ -181,14 +178,13 @@ export default class PreviewImageFoundation<P = Record<string, any>, S = Record<
         };
         };
     };
     };
 
 
-    handleZoomChange = (newZoom: number, e: any): void => {
+    calculatePreviewImage = (newZoom: number, e: any): void => {
         const imageDOM = this._adapter.getImage();
         const imageDOM = this._adapter.getImage();
-        const { originImageWidth, originImageHeight } = this._adapter.getOriginImageSize();
         const { canDragVertical, canDragHorizontal } = this.calcCanDragDirection();
         const { canDragVertical, canDragHorizontal } = this.calcCanDragDirection();
         const canDrag = canDragVertical || canDragHorizontal;
         const canDrag = canDragVertical || canDragHorizontal;
         const { width: containerWidth, height: containerHeight } = this._getContainerBounds();
         const { width: containerWidth, height: containerHeight } = this._getContainerBounds();
-        const newWidth = Math.floor(originImageWidth * newZoom);
-        const newHeight = Math.floor(originImageHeight * newZoom);
+        const newWidth = Math.floor(this.originImageWidth * newZoom);
+        const newHeight = Math.floor(this.originImageHeight * newZoom);
 
 
         // debugger;
         // debugger;
         let _offset;
         let _offset;
@@ -242,15 +238,15 @@ export default class PreviewImageFoundation<P = Record<string, any>, S = Record<
 
 
     handleMoveImage = (e: any): void => {
     handleMoveImage = (e: any): void => {
         const { offset, width, height } = this.getStates();
         const { offset, width, height } = this.getStates();
-        const startMouseMove = this._adapter.getMouseMove();
-        const startMouseOffset = this._adapter.getMouseOffset();
         const { canDragVertical, canDragHorizontal } = this.calcCanDragDirection();
         const { canDragVertical, canDragHorizontal } = this.calcCanDragDirection();
-        if (startMouseMove && (canDragVertical || canDragHorizontal)) {
+        // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/buttons
+        const mouseLeftPress = e.buttons === 1;
+        if (mouseLeftPress && (canDragVertical || canDragHorizontal)) {
             const { clientX, clientY } = e;
             const { clientX, clientY } = e;
             const { left: containerLeft, top: containerTop } = this._getContainerBounds();
             const { left: containerLeft, top: containerTop } = this._getContainerBounds();
             const { left: extremeLeft, top: extremeTop } = this.calcExtremeBounds();
             const { left: extremeLeft, top: extremeTop } = this.calcExtremeBounds();
-            let newX = canDragHorizontal ? clientX - containerLeft - startMouseOffset.x : offset.x;
-            let newY = canDragVertical ? clientY - containerTop - startMouseOffset.y : offset.y;
+            let newX = canDragHorizontal ? clientX - containerLeft - this.startMouseOffset.x : offset.x;
+            let newY = canDragVertical ? clientY - containerTop - this.startMouseOffset.y : offset.y;
             if (canDragHorizontal) {
             if (canDragHorizontal) {
                 newX = newX > 0 ? 0 : newX < extremeLeft ? extremeLeft : newX;
                 newX = newX > 0 ? 0 : newX < extremeLeft ? extremeLeft : newX;
             }
             }
@@ -270,11 +266,7 @@ export default class PreviewImageFoundation<P = Record<string, any>, S = Record<
     };
     };
 
 
     handleImageMouseDown = (e: any): void => {
     handleImageMouseDown = (e: any): void => {
-        this._adapter.setStartMouseOffset(this._getOffset(e));
-        this._adapter.setStartMouseMove(true);
+        this.startMouseOffset = this._getOffset(e);
     };
     };
 
 
-    handleImageMouseUp = (): void => {
-        this._adapter.setStartMouseMove(false);
-    };
 }
 }

+ 77 - 34
packages/semi-foundation/image/previewInnerFoundation.ts

@@ -1,6 +1,8 @@
+import { handlePrevent } from "../utils/a11y";
 import BaseFoundation, { DefaultAdapter } from "../base/foundation";
 import BaseFoundation, { DefaultAdapter } from "../base/foundation";
 import KeyCode from "../utils/keyCode";
 import KeyCode from "../utils/keyCode";
 import { getPreloadImagArr, downloadImage, isTargetEmit } from "./utils";
 import { getPreloadImagArr, downloadImage, isTargetEmit } from "./utils";
+import { isUndefined, throttle } from "lodash";
 
 
 export type RatioType = "adaptation" | "realSize";
 export type RatioType = "adaptation" | "realSize";
 export interface PreviewInnerAdapter<P = Record<string, any>, S = Record<string, any>> extends DefaultAdapter<P, S> {
 export interface PreviewInnerAdapter<P = Record<string, any>, S = Record<string, any>> extends DefaultAdapter<P, S> {
@@ -14,15 +16,10 @@ export interface PreviewInnerAdapter<P = Record<string, any>, S = Record<string,
     notifyDownload: (src: string, index: number) => void;
     notifyDownload: (src: string, index: number) => void;
     registerKeyDownListener: () => void;
     registerKeyDownListener: () => void;
     unregisterKeyDownListener: () => void;
     unregisterKeyDownListener: () => void;
-    getMouseActiveTime: () => number;
-    getStopTiming: () => boolean;
-    setStopTiming: (value: boolean) => void;
-    getStartMouseDown: () => {x: number; y: number};
-    setStartMouseDown: (x: number, y: number) => void;
-    setMouseActiveTime: (time: number) => void;
     disabledBodyScroll: () => void;
     disabledBodyScroll: () => void;
     enabledBodyScroll: () => void;
     enabledBodyScroll: () => void;
-    getSetDownloadFunc: () => (src: string) => string
+    getSetDownloadFunc: () => (src: string) => string;
+    isValidTarget: (e: any) => boolean
 }
 }
 
 
 
 
@@ -34,50 +31,94 @@ export default class PreviewInnerFoundation<P = Record<string, any>, S = Record<
         super({ ...adapter });
         super({ ...adapter });
     }
     }
 
 
+    _timer = null;
+    _startMouseDown = { x: 0, y: 0 };
+
     beforeShow() {
     beforeShow() {
         this._adapter.registerKeyDownListener();
         this._adapter.registerKeyDownListener();
         this._adapter.disabledBodyScroll();
         this._adapter.disabledBodyScroll();
+        this.updateTimer();
     }
     }
 
 
     afterHide() {
     afterHide() {
         this._adapter.unregisterKeyDownListener();
         this._adapter.unregisterKeyDownListener();
         this._adapter.enabledBodyScroll();
         this._adapter.enabledBodyScroll();
+        this.clearTimer();
     }
     }
 
 
     handleViewVisibleChange = () => {
     handleViewVisibleChange = () => {
-        const nowTime = new Date().getTime();
-        const mouseActiveTime = this._adapter.getMouseActiveTime();
-        const stopTiming = this._adapter.getStopTiming();
-        const { viewerVisibleDelay } = this.getProps();
         const { viewerVisible } = this.getStates();
         const { viewerVisible } = this.getStates();
-        if (nowTime - mouseActiveTime > viewerVisibleDelay && !stopTiming) {
-            viewerVisible && this.setState({
+        if (viewerVisible) {
+            this.setState({
                 viewerVisible: false,
                 viewerVisible: false,
             } as any);
             } as any);
+            this.clearTimer();
         }
         }
     }
     }
 
 
-    handleMouseMoveEvent = (e: any, event: string) => {
-        const isTarget = isTargetEmit(e, STOP_CLOSE_TARGET);
-        if (isTarget && event === "over") {
-            this._adapter.setStopTiming(true);
-        } else if (isTarget && event === "out") {
-            this._adapter.setStopTiming(false);
+    handleMouseMove = (e) => {
+        this._persistEvent(e);
+        this.mouseMoveHandler(e);
+    }
+    
+    mouseMoveHandler = throttle((e: any) => {
+        const { viewerVisible } = this.getStates();
+        const isValidTarget = this._adapter.isValidTarget(e);
+        if (isValidTarget) {
+            if (!viewerVisible) {
+                this.setState({
+                    viewerVisible: true,
+                } as any);
+            }
+            this.updateTimer();
+        } else {
+            this.clearTimer();
         }
         }
+    }, 50);
+
+    updateTimer = () => {
+        const { viewerVisibleDelay } = this.getProps();
+        this.clearTimer();
+        this._timer = setTimeout(this.handleViewVisibleChange, viewerVisibleDelay);
     }
     }
 
 
-    handleMouseMove = (e: any) => {
-        this._adapter.setMouseActiveTime(new Date().getTime());
-        this.setState({
-            viewerVisible: true,
-        } as any);
+    clearTimer = () => {
+        if (this._timer) {
+            clearTimeout(this._timer);
+            this._timer = null;
+        }
     }
     }
 
 
+    handleWheel = (e: any) => {
+        this.onWheel(e);
+        handlePrevent(e);
+    }
+
+    onWheel = (e: any): void => {
+        const { zoomStep, maxZoom, minZoom } = this.getProps();
+        const { zoom: currZoom } = this.getStates();
+        let _zoom: number;
+        if (e.deltaY < 0) {
+            /* zoom in */
+            if (currZoom + zoomStep <= maxZoom) {
+                _zoom = Number((currZoom + zoomStep).toFixed(2));
+            }
+        } else if (e.deltaY > 0) {
+            /* zoom out */
+            if (currZoom - zoomStep >= minZoom) {
+                _zoom = Number((currZoom - zoomStep).toFixed(2));
+            }
+        }
+        if (!isUndefined(_zoom)) {
+            this.handleZoomImage(_zoom);
+        }
+    };
+
     handleMouseUp = (e: any) => {
     handleMouseUp = (e: any) => {
         const { maskClosable } = this.getProps();
         const { maskClosable } = this.getProps();
         let couldClose = !isTargetEmit(e, NOT_CLOSE_TARGETS);
         let couldClose = !isTargetEmit(e, NOT_CLOSE_TARGETS);
         const { clientX, clientY } = e;
         const { clientX, clientY } = e;
-        const { x, y } = this._adapter.getStartMouseDown();
+        const { x, y } = this._startMouseDown;
         // 对鼠标移动做容错处理,当 x 和 y 方向在 mouseUp 的时候移动距离都小于等于 5px 时候就可以关闭预览
         // 对鼠标移动做容错处理,当 x 和 y 方向在 mouseUp 的时候移动距离都小于等于 5px 时候就可以关闭预览
         // Error-tolerant processing of mouse movement, when the movement distance in the x and y directions is less than or equal to 5px in mouseUp, the preview can be closed
         // Error-tolerant processing of mouse movement, when the movement distance in the x and y directions is less than or equal to 5px in mouseUp, the preview can be closed
         // 不做容错处理的话,直接用 clientX !== x || y !== clientY 做判断,鼠标在用户点击时候无意识的轻微移动无法关闭预览,不符合用户预期
         // 不做容错处理的话,直接用 clientX !== x || y !== clientY 做判断,鼠标在用户点击时候无意识的轻微移动无法关闭预览,不符合用户预期
@@ -86,13 +127,13 @@ export default class PreviewInnerFoundation<P = Record<string, any>, S = Record<
             couldClose = false;
             couldClose = false;
         }
         }
         if (couldClose && maskClosable) {
         if (couldClose && maskClosable) {
-            this.handlePreviewClose();
+            this._adapter.notifyVisibleChange(false);
         }
         }
     }
     }
 
 
     handleMouseDown = (e: any) => {
     handleMouseDown = (e: any) => {
         const { clientX, clientY } = e;
         const { clientX, clientY } = e;
-        this._adapter.setStartMouseDown(clientX, clientY);
+        this._startMouseDown = { x: clientX, y: clientY } ;
     }
     }
 
 
     handleKeyDown = (e: any) => {
     handleKeyDown = (e: any) => {
@@ -125,7 +166,6 @@ export default class PreviewInnerFoundation<P = Record<string, any>, S = Record<
             direction,
             direction,
             rotation: 0,
             rotation: 0,
         } as any);
         } as any);
-        this._adapter.notifyRotateChange(0);
     }
     }
 
 
     handleDownload = () => {
     handleDownload = () => {
@@ -137,9 +177,10 @@ export default class PreviewInnerFoundation<P = Record<string, any>, S = Record<
         this._adapter.notifyDownload(downloadSrc, currentIndex);
         this._adapter.notifyDownload(downloadSrc, currentIndex);
     }
     }
 
 
-    handlePreviewClose = () => {
+    handlePreviewClose = (e: any) => {
         this._adapter.notifyVisibleChange(false);
         this._adapter.notifyVisibleChange(false);
         this._adapter.notifyClose();
         this._adapter.notifyClose();
+        handlePrevent(e);
     }
     }
 
 
     handleAdjustRatio = (type: RatioType) => {
     handleAdjustRatio = (type: RatioType) => {
@@ -158,12 +199,14 @@ export default class PreviewInnerFoundation<P = Record<string, any>, S = Record<
         this._adapter.notifyRotateChange(newRotation);
         this._adapter.notifyRotateChange(newRotation);
     }
     }
 
 
-    handleZoomImage = (newZoom: number) => {
+    handleZoomImage = (newZoom: number, notify: boolean = true) => {
         const { zoom } = this.getStates();
         const { zoom } = this.getStates();
-        this._adapter.notifyZoom(newZoom, newZoom > zoom);
-        this.setState({
-            zoom: newZoom,
-        } as any);
+        if (zoom !== newZoom) {
+            notify && this._adapter.notifyZoom(newZoom, newZoom > zoom);
+            this.setState({
+                zoom: newZoom,
+            } as any);
+        }
     }
     }
 
 
     // 当 visible 改变之后,预览组件完成首张图片加载后,启动预加载
     // 当 visible 改变之后,预览组件完成首张图片加载后,启动预加载

+ 33 - 12
packages/semi-foundation/input/textareaFoundation.ts

@@ -113,15 +113,21 @@ export default class TextAreaFoundation extends BaseFoundation<TextAreaAdapter>
      */
      */
     handleVisibleMaxLength(value: string) {
     handleVisibleMaxLength(value: string) {
         const { maxLength, getValueLength } = this._adapter.getProps();
         const { maxLength, getValueLength } = this._adapter.getProps();
-        if (isNumber(maxLength) && maxLength >= 0 && isFunction(getValueLength) && isString(value)) {
-            const valueLength = getValueLength(value);
-            if (valueLength > maxLength) {
-                console.warn('[Semi TextArea] The input character is truncated because the input length exceeds the maximum length limit');
-                const truncatedValue = this.handleTruncateValue(value, maxLength);
-                return truncatedValue;
+        if (isNumber(maxLength) && maxLength >= 0 && isString(value)) {
+            if (isFunction(getValueLength)) {
+                const valueLength = getValueLength(value);
+                if (valueLength > maxLength) {
+                    console.warn('[Semi TextArea] The input character is truncated because the input length exceeds the maximum length limit');
+                    const truncatedValue = this.handleTruncateValue(value, maxLength);
+                    return truncatedValue;
+                }
             } else {
             } else {
-                return value;
+                if (value.length > maxLength) {
+                    console.warn('[Semi TextArea] The input character is truncated because the input length exceeds the maximum length limit');
+                    return value.slice(0, maxLength);
+                }
             }
             }
+            return value;
         }
         }
         return undefined;
         return undefined;
     }
     }
@@ -158,8 +164,26 @@ export default class TextAreaFoundation extends BaseFoundation<TextAreaAdapter>
 
 
     handleBlur(e: any) {
     handleBlur(e: any) {
         const { value } = this.getStates();
         const { value } = this.getStates();
+        const { maxLength } = this.getProps();
+        let realValue = value;
+        if (maxLength) {
+            // 如果设置了 maxLength,在中文输输入过程中,如果点击外部触发 blur,则拼音字符的所有内容会回显,
+            // 该表现不符合 maxLength 规定,因此需要在 blur 的时候二次确认
+            // 详情见 https://github.com/DouyinFE/semi-design/issues/2005
+            // If maxLength is set, during the Chinese input process, if you click outside to trigger blur, 
+            // all the contents of the Pinyin characters will be echoed.
+            // This behavior does not meet the maxLength requirement, so we need to confirm twice when blurring。
+            // For details, see https://github.com/DouyinFE/semi-design/issues/2005
+            realValue = this.handleVisibleMaxLength(value);
+            if (realValue !== value) {
+                if (!this._isControlledComponent()) {
+                    this._adapter.setValue(realValue);
+                }
+                this._adapter.notifyChange(realValue, e);
+            }
+        }
         this._adapter.toggleFocusing(false);
         this._adapter.toggleFocusing(false);
-        this._adapter.notifyBlur(value, e);
+        this._adapter.notifyBlur(realValue, e);
     }
     }
 
 
     handleKeyDown(e: any) {
     handleKeyDown(e: any) {
@@ -169,14 +193,13 @@ export default class TextAreaFoundation extends BaseFoundation<TextAreaAdapter>
         }
         }
     }
     }
 
 
-    resizeTextarea = (cb?: any) => {
+    resizeTextarea = () => {
         const { height } = this.getStates();
         const { height } = this.getStates();
         const { rows, autosize } = this.getProps();
         const { rows, autosize } = this.getProps();
         const node = this._adapter.getRef();
         const node = this._adapter.getRef();
         const nodeSizingData = getSizingData(node);
         const nodeSizingData = getSizingData(node);
 
 
         if (!nodeSizingData) {
         if (!nodeSizingData) {
-            cb && cb();
             return;
             return;
         }
         }
 
 
@@ -197,8 +220,6 @@ export default class TextAreaFoundation extends BaseFoundation<TextAreaAdapter>
             node.style.height = `${newHeight}px`;
             node.style.height = `${newHeight}px`;
             return;
             return;
         }
         }
-
-        cb && cb();
     };
     };
 
 
     // e: MouseEvent
     // e: MouseEvent

+ 4 - 0
packages/semi-foundation/modal/modalFoundation.ts

@@ -111,6 +111,10 @@ export default class ModalFoundation extends BaseFoundation<ModalAdapter> {
         this._adapter.notifyClose();
         this._adapter.notifyClose();
     }
     }
 
 
+    enabledBodyScroll() {
+        this._adapter.enabledBodyScroll();
+    }
+
     // afterClose() {
     // afterClose() {
     //     this._adapter.notifyClose();
     //     this._adapter.notifyClose();
     // }
     // }

+ 3 - 3
packages/semi-foundation/notification/notificationFoundation.ts

@@ -10,16 +10,16 @@ export type NoticeTheme = 'light' | 'normal';
 
 
 export interface NoticeProps {
 export interface NoticeProps {
     duration?: number;
     duration?: number;
-    id?: string | number;
+    id?: string;
     title?: any;
     title?: any;
     content?: any;
     content?: any;
     position?: NoticePosition;
     position?: NoticePosition;
     type?: NoticeType;
     type?: NoticeType;
     onClick?: (e: any) => void;
     onClick?: (e: any) => void;
     onClose?: () => void;
     onClose?: () => void;
-    onCloseClick?: (id: string | number) => void;
+    onCloseClick?: (id: string) => void;
     showClose?: boolean;
     showClose?: boolean;
-    close?: (id: string | number) => void;
+    close?: (id: string) => void;
     zIndex?: number;
     zIndex?: number;
     icon?: any;
     icon?: any;
     getPopupContainer?: () => HTMLElement;
     getPopupContainer?: () => HTMLElement;

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

@@ -1,13 +1,13 @@
 {
 {
     "name": "@douyinfe/semi-foundation",
     "name": "@douyinfe/semi-foundation",
-    "version": "2.49.0-beta.0",
+    "version": "2.51.3",
     "description": "",
     "description": "",
     "scripts": {
     "scripts": {
         "build:lib": "node ./scripts/compileLib.js",
         "build:lib": "node ./scripts/compileLib.js",
         "prepublishOnly": "npm run build:lib"
         "prepublishOnly": "npm run build:lib"
     },
     },
     "dependencies": {
     "dependencies": {
-        "@douyinfe/semi-animation": "2.49.0-beta.0",
+        "@douyinfe/semi-animation": "2.51.3",
         "async-validator": "^3.5.0",
         "async-validator": "^3.5.0",
         "classnames": "^2.2.6",
         "classnames": "^2.2.6",
         "date-fns": "^2.29.3",
         "date-fns": "^2.29.3",

+ 5 - 2
packages/semi-foundation/select/foundation.ts

@@ -352,6 +352,9 @@ export default class SelectFoundation extends BaseFoundation<SelectAdapter> {
             const newOptions = this._filterOption(options, sugInput).filter(item => !item._inputCreateOnly);
             const newOptions = this._filterOption(options, sugInput).filter(item => !item._inputCreateOnly);
             this._adapter.updateOptions(newOptions);
             this._adapter.updateOptions(newOptions);
             this.toggle2SearchInput(true);
             this.toggle2SearchInput(true);
+        } else {
+            // whether it is a filter or not, isFocus is guaranteed to be true when open
+            this._adapter.updateFocusState(true);
         }
         }
         this._adapter.openMenu();
         this._adapter.openMenu();
         this._setDropdownWidth();
         this._setDropdownWidth();
@@ -383,8 +386,8 @@ export default class SelectFoundation extends BaseFoundation<SelectAdapter> {
         this._adapter.setIsFocusInContainer(false);
         this._adapter.setIsFocusInContainer(false);
         // this.unBindKeyBoardEvent();
         // this.unBindKeyBoardEvent();
         // this._notifyBlur(e);
         // this._notifyBlur(e);
-        this._adapter.unregisterClickOutsideHandler();
         // this._adapter.updateFocusState(false);
         // this._adapter.updateFocusState(false);
+        this._adapter.unregisterClickOutsideHandler();
 
 
         const isFilterable = this._isFilterable();
         const isFilterable = this._isFilterable();
         if (isFilterable) {
         if (isFilterable) {
@@ -1053,13 +1056,13 @@ export default class SelectFoundation extends BaseFoundation<SelectAdapter> {
     }
     }
 
 
     handleTriggerBlur(e: FocusEvent) {
     handleTriggerBlur(e: FocusEvent) {
-        this._adapter.updateFocusState(false);
         const { filter, autoFocus } = this.getProps();
         const { filter, autoFocus } = this.getProps();
         const { isOpen, isFocus } = this.getStates();
         const { isOpen, isFocus } = this.getStates();
         // Under normal circumstances, blur will be accompanied by clickOutsideHandler, so the notify of blur can be called uniformly in clickOutsideHandler
         // Under normal circumstances, blur will be accompanied by clickOutsideHandler, so the notify of blur can be called uniformly in clickOutsideHandler
         // But when autoFocus or the panel is close, because clickOutsideHandler is not register or unregister, you need to listen for the trigger's blur and trigger the notify callback
         // But when autoFocus or the panel is close, because clickOutsideHandler is not register or unregister, you need to listen for the trigger's blur and trigger the notify callback
         if (isFocus && !isOpen) {
         if (isFocus && !isOpen) {
             this._notifyBlur(e);
             this._notifyBlur(e);
+            this._adapter.updateFocusState(false);
         }
         }
     }
     }
 
 

+ 4 - 0
packages/semi-foundation/steps/bacisSteps.scss

@@ -84,6 +84,10 @@ $basicType: #{$module}-basic;
         display: flex;
         display: flex;
         flex-flow: column nowrap;
         flex-flow: column nowrap;
 
 
+        .#{$item}-icon {
+            box-sizing: content-box;
+        }
+
         &.#{$module}-small {
         &.#{$module}-small {
             .#{$item} {
             .#{$item} {
                 .#{$item}-content {
                 .#{$item}-content {

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

@@ -989,7 +989,8 @@ class TableFoundation<RecordType> extends BaseFoundation<TableAdapter<RecordType
             }
             }
             return true;
             return true;
         } else {
         } else {
-            return false;
+            const isAllSelected = allKeys.every(rowKey => selectedRowKeysSet.has(rowKey));
+            return isAllSelected || false;
         }
         }
     }
     }
 
 

+ 16 - 0
packages/semi-foundation/tree/rtl.scss

@@ -20,6 +20,8 @@ $module: #{$prefix}-tree;
         }
         }
 
 
         .#{$module}-option {
         .#{$module}-option {
+            padding-left: 0;
+            padding-right: $spacing-tree_option_level1-paddingLeft;
             &-label {
             &-label {
                 & > .#{$prefix}-icon {
                 & > .#{$prefix}-icon {
                     margin-right: 0;
                     margin-right: 0;
@@ -39,10 +41,24 @@ $module: #{$prefix}-tree;
             }
             }
         }
         }
 
 
+        @for $i from 1 through 20 {
+            li.#{$module}-option.#{$module}-option-fullLabel-level-#{$i} {
+                padding-left: 0;
+                padding-right: $spacing-tree_option_level-paddingLeft * ($i - 1) + $spacing-tree_option_level1-paddingLeft;
+            }
+        }
+
         .#{$module}-option-label-empty {
         .#{$module}-option-label-empty {
             padding-left: auto;
             padding-left: auto;
             padding-right: 0;
             padding-right: 0;
         }
         }
+
+        .#{$module}-option {
+            &-switcher {
+                margin-right: 0;
+                margin-left: $spacing-tree_icon-marginRight;
+            }
+        }
     }
     }
 
 
     .#{$module}-option-list-block {
     .#{$module}-option-list-block {

+ 6 - 0
packages/semi-foundation/tree/tree.scss

@@ -329,6 +329,12 @@ $module: #{$prefix}-tree;
         }
         }
     }
     }
 
 
+    @for $i from 1 through 20 {
+        li.#{$module}-option.#{$module}-option-fullLabel-level-#{$i} {
+            padding-left: $spacing-tree_option_level-paddingLeft * ($i - 1) + $spacing-tree_option_level1-paddingLeft;
+        }
+    }
+
     .#{$module}-option-empty {
     .#{$module}-option-empty {
         &:hover,
         &:hover,
         &:active {
         &:active {

+ 12 - 8
packages/semi-foundation/treeSelect/foundation.ts

@@ -150,6 +150,7 @@ export interface BasicTreeSelectInnerData extends Pick<BasicTreeInnerData,
 'keyEntities'
 'keyEntities'
 | 'treeData'
 | 'treeData'
 | 'flattenNodes'
 | 'flattenNodes'
+| 'cachedFlattenNodes'
 | 'selectedKeys'
 | 'selectedKeys'
 | 'checkedKeys'
 | 'checkedKeys'
 | 'halfCheckedKeys'
 | 'halfCheckedKeys'
@@ -346,9 +347,7 @@ export default class TreeSelectFoundation<P = Record<string, any>, S = Record<st
         const isSearching = Boolean(inputValue);
         const isSearching = Boolean(inputValue);
         const treeNodeProps: BasicTreeNodeProps = {
         const treeNodeProps: BasicTreeNodeProps = {
             eventKey: key,
             eventKey: key,
-            expanded: isSearching && !this._isExpandControlled()
-                ? filteredExpandedKeys.has(key)
-                : expandedKeys.has(key),
+            expanded: isSearching ? filteredExpandedKeys.has(key) : expandedKeys.has(key),
             selected: selectedKeys.includes(key),
             selected: selectedKeys.includes(key),
             checked: realChecked,
             checked: realChecked,
             halfChecked: realHalfChecked,
             halfChecked: realHalfChecked,
@@ -444,6 +443,11 @@ export default class TreeSelectFoundation<P = Record<string, any>, S = Record<st
         });
         });
     }
     }
 
 
+    clearInputValue = () => {
+        const { inputValue } = this.getStates();
+        inputValue && this._adapter.updateInputValue('');
+    }
+
     // Scenes that may trigger focus:
     // Scenes that may trigger focus:
     //  1、click selection
     //  1、click selection
     _notifyFocus(e: any) {
     _notifyFocus(e: any) {
@@ -597,8 +601,8 @@ export default class TreeSelectFoundation<P = Record<string, any>, S = Record<st
         const newFlattenNodes = flattenTreeData(treeData, newExpandedKeys, keyMaps);
         const newFlattenNodes = flattenTreeData(treeData, newExpandedKeys, keyMaps);
 
 
         this._adapter.updateState({
         this._adapter.updateState({
-            expandedKeys: isExpandControlled ? expandedKeys : newExpandedKeys,
-            flattenNodes: isExpandControlled ? flattenNodes : newFlattenNodes,
+            expandedKeys: newExpandedKeys,
+            flattenNodes: newFlattenNodes,
             inputValue: '',
             inputValue: '',
             motionKeys: new Set([]),
             motionKeys: new Set([]),
             filteredKeys: new Set([]),
             filteredKeys: new Set([]),
@@ -637,8 +641,8 @@ export default class TreeSelectFoundation<P = Record<string, any>, S = Record<st
         const newFilteredExpandedKeys = new Set(expandedOptsKeys);
         const newFilteredExpandedKeys = new Set(expandedOptsKeys);
         this._adapter.notifySearch(sugInput, Array.from(newFilteredExpandedKeys));
         this._adapter.notifySearch(sugInput, Array.from(newFilteredExpandedKeys));
         this._adapter.updateState({
         this._adapter.updateState({
-            expandedKeys: this._isExpandControlled() ? expandedKeys : newExpandedKeys,
-            flattenNodes: this._isExpandControlled() ? flattenNodes : newFlattenNodes,
+            expandedKeys: newExpandedKeys,
+            flattenNodes: newFlattenNodes,
             motionKeys: new Set([]),
             motionKeys: new Set([]),
             filteredKeys: new Set(filteredOptsKeys),
             filteredKeys: new Set(filteredOptsKeys),
             filteredExpandedKeys: newFilteredExpandedKeys,
             filteredExpandedKeys: newFilteredExpandedKeys,
@@ -808,7 +812,7 @@ export default class TreeSelectFoundation<P = Record<string, any>, S = Record<st
         }
         }
 
 
         const isExpandControlled = this._isExpandControlled();
         const isExpandControlled = this._isExpandControlled();
-        if (isSearching && !isExpandControlled) {
+        if (isSearching) {
             this.handleNodeExpandInSearch(e, treeNode);
             this.handleNodeExpandInSearch(e, treeNode);
             return;
             return;
         }
         }

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

@@ -1,6 +1,6 @@
 {
 {
   "name": "@douyinfe/semi-icons-lab",
   "name": "@douyinfe/semi-icons-lab",
-  "version": "2.49.0-beta.0",
+  "version": "2.51.3",
   "description": "semi icons lab",
   "description": "semi icons lab",
   "keywords": [
   "keywords": [
     "semi",
     "semi",

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

@@ -1,6 +1,6 @@
 {
 {
     "name": "@douyinfe/semi-icons",
     "name": "@douyinfe/semi-icons",
-    "version": "2.49.0-beta.0",
+    "version": "2.51.3",
     "description": "semi icons",
     "description": "semi icons",
     "keywords": [
     "keywords": [
         "semi",
         "semi",

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

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

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

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

+ 9 - 9
packages/semi-rspack/README.md

@@ -1,7 +1,7 @@
-> A repack plugin for Semi Design to custom theme、replace prefix and so on.
+> A rspack plugin for Semi Design to custom theme、replace prefix and so on.
 
 
 ## Introduction
 ## Introduction
-The plugin is designed for Semi Design, support webpack4 and webpack5, provides two major abilities:
+The plugin is designed for Semi Design, support rspack, provides two major abilities:
 - Custom theme
 - Custom theme
 - Replace prefix of CSS selector 
 - Replace prefix of CSS selector 
 
 
@@ -29,7 +29,7 @@ Priority from low to high.
 In order to use the npm package, you need to customize the theme through [Semi Design System](https://semi.design/dsm/).After finishing the customization, Semi DSM will generate a npm package for you, and then you can use it like this.
 In order to use the npm package, you need to customize the theme through [Semi Design System](https://semi.design/dsm/).After finishing the customization, Semi DSM will generate a npm package for you, and then you can use it like this.
 
 
 ``` js
 ``` js
-// webpack.config.js
+// rspack.config.js
 const SemiPlugin = require('@douyinfe/semi-rspack-plugin').default;
 const SemiPlugin = require('@douyinfe/semi-rspack-plugin').default;
 
 
 module.exports = {
 module.exports = {
@@ -53,9 +53,9 @@ You can check which tokens can be customized on the [Semi WebSite](https://semi.
 $font-size-small: 16px;
 $font-size-small: 16px;
 
 
 ```
 ```
-- step2: config webpack
+- step2: config rspack
 ``` js
 ``` js
-// webpack.config.js
+// rspack.config.js
 const path = require('path');
 const path = require('path');
 const SemiPlugin = require('@douyinfe/semi-rspack-plugin').default;
 const SemiPlugin = require('@douyinfe/semi-rspack-plugin').default;
 
 
@@ -71,7 +71,7 @@ module.exports = {
 
 
 #### Through parameters
 #### Through parameters
 ``` js
 ``` js
-// webpack.config.js
+// rspack.config.js
 const SemiPlugin = require('@douyinfe/semi-rspack-plugin').default;
 const SemiPlugin = require('@douyinfe/semi-rspack-plugin').default;
 
 
 module.exports = {
 module.exports = {
@@ -90,7 +90,7 @@ module.exports = {
 The CSS selectors used by Semi Design is prefixed with semi by default(e.g, `.semi-button`).You can replace the prefix through this plugin.
 The CSS selectors used by Semi Design is prefixed with semi by default(e.g, `.semi-button`).You can replace the prefix through this plugin.
 
 
 ``` js
 ``` js
-// webpack.config.js
+// rspack.config.js
 const SemiPlugin = require('@douyinfe/semi-rspack-plugin').default;
 const SemiPlugin = require('@douyinfe/semi-rspack-plugin').default;
 
 
 module.exports = {
 module.exports = {
@@ -148,13 +148,13 @@ In the compilation phase, whether to exclude css references.Used to solve the pr
 
 
 Type: `String`
 Type: `String`
 
 
-The path of webpack loader that extract css.
+The path of webpack/rspack loader that extract css.
 
 
 ##### options.extractCssOptions.loaderOptions
 ##### options.extractCssOptions.loaderOptions
 
 
 Type: `Object`
 Type: `Object`
 
 
-The options of webpack loader that extract css.
+The options of webpack/rspack loader that extract css.
 
 
 #### options.overrideStylesheetLoaders
 #### options.overrideStylesheetLoaders
 
 

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

@@ -1,6 +1,6 @@
 {
 {
     "name": "@douyinfe/semi-rspack-plugin",
     "name": "@douyinfe/semi-rspack-plugin",
-    "version": "2.49.0-beta.0",
+    "version": "2.51.3",
     "description": "",
     "description": "",
     "homepage": "",
     "homepage": "",
     "license": "MIT",
     "license": "MIT",

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

@@ -1,6 +1,6 @@
 {
 {
     "name": "@douyinfe/semi-scss-compile",
     "name": "@douyinfe/semi-scss-compile",
-    "version": "2.49.0-beta.0",
+    "version": "2.51.3",
     "description": "compile semi scss to css",
     "description": "compile semi scss to css",
     "author": "[email protected]",
     "author": "[email protected]",
     "license": "MIT",
     "license": "MIT",

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

@@ -1,6 +1,6 @@
 {
 {
     "name": "@douyinfe/semi-theme-default",
     "name": "@douyinfe/semi-theme-default",
-    "version": "2.49.0-beta.0",
+    "version": "2.51.3",
     "description": "semi-theme-default",
     "description": "semi-theme-default",
     "keywords": [
     "keywords": [
         "semi-theme",
         "semi-theme",

+ 314 - 291
packages/semi-ui/autoComplete/_story/autoComplete.stories.jsx

@@ -2,343 +2,342 @@ import React, { Component, useState } from 'react';
 
 
 import CustomTrigger from './CustomTrigger';
 import CustomTrigger from './CustomTrigger';
 import AutoComplete from '../index';
 import AutoComplete from '../index';
+import { Form } from '../../index';
 import { IconSearch } from '@douyinfe/semi-icons';
 import { IconSearch } from '@douyinfe/semi-icons';
 
 
 export default {
 export default {
-  title: 'AutoComplete',
-  parameters: {
-    chromatic: { disableSnapshot: true },
-  },
-}
+    title: 'AutoComplete',
+    parameters: {
+        chromatic: { disableSnapshot: true },
+    },
+};
 
 
 const props = {
 const props = {
-  onBlur: (v, e) => {
-    console.log('onBlur');
-    console.log(v, e);
-  },
-  onFocus: (v, e) => {
-    console.log('onFocus');
-    console.log(v, e);
-  },
+    onBlur: (v, e) => {
+        console.log('onBlur');
+        console.log(v, e);
+    },
+    onFocus: (v, e) => {
+        console.log('onFocus');
+        console.log(v, e);
+    },
 };
 };
 
 
 class Demo extends React.Component {
 class Demo extends React.Component {
-  constructor() {
-    super();
-    this.state = {
-      data: [],
-      data2: ['mike', 'tony', 'steve'],
-    };
-    this.acref = React.createRef();
-  }
-
-  handleSearch(value) {
-    // let data =  !value ? [] : [value, value + value, value + value + value];
-    let result; // if (!value || value.indexOf('@') >= 0) {
-    //     result = [];
-    // } else {
-
-    if (value) {
-      result = ['gmail.com', '163.com', 'qq.com'].map(domain => `${value}@${domain}`);
-    } else {
-      result = [];
-    } // }
-
-    this.setState({
-      data: result,
-    });
-  }
-
-  handleSearch2(value) {
-    // let data2 =  !value ? [] : [value, value + value, value + value + value];
-    let result;
-
-    if (!value || value.indexOf('@') >= 0) {
-      result = [];
-    } else {
-      result = ['gmail.com', '163.com', 'qq.com'].map(domain => `${value}@${domain}`);
+    constructor() {
+        super();
+        this.state = {
+            data: [],
+            data2: ['mike', 'tony', 'steve'],
+        };
+        this.acref = React.createRef();
     }
     }
 
 
-    this.setState({
-      data2: result,
-    });
-  }
-
-  render() {
-    const { data, data2 } = this.state;
-    return (
-      <div>
-        <AutoComplete
-          placeholder="fe"
-          className="test-ac"
-          prefix={<IconSearch />}
-          showClear
-          data={data}
-          style={{
-            width: 300,
-          }}
-          onSearch={this.handleSearch.bind(this)}
-          onSelect={v => console.log(v)}
-          {...props}
-          ref={this.acref}
-        />
-      </div>
-    );
-  }
-}
+    handleSearch(value) {
+        // let data =  !value ? [] : [value, value + value, value + value + value];
+        let result; // if (!value || value.indexOf('@') >= 0) {
+        //     result = [];
+        // } else {
+
+        if (value) {
+            result = ['gmail.com', '163.com', 'qq.com'].map(domain => `${value}@${domain}`);
+        } else {
+            result = [];
+        } // }
+
+        this.setState({
+            data: result,
+        });
+    }
 
 
-export const BasicUsage = () => <Demo />;
+    handleSearch2(value) {
+        // let data2 =  !value ? [] : [value, value + value, value + value + value];
+        let result;
 
 
-class CustomOptionDemo extends Component {
-  constructor(props) {
-    super(props);
-    this.state = {
-      data: [],
-      data2: [],
-    };
-  }
+        if (!value || value.indexOf('@') >= 0) {
+            result = [];
+        } else {
+            result = ['gmail.com', '163.com', 'qq.com'].map(domain => `${value}@${domain}`);
+        }
 
 
-  search = value => {
-    let result;
+        this.setState({
+            data2: result,
+        });
+    }
 
 
-    if (!value) {
-      result = [];
-    } else {
-      result = ['gmail.com', '163.com', 'qq.com'].map(domain => `${value}@${domain}`);
+    render() {
+        const { data, data2 } = this.state;
+        return (
+            <div>
+                <AutoComplete
+                    placeholder="fe"
+                    className="test-ac"
+                    prefix={<IconSearch />}
+                    showClear
+                    data={data}
+                    style={{
+                        width: 300,
+                    }}
+                    onSearch={this.handleSearch.bind(this)}
+                    onSelect={v => console.log(v)}
+                    {...props}
+                    ref={this.acref}
+                />
+            </div>
+        );
     }
     }
+}
 
 
-    this.setState({
-      data: result,
-    });
-  };
-  renderOption = item => {
-    return (
-      <>
-        <span
-          style={{
-            color: 'pink',
-          }}
-        >
-          邮箱
-        </span>
-        : <span>{item}</span>
-      </>
-    );
-  };
-  search2 = value => {
-    let result;
-
-    if (!value) {
-      result = [];
-    } else {
-      result = ['gmail.com', '163.com', 'qq.com'].map(domain => {
-        return {
-          email: `${value}@${domain}`,
-          time: new Date().valueOf(),
-          value: `${value}@${domain}`,
+export const BasicUsage = () => <Demo />;
+
+class CustomOptionDemo extends Component {
+    constructor(props) {
+        super(props);
+        this.state = {
+            data: [],
+            data2: [],
         };
         };
-      });
     }
     }
 
 
-    this.setState({
-      data2: result,
-    });
-  };
-  renderObjectOption = item => {
-    return (
-      <div>
-        <span
-          style={{
-            color: 'pink',
-          }}
-        >
-          邮箱
-        </span>
-        : <span>{item.email}</span>
-        <span>time</span>: <span>{item.time}</span>
-      </div>
-    );
-  };
+    search = value => {
+        let result;
 
 
-  render() {
-    return (
-      <>
-        <AutoComplete
-          showClear
-          data={this.state.data}
-          renderItem={this.renderOption}
-          style={{
-            width: '250px',
-          }}
-          onSearch={this.search}
-        ></AutoComplete>
-        <br />
-        <br />
-        <AutoComplete
-          onChangeWithObject
-          style={{
-            width: '250px',
-          }}
-          renderItem={this.renderObjectOption}
-          renderSelectedItem={node => node.email}
-          data={this.state.data2}
-          onSearch={this.search2}
-        />
-      </>
-    );
-  }
+        if (!value) {
+            result = [];
+        } else {
+            result = ['gmail.com', '163.com', 'qq.com'].map(domain => `${value}@${domain}`);
+        }
+
+        this.setState({
+            data: result,
+        });
+    };
+    renderOption = item => {
+        return (
+            <>
+                <span
+                    style={{
+                        color: 'pink',
+                    }}
+                >
+                    邮箱
+                </span>
+                : <span>{item}</span>
+            </>
+        );
+    };
+    search2 = value => {
+        let result;
+
+        if (!value) {
+            result = [];
+        } else {
+            result = ['gmail.com', '163.com', 'qq.com'].map(domain => {
+                return {
+                    email: `${value}@${domain}`,
+                    time: new Date().valueOf(),
+                    value: `${value}@${domain}`,
+                };
+            });
+        }
+
+        this.setState({
+            data2: result,
+        });
+    };
+    renderObjectOption = item => {
+        return (
+            <div>
+                <span
+                    style={{
+                        color: 'pink',
+                    }}
+                >
+                    邮箱
+                </span>
+                : <span>{item.email}</span>
+                <span>time</span>: <span>{item.time}</span>
+            </div>
+        );
+    };
+
+    render() {
+        return (
+            <>
+                <AutoComplete
+                    showClear
+                    data={this.state.data}
+                    renderItem={this.renderOption}
+                    style={{
+                        width: '250px',
+                    }}
+                    onSearch={this.search}
+                ></AutoComplete>
+                <br />
+                <br />
+                <AutoComplete
+                    onChangeWithObject
+                    style={{
+                        width: '250px',
+                    }}
+                    renderItem={this.renderObjectOption}
+                    renderSelectedItem={node => node.email}
+                    data={this.state.data2}
+                    onSearch={this.search2}
+                />
+            </>
+        );
+    }
 }
 }
 
 
 export const RenderItem = () => <CustomOptionDemo />;
 export const RenderItem = () => <CustomOptionDemo />;
 
 
 class WithDefaultValue extends React.Component {
 class WithDefaultValue extends React.Component {
-  constructor() {
-    super();
-    this.state = {
-      data: ['[email protected]', '[email protected]', '[email protected]'],
-    };
-    this.onSearch = this.onSearch.bind(this);
-  }
-  onSearch(value) {
-    let result;
-
-    if (!value) {
-      result = [];
-    } else {
-      result = ['gmail.com', '163.com', 'qq.com'].map(domain => `${value}@${domain}`);
+    constructor() {
+        super();
+        this.state = {
+            data: ['[email protected]', '[email protected]', '[email protected]'],
+        };
+        this.onSearch = this.onSearch.bind(this);
+    }
+    onSearch(value) {
+        let result;
+
+        if (!value) {
+            result = [];
+        } else {
+            result = ['gmail.com', '163.com', 'qq.com'].map(domain => `${value}@${domain}`);
+        }
+
+        this.setState({
+            data: result,
+        });
     }
     }
 
 
-    this.setState({
-      data: result,
-    });
-  }
-
-  render() {
-    let { data } = this.state;
-    return (
-      <>
-        {/* <AutoComplete
+    render() {
+        let { data } = this.state;
+        return (
+            <>
+                {/* <AutoComplete
            defaultValue='[email protected]'
            defaultValue='[email protected]'
            data={data}
            data={data}
            onSearch={this.onSearch}
            onSearch={this.onSearch}
         /> */}
         /> */}
 
 
-        <AutoComplete defaultValue="semi" data={data} onSearch={this.onSearch} />
-      </>
-    );
-  }
+                <AutoComplete defaultValue="semi" data={data} onSearch={this.onSearch} />
+            </>
+        );
+    }
 }
 }
 
 
 export const DefaultValue = () => <WithDefaultValue />;
 export const DefaultValue = () => <WithDefaultValue />;
 
 
 class ControlledMode extends React.Component {
 class ControlledMode extends React.Component {
-  constructor() {
-    super();
-    this.state = {
-      data: [],
-      dataObject: [],
-      value: '',
-    };
-    this.onSearch = this.onSearch.bind(this);
-    this.onChange = this.onChange.bind(this);
-  }
-
-  onSearch(value) {
-    let result, resultObject;
-
-    if (!value) {
-      result = [];
-      resultObject = [];
-    } else {
-      result = ['gmail.com', '163.com', 'qq.com'].map(domain => `${value}@${domain}`);
-      resultObject = ['gmail.com', '163.com', 'qq.com'].map(domain => ({
-        label: `${value}@${domain}`,
-        value: `${value}@${domain}`,
-      }));
+    constructor() {
+        super();
+        this.state = {
+            data: [],
+            dataObject: [],
+            value: '',
+        };
+        this.onSearch = this.onSearch.bind(this);
+        this.onChange = this.onChange.bind(this);
     }
     }
 
 
-    this.setState({
-      data: result,
-      dataObject: resultObject,
-    });
-  }
+    onSearch(value) {
+        let result, resultObject;
+
+        if (!value) {
+            result = [];
+            resultObject = [];
+        } else {
+            result = ['gmail.com', '163.com', 'qq.com'].map(domain => `${value}@${domain}`);
+            resultObject = ['gmail.com', '163.com', 'qq.com'].map(domain => ({
+                label: `${value}@${domain}`,
+                value: `${value}@${domain}`,
+            }));
+        }
+
+        this.setState({
+            data: result,
+            dataObject: resultObject,
+        });
+    }
 
 
-  onChange(value) {
-    this.setState({
-      value: value,
-    });
-  }
+    onChange(value) {
+        this.setState({
+            value: value,
+        });
+    }
 
 
-  render() {
-    let { data, value, dataObject } = this.state;
-    return (
-      <>
-        <AutoComplete
-          showClear
-          value={value}
-          data={data}
-          onChange={this.onChange}
-          onSearch={this.onSearch}
-          style={{
-            width: 200,
-          }}
-        />
-        <br />
-        <AutoComplete
-          showClear
-          value={value}
-          data={dataObject}
-          onChange={this.onChange}
-          onSearch={this.onSearch}
-          style={{
-            width: 200,
-          }}
-        />
-        <br />
-        <AutoComplete
-          defaultValue={'hello semi'}
-          showClear
-          value={value}
-          data={dataObject}
-          onChange={this.onChange}
-          onSearch={this.onSearch}
-          style={{
-            width: 200,
-          }}
-        />
-      </>
-    );
-  }
+    render() {
+        let { data, value, dataObject } = this.state;
+        return (
+            <>
+                <AutoComplete
+                    showClear
+                    value={value}
+                    data={data}
+                    onChange={this.onChange}
+                    onSearch={this.onSearch}
+                    style={{
+                        width: 200,
+                    }}
+                />
+                <br />
+                <AutoComplete
+                    showClear
+                    value={value}
+                    data={dataObject}
+                    onChange={this.onChange}
+                    onSearch={this.onSearch}
+                    style={{
+                        width: 200,
+                    }}
+                />
+                <br />
+                <AutoComplete
+                    defaultValue={'hello semi'}
+                    showClear
+                    value={value}
+                    data={dataObject}
+                    onChange={this.onChange}
+                    onSearch={this.onSearch}
+                    style={{
+                        width: 200,
+                    }}
+                />
+            </>
+        );
+    }
 }
 }
 
 
 export const EmptyContent = () => {
 export const EmptyContent = () => {
-  let [data, setData] = useState([]);
-  const [loading, setLoading] = useState(false);
-
-  const fetchData = v => {
-    setLoading(true);
-    setTimeout(() => {
-      if (!v) {
-        setData([]);
-        setLoading(false);
-        return;
-      }
-
-      setData(() => {
-        const res = Array.from(Array(5)).map(c => Math.random());
-        return res;
-      });
-      setLoading(false);
-    }, 1000);
-  };
-
-  return (
-    <AutoComplete loading={loading} data={data} emptyContent={'空数据'} onSearch={fetchData} />
-  );
+    let [data, setData] = useState([]);
+    const [loading, setLoading] = useState(false);
+
+    const fetchData = v => {
+        setLoading(true);
+        setTimeout(() => {
+            if (!v) {
+                setData([]);
+                setLoading(false);
+                return;
+            }
+
+            setData(() => {
+                const res = Array.from(Array(5)).map(c => Math.random());
+                return res;
+            });
+            setLoading(false);
+        }, 1000);
+    };
+
+    return <AutoComplete loading={loading} data={data} emptyContent={'空数据'} onSearch={fetchData} />;
 };
 };
 
 
 export const AutoFocus = () => {
 export const AutoFocus = () => {
-  return <AutoComplete autoFocus />;
+    return <AutoComplete autoFocus />;
 };
 };
 
 
 export const ControlledValue = () => <ControlledMode />;
 export const ControlledValue = () => <ControlledMode />;
@@ -347,4 +346,28 @@ export const CustomTriggerDemo = () => <CustomTrigger />;
 
 
 export const Disabled = () => <AutoComplete disabled />;
 export const Disabled = () => <AutoComplete disabled />;
 
 
-export const KeyDown = () => <AutoComplete onKeyDown={(e) => { console.log('onKeyDown', e.keyCode) }} />;
+export const KeyDown = () => (
+    <AutoComplete
+        onKeyDown={e => {
+            console.log('onKeyDown', e.keyCode);
+        }}
+    />
+);
+
+export const ControlledOnSelectWithObjectDemo = () => {
+    const [v, setV] = useState();
+    return (
+        <Form>
+            <AutoComplete
+                onSelectWithObject
+                data={[]}
+                showClear
+                value={v}
+                placeholder='controlled autocomplete'
+                onChange={val => setV(val)}
+                style={{ width: 200 }}
+            />
+            <Form.AutoComplete field='test' placeholder='form autocomplete' onSelectWithObject data={[]} showClear style={{ width: 200 }} />
+        </Form>
+    );
+};

+ 15 - 2
packages/semi-ui/cascader/__test__/cascader.test.js

@@ -1257,7 +1257,7 @@ describe('Cascader', () => {
         const args = firstCall.args[0]; 
         const args = firstCall.args[0]; 
         /* check arguments of triggerRender */
         /* check arguments of triggerRender */
         expect(args.value.size).toEqual(1);
         expect(args.value.size).toEqual(1);
-        expect(args.value).toEqual(new Set('0'));
+        expect(args.value).toEqual(new Set(['Asia']));
         cascaderAutoMerge.unmount();
         cascaderAutoMerge.unmount();
 
 
         const spyTriggerRender2 = sinon.spy(() => <span>123</span>);
         const spyTriggerRender2 = sinon.spy(() => <span>123</span>);
@@ -1272,7 +1272,7 @@ describe('Cascader', () => {
         const args2 = firstCall2.args[0]; 
         const args2 = firstCall2.args[0]; 
         /* check arguments of triggerRender */
         /* check arguments of triggerRender */
         expect(args2.value.size).toEqual(4);
         expect(args2.value.size).toEqual(4);
-        expect(args2.value).toEqual(new Set(['0','0-0','0-0-1','0-0-0']));
+        expect(args2.value).toEqual(new Set(["Asia","Asia_SEMI_CASCADER_SPLIT_China","Asia_SEMI_CASCADER_SPLIT_China_SEMI_CASCADER_SPLIT_Beijing","Asia_SEMI_CASCADER_SPLIT_China_SEMI_CASCADER_SPLIT_Shanghai"]));
         cascaderNoAutoMerge.unmount();
         cascaderNoAutoMerge.unmount();
     });
     });
 
 
@@ -1369,4 +1369,17 @@ describe('Cascader', () => {
         r.close();
         r.close();
         expect(select.state().isOpen).toEqual(false);
         expect(select.state().isOpen).toEqual(false);
     });
     });
+
+    it('autoMerge false & value []', () => {
+        const cascader = render({
+            multiple: true,
+            autoMergeValue: false,
+            value: [],
+            placeholder: "autoMergeValue 为 false"
+        });
+
+        const placeholder = cascader.find(`.${BASE_CLASS_PREFIX}-cascader-selection-placeholder`)
+        expect(placeholder.getDOMNode().textContent).toEqual('autoMergeValue 为 false');
+        cascader.unmount();
+    })
 });
 });

+ 140 - 1
packages/semi-ui/cascader/_story/cascader.stories.jsx

@@ -1626,7 +1626,7 @@ export const DynamicTreeData = () => {
 
 
 
 
 export const SuperLongList = () => {
 export const SuperLongList = () => {
-    let treeData = new Array(100).fill().map(() => ({ label: '浙江省', value: 'zhejiang' }));
+    let treeData = new Array(100).fill().map((item, index) => ({ label: `浙江省${index}`, value: `zhejiang${index}` }));
     treeData.push({ label: '到底啦', value: 'bottom' })
     treeData.push({ label: '到底啦', value: 'bottom' })
     return (
     return (
         <Cascader
         <Cascader
@@ -2184,3 +2184,142 @@ export const VirtualizeInSearch = () => {
       />
       />
   );
   );
 };
 };
+
+function generateOptions(arr, level, frontKey) {
+  const realLevel = level ?? 0;
+  const notLeaf = realLevel !== arr.length - 1;
+  const realFrontKey = frontKey ? `${frontKey}-` : '';
+  return new Array(arr[realLevel])
+    .fill(0)
+    .map((_item, index) => {
+      const data = {
+        label: `label-${realFrontKey}${index}`,
+        value: `value-${realFrontKey}${index}`,
+      };
+      if (notLeaf) {
+        data.children = generateOptions(
+          arr,
+          realLevel + 1,
+          `${realFrontKey}${index}`,
+        );
+      }
+      return data;
+    });
+}
+
+export const LeafOnlyPF = () => {
+  const treeData = useMemo(() => {
+    return generateOptions([4, 10, 10, 10]);
+  }, []);
+
+  return (
+    <Cascader
+      multiple
+      leafOnly
+      maxTagCount={4}
+      treeData={treeData}
+      style={{ width: 200 }}
+    />
+  );
+};
+
+export const SearchPF = () => {
+  const treeData = useMemo(() => {
+    return generateOptions([4, 10, 10, 10]);
+  }, []);
+
+  return (
+    <Cascader
+      filterTreeNode
+      multiple
+      leafOnly
+      maxTagCount={4}
+      treeData={treeData}
+      style={{ width: 200 }}
+    />
+  );
+};
+
+export const ControlledPF = () => {
+  const [cValue, setCValue] = useState([]);
+  const onCascaderChange = useCallback(value => {
+    // console.log('cValue', value);
+    setCValue(value);
+  }, []);
+
+  const treeData = useMemo(() => {
+    return generateOptions([4, 10, 10, 10, 10]);
+  }, []);
+
+  return (
+    <Cascader
+      value={cValue}
+      onChange={onCascaderChange}
+      filterTreeNode
+      leafOnly
+      multiple
+      maxTagCount={4}
+      treeData={treeData}
+      style={{ width: 200 }}
+    />
+  )
+}
+
+export const AutoMergeFalse = () => {
+  const [value, setValue] = useState([]);
+  const onChange = value => {
+      console.log(value);
+      setValue(value);
+  };
+  const treeData = [
+      {
+          label: '浙江省',
+          value: 'zhejiang',
+          children: [
+              {
+                  label: '杭州市',
+                  value: 'hangzhou',
+                  children: [
+                      {
+                          label: '西湖区',
+                          value: 'xihu',
+                      },
+                      {
+                          label: '萧山区',
+                          value: 'xiaoshan',
+                      },
+                      {
+                          label: '临安区',
+                          value: 'linan',
+                      },
+                  ],
+              },
+              {
+                  label: '宁波市',
+                  value: 'ningbo',
+                  children: [
+                      {
+                          label: '海曙区',
+                          value: 'haishu',
+                      },
+                      {
+                          label: '江北区',
+                          value: 'jiangbei',
+                      }
+                  ]
+              },
+          ],
+      }
+  ];
+  return (
+      <Cascader
+          style={{ width: 300 }}
+          treeData={treeData}
+          placeholder="autoMergeValue 为 false"
+          value={value}
+          multiple
+          autoMergeValue={false}
+          onChange={e => onChange(e)}
+      />
+  );
+}

+ 18 - 30
packages/semi-ui/cascader/index.tsx

@@ -14,10 +14,10 @@ import CascaderFoundation, {
 } from '@douyinfe/semi-foundation/cascader/foundation';
 } from '@douyinfe/semi-foundation/cascader/foundation';
 import { cssClasses, strings } from '@douyinfe/semi-foundation/cascader/constants';
 import { cssClasses, strings } from '@douyinfe/semi-foundation/cascader/constants';
 import { numbers as popoverNumbers } from '@douyinfe/semi-foundation/popover/constants';
 import { numbers as popoverNumbers } from '@douyinfe/semi-foundation/popover/constants';
-import { isSet, isEqual, isString, isEmpty, isFunction, isNumber, noop, flatten } from 'lodash';
+import { isSet, isEqual, isString, isEmpty, isFunction, isNumber, noop, flatten, isObject } from 'lodash';
 import '@douyinfe/semi-foundation/cascader/cascader.scss';
 import '@douyinfe/semi-foundation/cascader/cascader.scss';
 import { IconClear, IconChevronDown } from '@douyinfe/semi-icons';
 import { IconClear, IconChevronDown } from '@douyinfe/semi-icons';
-import { findKeysForValues, convertDataToEntities, calcMergeType } from '@douyinfe/semi-foundation/cascader/util';
+import { convertDataToEntities, calcMergeType, getKeyByValuePath } from '@douyinfe/semi-foundation/cascader/util';
 import { calcCheckedKeys, normalizeKeyList, calcDisabledKeys } from '@douyinfe/semi-foundation/tree/treeUtil';
 import { calcCheckedKeys, normalizeKeyList, calcDisabledKeys } from '@douyinfe/semi-foundation/tree/treeUtil';
 import ConfigContext, { ContextValue } from '../configProvider/context';
 import ConfigContext, { ContextValue } from '../configProvider/context';
 import BaseComponent, { ValidateStatus } from '../_base/baseComponent';
 import BaseComponent, { ValidateStatus } from '../_base/baseComponent';
@@ -424,31 +424,27 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
             return firstInProps || treeDataHasChange;
             return firstInProps || treeDataHasChange;
         };
         };
         const getRealKeys = (realValue: Value, keyEntities: Entities) => {
         const getRealKeys = (realValue: Value, keyEntities: Entities) => {
-            // normallizedValue is used to save the value in two-dimensional array format
-            let normallizedValue: SimpleValueType[][] = [];
+            // normalizedValue is used to save the value in two-dimensional array format
+            let normalizedValue: SimpleValueType[][] = [];
             if (Array.isArray(realValue)) {
             if (Array.isArray(realValue)) {
-                normallizedValue = Array.isArray(realValue[0])
+                normalizedValue = Array.isArray(realValue[0])
                     ? (realValue as SimpleValueType[][])
                     ? (realValue as SimpleValueType[][])
                     : ([realValue] as SimpleValueType[][]);
                     : ([realValue] as SimpleValueType[][]);
             } else {
             } else {
                 if (realValue !== undefined) {
                 if (realValue !== undefined) {
-                    normallizedValue = [[realValue]];
+                    normalizedValue = [[realValue]];
                 }
                 }
             }
             }
             // formatValuePath is used to save value of valuePath
             // formatValuePath is used to save value of valuePath
             const formatValuePath: (string | number)[][] = [];
             const formatValuePath: (string | number)[][] = [];
-            normallizedValue.forEach((valueItem: SimpleValueType[]) => {
-                const formatItem: (string | number)[] = onChangeWithObject ?
+            normalizedValue.forEach((valueItem: SimpleValueType[]) => {
+                const formatItem: (string | number)[] = onChangeWithObject && isObject(valueItem[0]) ?
                     (valueItem as CascaderData[]).map(i => i?.value) :
                     (valueItem as CascaderData[]).map(i => i?.value) :
                     valueItem as (string | number)[];
                     valueItem as (string | number)[];
-                formatValuePath.push(formatItem);
+                formatItem.length > 0 && (formatValuePath.push(formatItem));
             });
             });
             // formatKeys is used to save key of value
             // formatKeys is used to save key of value
-            const formatKeys: any[] = [];
-            formatValuePath.forEach(v => {
-                const formatKeyItem = findKeysForValues(v, keyEntities);
-                !isEmpty(formatKeyItem) && formatKeys.push(formatKeyItem);
-            });
+            const formatKeys = formatValuePath.map(v => getKeyByValuePath(v));
             return formatKeys;
             return formatKeys;
         };
         };
         const needUpdateTreeData = needUpdate('treeData') || needUpdateData();
         const needUpdateTreeData = needUpdate('treeData') || needUpdateData();
@@ -478,7 +474,7 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
                 if (isSet(realKeys)) {
                 if (isSet(realKeys)) {
                     realKeys = [...realKeys];
                     realKeys = [...realKeys];
                 }
                 }
-                const calRes = calcCheckedKeys(flatten(realKeys), keyEntities);
+                const calRes = calcCheckedKeys(realKeys, keyEntities);
                 const checkedKeys = new Set(calRes.checkedKeys);
                 const checkedKeys = new Set(calRes.checkedKeys);
                 const halfCheckedKeys = new Set(calRes.halfCheckedKeys);
                 const halfCheckedKeys = new Set(calRes.halfCheckedKeys);
                 // disableStrictly
                 // disableStrictly
@@ -505,7 +501,7 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
 
 
     componentDidUpdate(prevProps: CascaderProps) {
     componentDidUpdate(prevProps: CascaderProps) {
         let isOptionsChanged = false;
         let isOptionsChanged = false;
-        if (!isEqual(prevProps.treeData, this.props.treeData)) {
+        if (!isEqual(prevProps.treeData, this.props.treeData) && !this.props.multiple) {
             isOptionsChanged = true;
             isOptionsChanged = true;
             this.foundation.collectOptions();
             this.foundation.collectOptions();
         }
         }
@@ -527,13 +523,12 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
         this.handleTagRemove(null, keyEntities[key].valuePath);
         this.handleTagRemove(null, keyEntities[key].valuePath);
     }
     }
 
 
-    renderTagItem = (value: string | Array<string>, idx: number, type: string) => {
+    renderTagItem = (nodeKey: string, idx: number) => {
         const { keyEntities, disabledKeys } = this.state;
         const { keyEntities, disabledKeys } = this.state;
         const { size, disabled, displayProp, displayRender, disableStrictly } = this.props;
         const { size, disabled, displayProp, displayRender, disableStrictly } = this.props;
-        const nodeKey = type === strings.IS_VALUE ? findKeysForValues(value, keyEntities)[0] : value;
         const isDsiabled =
         const isDsiabled =
             disabled || keyEntities[nodeKey].data.disabled || (disableStrictly && disabledKeys.has(nodeKey));
             disabled || keyEntities[nodeKey].data.disabled || (disableStrictly && disabledKeys.has(nodeKey));
-        if (!isEmpty(keyEntities) && !isEmpty(keyEntities[nodeKey])) {
+        if (keyEntities[nodeKey]) {
             const tagCls = cls(`${prefixcls}-selection-tag`, {
             const tagCls = cls(`${prefixcls}-selection-tag`, {
                 [`${prefixcls}-selection-tag-disabled`]: isDsiabled,
                 [`${prefixcls}-selection-tag-disabled`]: isDsiabled,
             });
             });
@@ -567,25 +562,18 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
         const { size, disabled, placeholder, maxTagCount, showRestTagsPopover, restTagsPopoverProps } = this.props;
         const { size, disabled, placeholder, maxTagCount, showRestTagsPopover, restTagsPopoverProps } = this.props;
         const { inputValue, checkedKeys, keyEntities, resolvedCheckedKeys } = this.state;
         const { inputValue, checkedKeys, keyEntities, resolvedCheckedKeys } = this.state;
         const tagInputcls = cls(`${prefixcls}-tagInput-wrapper`);
         const tagInputcls = cls(`${prefixcls}-tagInput-wrapper`);
-        const tagValue: Array<Array<string>> = [];
         const realKeys = this.mergeType === strings.NONE_MERGE_TYPE ? checkedKeys : resolvedCheckedKeys;
         const realKeys = this.mergeType === strings.NONE_MERGE_TYPE ? checkedKeys : resolvedCheckedKeys;
-        [...realKeys].forEach(checkedKey => {
-            if (!isEmpty(keyEntities[checkedKey])) {
-                tagValue.push(keyEntities[checkedKey].valuePath);
-            }
-        });
         return (
         return (
             <TagInput
             <TagInput
                 className={tagInputcls}
                 className={tagInputcls}
                 ref={this.inputRef as any}
                 ref={this.inputRef as any}
                 disabled={disabled}
                 disabled={disabled}
                 size={size}
                 size={size}
-                // TODO Modify logic, not modify type
-                value={(tagValue as unknown) as string[]}
+                value={[...realKeys]}
                 showRestTagsPopover={showRestTagsPopover}
                 showRestTagsPopover={showRestTagsPopover}
                 restTagsPopoverProps={restTagsPopoverProps}
                 restTagsPopoverProps={restTagsPopoverProps}
                 maxTagCount={maxTagCount}
                 maxTagCount={maxTagCount}
-                renderTagItem={(value, index) => this.renderTagItem(value, index, strings.IS_VALUE)}
+                renderTagItem={(value, index) => this.renderTagItem(value, index)}
                 inputValue={inputValue}
                 inputValue={inputValue}
                 onInputChange={this.handleInputChange}
                 onInputChange={this.handleInputChange}
                 // TODO Modify logic, not modify type
                 // TODO Modify logic, not modify type
@@ -747,7 +735,7 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
         const hiddenTag: Array<ReactNode> = [];
         const hiddenTag: Array<ReactNode> = [];
         [...realKeys].forEach((checkedKey, idx) => {
         [...realKeys].forEach((checkedKey, idx) => {
             const notExceedMaxTagCount = !isNumber(maxTagCount) || maxTagCount >= idx + 1;
             const notExceedMaxTagCount = !isNumber(maxTagCount) || maxTagCount >= idx + 1;
-            const item = this.renderTagItem(checkedKey, idx, strings.IS_KEY);
+            const item = this.renderTagItem(checkedKey, idx);
             if (notExceedMaxTagCount) {
             if (notExceedMaxTagCount) {
                 displayTag.push(item);
                 displayTag.push(item);
             } else {
             } else {
@@ -795,7 +783,7 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
 
 
         if (!searchable) {
         if (!searchable) {
             if (multiple) {
             if (multiple) {
-                if (isEmpty(checkedKeys)) {
+                if (checkedKeys.size === 0) {
                     return <span className={`${prefixcls}-selection-placeholder`}>{placeholder}</span>;
                     return <span className={`${prefixcls}-selection-placeholder`}>{placeholder}</span>;
                 }
                 }
                 return this.renderMultipleTags();
                 return this.renderMultipleTags();

+ 6 - 1
packages/semi-ui/datePicker/_story/datePicker.stories.jsx

@@ -69,7 +69,8 @@ export {
     FeatEtcGMT,
     FeatEtcGMT,
     FixDisabledDate,
     FixDisabledDate,
     FeatInsetInputShowClear,
     FeatInsetInputShowClear,
-    AutoSplitInput
+    AutoSplitInput,
+    FixNeedConfirmControlled
 } from './v2';
 } from './v2';
 
 
 
 
@@ -1165,3 +1166,7 @@ NeedConfirmDelete.storyName = "cashedSelectedValue return to last selected when
   );
   );
 };
 };
 CashedSelectedValue.storyName = "cashedSelectedValue";
 CashedSelectedValue.storyName = "cashedSelectedValue";
+
+export const Fix1982 = () => {
+  return <DatePicker type="monthRange" style={{ width: 200 }} />
+}

+ 22 - 0
packages/semi-ui/datePicker/_story/v2/FixNeedConfirmControlled.tsx

@@ -0,0 +1,22 @@
+import React, { useState } from 'react';
+import { Button, DatePicker, Space } from '@douyinfe/semi-ui';
+
+/**
+ * test with cypress, please modify this story
+ * @returns
+ */
+export default function App() {
+    const [value, setValue] = useState([]);
+    return (
+        <Space>
+            <DatePicker
+                needConfirm
+                defaultPickerValue="2024-02-15"
+                value={value}
+                type="dateTimeRange"
+                onChange={v => setValue(v)}
+            />
+            <Button>body click</Button>
+        </Space>
+    );
+}

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

@@ -27,3 +27,4 @@ export { default as FixDisabledDate } from './FixDisabledDate';
 export { default as FeatYearScrollRange } from './FeatYearScrollRange';
 export { default as FeatYearScrollRange } from './FeatYearScrollRange';
 export { default as FeatInsetInputShowClear } from './FeatInsetInputShowClear';
 export { default as FeatInsetInputShowClear } from './FeatInsetInputShowClear';
 export { default as AutoSplitInput } from './AutoSplitInput';
 export { default as AutoSplitInput } from './AutoSplitInput';
+export { default as FixNeedConfirmControlled } from './FixNeedConfirmControlled';

+ 1 - 5
packages/semi-ui/datePicker/yearAndMonth.tsx

@@ -139,11 +139,7 @@ class YearAndMonth extends BaseComponent<YearAndMonthProps, YearAndMonthState> {
 
 
         const needDisabled = (year) => {
         const needDisabled = (year) => {
             if (panelType === right && currentYear[left]) {
             if (panelType === right && currentYear[left]) {
-                if (currentMonth[left] <= currentMonth[right]) {
-                    return currentYear[left] > year;
-                } else {
-                    return currentYear[left] >= year;
-                }
+                return currentYear[left] > year;
             }
             }
             return false;
             return false;
         };
         };

+ 1 - 1
packages/semi-ui/dropdown/dropdownItem.tsx

@@ -127,7 +127,7 @@ class DropdownItem extends BaseComponent<DropdownItemProps> {
         }
         }
         return (
         return (
             <li role="menuitem" tabIndex={-1} aria-disabled={disabled} {...events} onKeyDown={onKeyDown}
             <li role="menuitem" tabIndex={-1} aria-disabled={disabled} {...events} onKeyDown={onKeyDown}
-                ref={ref => forwardRef(ref)} className={itemclass} style={style}>
+                ref={ref => forwardRef(ref)} className={itemclass} style={style} {...this.getDataAttr(this.props)}>
                 {tick}
                 {tick}
                 {iconContent}
                 {iconContent}
                 {children}
                 {children}

+ 52 - 1
packages/semi-ui/image/_story/image.stories.jsx

@@ -48,11 +48,21 @@ const srcList2 = [
     "https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/imag8.png",
     "https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/imag8.png",
 ];
 ];
 
 
+const srcList3 = [
+    "https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/imag1.png",
+    "https://lf3-static.bytednsdoc.com/obj/eden-cn/9130eh7pltbfnuhog/small-size.jpeg",
+    "https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/imag3.png",
+    "https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/beach.jpeg",
+    "https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/imag5.png",
+    'https://lf3-static.bytednsdoc.com/obj/eden-cn/9130eh7pltbfnuhog/200100.jpeg',
+];
+
 export const basicImage = () => {
 export const basicImage = () => {
     const [escOut, setEscOut] = useState(true);
     const [escOut, setEscOut] = useState(true);
     const [disableDownload, setDisableDownload] = useState(false);
     const [disableDownload, setDisableDownload] = useState(false);
     const [maskClosable, setMaskClosable] = useState(true);
     const [maskClosable, setMaskClosable] = useState(true);
     const [preview, setPreview] = useState(true);
     const [preview, setPreview] = useState(true);
+    const [closable, setClosable] = useState(true);
 
 
     const itemStyle = { display: 'flex', alignItems: 'center', flexShrink: 0, width: 'fit-content', margin: '10px 20px 0 0' };
     const itemStyle = { display: 'flex', alignItems: 'center', flexShrink: 0, width: 'fit-content', margin: '10px 20px 0 0' };
     const menuStyle = { marginBottom: 20, display: 'flex', flexWrap: 'wrap' };
     const menuStyle = { marginBottom: 20, display: 'flex', flexWrap: 'wrap' };
@@ -72,6 +82,10 @@ export const basicImage = () => {
                 <span >是否禁用下载:</span>
                 <span >是否禁用下载:</span>
                 <Switch checked={disableDownload} checkedText="是" uncheckedText="否" onChange={setDisableDownload}/>
                 <Switch checked={disableDownload} checkedText="是" uncheckedText="否" onChange={setDisableDownload}/>
             </div>
             </div>
+            <div style={itemStyle} id='closable'>
+                <span>是否显示预览关闭按钮:</span>
+                <Switch checked={closable} checkedText="是" uncheckedText="否" onChange={setClosable} />
+            </div>
             <div style={itemStyle} id='maskClosable'>
             <div style={itemStyle} id='maskClosable'>
                 <span >点击遮罩层是否关闭预览:</span>
                 <span >点击遮罩层是否关闭预览:</span>
                 <Switch checked={maskClosable} checkedText="是" uncheckedText="否" onChange={setMaskClosable}/>
                 <Switch checked={maskClosable} checkedText="是" uncheckedText="否" onChange={setMaskClosable}/>
@@ -84,7 +98,8 @@ export const basicImage = () => {
             preview={preview ? {
             preview={preview ? {
                 closeOnEsc: escOut,
                 closeOnEsc: escOut,
                 disableDownload,
                 disableDownload,
-                maskClosable
+                maskClosable,
+                closable
             } : false}
             } : false}
         />
         />
     </>
     </>
@@ -400,6 +415,7 @@ export const GridImage= () => {
             infinite={infinite}
             infinite={infinite}
         >
         >
             <Row style={{ width: 800 }}>
             <Row style={{ width: 800 }}>
+                {/* {srcList3.map((src, index) => { */}
                 {srcList2.map((src, index) => {
                 {srcList2.map((src, index) => {
                     return (
                     return (
                         <Col span={6} style={{ height: 200 }} key={`col${index}`}>
                         <Col span={6} style={{ height: 200 }} key={`col${index}`}>
@@ -718,4 +734,39 @@ export const SmallHeightImage = () => {
             src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/abstract.jpg"
             src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/abstract.jpg"
         />
         />
     </>
     </>
+}
+
+export const previewClsAndPreviewStyle = () => {
+   return <>
+        <span>1.previewCls为 test-preview, previewStyle 的 background 为 lightblue </span>
+        <br />
+        <Image 
+            width={360}
+            height={200}
+            src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/abstract.jpg"
+            preview={{
+                previewCls: 'test-preview',
+                previewStyle: { background: 'lightblue' }
+            }}
+        />
+        <br />
+        <span>2.previewCls为 test-imagePreview, previewStyle 的 background 为 lightgreen </span>
+        <br />
+        <ImagePreview
+            previewCls='test-imagePreview'
+            previewStyle={{ background: 'lightgreen' }}
+        >
+            {srcList1.map((src, index) => {
+                return (
+                    <Image 
+                        key={index} 
+                        src={src} 
+                        width={200} 
+                        alt={`lamp${index + 1}`} 
+                        style={{ marginRight: 5 }}
+                    />
+                );
+            })}
+        </ImagePreview> 
+    </>
 }
 }

+ 1 - 0
packages/semi-ui/image/_story/image.stories.tsx

@@ -73,6 +73,7 @@ export const BasicPreview = () => {
                             width={200}
                             width={200}
                             alt={`lamp${index + 1}`}
                             alt={`lamp${index + 1}`}
                             data-test={'data-test'}
                             data-test={'data-test'}
+                            onClick={()=>{}}
                         />
                         />
                 )})}
                 )})}
             </ImagePreview>
             </ImagePreview>

+ 7 - 2
packages/semi-ui/image/image.tsx

@@ -10,7 +10,7 @@ import { PreviewContext, PreviewContextProps } from "./previewContext";
 import ImageFoundation, { ImageAdapter } from "@douyinfe/semi-foundation/image/imageFoundation";
 import ImageFoundation, { ImageAdapter } from "@douyinfe/semi-foundation/image/imageFoundation";
 import LocaleConsumer from "../locale/localeConsumer";
 import LocaleConsumer from "../locale/localeConsumer";
 import { Locale } from "../locale/interface";
 import { Locale } from "../locale/interface";
-import { isBoolean, isObject, isUndefined } from "lodash";
+import { isBoolean, isObject, isUndefined, omit } from "lodash";
 import Skeleton from "../skeleton";
 import Skeleton from "../skeleton";
 import "@douyinfe/semi-foundation/image/image.scss";
 import "@douyinfe/semi-foundation/image/image.scss";
 
 
@@ -31,6 +31,7 @@ export default class Image extends BaseComponent<ImageProps, ImageStates> {
         preview: PropTypes.oneOfType([PropTypes.bool, PropTypes.object]),
         preview: PropTypes.oneOfType([PropTypes.bool, PropTypes.object]),
         onLoad: PropTypes.func,
         onLoad: PropTypes.func,
         onError: PropTypes.func,
         onError: PropTypes.func,
+        onClick: PropTypes.func,
         crossOrigin: PropTypes.string,
         crossOrigin: PropTypes.string,
         imageID: PropTypes.number,
         imageID: PropTypes.number,
     }
     }
@@ -179,7 +180,11 @@ export default class Image extends BaseComponent<ImageProps, ImageStates> {
         const canPreview = loadStatus === "success" && preview && !this.isInGroup();
         const canPreview = loadStatus === "success" && preview && !this.isInGroup();
         const showPreviewCursor = preview && loadStatus === "success";
         const showPreviewCursor = preview && loadStatus === "success";
         const previewSrc = isObject(preview) ? ((preview as any).src ?? src) : src;
         const previewSrc = isObject(preview) ? ((preview as any).src ?? src) : src;
-        const previewProps = isObject(preview) ? preview : {};
+        const previewProps = isObject(preview) && canPreview ? { 
+            ...omit(preview, ['className', 'style', 'previewCls', 'previewStyle']), 
+            className: preview?.previewCls, 
+            style: preview?.previewStyle 
+        }: {} as any;
         return ( 
         return ( 
             <div
             <div
                 style={outerStyle}
                 style={outerStyle}

+ 15 - 5
packages/semi-ui/image/interface.tsx

@@ -21,6 +21,7 @@ export interface ImageProps extends BaseProps{
     preview?: boolean | PreviewProps;
     preview?: boolean | PreviewProps;
     onError?: (event: Event) => void;
     onError?: (event: Event) => void;
     onLoad?: (event: Event) => void;
     onLoad?: (event: Event) => void;
+    onClick?: (event: any) => void;
     crossOrigin?: "anonymous"| "use-credentials";
     crossOrigin?: "anonymous"| "use-credentials";
     children?: ReactNode;
     children?: ReactNode;
     imageID?: number;
     imageID?: number;
@@ -57,6 +58,10 @@ export interface PreviewProps extends BaseProps {
     zIndex?: number;
     zIndex?: number;
     children?: ReactNode;
     children?: ReactNode;
     crossOrigin?: "anonymous"| "use-credentials";
     crossOrigin?: "anonymous"| "use-credentials";
+    maxZoom?: number;
+    minZoom?: number;
+    previewCls?: string;
+    previewStyle?: React.CSSProperties;
     renderHeader?: (info: any) => ReactNode;
     renderHeader?: (info: any) => ReactNode;
     renderPreviewMenu?: (props: MenuProps) => ReactNode;
     renderPreviewMenu?: (props: MenuProps) => ReactNode;
     getPopupContainer?: () => HTMLElement;
     getPopupContainer?: () => HTMLElement;
@@ -73,6 +78,8 @@ export interface PreviewProps extends BaseProps {
     setDownloadName?: (src: string) => string
     setDownloadName?: (src: string) => string
 }
 }
 
 
+export interface PreviewInnerProps extends Omit<PreviewProps, "previewCls" | "previewStyle"> {}
+
 export interface MenuProps {
 export interface MenuProps {
     min?: number;
     min?: number;
     max?: number;
     max?: number;
@@ -114,11 +121,12 @@ export interface SliderProps {
 }
 }
 
 
 export interface HeaderProps {
 export interface HeaderProps {
+    closable: boolean;
     renderHeader?: (info: any) => ReactNode;
     renderHeader?: (info: any) => ReactNode;
     title?: string;
     title?: string;
     titleStyle?: React.CSSProperties;
     titleStyle?: React.CSSProperties;
     className?: string;
     className?: string;
-    onClose?: () => void
+    onClose?: (e: React.MouseEvent<HTMLElement>) => void
 }
 }
 
 
 export interface FooterProps extends SliderProps {
 export interface FooterProps extends SliderProps {
@@ -139,6 +147,7 @@ export interface FooterProps extends SliderProps {
     adaptiveTip?: string;
     adaptiveTip?: string;
     originTip?: string;
     originTip?: string;
     showTooltip?: boolean;
     showTooltip?: boolean;
+    zIndex?: number;
     onZoomIn?: (zoom: number) => void;
     onZoomIn?: (zoom: number) => void;
     onZoomOut?: (zoom: number) => void;
     onZoomOut?: (zoom: number) => void;
     onPrev?: () => void;
     onPrev?: () => void;
@@ -146,16 +155,17 @@ export interface FooterProps extends SliderProps {
     onAdjustRatio?: (type: RatioType) => void;
     onAdjustRatio?: (type: RatioType) => void;
     onRotate?: (direction: string) => void;
     onRotate?: (direction: string) => void;
     onDownload?: () => void;
     onDownload?: () => void;
-    renderPreviewMenu?: (props: MenuProps) => ReactNode
+    renderPreviewMenu?: (props: MenuProps) => ReactNode;
+    forwardRef?: React.RefObject<HTMLElement>
 }
 }
 
 
 export interface PreviewImageProps {
 export interface PreviewImageProps {
     src?: string;
     src?: string;
     rotation?: number;
     rotation?: number;
     style?: React.CSSProperties;
     style?: React.CSSProperties;
-    maxZoom?: number;
-    minZoom?: number;
-    zoomStep?: number;
+    // maxZoom?: number;
+    // minZoom?: number;
+    // zoomStep?: number;
     zoom?: number;
     zoom?: number;
     ratio?: RatioType;
     ratio?: RatioType;
     disableDownload?: boolean;
     disableDownload?: boolean;

+ 10 - 1
packages/semi-ui/image/preview.tsx

@@ -10,6 +10,7 @@ import { cssClasses } from "@douyinfe/semi-foundation/image/constants";
 import { isObject, isEqual } from "lodash";
 import { isObject, isEqual } from "lodash";
 import "@douyinfe/semi-foundation/image/image.scss";
 import "@douyinfe/semi-foundation/image/image.scss";
 import cls from "classnames";
 import cls from "classnames";
+import { omit } from "lodash";
 
 
 const prefixCls = cssClasses.PREFIX;
 const prefixCls = cssClasses.PREFIX;
 
 
@@ -39,6 +40,8 @@ export default class Preview extends BaseComponent<PreviewProps, PreviewState> {
         lazyLoadMargin: PropTypes.string,
         lazyLoadMargin: PropTypes.string,
         preLoad: PropTypes.bool,
         preLoad: PropTypes.bool,
         preLoadGap: PropTypes.number,
         preLoadGap: PropTypes.number,
+        previewCls: PropTypes.string,
+        previewStyle: PropTypes.object,
         disableDownload: PropTypes.bool,
         disableDownload: PropTypes.bool,
         zIndex: PropTypes.number,
         zIndex: PropTypes.number,
         renderHeader: PropTypes.func,
         renderHeader: PropTypes.func,
@@ -60,6 +63,7 @@ export default class Preview extends BaseComponent<PreviewProps, PreviewState> {
         src: [],
         src: [],
         lazyLoad: true,
         lazyLoad: true,
         lazyLoadMargin: "0px 100px 100px 0px",
         lazyLoadMargin: "0px 100px 100px 0px",
+        closable: true
     };
     };
 
 
     get adapter() {
     get adapter() {
@@ -193,6 +197,11 @@ export default class Preview extends BaseComponent<PreviewProps, PreviewState> {
 
 
     render() {
     render() {
         const { src, className, style, lazyLoad, setDownloadName, ...restProps } = this.props;
         const { src, className, style, lazyLoad, setDownloadName, ...restProps } = this.props;
+        const previewInnerProps = { 
+            ...omit(restProps, ['previewCls', 'previewStyle']), 
+            className: restProps?.previewCls, 
+            style: restProps?.previewStyle 
+        };
         const { currentIndex, visible } = this.state;
         const { currentIndex, visible } = this.state;
         const { srcListInChildren, newChildren, titles } = this.loopImageIndex();
         const { srcListInChildren, newChildren, titles } = this.loopImageIndex();
         const srcArr = Array.isArray(src) ? src : (typeof src === "string" ? [src] : []);
         const srcArr = Array.isArray(src) ? src : (typeof src === "string" ? [src] : []);
@@ -216,7 +225,7 @@ export default class Preview extends BaseComponent<PreviewProps, PreviewState> {
                     {newChildren}
                     {newChildren}
                 </div>
                 </div>
                 <PreviewInner
                 <PreviewInner
-                    {...restProps}
+                    {...previewInnerProps}
                     ref={this.previewRef}
                     ref={this.previewRef}
                     src={finalSrcList}
                     src={finalSrcList}
                     currentIndex={currentIndex}
                     currentIndex={currentIndex}

+ 4 - 9
packages/semi-ui/image/previewFooter.tsx

@@ -17,8 +17,6 @@ import { throttle } from "lodash";
 const prefixCls = cssClasses.PREFIX;
 const prefixCls = cssClasses.PREFIX;
 const footerPrefixCls = `${cssClasses.PREFIX}-preview-footer`;
 const footerPrefixCls = `${cssClasses.PREFIX}-preview-footer`;
 
 
-let mouseActiveTime: number = 0;
-
 export default class Footer extends BaseComponent<FooterProps> {
 export default class Footer extends BaseComponent<FooterProps> {
     static propTypes = {
     static propTypes = {
         curPage: PropTypes.number,
         curPage: PropTypes.number,
@@ -58,9 +56,6 @@ export default class Footer extends BaseComponent<FooterProps> {
     get adapter(): PreviewFooterAdapter<FooterProps> {
     get adapter(): PreviewFooterAdapter<FooterProps> {
         return {
         return {
             ...super.adapter,
             ...super.adapter,
-            setStartMouseOffset: (time: number) => {
-                mouseActiveTime = time;
-            }
         };
         };
     }
     }
 
 
@@ -121,9 +116,9 @@ export default class Footer extends BaseComponent<FooterProps> {
     // According to showTooltip in props, decide whether to use Tooltip to pack a layer
     // According to showTooltip in props, decide whether to use Tooltip to pack a layer
     // 根据 props 中的 showTooltip 决定是否使用 Tooltip 包一层
     // 根据 props 中的 showTooltip 决定是否使用 Tooltip 包一层
     getFinalIconElement = (element: ReactNode, content: ReactNode, key: string) => {
     getFinalIconElement = (element: ReactNode, content: ReactNode, key: string) => {
-        const { showTooltip } = this.props;
+        const { showTooltip, zIndex } = this.props;
         return showTooltip ? (
         return showTooltip ? (
-            <Tooltip content={content} key={`tooltip-${key}`}>
+            <Tooltip content={content} key={`tooltip-${key}`} zIndex={zIndex + 1}>
                 {element}
                 {element}
             </Tooltip>
             </Tooltip>
         ): element;
         ): element;
@@ -275,7 +270,7 @@ export default class Footer extends BaseComponent<FooterProps> {
     }
     }
 
 
     render() {
     render() {
-        const { className, renderPreviewMenu } = this.props;
+        const { className, renderPreviewMenu, forwardRef } = this.props;
 
 
         const menuCls = cls(footerPrefixCls, `${footerPrefixCls}-wrapper`, className,
         const menuCls = cls(footerPrefixCls, `${footerPrefixCls}-wrapper`, className,
             {
             {
@@ -284,7 +279,7 @@ export default class Footer extends BaseComponent<FooterProps> {
         );
         );
 
 
         return (
         return (
-            <section className={menuCls} >
+            <section className={menuCls} ref={forwardRef}>
                 {renderPreviewMenu ? this.customRenderViewMenu() : this.getFooterMenu()}
                 {renderPreviewMenu ? this.customRenderViewMenu() : this.getFooterMenu()}
             </section>
             </section>
         );
         );

+ 6 - 6
packages/semi-ui/image/previewHeader.tsx

@@ -1,4 +1,4 @@
-import * as React from "react";
+import React, { forwardRef } from "react";
 import { IconClose } from "@douyinfe/semi-icons";
 import { IconClose } from "@douyinfe/semi-icons";
 import { cssClasses } from "@douyinfe/semi-foundation/image/constants";
 import { cssClasses } from "@douyinfe/semi-foundation/image/constants";
 import cls from "classnames";
 import cls from "classnames";
@@ -7,7 +7,7 @@ import { PreviewContext } from "./previewContext";
 
 
 const prefixCls = `${cssClasses.PREFIX}-preview-header`;
 const prefixCls = `${cssClasses.PREFIX}-preview-header`;
 
 
-const Header: React.FC<HeaderProps> = ({ onClose, titleStyle, className, renderHeader }) => (
+const Header = forwardRef(({ onClose, titleStyle, className, renderHeader, closable }: HeaderProps, ref: React.LegacyRef<HTMLElement>) => (
     <PreviewContext.Consumer>
     <PreviewContext.Consumer>
         {({ currentIndex, titles }) => {
         {({ currentIndex, titles }) => {
             let title;
             let title;
@@ -15,16 +15,16 @@ const Header: React.FC<HeaderProps> = ({ onClose, titleStyle, className, renderH
                 title = titles[currentIndex];
                 title = titles[currentIndex];
             }
             }
             return (
             return (
-                <section className={cls(prefixCls, className)}>
+                <section ref={ref} className={cls(prefixCls, className)}>
                     <section className={`${prefixCls}-title`} style={titleStyle}>{renderHeader ? renderHeader(title) : title}</section>
                     <section className={`${prefixCls}-title`} style={titleStyle}>{renderHeader ? renderHeader(title) : title}</section>
                     {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
                     {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
-                    <section className={`${prefixCls}-close`} onMouseUp={onClose}>
+                    {closable && <section className={`${prefixCls}-close`} onMouseUp={onClose}>
                         <IconClose />
                         <IconClose />
-                    </section>
+                    </section>}
                 </section>
                 </section>
             );
             );
         }}
         }}
     </PreviewContext.Consumer>
     </PreviewContext.Consumer>
-);
+));
 
 
 export default Header;
 export default Header;

+ 26 - 80
packages/semi-ui/image/previewImage.tsx

@@ -8,20 +8,15 @@ import PreviewImageFoundation, { PreviewImageAdapter } from "@douyinfe/semi-foun
 
 
 const prefixCls = cssClasses.PREFIX;
 const prefixCls = cssClasses.PREFIX;
 const preViewImgPrefixCls = `${prefixCls}-preview-image`;
 const preViewImgPrefixCls = `${prefixCls}-preview-image`;
-let originImageWidth = null;
-let originImageHeight = null;
-let startMouseMove = false;
-// startMouseOffset:The offset of the mouse relative to the left and top of the picture
-let startMouseOffset = { x: 0, y: 0 };
 
 
 export default class PreviewImage extends BaseComponent<PreviewImageProps, PreviewImageStates> {
 export default class PreviewImage extends BaseComponent<PreviewImageProps, PreviewImageStates> {
     static propTypes = {
     static propTypes = {
         src: PropTypes.string,
         src: PropTypes.string,
         rotation: PropTypes.number,
         rotation: PropTypes.number,
         style: PropTypes.object,
         style: PropTypes.object,
-        maxZoom: PropTypes.number,
-        minZoom: PropTypes.number,
-        zoomStep: PropTypes.number,
+        // maxZoom: PropTypes.number,
+        // minZoom: PropTypes.number,
+        // zoomStep: PropTypes.number,
         zoom: PropTypes.number,
         zoom: PropTypes.number,
         ratio: PropTypes.string,
         ratio: PropTypes.string,
         disableDownload: PropTypes.bool,
         disableDownload: PropTypes.bool,
@@ -33,43 +28,34 @@ export default class PreviewImage extends BaseComponent<PreviewImageProps, Previ
     }
     }
 
 
     static defaultProps = {
     static defaultProps = {
-        maxZoom: 5,
-        minZoom: 0.1,
-        zoomStep: 0.1,
+        // maxZoom: 5,
+        // minZoom: 0.1,
+        // zoomStep: 0.1,
         zoom: undefined,
         zoom: undefined,
     };
     };
 
 
     get adapter(): PreviewImageAdapter<PreviewImageProps, PreviewImageStates> {
     get adapter(): PreviewImageAdapter<PreviewImageProps, PreviewImageStates> {
         return {
         return {
             ...super.adapter,
             ...super.adapter,
-            getOriginImageSize: () => ({ originImageWidth, originImageHeight }),
-            setOriginImageSize: (size: { originImageWidth: number; originImageHeight: number }) => {
-                originImageWidth = size.originImageWidth;
-                originImageHeight = size.originImageHeight;
-            },
             getContainer: () => {
             getContainer: () => {
                 return this.containerRef.current;
                 return this.containerRef.current;
             },
             },
             getImage: () => {
             getImage: () => {
-                return this.imageRef;
+                return this.imageRef.current;
             },
             },
-            getMouseMove: () => startMouseMove,
-            setStartMouseMove: (move: boolean) => { startMouseMove = move; },
-            getMouseOffset: () => startMouseOffset,
-            setStartMouseOffset: (offset: { x: number; y: number }) => { startMouseOffset = offset; },
             setLoading: (loading: boolean) => { 
             setLoading: (loading: boolean) => { 
                 this.setState({
                 this.setState({
                     loading,
                     loading,
                 });
                 });
             },
             },
             setImageCursor: (canDrag: boolean) => {
             setImageCursor: (canDrag: boolean) => {
-                this.imageRef.style.cursor = canDrag ? "grab" : "default";
+                this.imageRef.current.style.cursor = canDrag ? "grab" : "default";
             }
             }
         };
         };
     }
     }
 
 
     containerRef: React.RefObject<HTMLDivElement>;
     containerRef: React.RefObject<HTMLDivElement>;
-    imageRef: HTMLImageElement | null;
+    imageRef: React.RefObject<HTMLImageElement>;
     foundation: PreviewImageFoundation;
     foundation: PreviewImageFoundation;
 
 
     constructor(props) {
     constructor(props) {
@@ -84,7 +70,7 @@ export default class PreviewImage extends BaseComponent<PreviewImageProps, Previ
             left: 0,
             left: 0,
         };
         };
         this.containerRef = React.createRef<HTMLDivElement>();
         this.containerRef = React.createRef<HTMLDivElement>();
-        this.imageRef = null;
+        this.imageRef = React.createRef<HTMLImageElement>();
         this.foundation = new PreviewImageFoundation(this.adapter);
         this.foundation = new PreviewImageFoundation(this.adapter);
     }
     }
 
 
@@ -98,47 +84,34 @@ export default class PreviewImage extends BaseComponent<PreviewImageProps, Previ
 
 
     componentDidUpdate(prevProps: PreviewImageProps, prevStates: PreviewImageStates) {
     componentDidUpdate(prevProps: PreviewImageProps, prevStates: PreviewImageStates) {
         // If src changes, start a new loading
         // If src changes, start a new loading
-        if (this.props.src && this.props.src !== prevProps.src) {
+        const zoomChange = "zoom" in this.props && this.props.zoom !== this.state.currZoom;
+        const srcChange = this.props.src && this.props.src !== prevProps.src;
+        if (srcChange) {
             this.foundation.setLoading(true);
             this.foundation.setLoading(true);
-        } 
+        }
         // If the incoming zoom changes, other content changes are determined based on the new zoom value
         // If the incoming zoom changes, other content changes are determined based on the new zoom value
-        if ("zoom" in this.props && this.props.zoom !== prevStates.currZoom) {
-            this.handleZoomChange(this.props.zoom, null);
+        if (zoomChange) {
+            this.foundation.calculatePreviewImage(this.props.zoom, null);
         }
         }
-        // When the incoming ratio is changed, if it"s adaptation, then resizeImage is triggered to make the image adapt to the page
-        // else if it"s adaptation is realSize, then onZoom(1) is called to make the image size the original size;
-        if ("ratio" in this.props && this.props.ratio !== prevProps.ratio) {
-            if (originImageWidth && originImageHeight) {
-                if (this.props.ratio === "adaptation") {
-                    this.resizeImage();
-                } else {
-                    this.props.onZoom(1);
-                }
+        if (!zoomChange && !srcChange && prevProps) {
+            if ("ratio" in this.props && this.props.ratio !== prevProps.ratio) {
+                this.foundation.handleRatioChange();
             }
             }
-        }
-        // When the incoming rotation angle of the image changes, it needs to be resized to make the image fit on the page
-        if ("rotation" in this.props && this.props.rotation !== prevProps.rotation) {
-            this.onWindowResize();
-        }
+            if ("rotation" in this.props && this.props.rotation !== prevProps.rotation) {
+                this.onWindowResize();
+            }
+        }   
     }
     }
 
 
     onWindowResize = (): void => {
     onWindowResize = (): void => {
         this.foundation.handleWindowResize();
         this.foundation.handleWindowResize();
     };
     };
 
 
-    handleZoomChange = (newZoom, e): void => {
-        this.foundation.handleZoomChange(newZoom, e);
-    };
-
     // Determine the response method of right click according to the disableDownload parameter in props
     // Determine the response method of right click according to the disableDownload parameter in props
     handleRightClickImage = (e) => {
     handleRightClickImage = (e) => {
         this.foundation.handleRightClickImage(e);
         this.foundation.handleRightClickImage(e);
     };
     };
 
 
-    handleWheel = (e) => {
-        this.foundation.handleWheel(e);
-    }
-
     handleLoad = (e): void => {
     handleLoad = (e): void => {
         this.foundation.handleLoad(e);
         this.foundation.handleLoad(e);
     }
     }
@@ -147,40 +120,14 @@ export default class PreviewImage extends BaseComponent<PreviewImageProps, Previ
         this.foundation.handleError(e);
         this.foundation.handleError(e);
     }
     }
 
 
-    resizeImage = () => {
-        this.foundation.handleResizeImage();
-    }
-
     handleMoveImage = (e): void => {
     handleMoveImage = (e): void => {
         this.foundation.handleMoveImage(e);
         this.foundation.handleMoveImage(e);
     };
     };
-  
-    // 为什么通过ref注册wheel而不是使用onWheel事件?
-    // 因为对于wheel事件,浏览器将 addEventListener 的 passive 默认值更改为 true。如此,事件监听器便不能取消事件,也不会在用户滚动页面时阻止页面呈现。
-    // 这里我们需要保持页面不动,仅放大图片,因此此处需要将 passive 更改设置为 false。
-    // Why register wheel via ref instead of using onWheel event?
-    // Because for wheel events, the browser changes the passive default of addEventListener to true. This way, the event listener cannot cancel the event, nor prevent the page from rendering when the user scrolls.
-    // Here we need to keep the page still and only zoom in on the image, so here we need to set the passive change to false.
-    // https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#improving_scrolling_performance_with_passive_listeners。
-    
-    registryImageRef = (ref): void => {
-        if (this.imageRef) {
-            (this.imageRef as any).removeEventListener("wheel", this.handleWheel);
-        }
-        if (ref) {
-            ref.addEventListener("wheel", this.handleWheel, { passive: false });
-        }
-        this.imageRef = ref;
-    };
 
 
     onImageMouseDown = (e: React.MouseEvent<HTMLImageElement>): void => {
     onImageMouseDown = (e: React.MouseEvent<HTMLImageElement>): void => {
         this.foundation.handleImageMouseDown(e);
         this.foundation.handleImageMouseDown(e);
     };
     };
 
 
-    onImageMouseUp = (): void => {
-        this.foundation.handleImageMouseUp();
-    };
-
     render() {
     render() {
         const { src, rotation, crossOrigin } = this.props;
         const { src, rotation, crossOrigin } = this.props;
         const { loading, width, height, top, left } = this.state;
         const { loading, width, height, top, left } = this.state;
@@ -190,8 +137,8 @@ export default class PreviewImage extends BaseComponent<PreviewImageProps, Previ
             transform: `rotate(${-rotation}deg)`,
             transform: `rotate(${-rotation}deg)`,
             top,
             top,
             left,
             left,
-            width: loading ? "auto" : `${width}px`,
-            height: loading ? "auto" : `${height}px`,
+            width,
+            height,
         };
         };
         return (
         return (
             <div 
             <div 
@@ -200,14 +147,13 @@ export default class PreviewImage extends BaseComponent<PreviewImageProps, Previ
             >
             >
                 {/* eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions */}
                 {/* eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions */}
                 <img
                 <img
-                    ref={this.registryImageRef}
+                    ref={this.imageRef}
                     src={src}
                     src={src}
                     alt="previewImag"
                     alt="previewImag"
                     className={`${preViewImgPrefixCls}-img`}
                     className={`${preViewImgPrefixCls}-img`}
                     key={src}
                     key={src}
                     onMouseMove={this.handleMoveImage}
                     onMouseMove={this.handleMoveImage}
                     onMouseDown={this.onImageMouseDown}
                     onMouseDown={this.onImageMouseDown}
-                    onMouseUp={this.onImageMouseUp}
                     onContextMenu={this.handleRightClickImage}
                     onContextMenu={this.handleRightClickImage}
                     onDragStart={(e): void => e.preventDefault()}
                     onDragStart={(e): void => e.preventDefault()}
                     onLoad={this.handleLoad}
                     onLoad={this.handleLoad}

+ 147 - 115
packages/semi-ui/image/previewInner.tsx

@@ -1,8 +1,8 @@
 import React, { CSSProperties } from "react";
 import React, { CSSProperties } from "react";
 import BaseComponent from "../_base/baseComponent";
 import BaseComponent from "../_base/baseComponent";
-import { PreviewProps as PreviewInnerProps, PreviewInnerStates } from "./interface";
+import { PreviewInnerProps, PreviewInnerStates } from "./interface";
 import PropTypes from "prop-types";
 import PropTypes from "prop-types";
-import { cssClasses } from "@douyinfe/semi-foundation/image/constants";
+import { cssClasses, numbers } from "@douyinfe/semi-foundation/image/constants";
 import cls from "classnames";
 import cls from "classnames";
 import { isEqual, isFunction } from "lodash";
 import { isEqual, isFunction } from "lodash";
 import Portal from "../_portal";
 import Portal from "../_portal";
@@ -13,16 +13,10 @@ import PreviewImage from "./previewImage";
 import PreviewInnerFoundation, { PreviewInnerAdapter, RatioType } from "@douyinfe/semi-foundation/image/previewInnerFoundation";
 import PreviewInnerFoundation, { PreviewInnerAdapter, RatioType } from "@douyinfe/semi-foundation/image/previewInnerFoundation";
 import { PreviewContext, PreviewContextProps } from "./previewContext";
 import { PreviewContext, PreviewContextProps } from "./previewContext";
 import { getScrollbarWidth } from "../_utils";
 import { getScrollbarWidth } from "../_utils";
+import ReactDOM from "react-dom";
 
 
 const prefixCls = cssClasses.PREFIX;
 const prefixCls = cssClasses.PREFIX;
 
 
-let startMouseDown = { x: 0, y: 0 };
-
-let mouseActiveTime: number = null;
-let stopTiming = false;
-let timer = null;
-// let bodyOverflowValue = document.body.style.overflow;
-
 export default class PreviewInner extends BaseComponent<PreviewInnerProps, PreviewInnerStates> {
 export default class PreviewInner extends BaseComponent<PreviewInnerProps, PreviewInnerStates> {
     static contextType = PreviewContext;
     static contextType = PreviewContext;
 
 
@@ -53,6 +47,8 @@ export default class PreviewInner extends BaseComponent<PreviewInnerProps, Previ
         disableDownload: PropTypes.bool,
         disableDownload: PropTypes.bool,
         viewerVisibleDelay: PropTypes.number,
         viewerVisibleDelay: PropTypes.number,
         zIndex: PropTypes.number,
         zIndex: PropTypes.number,
+        maxZoom: PropTypes.number,
+        minZoom: PropTypes.number,
         renderHeader: PropTypes.func,
         renderHeader: PropTypes.func,
         renderPreviewMenu: PropTypes.func,
         renderPreviewMenu: PropTypes.func,
         getPopupContainer: PropTypes.func,
         getPopupContainer: PropTypes.func,
@@ -76,9 +72,11 @@ export default class PreviewInner extends BaseComponent<PreviewInnerProps, Previ
         lazyLoad: false,
         lazyLoad: false,
         preLoad: true,
         preLoad: true,
         preLoadGap: 2,
         preLoadGap: 2,
-        zIndex: 1000,
+        zIndex: numbers.DEFAULT_Z_INDEX,
         maskClosable: true,
         maskClosable: true,
         viewerVisibleDelay: 10000,
         viewerVisibleDelay: 10000,
+        maxZoom: 5,
+        minZoom: 0.1
     };
     };
 
 
     private bodyOverflow: string;
     private bodyOverflow: string;
@@ -147,34 +145,38 @@ export default class PreviewInner extends BaseComponent<PreviewInnerProps, Previ
             unregisterKeyDownListener: () => {
             unregisterKeyDownListener: () => {
                 window && window.removeEventListener("keydown", this.handleKeyDown);
                 window && window.removeEventListener("keydown", this.handleKeyDown);
             },
             },
-            getMouseActiveTime: () => {
-                return mouseActiveTime;
-            },
-            getStopTiming: () => {
-                return stopTiming;
-            },
-            setStopTiming: (value) => {
-                stopTiming = value;
-            },
-            getStartMouseDown: () => {
-                return startMouseDown;
-            },
-            setStartMouseDown: (x: number, y: number) => {
-                startMouseDown = { x, y };
-            },
-            setMouseActiveTime: (time: number) => {
-                mouseActiveTime = time;
-            },
             getSetDownloadFunc: () => {
             getSetDownloadFunc: () => {
                 return this.context?.setDownloadName ?? this.props.setDownloadName;
                 return this.context?.setDownloadName ?? this.props.setDownloadName;
+            },
+            isValidTarget: (e) => {
+                const headerDom = this.headerRef && this.headerRef.current;
+                const footerDom = this.footerRef && this.footerRef.current;
+                const leftIconDom = this.leftIconRef && this.leftIconRef.current;
+                const rightIconDom = this.rightIconRef && this.rightIconRef.current;
+                const target = e.target as any;
+                if (
+                    headerDom && headerDom.contains(target) ||
+                    footerDom && footerDom.contains(target) ||
+                    leftIconDom && leftIconDom.contains(target) ||
+                    rightIconDom && rightIconDom.contains(target)  
+                ) {
+                    // Move in the operation area, return false
+                    return false;
+                }
+                // Move in the preview area except the operation area, return true
+                return true;
             }
             }
         };
         };
 
 
     }
     }
 
 
-    timer;
     context: PreviewContextProps;
     context: PreviewContextProps;
     foundation: PreviewInnerFoundation;
     foundation: PreviewInnerFoundation;
+    imageWrapRef: React.RefObject<HTMLDivElement>;
+    headerRef: React.RefObject<HTMLElement>;
+    footerRef: React.RefObject<HTMLElement>;
+    leftIconRef: React.RefObject<HTMLDivElement>;
+    rightIconRef: React.RefObject<HTMLDivElement>;
 
 
     constructor(props: PreviewInnerProps) {
     constructor(props: PreviewInnerProps) {
         super(props);
         super(props);
@@ -194,6 +196,11 @@ export default class PreviewInner extends BaseComponent<PreviewInnerProps, Previ
         this.bodyOverflow = '';
         this.bodyOverflow = '';
         this.originBodyWidth = '100%';
         this.originBodyWidth = '100%';
         this.scrollBarWidth = 0;
         this.scrollBarWidth = 0;
+        this.imageWrapRef = null;
+        this.headerRef = React.createRef<HTMLElement>();
+        this.footerRef= React.createRef<HTMLElement>();
+        this.leftIconRef= React.createRef<HTMLDivElement>();
+        this.rightIconRef= React.createRef<HTMLDivElement>();
     }
     }
 
 
     static getDerivedStateFromProps(props: PreviewInnerProps, state: PreviewInnerStates) {
     static getDerivedStateFromProps(props: PreviewInnerProps, state: PreviewInnerStates) {
@@ -210,6 +217,9 @@ export default class PreviewInner extends BaseComponent<PreviewInnerProps, Previ
             willUpdateStates.visible = props.visible;
             willUpdateStates.visible = props.visible;
             if (props.visible) {
             if (props.visible) {
                 willUpdateStates.preloadAfterVisibleChange = true;
                 willUpdateStates.preloadAfterVisibleChange = true;
+                willUpdateStates.viewerVisible = true;
+                willUpdateStates.rotation = 0;
+                willUpdateStates.ratio = 'adaptation';
             }
             }
         }
         }
         if ("currentIndex" in props && props.currentIndex !== state.currentIndex) {
         if ("currentIndex" in props && props.currentIndex !== state.currentIndex) {
@@ -230,10 +240,8 @@ export default class PreviewInner extends BaseComponent<PreviewInnerProps, Previ
     }
     }
 
 
     componentDidUpdate(prevProps: PreviewInnerProps, prevState: PreviewInnerStates) {
     componentDidUpdate(prevProps: PreviewInnerProps, prevState: PreviewInnerStates) {
-        if (prevState.visible !== this.props.visible && this.props.visible) {
-            mouseActiveTime = new Date().getTime();
-            timer && clearInterval(timer);
-            timer = setInterval(this.viewVisibleChange, 1000);
+        if (prevProps.src !== this.props.src) {
+            this.foundation.updateTimer();
         }
         }
         // hide => show
         // hide => show
         if (!prevProps.visible && this.props.visible) {
         if (!prevProps.visible && this.props.visible) {
@@ -246,7 +254,7 @@ export default class PreviewInner extends BaseComponent<PreviewInnerProps, Previ
     }
     }
 
 
     componentWillUnmount() {
     componentWillUnmount() {
-        timer && clearInterval(timer);
+        this.foundation.clearTimer();
     }
     }
 
 
     isInGroup() {
     isInGroup() {
@@ -265,8 +273,8 @@ export default class PreviewInner extends BaseComponent<PreviewInnerProps, Previ
         this.foundation.handleDownload();
         this.foundation.handleDownload();
     }
     }
 
 
-    handlePreviewClose = () => {
-        this.foundation.handlePreviewClose();
+    handlePreviewClose = (e: React.MouseEvent<HTMLElement>) => {
+        this.foundation.handlePreviewClose(e);
     }
     }
 
 
     handleAdjustRatio = (type: RatioType) => {
     handleAdjustRatio = (type: RatioType) => {
@@ -277,8 +285,8 @@ export default class PreviewInner extends BaseComponent<PreviewInnerProps, Previ
         this.foundation.handleRotateImage(direction);
         this.foundation.handleRotateImage(direction);
     }
     }
 
 
-    handleZoomImage = (newZoom: number) => {
-        this.foundation.handleZoomImage(newZoom);
+    handleZoomImage = (newZoom: number, notify: boolean = true) => {
+        this.foundation.handleZoomImage(newZoom, notify);
     }
     }
 
 
     handleMouseUp = (e): void => {
     handleMouseUp = (e): void => {
@@ -289,9 +297,6 @@ export default class PreviewInner extends BaseComponent<PreviewInnerProps, Previ
         this.foundation.handleMouseMove(e);
         this.foundation.handleMouseMove(e);
     }
     }
 
 
-    handleMouseEvent = (e, event: string) => {
-        this.foundation.handleMouseMoveEvent(e, event);
-    }
 
 
     handleKeyDown = (e: KeyboardEvent) => {
     handleKeyDown = (e: KeyboardEvent) => {
         this.foundation.handleKeyDown(e);
         this.foundation.handleKeyDown(e);
@@ -309,9 +314,35 @@ export default class PreviewInner extends BaseComponent<PreviewInnerProps, Previ
         this.foundation.handleMouseDown(e);
         this.foundation.handleMouseDown(e);
     }
     }
 
 
+    handleWheel = (e) => {
+        this.foundation.handleWheel(e);
+    }
+
+    // 为什么通过 addEventListener 注册 wheel 事件而不是使用 onWheel 事件?
+    // 因为 Passive Event Listeners(https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#improving_scrolling_performance_with_passive_listeners)
+    // Passive Event Listeners 是一种优化技术,用于提高滚动性能。在默认情况下,浏览器会假设事件的监听器不会调用 
+    // preventDefault() 方法来阻止事件的默认行为,从而允许进行一些优化操作,例如滚动平滑。
+    // 对于 Image 而言,如果使用触控板,双指朝不同方向分开放大图片,则需要  preventDefault 防止页面整体放大。
+    // Why register wheel event through addEventListener instead of using onWheel event?
+    // Because of Passive Event Listeners(an optimization technique used to improve scrolling performance. By default, 
+    // the browser will assume that event listeners will not call preventDefault() method to prevent the default behavior of the event, 
+    // allowing some optimization operations such as scroll smoothing.)
+    // For Image, if we use the trackpad and spread your fingers in different directions to enlarge the image, we need to preventDefault
+    // to prevent the page from being enlarged as a whole.
+    registryImageWrapRef = (ref): void => {
+        if (this.imageWrapRef) {
+            (this.imageWrapRef as any).removeEventListener("wheel", this.handleWheel);
+        }
+        if (ref) {
+            ref.addEventListener("wheel", this.handleWheel, { passive: false });
+        }
+        this.imageWrapRef = ref;
+    };
+
     render() {
     render() {
         const {
         const {
             getPopupContainer,
             getPopupContainer,
+            closable,
             zIndex,
             zIndex,
             visible,
             visible,
             className,
             className,
@@ -359,82 +390,83 @@ export default class PreviewInner extends BaseComponent<PreviewInnerProps, Previ
         const showPrev = total !== 1 && (infinite || currentIndex !== 0);
         const showPrev = total !== 1 && (infinite || currentIndex !== 0);
         const showNext = total !== 1 && (infinite || currentIndex !== total - 1);
         const showNext = total !== 1 && (infinite || currentIndex !== total - 1);
         return (
         return (
-            <Portal
+            visible && <Portal
                 getPopupContainer={getPopupContainer}
                 getPopupContainer={getPopupContainer}
                 style={wrapperStyle}
                 style={wrapperStyle}
-            >
-                {visible &&
-                    // eslint-disable-next-line jsx-a11y/mouse-events-have-key-events,jsx-a11y/no-static-element-interactions
-                    <div
-                        className={previewWrapperCls}
-                        style={style}
-                        onMouseDown={this.handleMouseDown}
-                        onMouseUp={this.handleMouseUp}
-                        onMouseMove={this.handleMouseMove}
-                        onMouseOver={(e): void => this.handleMouseEvent(e.nativeEvent, "over")}
-                        onMouseOut={(e): void => this.handleMouseEvent(e.nativeEvent, "out")}
-                    >
-                        <Header className={cls(hideViewerCls)} onClose={this.handlePreviewClose} renderHeader={renderHeader} />
-                        <PreviewImage
-                            src={imgSrc[currentIndex]}
-                            onZoom={this.handleZoomImage}
-                            disableDownload={disableDownload}
-                            setRatio={this.handleAdjustRatio}
-                            zoom={zoom}
-                            ratio={ratio}
-                            zoomStep={zoomStep}
-                            rotation={rotation}
-                            crossOrigin={crossOrigin}
-                            onError={this.onImageError}
-                            onLoad={this.onImageLoad}
-                        />
-                        {showPrev && (
-                            // eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions
-                            <div
-                                className={cls(`${previewPrefixCls}-icon`, `${previewPrefixCls}-prev`, hideViewerCls)}
-                                onClick={(): void => this.handleSwitchImage("prev")}
-                            >
-                                <IconArrowLeft size="large" />
-                            </div>
-                        )}
-                        {showNext && (
-                            // eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions
-                            <div
-                                className={cls(`${previewPrefixCls}-icon`, `${previewPrefixCls}-next`, hideViewerCls)}
-                                onClick={(): void => this.handleSwitchImage("next")}
-                            >
-                                <IconArrowRight size="large" />
-                            </div>
-                        )}
-                        <Footer
-                            className={hideViewerCls}
-                            totalNum={total}
-                            curPage={currentIndex + 1}
-                            disabledPrev={!showPrev}
-                            disabledNext={!showNext}
-                            zoom={zoom * 100}
-                            step={zoomStep * 100}
-                            showTooltip={showTooltip}
-                            ratio={ratio}
-                            prevTip={prevTip}
-                            nextTip={nextTip}
-                            zoomInTip={zoomInTip}
-                            zoomOutTip={zoomOutTip}
-                            rotateTip={rotateTip}
-                            downloadTip={downloadTip}
-                            disableDownload={disableDownload}
-                            adaptiveTip={adaptiveTip}
-                            originTip={originTip}
-                            onPrev={(): void => this.handleSwitchImage("prev")}
-                            onNext={(): void => this.handleSwitchImage("next")}
-                            onZoomIn={this.handleZoomImage}
-                            onZoomOut={this.handleZoomImage}
-                            onDownload={this.handleDownload}
-                            onRotate={this.handleRotateImage}
-                            onAdjustRatio={this.handleAdjustRatio}
-                            renderPreviewMenu={renderPreviewMenu}
-                        />
-                    </div>}
+            >  
+                {/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */}
+                <div
+                    className={previewWrapperCls}
+                    style={style}
+                    onMouseDown={this.handleMouseDown}
+                    onMouseUp={this.handleMouseUp}
+                    ref={this.registryImageWrapRef}
+                    onMouseMove={this.handleMouseMove}
+                >
+                    <Header ref={this.headerRef} className={cls(hideViewerCls)} onClose={this.handlePreviewClose} renderHeader={renderHeader} closable={closable}/>
+                    <PreviewImage
+                        src={imgSrc[currentIndex]}
+                        onZoom={this.handleZoomImage}
+                        disableDownload={disableDownload}
+                        setRatio={this.handleAdjustRatio}
+                        zoom={zoom}
+                        ratio={ratio}
+                        rotation={rotation}
+                        crossOrigin={crossOrigin}
+                        onError={this.onImageError}
+                        onLoad={this.onImageLoad}
+                    />
+                    {showPrev && (
+                        // eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions
+                        <div
+                            ref={this.leftIconRef}
+                            className={cls(`${previewPrefixCls}-icon`, `${previewPrefixCls}-prev`, hideViewerCls)}
+                            onClick={(): void => this.handleSwitchImage("prev")}
+                        >
+                            <IconArrowLeft size="large" />
+                        </div>
+                    )}
+                    {showNext && (
+                        // eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions
+                        <div
+                            ref={this.rightIconRef}
+                            className={cls(`${previewPrefixCls}-icon`, `${previewPrefixCls}-next`, hideViewerCls)}
+                            onClick={(): void => this.handleSwitchImage("next")}
+                        >
+                            <IconArrowRight size="large" />
+                        </div>
+                    )}
+                    <Footer
+                        forwardRef={this.footerRef}
+                        className={hideViewerCls}
+                        totalNum={total}
+                        curPage={currentIndex + 1}
+                        disabledPrev={!showPrev}
+                        disabledNext={!showNext}
+                        zoom={zoom * 100}
+                        step={zoomStep * 100}
+                        showTooltip={showTooltip}
+                        ratio={ratio}
+                        prevTip={prevTip}
+                        nextTip={nextTip}
+                        zIndex={zIndex}
+                        zoomInTip={zoomInTip}
+                        zoomOutTip={zoomOutTip}
+                        rotateTip={rotateTip}
+                        downloadTip={downloadTip}
+                        disableDownload={disableDownload}
+                        adaptiveTip={adaptiveTip}
+                        originTip={originTip}
+                        onPrev={(): void => this.handleSwitchImage("prev")}
+                        onNext={(): void => this.handleSwitchImage("next")}
+                        onZoomIn={this.handleZoomImage}
+                        onZoomOut={this.handleZoomImage}
+                        onDownload={this.handleDownload}
+                        onRotate={this.handleRotateImage}
+                        onAdjustRatio={this.handleAdjustRatio}
+                        renderPreviewMenu={renderPreviewMenu}
+                    />
+                </div>
             </Portal>
             </Portal>
         );
         );
     }
     }

+ 3 - 1
packages/semi-ui/index.ts

@@ -1,7 +1,9 @@
 import './_base/base.scss';
 import './_base/base.scss';
+export { default as BaseFoundation } from "@douyinfe/semi-foundation/base/foundation";
+export { default as BaseComponent } from "./_base/baseComponent";
 export { default as Anchor } from './anchor';
 export { default as Anchor } from './anchor';
 export { default as AutoComplete } from './autoComplete';
 export { default as AutoComplete } from './autoComplete';
-export { default as Avatar } from './avatar';
+export { default as Avatar } from './avatar'; 
 export { default as AvatarGroup } from './avatar/avatarGroup';
 export { default as AvatarGroup } from './avatar/avatarGroup';
 export { default as BackTop } from './backtop';
 export { default as BackTop } from './backtop';
 export { default as Badge } from './badge';
 export { default as Badge } from './badge';

+ 16 - 0
packages/semi-ui/input/_story/input.stories.jsx

@@ -1015,3 +1015,19 @@ export const forwardRefFocus = () => {
     </div>
     </div>
   </>
   </>
 )};
 )};
+
+export const TextAutoSizeResize = () => {
+  const [width, setWidth] = useState(800);
+
+  return (
+    <div>
+      <Space style={{ marginBottom: 20 }}>
+        <Button onClick={() => setWidth(100)}>width=100</Button>
+        <Button onClick={() => setWidth(1000)}>width=1000</Button>
+      </Space>
+      <div style={{ width, maxWidth: '100%' }}>
+        <TextArea autosize defaultValue='semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design ' />
+      </div>
+    </div>
+  )
+};

+ 56 - 78
packages/semi-ui/input/textarea.tsx

@@ -5,8 +5,10 @@ import TextAreaFoundation from '@douyinfe/semi-foundation/input/textareaFoundati
 import { cssClasses } from '@douyinfe/semi-foundation/input/constants';
 import { cssClasses } from '@douyinfe/semi-foundation/input/constants';
 import BaseComponent, { ValidateStatus } from '../_base/baseComponent';
 import BaseComponent, { ValidateStatus } from '../_base/baseComponent';
 import '@douyinfe/semi-foundation/input/textarea.scss';
 import '@douyinfe/semi-foundation/input/textarea.scss';
-import { noop, omit, isFunction, isUndefined, isObject } from 'lodash';
+import { noop, omit, isFunction, isUndefined, isObject, throttle } from 'lodash';
+import type { DebouncedFunc } from 'lodash';
 import { IconClear } from '@douyinfe/semi-icons';
 import { IconClear } from '@douyinfe/semi-icons';
+import ResizeObserver from '../resizeObserver';
 
 
 const prefixCls = cssClasses.PREFIX;
 const prefixCls = cssClasses.PREFIX;
 
 
@@ -20,15 +22,14 @@ type OmitTextareaAttr =
     | 'onKeyDown'
     | 'onKeyDown'
     | 'onKeyPress'
     | 'onKeyPress'
     | 'onKeyUp'
     | 'onKeyUp'
-    | 'onResize'
+    | 'onResize';
 
 
 export type AutosizeRow = {
 export type AutosizeRow = {
     minRows?: number;
     minRows?: number;
     maxRows?: number
     maxRows?: number
-}
+};
 
 
-export interface TextAreaProps extends
-    Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, OmitTextareaAttr> {
+export interface TextAreaProps extends Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, OmitTextareaAttr> {
     autosize?: boolean | AutosizeRow;
     autosize?: boolean | AutosizeRow;
     borderless?: boolean;
     borderless?: boolean;
     placeholder?: string;
     placeholder?: string;
@@ -53,7 +54,7 @@ export interface TextAreaProps extends
     onKeyPress?: (e: React.KeyboardEvent<HTMLTextAreaElement>) => void;
     onKeyPress?: (e: React.KeyboardEvent<HTMLTextAreaElement>) => void;
     onEnterPress?: (e: React.KeyboardEvent<HTMLTextAreaElement>) => void;
     onEnterPress?: (e: React.KeyboardEvent<HTMLTextAreaElement>) => void;
     onPressEnter?: (e: React.KeyboardEvent<HTMLTextAreaElement>) => void;
     onPressEnter?: (e: React.KeyboardEvent<HTMLTextAreaElement>) => void;
-    onResize?: (data: {height: number}) => void;
+    onResize?: (data: { height: number }) => void;
     getValueLength?: (value: string) => number;
     getValueLength?: (value: string) => number;
     forwardRef?: ((instance: HTMLTextAreaElement) => void) | React.MutableRefObject<HTMLTextAreaElement> | null
     forwardRef?: ((instance: HTMLTextAreaElement) => void) | React.MutableRefObject<HTMLTextAreaElement> | null
 }
 }
@@ -107,9 +108,8 @@ class TextArea extends BaseComponent<TextAreaProps, TextAreaState> {
 
 
     focusing: boolean;
     focusing: boolean;
     libRef: React.RefObject<HTMLInputElement>;
     libRef: React.RefObject<HTMLInputElement>;
-    _resizeLock: boolean;
-    _resizeListener: any;
     foundation: TextAreaFoundation;
     foundation: TextAreaFoundation;
+    throttledResizeTextarea: DebouncedFunc<typeof this.foundation.resizeTextarea>;
 
 
     constructor(props: TextAreaProps) {
     constructor(props: TextAreaProps) {
         super(props);
         super(props);
@@ -124,17 +124,18 @@ class TextArea extends BaseComponent<TextAreaProps, TextAreaState> {
         this.foundation = new TextAreaFoundation(this.adapter);
         this.foundation = new TextAreaFoundation(this.adapter);
 
 
         this.libRef = React.createRef<HTMLInputElement>();
         this.libRef = React.createRef<HTMLInputElement>();
-        this._resizeLock = false;
+        this.throttledResizeTextarea = throttle(this.foundation.resizeTextarea, 10);
     }
     }
 
 
     get adapter() {
     get adapter() {
         return {
         return {
             ...super.adapter,
             ...super.adapter,
-            setValue: (value: string) => this.setState({ value }, () => {
-                if (this.props.autosize) {
-                    this.foundation.resizeTextarea();
-                }
-            }),
+            setValue: (value: string) =>
+                this.setState({ value }, () => {
+                    if (this.props.autosize) {
+                        this.foundation.resizeTextarea();
+                    }
+                }),
             getRef: () => this.libRef.current,
             getRef: () => this.libRef.current,
             toggleFocusing: (focusing: boolean) => this.setState({ isFocus: focusing }),
             toggleFocusing: (focusing: boolean) => this.setState({ isFocus: focusing }),
             toggleHovering: (hovering: boolean) => this.setState({ isHover: hovering }),
             toggleHovering: (hovering: boolean) => this.setState({ isHover: hovering }),
@@ -169,35 +170,18 @@ class TextArea extends BaseComponent<TextAreaProps, TextAreaState> {
         return willUpdateStates;
         return willUpdateStates;
     }
     }
 
 
-    componentDidMount() {
-        this.foundation.init();
-        this._resizeListener = null;
-        if (this.props.autosize) {
-            // Working around Firefox bug which runs resize listeners even when other JS is running at the same moment
-            // causing competing rerenders (due to setState in the listener) in React.
-            // More can be found here - facebook/react#6324
-            // // Reference to https://github.com/andreypopp/react-textarea-autosize/
-            this._resizeListener = () => {
-                if (this._resizeLock) {
-                    return;
-                }
-                this._resizeLock = true;
-                this.foundation.resizeTextarea(() => {
-                    this._resizeLock = false;
-                });
-            };
-            window.addEventListener('resize', this._resizeListener);
+    componentWillUnmount(): void {
+        if (this.throttledResizeTextarea) {
+            this.throttledResizeTextarea?.cancel?.();
+            this.throttledResizeTextarea = null;
         }
         }
     }
     }
 
 
-    componentWillUnmount() {
-        this.foundation.destroy();
-        this._resizeListener && window.removeEventListener('resize', this._resizeListener);
-    }
-
     componentDidUpdate(prevProps: TextAreaProps, prevState: TextAreaState) {
     componentDidUpdate(prevProps: TextAreaProps, prevState: TextAreaState) {
-
-        if ((this.props.value !== prevProps.value || this.props.placeholder !== prevProps.placeholder) && this.props.autosize) {
+        if (
+            (this.props.value !== prevProps.value || this.props.placeholder !== prevProps.placeholder) &&
+            this.props.autosize
+        ) {
             this.foundation.resizeTextarea();
             this.foundation.resizeTextarea();
         }
         }
     }
     }
@@ -215,10 +199,7 @@ class TextArea extends BaseComponent<TextAreaProps, TextAreaState> {
         if (showClear) {
         if (showClear) {
             return (
             return (
                 // eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions
                 // eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions
-                <div
-                    className={clearCls}
-                    onClick={this.handleClear}
-                >
+                <div className={clearCls} onClick={this.handleClear}>
                     <IconClear />
                     <IconClear />
                 </div>
                 </div>
             );
             );
@@ -227,25 +208,21 @@ class TextArea extends BaseComponent<TextAreaProps, TextAreaState> {
     }
     }
 
 
     renderCounter() {
     renderCounter() {
-        let counter: React.ReactNode,
-            current: number,
-            total: number,
-            countCls: string;
+        let counter: React.ReactNode, current: number, total: number, countCls: string;
         const { showCounter, maxCount, getValueLength } = this.props;
         const { showCounter, maxCount, getValueLength } = this.props;
         if (showCounter || maxCount) {
         if (showCounter || maxCount) {
             const { value } = this.state;
             const { value } = this.state;
             // eslint-disable-next-line no-nested-ternary
             // eslint-disable-next-line no-nested-ternary
-            current = value ? isFunction(getValueLength) ? getValueLength(value) : value.length : 0;
+            current = value ? (isFunction(getValueLength) ? getValueLength(value) : value.length) : 0;
             total = maxCount || null;
             total = maxCount || null;
-            countCls = cls(
-                `${prefixCls}-textarea-counter`,
-                {
-                    [`${prefixCls}-textarea-counter-exceed`]: current > total
-                }
-            );
+            countCls = cls(`${prefixCls}-textarea-counter`, {
+                [`${prefixCls}-textarea-counter-exceed`]: current > total,
+            });
             counter = (
             counter = (
                 <div className={countCls}>
                 <div className={countCls}>
-                    {current}{total ? '/' : null}{total}
+                    {current}
+                    {total ? '/' : null}
+                    {total}
                 </div>
                 </div>
             );
             );
         } else {
         } else {
@@ -289,28 +266,21 @@ class TextArea extends BaseComponent<TextAreaProps, TextAreaState> {
             ...rest
             ...rest
         } = this.props;
         } = this.props;
         const { isFocus, value, minLength: stateMinLength } = this.state;
         const { isFocus, value, minLength: stateMinLength } = this.state;
-        const wrapperCls = cls(
-            className,
-            `${prefixCls}-textarea-wrapper`,
-            {
-                [`${prefixCls}-textarea-borderless`]: borderless,
-                [`${prefixCls}-textarea-wrapper-disabled`]: disabled,
-                [`${prefixCls}-textarea-wrapper-readonly`]: readonly,
-                [`${prefixCls}-textarea-wrapper-${validateStatus}`]: Boolean(validateStatus),
-                [`${prefixCls}-textarea-wrapper-focus`]: isFocus,
-                // [`${prefixCls}-textarea-wrapper-resize`]: !autosize && resize,
-            }
-        );
+        const wrapperCls = cls(className, `${prefixCls}-textarea-wrapper`, {
+            [`${prefixCls}-textarea-borderless`]: borderless,
+            [`${prefixCls}-textarea-wrapper-disabled`]: disabled,
+            [`${prefixCls}-textarea-wrapper-readonly`]: readonly,
+            [`${prefixCls}-textarea-wrapper-${validateStatus}`]: Boolean(validateStatus),
+            [`${prefixCls}-textarea-wrapper-focus`]: isFocus,
+            // [`${prefixCls}-textarea-wrapper-resize`]: !autosize && resize,
+        });
         // const ref = this.props.forwardRef || this.textAreaRef;
         // const ref = this.props.forwardRef || this.textAreaRef;
-        const itemCls = cls(
-            `${prefixCls}-textarea`,
-            {
-                [`${prefixCls}-textarea-disabled`]: disabled,
-                [`${prefixCls}-textarea-readonly`]: readonly,
-                [`${prefixCls}-textarea-autosize`]: isObject(autosize) ? isUndefined(autosize?.maxRows) : autosize,
-                [`${prefixCls}-textarea-showClear`]: showClear,
-            }
-        );
+        const itemCls = cls(`${prefixCls}-textarea`, {
+            [`${prefixCls}-textarea-disabled`]: disabled,
+            [`${prefixCls}-textarea-readonly`]: readonly,
+            [`${prefixCls}-textarea-autosize`]: isObject(autosize) ? isUndefined(autosize?.maxRows) : autosize,
+            [`${prefixCls}-textarea-showClear`]: showClear,
+        });
         const itemProps = {
         const itemProps = {
             ...omit(rest, 'insetLabel', 'insetLabelId', 'getValueLength', 'onClear', 'showClear'),
             ...omit(rest, 'insetLabel', 'insetLabelId', 'getValueLength', 'onClear', 'showClear'),
             autoFocus: autoFocus || this.props['autofocus'],
             autoFocus: autoFocus || this.props['autofocus'],
@@ -338,7 +308,13 @@ class TextArea extends BaseComponent<TextAreaProps, TextAreaState> {
                 onMouseEnter={e => this.foundation.handleMouseEnter(e)}
                 onMouseEnter={e => this.foundation.handleMouseEnter(e)}
                 onMouseLeave={e => this.foundation.handleMouseLeave(e)}
                 onMouseLeave={e => this.foundation.handleMouseLeave(e)}
             >
             >
-                <textarea {...itemProps} ref={this.setRef} />
+                {autosize ? (
+                    <ResizeObserver onResize={this.throttledResizeTextarea}>
+                        <textarea {...itemProps} ref={this.setRef} />
+                    </ResizeObserver>
+                ) : (
+                    <textarea {...itemProps} ref={this.setRef} />
+                )}
                 {this.renderClearBtn()}
                 {this.renderClearBtn()}
                 {this.renderCounter()}
                 {this.renderCounter()}
             </div>
             </div>
@@ -346,6 +322,8 @@ class TextArea extends BaseComponent<TextAreaProps, TextAreaState> {
     }
     }
 }
 }
 
 
-const ForwardTextarea = React.forwardRef<HTMLTextAreaElement, Omit<TextAreaProps, 'forwardRef'>>((props, ref) => <TextArea {...props} forwardRef={ref} />);
+const ForwardTextarea = React.forwardRef<HTMLTextAreaElement, Omit<TextAreaProps, 'forwardRef'>>((props, ref) => (
+    <TextArea {...props} forwardRef={ref} />
+));
 
 
 export default ForwardTextarea;
 export default ForwardTextarea;

+ 2 - 0
packages/semi-ui/modal/Modal.tsx

@@ -243,6 +243,8 @@ class Modal extends BaseComponent<ModalReactProps, ModalState> {
     componentWillUnmount() {
     componentWillUnmount() {
         if (this.props.visible) {
         if (this.props.visible) {
             this.foundation.destroy();
             this.foundation.destroy();
+        } else {
+            this.foundation.enabledBodyScroll();
         }
         }
     }
     }
 
 

+ 8 - 7
packages/semi-ui/notification/index.tsx

@@ -98,6 +98,7 @@ class NotificationList extends BaseComponent<NotificationListProps, Notification
     }
     }
 
 
     static addNotice(notice: NoticeProps) {
     static addNotice(notice: NoticeProps) {
+        notice = { ...defaultConfig, ...notice };
         const id = notice.id ?? getUuid('notification');
         const id = notice.id ?? getUuid('notification');
         if (!ref) {
         if (!ref) {
             const { getPopupContainer } = notice;
             const { getPopupContainer } = notice;
@@ -137,23 +138,23 @@ class NotificationList extends BaseComponent<NotificationListProps, Notification
     }
     }
 
 
     static info(opts: NoticeProps) {
     static info(opts: NoticeProps) {
-        return this.addNotice({ ...defaultConfig, ...opts, type: 'info' });
+        return this.addNotice({ ...opts, type: 'info' });
     }
     }
 
 
     static success(opts: NoticeProps) {
     static success(opts: NoticeProps) {
-        return this.addNotice({ ...defaultConfig, ...opts, type: 'success' });
+        return this.addNotice({ ...opts, type: 'success' });
     }
     }
 
 
     static error(opts: NoticeProps) {
     static error(opts: NoticeProps) {
-        return this.addNotice({ ...defaultConfig, ...opts, type: 'error' });
+        return this.addNotice({ ...opts, type: 'error' });
     }
     }
 
 
     static warning(opts: NoticeProps) {
     static warning(opts: NoticeProps) {
-        return this.addNotice({ ...defaultConfig, ...opts, type: 'warning' });
+        return this.addNotice({ ...opts, type: 'warning' });
     }
     }
 
 
     static open(opts: NoticeProps) {
     static open(opts: NoticeProps) {
-        return this.addNotice({ ...defaultConfig, ...opts, type: 'default' });
+        return this.addNotice({ ...opts, type: 'default' });
     }
     }
 
 
     static close(id: string) {
     static close(id: string) {
@@ -193,13 +194,13 @@ class NotificationList extends BaseComponent<NotificationListProps, Notification
 
 
     has = (id: string) => this.foundation.has(id);
     has = (id: string) => this.foundation.has(id);
 
 
-    remove = (id: string | number) => {
+    remove = (id: string) => {
         this.foundation.removeNotice(String(id));
         this.foundation.removeNotice(String(id));
     };
     };
 
 
 
 
 
 
-    update = (id: string|number, opts: NoticeProps)=>{
+    update = (id: string, opts: NoticeProps)=>{
         return this.foundation.update(id, opts);
         return this.foundation.update(id, opts);
     }
     }
 
 

+ 1 - 1
packages/semi-ui/notification/notice.tsx

@@ -33,7 +33,7 @@ class Notice extends BaseComponent<NoticeReactProps, NoticeState> {
     static contextType = ConfigContext;
     static contextType = ConfigContext;
     static propTypes = {
     static propTypes = {
         duration: PropTypes.number,
         duration: PropTypes.number,
-        id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+        id: PropTypes.string,
         title: PropTypes.node,
         title: PropTypes.node,
         content: PropTypes.node, // strings、numbers、array、element
         content: PropTypes.node, // strings、numbers、array、element
         type: PropTypes.oneOf(types),
         type: PropTypes.oneOf(types),

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

@@ -1,6 +1,6 @@
 {
 {
     "name": "@douyinfe/semi-ui",
     "name": "@douyinfe/semi-ui",
-    "version": "2.49.0-beta.0",
+    "version": "2.51.3",
     "description": "A modern, comprehensive, flexible design system and UI library. Connect DesignOps & DevOps. Quickly build beautiful React apps. Maintained by Douyin-fe team.",
     "description": "A modern, comprehensive, flexible design system and UI library. Connect DesignOps & DevOps. Quickly build beautiful React apps. Maintained by Douyin-fe team.",
     "main": "lib/cjs/index.js",
     "main": "lib/cjs/index.js",
     "module": "lib/es/index.js",
     "module": "lib/es/index.js",
@@ -20,12 +20,12 @@
         "@dnd-kit/core": "^6.0.8",
         "@dnd-kit/core": "^6.0.8",
         "@dnd-kit/sortable": "^7.0.2",
         "@dnd-kit/sortable": "^7.0.2",
         "@dnd-kit/utilities": "^3.2.1",
         "@dnd-kit/utilities": "^3.2.1",
-        "@douyinfe/semi-animation": "2.49.0-beta.0",
-        "@douyinfe/semi-animation-react": "2.49.0-beta.0",
-        "@douyinfe/semi-foundation": "2.49.0-beta.0",
-        "@douyinfe/semi-icons": "2.49.0-beta.0",
-        "@douyinfe/semi-illustrations": "2.49.0-beta.0",
-        "@douyinfe/semi-theme-default": "2.49.0-beta.0",
+        "@douyinfe/semi-animation": "2.51.3",
+        "@douyinfe/semi-animation-react": "2.51.3",
+        "@douyinfe/semi-foundation": "2.51.3",
+        "@douyinfe/semi-icons": "2.51.3",
+        "@douyinfe/semi-illustrations": "2.51.3",
+        "@douyinfe/semi-theme-default": "2.51.3",
         "async-validator": "^3.5.0",
         "async-validator": "^3.5.0",
         "classnames": "^2.2.6",
         "classnames": "^2.2.6",
         "copy-text-to-clipboard": "^2.1.1",
         "copy-text-to-clipboard": "^2.1.1",

+ 102 - 1
packages/semi-ui/select/_story/select.stories.jsx

@@ -1,7 +1,7 @@
 import React, { useState, useRef, useEffect } from 'react';
 import React, { useState, useRef, useEffect } from 'react';
 
 
 import './select.scss';
 import './select.scss';
-import { Input, Select, Button, Icon, Avatar, Checkbox, Form, withField, Space, Tag, Switch } from '../../index';
+import { Input, Select, Button, Icon, Avatar, Checkbox, Form, withField, Space, Tag, Switch, Divider } from '../../index';
 import CustomTrigger from './CustomTrigger';
 import CustomTrigger from './CustomTrigger';
 import classNames from 'classnames';
 import classNames from 'classnames';
 const Option = Select.Option;
 const Option = Select.Option;
@@ -2207,11 +2207,13 @@ const BlurDemo = () => {
   const onBlur = (value, e) => {
   const onBlur = (value, e) => {
     console.log(value);
     console.log(value);
     console.log(e);
     console.log(e);
+    console.log('onBlur');
   };
   };
 
 
   const onFocus = (value, e) => {
   const onFocus = (value, e) => {
     console.log(value);
     console.log(value);
     console.log(e);
     console.log(e);
+    console.log('onFocus');
   };
   };
 
 
   return (
   return (
@@ -2230,6 +2232,24 @@ const BlurDemo = () => {
         <Select.Option value="deguo">Germany</Select.Option>
         <Select.Option value="deguo">Germany</Select.Option>
         <Select.Option value="faguo">France</Select.Option>
         <Select.Option value="faguo">France</Select.Option>
       </Select>
       </Select>
+      <br />
+      <br />
+      <br />
+      <Select
+        filter
+        placeholder="多选"
+        style={{
+          width: 180,
+        }}
+        onBlur={onBlur}
+        onFocus={onFocus}
+        multiple
+      >
+        <Select.Option value="zhongguo">China</Select.Option>
+        <Select.Option value="hanguo">Korea</Select.Option>
+        <Select.Option value="deguo">Germany</Select.Option>
+        <Select.Option value="faguo">France</Select.Option>
+      </Select>
     </>
     </>
   );
   );
 };
 };
@@ -3393,4 +3413,85 @@ export const TestOptionKey = () => {
     ]}>
     ]}>
     </Select>
     </Select>
   </>
   </>
+}
+
+export const AllCaseOfBlur = () => {
+  return (
+    <div>
+      <h3>单选</h3>
+      <Divider margin='12px' />
+      <h5>默认配置</h5>
+      <Select defaultValue="abc" style={{ width: 120 }} onBlur={()=>{console.log('single default onBlur')}} >
+        <Select.Option value="abc">抖音</Select.Option>
+        <Select.Option value="ulikecam">轻颜相机</Select.Option>
+        <Select.Option value="jianying" disabled>
+            剪映
+        </Select.Option>
+        <Select.Option value="xigua">西瓜视频</Select.Option>
+      </Select>
+      <br />
+      <h5>filter</h5>
+      <Select defaultValue="abc" style={{ width: 120 }} filter onBlur={()=>{console.log('single filter onBlur')}}>
+        <Select.Option value="abc">抖音</Select.Option>
+        <Select.Option value="ulikecam">轻颜相机</Select.Option>
+        <Select.Option value="jianying" disabled>
+            剪映
+        </Select.Option>
+        <Select.Option value="xigua">西瓜视频</Select.Option>
+      </Select>
+      <br />
+      <h5>autoFocus</h5>
+      <Select defaultValue="abc" style={{ width: 120 }} autoFocus onBlur={()=>{console.log('single autoFocus onBlur')}}>
+        <Select.Option value="abc">抖音</Select.Option>
+        <Select.Option value="ulikecam">轻颜相机</Select.Option>
+        <Select.Option value="jianying" disabled>
+            剪映
+        </Select.Option>
+        <Select.Option value="xigua">西瓜视频</Select.Option>
+      </Select>
+      <br />
+      <h5>clickToHide</h5>
+      <Select defaultValue="abc" style={{ width: 120 }} clickToHide onBlur={()=>{console.log('single clickToHide onBlur')}}>
+        <Select.Option value="abc">抖音</Select.Option>
+        <Select.Option value="ulikecam">轻颜相机</Select.Option>
+        <Select.Option value="jianying" disabled>
+            剪映
+        </Select.Option>
+        <Select.Option value="xigua">西瓜视频</Select.Option>
+      </Select>
+      <br />
+      <h3>多选</h3>
+      <Divider margin='12px' />
+      <h5>默认配置</h5>
+      <Select defaultValue="abc" style={{ width: 220 }} multiple onBlur={()=>{console.log('multiple default onBlur')}}>
+        <Select.Option value="abc">抖音</Select.Option>
+        <Select.Option value="ulikecam">轻颜相机</Select.Option>
+        <Select.Option value="jianying" disabled>
+            剪映
+        </Select.Option>
+        <Select.Option value="xigua">西瓜视频</Select.Option>
+      </Select>
+      <br />
+      <h5>filter</h5>
+      <Select defaultValue="abc" style={{ width: 220 }} multiple filter onBlur={()=>{console.log('multiple filter onBlur')}}>
+        <Select.Option value="abc">抖音</Select.Option>
+        <Select.Option value="ulikecam">轻颜相机</Select.Option>
+        <Select.Option value="jianying" disabled>
+            剪映
+        </Select.Option>
+        <Select.Option value="xigua">西瓜视频</Select.Option>
+      </Select>
+      <h5>clickToHide</h5>
+      <Select defaultValue="abc" style={{ width: 120 }} multiple clickToHide onBlur={()=>{console.log('multiple clickToHide onBlur')}}>
+        <Select.Option value="abc">抖音</Select.Option>
+        <Select.Option value="ulikecam">轻颜相机</Select.Option>
+        <Select.Option value="jianying" disabled>
+            剪映
+        </Select.Option>
+        <Select.Option value="xigua">西瓜视频</Select.Option>
+      </Select>
+      <br />
+      <br />
+    </div>
+  )
 }
 }

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

@@ -170,7 +170,7 @@ export type SelectProps = {
     onDeselect?: (value: SelectProps['value'], option: Record<string, any>) => void;
     onDeselect?: (value: SelectProps['value'], option: Record<string, any>) => void;
     onSelect?: (value: SelectProps['value'], option: Record<string, any>) => void;
     onSelect?: (value: SelectProps['value'], option: Record<string, any>) => void;
     allowCreate?: boolean;
     allowCreate?: boolean;
-    triggerRender?: (props?: TriggerRenderProps) => React.ReactNode;
+    triggerRender?: (props: TriggerRenderProps) => React.ReactNode;
     onClear?: () => void;
     onClear?: () => void;
     virtualize?: virtualListProps;
     virtualize?: virtualListProps;
     onFocus?: (e: React.FocusEvent) => void;
     onFocus?: (e: React.FocusEvent) => void;

+ 47 - 42
packages/semi-ui/table/Body/BaseRow.tsx

@@ -62,51 +62,56 @@ export interface BaseRowProps {
     virtualized?: Virtualized;
     virtualized?: Virtualized;
     visible: boolean; // required
     visible: boolean; // required
     /** whether display none */
     /** whether display none */
-    displayNone?: boolean;
+    displayNone?: boolean
 }
 }
 
 
+/**
+ * avoid affected by https://www.npmjs.com/package/babel-plugin-transform-react-remove-prop-types
+ */
+export const baseRowPropTypes = {
+    anyColumnFixed: PropTypes.bool,
+    cellWidths: PropTypes.array.isRequired,
+    className: PropTypes.string,
+    columns: PropTypes.array.isRequired,
+    components: PropTypes.object.isRequired,
+    disabled: PropTypes.bool,
+    expandIcon: PropTypes.oneOfType([PropTypes.bool, PropTypes.func, PropTypes.node]),
+    expandableRow: PropTypes.bool,
+    expanded: PropTypes.bool,
+    displayNone: PropTypes.bool,
+    expandedRow: PropTypes.bool,
+    fixed: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
+    height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+    hideExpandedColumn: PropTypes.bool,
+    hovered: PropTypes.bool.isRequired,
+    indent: PropTypes.number,
+    indentSize: PropTypes.number,
+    index: PropTypes.number,
+    isSection: PropTypes.bool,
+    level: PropTypes.number,
+    onDidUpdate: PropTypes.func,
+    onHover: PropTypes.func,
+    onRow: PropTypes.func,
+    onRowClick: PropTypes.func,
+    onRowContextMenu: PropTypes.func,
+    onRowDoubleClick: PropTypes.func,
+    onRowMouseEnter: PropTypes.func,
+    onRowMouseLeave: PropTypes.func,
+    prefixCls: PropTypes.string,
+    record: PropTypes.object,
+    renderExpandIcon: PropTypes.func,
+    replaceClassName: PropTypes.string,
+    rowExpandable: PropTypes.func,
+    rowKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, // real key of the row
+    selected: PropTypes.bool,
+    store: PropTypes.object,
+    style: PropTypes.object,
+    virtualized: PropTypes.oneOfType([PropTypes.object, PropTypes.bool]),
+    visible: PropTypes.bool.isRequired,
+};
+
 export default class TableRow extends BaseComponent<BaseRowProps, Record<string, any>> {
 export default class TableRow extends BaseComponent<BaseRowProps, Record<string, any>> {
-    static propTypes = {
-        anyColumnFixed: PropTypes.bool,
-        cellWidths: PropTypes.array.isRequired,
-        className: PropTypes.string,
-        columns: PropTypes.array.isRequired,
-        components: PropTypes.object.isRequired,
-        disabled: PropTypes.bool,
-        expandIcon: PropTypes.oneOfType([PropTypes.bool, PropTypes.func, PropTypes.node]),
-        expandableRow: PropTypes.bool,
-        expanded: PropTypes.bool,
-        displayNone: PropTypes.bool,
-        expandedRow: PropTypes.bool,
-        fixed: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
-        height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
-        hideExpandedColumn: PropTypes.bool,
-        hovered: PropTypes.bool.isRequired,
-        indent: PropTypes.number,
-        indentSize: PropTypes.number,
-        index: PropTypes.number,
-        isSection: PropTypes.bool,
-        level: PropTypes.number,
-        onDidUpdate: PropTypes.func,
-        onHover: PropTypes.func,
-        onRow: PropTypes.func,
-        onRowClick: PropTypes.func,
-        onRowContextMenu: PropTypes.func,
-        onRowDoubleClick: PropTypes.func,
-        onRowMouseEnter: PropTypes.func,
-        onRowMouseLeave: PropTypes.func,
-        prefixCls: PropTypes.string,
-        record: PropTypes.object,
-        renderExpandIcon: PropTypes.func,
-        replaceClassName: PropTypes.string,
-        rowExpandable: PropTypes.func,
-        rowKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, // real key of the row
-        selected: PropTypes.bool,
-        store: PropTypes.object,
-        style: PropTypes.object,
-        virtualized: PropTypes.oneOfType([PropTypes.object, PropTypes.bool]),
-        visible: PropTypes.bool.isRequired,
-    };
+    static propTypes = baseRowPropTypes;
 
 
     static defaultProps = {
     static defaultProps = {
         columns: [] as [],
         columns: [] as [],

+ 27 - 21
packages/semi-ui/table/Body/SectionRow.tsx

@@ -40,32 +40,38 @@ export interface SectionRowProps {
     rowKey?: RowKey<any>
     rowKey?: RowKey<any>
 }
 }
 
 
+/**
+ * avoid affected by https://www.npmjs.com/package/babel-plugin-transform-react-remove-prop-types
+ */
+export const sectionRowPropTypes = {
+    record: PropTypes.object,
+    index: PropTypes.number,
+    columns: PropTypes.array,
+    group: PropTypes.object.isRequired,
+    groupKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
+    data: PropTypes.array,
+    renderGroupSection: PropTypes.func, // render group title
+    onGroupedRow: PropTypes.func,
+    clickGroupedRowToExpand: PropTypes.bool,
+    components: PropTypes.object,
+    expanded: PropTypes.bool,
+    prefixCls: PropTypes.string,
+    onExpand: PropTypes.func,
+    virtualized: PropTypes.oneOfType([PropTypes.bool, PropTypes.object]),
+    style: PropTypes.object,
+    renderExpandIcon: PropTypes.func, // passing to baseRow
+    className: PropTypes.string,
+    store: PropTypes.object,
+    rowKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.func]),
+};
+
 /**
 /**
  * Grouping component title row
  * Grouping component title row
  */
  */
 class SectionRow extends PureComponent<SectionRowProps> {
 class SectionRow extends PureComponent<SectionRowProps> {
     static contextType = TableContext;
     static contextType = TableContext;
-    static propTypes = {
-        record: PropTypes.object,
-        index: PropTypes.number,
-        columns: PropTypes.array,
-        group: PropTypes.object.isRequired,
-        groupKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
-        data: PropTypes.array,
-        renderGroupSection: PropTypes.func, // render group title
-        onGroupedRow: PropTypes.func,
-        clickGroupedRowToExpand: PropTypes.bool,
-        components: PropTypes.object,
-        expanded: PropTypes.bool,
-        prefixCls: PropTypes.string,
-        onExpand: PropTypes.func,
-        virtualized: PropTypes.oneOfType([PropTypes.bool, PropTypes.object]),
-        style: PropTypes.object,
-        renderExpandIcon: PropTypes.func, // passing to baseRow
-        className: PropTypes.string,
-        store: PropTypes.object,
-        rowKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.func]),
-    };
+    static propTypes = sectionRowPropTypes;
+
     static defaultProps = {
     static defaultProps = {
         prefixCls: cssClasses.PREFIX,
         prefixCls: cssClasses.PREFIX,
         components: {
         components: {

+ 6 - 6
packages/semi-ui/table/Body/index.tsx

@@ -22,9 +22,9 @@ import Store from '@douyinfe/semi-foundation/utils/Store';
 import BaseComponent, { BaseProps } from '../../_base/baseComponent';
 import BaseComponent, { BaseProps } from '../../_base/baseComponent';
 import { logger } from '../utils';
 import { logger } from '../utils';
 import ColGroup from '../ColGroup';
 import ColGroup from '../ColGroup';
-import BaseRow from './BaseRow';
+import BaseRow, { baseRowPropTypes } from './BaseRow';
 import ExpandedRow from './ExpandedRow';
 import ExpandedRow from './ExpandedRow';
-import SectionRow from './SectionRow';
+import SectionRow, { sectionRowPropTypes } from './SectionRow';
 import TableHeader from '../TableHeader';
 import TableHeader from '../TableHeader';
 import ConfigContext from '../../configProvider/context';
 import ConfigContext from '../../configProvider/context';
 import TableContext, { TableContextProps } from '../table-context';
 import TableContext, { TableContextProps } from '../table-context';
@@ -74,7 +74,7 @@ export interface BodyProps extends BaseProps {
     renderExpandIcon: (record: Record<string, any>, isNested: boolean) => ReactNode | null;
     renderExpandIcon: (record: Record<string, any>, isNested: boolean) => ReactNode | null;
     headerRef?: React.MutableRefObject<HTMLDivElement> | ((instance: any) => void);
     headerRef?: React.MutableRefObject<HTMLDivElement> | ((instance: any) => void);
     onScroll?: VirtualizedOnScroll;
     onScroll?: VirtualizedOnScroll;
-    keepDOM?: boolean;
+    keepDOM?: boolean
 }
 }
 
 
 export interface BodyState {
 export interface BodyState {
@@ -457,7 +457,7 @@ class Body extends BaseComponent<BodyProps, BodyState> {
      */
      */
     renderSectionRow = (props: RenderSectionRowProps = { groupKey: undefined }) => {
     renderSectionRow = (props: RenderSectionRowProps = { groupKey: undefined }) => {
         const { dataSource, rowKey, group, groupKey, index } = props;
         const { dataSource, rowKey, group, groupKey, index } = props;
-        const sectionRowPickKeys = Object.keys(SectionRow.propTypes);
+        const sectionRowPickKeys = Object.keys(sectionRowPropTypes);
         const sectionRowProps: any = pick(props, sectionRowPickKeys);
         const sectionRowProps: any = pick(props, sectionRowPickKeys);
 
 
         const { handleRowExpanded } = this.context;
         const { handleRowExpanded } = this.context;
@@ -543,7 +543,7 @@ class Body extends BaseComponent<BodyProps, BodyState> {
             expandRowByClick,
             expandRowByClick,
         } = props;
         } = props;
 
 
-        const baseRowPickKeys = Object.keys(BaseRow.propTypes);
+        const baseRowPickKeys = Object.keys(baseRowPropTypes);
         const baseRowProps: Record<string, any> = pick(props, baseRowPickKeys);
         const baseRowProps: Record<string, any> = pick(props, baseRowPickKeys);
 
 
         let key = getRecordKey(record, rowKey);
         let key = getRecordKey(record, rowKey);
@@ -847,7 +847,7 @@ export interface RenderExpandedRowProps {
     virtualized?: Virtualized;
     virtualized?: Virtualized;
     level?: number;
     level?: number;
     keepDOM?: boolean;
     keepDOM?: boolean;
-    displayNone?: boolean;
+    displayNone?: boolean
 }
 }
 
 
 export interface RenderSectionRowProps {
 export interface RenderSectionRowProps {

+ 2 - 1
packages/semi-ui/table/_story/table.stories.jsx

@@ -106,7 +106,8 @@ export {
     FixedPagination,
     FixedPagination,
     ShowHeader,
     ShowHeader,
     KeepDOM,
     KeepDOM,
-    SortIcon
+    SortIcon,
+    FixedAllDisabledAndSelected
 } from './v2';
 } from './v2';
 export { default as FixSelectAll325 } from './Demos/rowSelection';
 export { default as FixSelectAll325 } from './Demos/rowSelection';
 
 

+ 65 - 0
packages/semi-ui/table/_story/v2/FixedAllDisabledAndSelected/index.tsx

@@ -0,0 +1,65 @@
+import React, { useEffect, useState } from 'react';
+import { Table } from '@douyinfe/semi-ui';
+
+export default function App() {
+    const [selectAll, setSelectAll] = useState(false);
+    const [clueIds, setClueIds] = useState([]);
+    const columns = [
+        {
+            title: '排行',
+            dataIndex: 'index',
+        },
+        {
+            title: 'name',
+            dataIndex: 'name',
+        },
+    ];
+    const data = Array(20)
+        .fill(0)
+        .map((_, index) => {
+            return {
+                key: index,
+                name: `name ${index}`,
+                index: index,
+                clue_id: index,
+            };
+        });
+    const rowSelection = {
+        disabled: selectAll,
+        getCheckboxProps: record => {
+            if (selectAll) {
+                return {
+                    disabled: true,
+                };
+            }
+            return {};
+        },
+
+        onChange: (selectedRowKeys, selectedRows) => {
+            console.log(`select all onChange: ${selectedRowKeys}`, selectedRows);
+            console.log(selectedRowKeys);
+            setClueIds(selectedRows.map(row => row.clue_id));
+        },
+        selectedRowKeys: clueIds,
+    };
+    useEffect(() => {
+        if (selectAll) {
+            let newIds = data.map(row => row.clue_id);
+            console.log(newIds);
+            setClueIds(newIds);
+        }
+    }, [selectAll]);
+
+    return (
+        <div>
+            <button
+                onClick={() => {
+                    setSelectAll(true);
+                }}
+            >
+                点击全选
+            </button>
+            <Table columns={columns} dataSource={data} rowSelection={rowSelection} />
+        </div>
+    );
+}

+ 1 - 0
packages/semi-ui/table/_story/v2/index.js

@@ -27,3 +27,4 @@ export { default as FixedPagination } from './FixedPagination';
 export { default as ShowHeader } from './ShowHeader';
 export { default as ShowHeader } from './ShowHeader';
 export { default as KeepDOM } from './KeepDOM';
 export { default as KeepDOM } from './KeepDOM';
 export { default as SortIcon } from './SortIcon';
 export { default as SortIcon } from './SortIcon';
+export { default as FixedAllDisabledAndSelected } from './FixedAllDisabledAndSelected';

+ 1 - 1
packages/semi-ui/timePicker/TimePicker.tsx

@@ -82,7 +82,7 @@ export type TimePickerProps = {
     secondStep?: number;
     secondStep?: number;
     showClear?: boolean;
     showClear?: boolean;
     size?: InputSize;
     size?: InputSize;
-    stopPropagation: boolean;
+    stopPropagation?: boolean;
     style?: React.CSSProperties;
     style?: React.CSSProperties;
     timeZone?: string | number;
     timeZone?: string | number;
     triggerRender?: (props?: any) => React.ReactNode;
     triggerRender?: (props?: any) => React.ReactNode;

+ 1 - 0
packages/semi-ui/tree/treeNode.tsx

@@ -355,6 +355,7 @@ export default class TreeNode extends PureComponent<TreeNodeProps, TreeNodeState
         const dragOverGapBottom = dragOverNodeKey === eventKey && dropPosition === 1;
         const dragOverGapBottom = dragOverNodeKey === eventKey && dropPosition === 1;
         const nodeCls = cls(prefixcls, {
         const nodeCls = cls(prefixcls, {
             [`${prefixcls}-level-${level + 1}`]: true,
             [`${prefixcls}-level-${level + 1}`]: true,
+            [`${prefixcls}-fullLabel-level-${level + 1}`]: renderFullLabel,
             [`${prefixcls}-collapsed`]: !expanded,
             [`${prefixcls}-collapsed`]: !expanded,
             [`${prefixcls}-disabled`]: Boolean(disabled),
             [`${prefixcls}-disabled`]: Boolean(disabled),
             [`${prefixcls}-selected`]: selected,
             [`${prefixcls}-selected`]: selected,

+ 93 - 61
packages/semi-ui/treeSelect/_story/treeSelect.stories.jsx

@@ -1,5 +1,5 @@
 import React, { useState, useMemo, useRef, useCallback, useEffect } from 'react';
 import React, { useState, useMemo, useRef, useCallback, useEffect } from 'react';
-import { Icon, Input, Button, Form, Popover, Tag, Typography, CheckboxGroup, TagInput, Switch } from '../../index';
+import { Icon, Input, Button, Form, Popover, Tag, Typography, CheckboxGroup, TagInput, Switch, Tree } from '../../index';
 import TreeSelect from '../index';
 import TreeSelect from '../index';
 import { flattenDeep, cloneDeep } from 'lodash';
 import { flattenDeep, cloneDeep } from 'lodash';
 import CustomTrigger from './CustomTrigger';
 import CustomTrigger from './CustomTrigger';
@@ -281,6 +281,67 @@ const specialTreeData = [
   },
   },
 ];
 ];
 
 
+const treeDataEn = [
+  {
+      label: 'Asia',
+      value: 'Asia',
+      key: '0',
+      children: [
+          {
+              label: 'China',
+              value: 'China',
+              key: '0-0',
+              children: [
+                  {
+                      label: 'Beijing',
+                      value: 'Beijing',
+                      key: '0-0-0',
+                  },
+                  {
+                      label: 'Shanghai',
+                      value: 'Shanghai',
+                      key: '0-0-1',
+                  },
+                  {
+                      label: 'Chengdu',
+                      value: 'Chengdu',
+                      key: '0-0-2',
+                  },
+              ],
+          },
+          {
+              label: 'Japan',
+              value: 'Japan',
+              key: '0-1',
+              children: [
+                  {
+                      label: 'Osaka',
+                      value: 'Osaka',
+                      key: '0-1-0'
+                  }
+              ]
+          },
+      ],
+  },
+  {
+      label: 'North America',
+      value: 'North America',
+      key: '1',
+      children: [
+          {
+              label: 'United States',
+              value: 'United States',
+              key: '1-0'
+          },
+          {
+              label: 'Canada',
+              value: 'Canada',
+              key: '1-1'
+          }
+      ]
+  }
+];
+
 export const TreeSelectWrapper = () => (
 export const TreeSelectWrapper = () => (
   <div>
   <div>
     <div>github issue 750 修改测试用例</div>
     <div>github issue 750 修改测试用例</div>
@@ -1382,66 +1443,7 @@ DisabledStrictly.story = {
 
 
 
 
 export const CheckRelationDemo = () => {
 export const CheckRelationDemo = () => {
-  const treeData = [
-    {
-        label: 'Asia',
-        value: 'Asia',
-        key: '0',
-        children: [
-            {
-                label: 'China',
-                value: 'China',
-                key: '0-0',
-                children: [
-                    {
-                        label: 'Beijing',
-                        value: 'Beijing',
-                        key: '0-0-0',
-                    },
-                    {
-                        label: 'Shanghai',
-                        value: 'Shanghai',
-                        key: '0-0-1',
-                    },
-                    {
-                        label: 'Chengdu',
-                        value: 'Chengdu',
-                        key: '0-0-2',
-                    },
-                ],
-            },
-            {
-                label: 'Japan',
-                value: 'Japan',
-                key: '0-1',
-                children: [
-                    {
-                        label: 'Osaka',
-                        value: 'Osaka',
-                        key: '0-1-0'
-                    }
-                ]
-            },
-        ],
-    },
-    {
-        label: 'North America',
-        value: 'North America',
-        key: '1',
-        children: [
-            {
-                label: 'United States',
-                value: 'United States',
-                key: '1-0'
-            },
-            {
-                label: 'Canada',
-                value: 'Canada',
-                key: '1-1'
-            }
-        ]
-    }
-  ];
+  const treeData = treeDataEn;
   const [value, setValue] = useState('China');
   const [value, setValue] = useState('China');
   const [value2, setValue2] = useState();
   const [value2, setValue2] = useState();
   const [value3, setValue3] = useState();
   const [value3, setValue3] = useState();
@@ -2653,3 +2655,33 @@ export const KeyMaps = () => {
     </> 
     </> 
   );
   );
 }
 }
+
+export const Issue1542 = () => {
+  const [expandedKeys, setExpandedKeys] = useState([]);
+  const treeData = treeDataEn;
+  const onExpand = useCallback((expandedKeys) => {
+    setExpandedKeys(expandedKeys);
+  }, [expandedKeys]);
+
+  const onSearch = useCallback((inputValue, filteredExpandedKeys) => {
+    const set = new Set([...filteredExpandedKeys, ...expandedKeys]);
+    setExpandedKeys(Array.from(set));
+  }, [setExpandedKeys]);
+
+  return (
+    <>
+      <TreeSelect
+          // multiple
+          style={{ width: 300 }}
+          dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
+          treeData={treeData}
+          filterTreeNode
+          searchPosition='trigger'
+          showFilteredOnly
+          expandedKeys={expandedKeys}
+          onExpand={onExpand}
+          onSearch={onSearch}
+      />
+    </>  
+  );
+};

+ 152 - 50
packages/semi-ui/treeSelect/index.tsx

@@ -25,6 +25,7 @@ import {
     calcDisabledKeys,
     calcDisabledKeys,
     normalizeValue,
     normalizeValue,
     updateKeys,
     updateKeys,
+    filterTreeData
 } from '@douyinfe/semi-foundation/tree/treeUtil';
 } from '@douyinfe/semi-foundation/tree/treeUtil';
 import { cssClasses, strings } from '@douyinfe/semi-foundation/treeSelect/constants';
 import { cssClasses, strings } from '@douyinfe/semi-foundation/treeSelect/constants';
 import { numbers as popoverNumbers } from '@douyinfe/semi-foundation/popover/constants';
 import { numbers as popoverNumbers } from '@douyinfe/semi-foundation/popover/constants';
@@ -144,7 +145,7 @@ export interface TreeSelectProps extends Omit<BasicTreeSelectProps, OverrideComm
     onSelect?: (selectedKey: string, selected: boolean, selectedNode: TreeNodeData) => void;
     onSelect?: (selectedKey: string, selected: boolean, selectedNode: TreeNodeData) => void;
     renderSelectedItem?: RenderSelectedItem;
     renderSelectedItem?: RenderSelectedItem;
     getPopupContainer?: () => HTMLElement;
     getPopupContainer?: () => HTMLElement;
-    triggerRender?: (props?: TriggerRenderProps) => React.ReactNode;
+    triggerRender?: (props: TriggerRenderProps) => React.ReactNode;
     onBlur?: (e: React.MouseEvent) => void;
     onBlur?: (e: React.MouseEvent) => void;
     onChange?: OnChange;
     onChange?: OnChange;
     onFocus?: (e: React.MouseEvent) => void;
     onFocus?: (e: React.MouseEvent) => void;
@@ -307,7 +308,7 @@ class TreeSelect extends BaseComponent<TreeSelectProps, TreeSelectState> {
     triggerRef: React.RefObject<HTMLDivElement>;
     triggerRef: React.RefObject<HTMLDivElement>;
     optionsRef: React.RefObject<any>;
     optionsRef: React.RefObject<any>;
     clickOutsideHandler: any;
     clickOutsideHandler: any;
-    _flattenNodes: TreeState['flattenNodes'];
+    // _flattenNodes: TreeState['flattenNodes'];
     onNodeClick: any;
     onNodeClick: any;
     onNodeDoubleClick: any;
     onNodeDoubleClick: any;
     onMotionEnd: any;
     onMotionEnd: any;
@@ -327,6 +328,7 @@ class TreeSelect extends BaseComponent<TreeSelectProps, TreeSelectState> {
             keyEntities: {},
             keyEntities: {},
             treeData: [],
             treeData: [],
             flattenNodes: [],
             flattenNodes: [],
+            cachedFlattenNodes: undefined,
             selectedKeys: [],
             selectedKeys: [],
             checkedKeys: new Set(),
             checkedKeys: new Set(),
             halfCheckedKeys: new Set(),
             halfCheckedKeys: new Set(),
@@ -373,7 +375,8 @@ class TreeSelect extends BaseComponent<TreeSelectProps, TreeSelectState> {
         };
         };
         const needUpdateTreeData = needUpdate('treeData');
         const needUpdateTreeData = needUpdate('treeData');
         const needUpdateExpandedKeys = needUpdate('expandedKeys');
         const needUpdateExpandedKeys = needUpdate('expandedKeys');
-
+        const isExpandControlled = 'expandedKeys' in props;
+        const isSearching = Boolean(props.filterTreeNode && prevState.inputValue && prevState.inputValue.length);
         // TreeNode
         // TreeNode
         if (needUpdateTreeData) {
         if (needUpdateTreeData) {
             treeData = props.treeData;
             treeData = props.treeData;
@@ -399,50 +402,135 @@ class TreeSelect extends BaseComponent<TreeSelectProps, TreeSelectState> {
             }
             }
         }
         }
         const expandAllWhenDataChange = needUpdateTreeData && props.expandAll;
         const expandAllWhenDataChange = needUpdateTreeData && props.expandAll;
-        // expandedKeys
-        if (needUpdateExpandedKeys || (prevProps && needUpdate('autoExpandParent'))) {
-            newState.expandedKeys = calcExpandedKeys(
-                props.expandedKeys,
-                keyEntities,
-                props.autoExpandParent || !prevProps
-            );
-            // only show animation when treeData does not change
-            if (prevProps && props.motion && !treeData) {
-                const { motionKeys, motionType } = calcMotionKeys(
-                    prevState.expandedKeys,
-                    newState.expandedKeys,
-                    keyEntities
+        if (!isSearching) {
+            // expandedKeys
+            if (needUpdateExpandedKeys || (prevProps && needUpdate('autoExpandParent'))) {
+                newState.expandedKeys = calcExpandedKeys(
+                    props.expandedKeys,
+                    keyEntities,
+                    props.autoExpandParent || !prevProps
+                );
+                // only show animation when treeData does not change
+                if (prevProps && props.motion && !treeData) {
+                    const { motionKeys, motionType } = calcMotionKeys(
+                        prevState.expandedKeys,
+                        newState.expandedKeys,
+                        keyEntities
+                    );
+                    newState.motionKeys = new Set(motionKeys);
+                    newState.motionType = motionType;
+                    if (motionType === 'hide') {
+                        // cache flatten nodes: expandedKeys changed may not be triggered by interaction
+                        newState.cachedFlattenNodes = cloneDeep(prevState.flattenNodes);
+                    }
+                }
+            } else if ((!prevProps && (props.defaultExpandAll || props.expandAll)) || expandAllWhenDataChange) {
+                newState.expandedKeys = new Set(Object.keys(keyEntities));
+            } else if (!prevProps && props.defaultExpandedKeys) {
+                newState.expandedKeys = calcExpandedKeys(props.defaultExpandedKeys, keyEntities);
+            } else if (!prevProps && props.defaultValue) {
+                newState.expandedKeys = calcExpandedKeysForValues(
+                    normalizeValue(props.defaultValue, withObject, keyMaps),
+                    keyEntities,
+                    props.multiple,
+                    valueEntities
+                );
+            } else if (!prevProps && props.value) {
+                newState.expandedKeys = calcExpandedKeysForValues(
+                    normalizeValue(props.value, withObject, keyMaps),
+                    keyEntities,
+                    props.multiple,
+                    valueEntities
+                );
+            } else if ((!isExpandControlled && needUpdateTreeData) && props.value) {
+                // 当 treeData 已经设置具体的值,并且设置了 props.loadData ,则认为 treeData 的更新是因为 loadData 导致的
+                // 如果是因为 loadData 导致 treeData改变, 此时在这里重新计算 key 会导致为未选中的展开项目被收起
+                // 所以此时不需要重新计算 expandedKeys,因为在点击展开按钮时候已经把被展开的项添加到 expandedKeys 中
+                // When treeData has a specific value and props.loadData is set, it is considered that the update of treeData is caused by loadData
+                // If the treeData is changed because of loadData, recalculating the key here will cause the unselected expanded items to be collapsed
+                // So there is no need to recalculate expandedKeys at this time, because the expanded item has been added to expandedKeys when the expand button is clicked
+                if (!(prevState.treeData && prevState.treeData?.length > 0 && props.loadData)) {
+                    newState.expandedKeys = calcExpandedKeysForValues(
+                        props.value,
+                        keyEntities,
+                        props.multiple,
+                        valueEntities
+                    );
+                }
+            }
+
+            if (!newState.expandedKeys) {
+                delete newState.expandedKeys;
+            }
+
+            if (treeData || newState.expandedKeys) {
+                const flattenNodes = flattenTreeData(
+                    treeData || prevState.treeData,
+                    newState.expandedKeys || prevState.expandedKeys,
+                    keyMaps
+                );
+                newState.flattenNodes = flattenNodes;
+            }
+        } else {
+            let filteredState;
+            // treeData changed while searching
+            if (treeData) {
+                // Get filter data
+                filteredState = filterTreeData({
+                    treeData,
+                    inputValue: prevState.inputValue,
+                    filterTreeNode: props.filterTreeNode,
+                    filterProps: props.treeNodeFilterProp,
+                    showFilteredOnly: props.showFilteredOnly,
+                    keyEntities: newState.keyEntities,
+                    prevExpandedKeys: [...prevState.filteredExpandedKeys],
+                    keyMaps: keyMaps
+                });
+                newState.flattenNodes = filteredState.flattenNodes;
+                newState.motionKeys = new Set([]);
+                newState.filteredKeys = filteredState.filteredKeys;
+                newState.filteredShownKeys = filteredState.filteredShownKeys;
+                newState.filteredExpandedKeys = filteredState.filteredExpandedKeys;
+            }
+
+            // expandedKeys changed while searching
+            if (props.expandedKeys) {
+                newState.filteredExpandedKeys = calcExpandedKeys(
+                    props.expandedKeys,
+                    keyEntities,
+                    props.autoExpandParent || !prevProps
+                );
+
+                if (prevProps && props.motion) {
+                    const prevKeys = prevState ? prevState.filteredExpandedKeys : new Set([]);
+                    // only show animation when treeData does not change
+                    if (!treeData) {
+                        const motionResult = calcMotionKeys(
+                            prevKeys,
+                            newState.filteredExpandedKeys,
+                            keyEntities
+                        );
+
+                        let { motionKeys } = motionResult;
+                        const { motionType } = motionResult;
+                        if (props.showFilteredOnly) {
+                            motionKeys = motionKeys.filter(key => prevState.filteredShownKeys.has(key));
+                        }
+                        if (motionType === 'hide') {
+                            // cache flatten nodes: expandedKeys changed may not be triggered by interaction
+                            newState.cachedFlattenNodes = cloneDeep(prevState.flattenNodes);
+                        }
+                        newState.motionKeys = new Set(motionKeys);
+                        newState.motionType = motionType;
+                    }
+                }
+                newState.flattenNodes = flattenTreeData(
+                    treeData || prevState.treeData,
+                    newState.filteredExpandedKeys || prevState.filteredExpandedKeys,
+                    keyMaps,
+                    props.showFilteredOnly && prevState.filteredShownKeys
                 );
                 );
-                newState.motionKeys = new Set(motionKeys);
-                newState.motionType = motionType;
             }
             }
-        } else if ((!prevProps && (props.defaultExpandAll || props.expandAll)) || expandAllWhenDataChange) {
-            newState.expandedKeys = new Set(Object.keys(keyEntities));
-        } else if (!prevProps && props.defaultExpandedKeys) {
-            newState.expandedKeys = calcExpandedKeys(props.defaultExpandedKeys, keyEntities);
-        } else if (!prevProps && props.defaultValue) {
-            newState.expandedKeys = calcExpandedKeysForValues(
-                normalizeValue(props.defaultValue, withObject, keyMaps),
-                keyEntities,
-                props.multiple,
-                valueEntities
-            );
-        } else if (!prevProps && props.value) {
-            newState.expandedKeys = calcExpandedKeysForValues(
-                normalizeValue(props.value, withObject, keyMaps),
-                keyEntities,
-                props.multiple,
-                valueEntities
-            );
-        }
-        // flattenNodes
-        if (treeData || needUpdateExpandedKeys) {
-            const flattenNodes = flattenTreeData(
-                treeData || prevState.treeData,
-                newState.expandedKeys || prevState.expandedKeys,
-                keyMaps,
-            );
-            newState.flattenNodes = flattenNodes;
         }
         }
 
 
         // selectedKeys: single mode controlled
         // selectedKeys: single mode controlled
@@ -590,7 +678,7 @@ class TreeSelect extends BaseComponent<TreeSelectProps, TreeSelectState> {
                 this.props.onSearch && this.props.onSearch(input, filteredExpandedKeys);
                 this.props.onSearch && this.props.onSearch(input, filteredExpandedKeys);
             },
             },
             cacheFlattenNodes: bool => {
             cacheFlattenNodes: bool => {
-                this._flattenNodes = bool ? cloneDeep(this.state.flattenNodes) : null;
+                this.setState({ cachedFlattenNodes: bool ? cloneDeep(this.state.flattenNodes) : undefined });
             },
             },
             notifyLoad: (newLoadedKeys, data) => {
             notifyLoad: (newLoadedKeys, data) => {
                 const { onLoad } = this.props;
                 const { onLoad } = this.props;
@@ -1306,14 +1394,27 @@ class TreeSelect extends BaseComponent<TreeSelectProps, TreeSelectState> {
     /* Event handler function after popover is closed */
     /* Event handler function after popover is closed */
     handlePopoverClose = isVisible => {
     handlePopoverClose = isVisible => {
         const { filterTreeNode, searchAutoFocus, searchPosition } = this.props;
         const { filterTreeNode, searchAutoFocus, searchPosition } = this.props;
-        if (isVisible === false && Boolean(filterTreeNode)) {
-            this.foundation.clearInput();
+        // 将 inputValue 清空,如果有选中值的话,选中项能够快速回显
+        // Clear the inputValue. If there is a selected value, the selected item can be quickly echoed.
+        if (isVisible === false && filterTreeNode) {
+            this.foundation.clearInputValue();
         }
         }
         if (filterTreeNode && searchPosition === strings.SEARCH_POSITION_DROPDOWN && isVisible && searchAutoFocus) {
         if (filterTreeNode && searchPosition === strings.SEARCH_POSITION_DROPDOWN && isVisible && searchAutoFocus) {
             this.foundation.focusInput(true);
             this.foundation.focusInput(true);
         }
         }
     }
     }
 
 
+    afterClose = () => {
+        // flattenNode 的变化将导致弹出层面板中的选项数目变化
+        // 在弹层完全收起之后,再通过 clearInput 重新计算 state 中的 expandedKey, flattenNode
+        // 防止在弹出层未收起时弹层面板中选项数目变化导致视觉上出现弹层闪动问题
+        // Changes to flattenNode will cause the number of options in the popup panel to change
+        // After the pop-up layer is completely closed, recalculate the expandedKey and flattenNode in the state through clearInput.
+        // Prevent the pop-up layer from flickering visually due to changes in the number of options in the pop-up panel when the pop-up layer is not collapsed.
+        const { filterTreeNode } = this.props;
+        filterTreeNode && this.foundation.clearInput();
+    }
+
     renderTreeNode = (treeNode: FlattenNode, ind: number, style: React.CSSProperties) => {
     renderTreeNode = (treeNode: FlattenNode, ind: number, style: React.CSSProperties) => {
         const { data, key } = treeNode;
         const { data, key } = treeNode;
         const treeNodeProps = this.foundation.getTreeNodeProps(key);
         const treeNodeProps = this.foundation.getTreeNodeProps(key);
@@ -1337,7 +1438,7 @@ class TreeSelect extends BaseComponent<TreeSelectProps, TreeSelectState> {
     };
     };
 
 
     renderNodeList = () => {
     renderNodeList = () => {
-        const { flattenNodes, motionKeys, motionType, filteredKeys } = this.state;
+        const { flattenNodes, cachedFlattenNodes, motionKeys, motionType, filteredKeys } = this.state;
         const { direction } = this.context;
         const { direction } = this.context;
         const { virtualize, motionExpand } = this.props;
         const { virtualize, motionExpand } = this.props;
         const isExpandControlled = 'expandedKeys' in this.props;
         const isExpandControlled = 'expandedKeys' in this.props;
@@ -1345,7 +1446,7 @@ class TreeSelect extends BaseComponent<TreeSelectProps, TreeSelectState> {
             return (
             return (
                 <NodeList
                 <NodeList
                     flattenNodes={flattenNodes}
                     flattenNodes={flattenNodes}
-                    flattenList={this._flattenNodes}
+                    flattenList={cachedFlattenNodes}
                     motionKeys={motionExpand ? motionKeys : new Set([])}
                     motionKeys={motionExpand ? motionKeys : new Set([])}
                     motionType={motionType}
                     motionType={motionType}
                     // When motionKeys is empty, but filteredKeys is not empty (that is, the search hits), this situation should be distinguished from ordinary motionKeys
                     // When motionKeys is empty, but filteredKeys is not empty (that is, the search hits), this situation should be distinguished from ordinary motionKeys
@@ -1496,6 +1597,7 @@ class TreeSelect extends BaseComponent<TreeSelectProps, TreeSelectState> {
                 mouseLeaveDelay={mouseLeaveDelay}
                 mouseLeaveDelay={mouseLeaveDelay}
                 mouseEnterDelay={mouseEnterDelay}
                 mouseEnterDelay={mouseEnterDelay}
                 onVisibleChange={this.handlePopoverClose}
                 onVisibleChange={this.handlePopoverClose}
+                afterClose={this.afterClose}
             >
             >
                 {selection}
                 {selection}
             </Popover>
             </Popover>

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

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

+ 190 - 190
sitemap.xml

@@ -2,22 +2,22 @@
 <urlset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd" xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
 <urlset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd" xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
     <url>
     <url>
         <loc>https://juejin.cn/post/7267418854124699702</loc>
         <loc>https://juejin.cn/post/7267418854124699702</loc>
-        <lastmod>2023-12-11T11:24:55.564Z</lastmod>
+        <lastmod>2024-01-19T10:05:20.882Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://medium.com/front-end-weekly/how-we-test-semi-design-component-libraries-64b854f63b65</loc>
         <loc>https://medium.com/front-end-weekly/how-we-test-semi-design-component-libraries-64b854f63b65</loc>
-        <lastmod>2023-12-11T11:24:54.530Z</lastmod>
+        <lastmod>2024-01-19T10:05:20.636Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://mp.weixin.qq.com/s/noHoWRuA25PgqFNcurhIUA</loc>
         <loc>https://mp.weixin.qq.com/s/noHoWRuA25PgqFNcurhIUA</loc>
-        <lastmod>2023-12-11T11:24:56.585Z</lastmod>
+        <lastmod>2024-01-19T10:05:23.681Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://mp.weixin.qq.com/s/O3js-SZDNPEOjGxh-aAkbw</loc>
         <loc>https://mp.weixin.qq.com/s/O3js-SZDNPEOjGxh-aAkbw</loc>
-        <lastmod>2023-12-11T11:24:56.547Z</lastmod>
+        <lastmod>2024-01-19T10:05:23.508Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
@@ -670,852 +670,852 @@
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/dsm_manual/zh-CN/introduction/case</loc>
         <loc>https://semi.design/dsm_manual/zh-CN/introduction/case</loc>
-        <lastmod>2023-10-30T13:34:19.513Z</lastmod>
+        <lastmod>2024-01-18T06:20:35.319Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
-        <scm>1.0.0.66</scm>
+        <scm>1.0.0.72</scm>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/dsm_manual/zh-CN/introduction/changelog</loc>
         <loc>https://semi.design/dsm_manual/zh-CN/introduction/changelog</loc>
-        <lastmod>2023-10-30T13:34:19.455Z</lastmod>
+        <lastmod>2024-01-18T06:20:35.045Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
-        <scm>1.0.0.66</scm>
+        <scm>1.0.0.72</scm>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/dsm_manual/zh-CN/introduction/faq</loc>
         <loc>https://semi.design/dsm_manual/zh-CN/introduction/faq</loc>
-        <lastmod>2023-10-30T13:34:19.458Z</lastmod>
+        <lastmod>2024-01-18T06:20:35.543Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
-        <scm>1.0.0.66</scm>
+        <scm>1.0.0.72</scm>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/dsm_manual/zh-CN/introduction/roadmap</loc>
         <loc>https://semi.design/dsm_manual/zh-CN/introduction/roadmap</loc>
-        <lastmod>2023-10-30T13:34:21.190Z</lastmod>
+        <lastmod>2024-01-18T06:20:36.067Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
-        <scm>1.0.0.66</scm>
+        <scm>1.0.0.72</scm>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/dsm_manual/zh-CN/introduction/start</loc>
         <loc>https://semi.design/dsm_manual/zh-CN/introduction/start</loc>
-        <lastmod>2023-10-30T13:34:19.738Z</lastmod>
+        <lastmod>2024-01-18T06:20:35.326Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
-        <scm>1.0.0.66</scm>
+        <scm>1.0.0.72</scm>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/dsm_manual/zh-CN/plugin/changeThemeModel</loc>
         <loc>https://semi.design/dsm_manual/zh-CN/plugin/changeThemeModel</loc>
-        <lastmod>2023-10-30T13:34:19.592Z</lastmod>
+        <lastmod>2024-01-18T06:20:35.351Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
-        <scm>1.0.0.66</scm>
+        <scm>1.0.0.72</scm>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/dsm_manual/zh-CN/plugin/genDocs</loc>
         <loc>https://semi.design/dsm_manual/zh-CN/plugin/genDocs</loc>
-        <lastmod>2023-10-30T13:34:19.835Z</lastmod>
+        <lastmod>2024-01-18T06:20:35.488Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
-        <scm>1.0.0.66</scm>
+        <scm>1.0.0.72</scm>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/dsm_manual/zh-CN/plugin/intallPlugin</loc>
         <loc>https://semi.design/dsm_manual/zh-CN/plugin/intallPlugin</loc>
-        <lastmod>2023-10-30T13:34:19.815Z</lastmod>
+        <lastmod>2024-01-18T06:20:35.491Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
-        <scm>1.0.0.66</scm>
+        <scm>1.0.0.72</scm>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/dsm_manual/zh-CN/plugin/syncInFigma</loc>
         <loc>https://semi.design/dsm_manual/zh-CN/plugin/syncInFigma</loc>
-        <lastmod>2023-10-30T13:34:19.793Z</lastmod>
+        <lastmod>2024-01-18T06:20:35.667Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
-        <scm>1.0.0.66</scm>
+        <scm>1.0.0.72</scm>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/dsm_manual/zh-CN/plugin/writeTheme</loc>
         <loc>https://semi.design/dsm_manual/zh-CN/plugin/writeTheme</loc>
-        <lastmod>2023-10-30T13:34:19.878Z</lastmod>
+        <lastmod>2024-01-18T06:20:35.649Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
-        <scm>1.0.0.66</scm>
+        <scm>1.0.0.72</scm>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/dsm_manual/zh-CN/themeStore/fork</loc>
         <loc>https://semi.design/dsm_manual/zh-CN/themeStore/fork</loc>
-        <lastmod>2023-10-30T13:34:20.219Z</lastmod>
+        <lastmod>2024-01-18T06:20:35.799Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
-        <scm>1.0.0.66</scm>
+        <scm>1.0.0.72</scm>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/dsm_manual/zh-CN/themeStore/preview</loc>
         <loc>https://semi.design/dsm_manual/zh-CN/themeStore/preview</loc>
-        <lastmod>2023-10-30T13:34:19.843Z</lastmod>
+        <lastmod>2024-01-18T06:20:35.813Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
-        <scm>1.0.0.66</scm>
+        <scm>1.0.0.72</scm>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/dsm_manual/zh-CN/themeStore/publish</loc>
         <loc>https://semi.design/dsm_manual/zh-CN/themeStore/publish</loc>
-        <lastmod>2023-10-30T13:34:19.812Z</lastmod>
+        <lastmod>2024-01-18T06:20:35.948Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
-        <scm>1.0.0.66</scm>
+        <scm>1.0.0.72</scm>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/dsm_manual/zh-CN/web/addPartner</loc>
         <loc>https://semi.design/dsm_manual/zh-CN/web/addPartner</loc>
-        <lastmod>2023-10-30T13:34:19.806Z</lastmod>
+        <lastmod>2024-01-18T06:20:35.802Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
-        <scm>1.0.0.66</scm>
+        <scm>1.0.0.72</scm>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/dsm_manual/zh-CN/web/componentToken</loc>
         <loc>https://semi.design/dsm_manual/zh-CN/web/componentToken</loc>
-        <lastmod>2023-10-30T13:34:20.038Z</lastmod>
+        <lastmod>2024-01-18T06:20:35.970Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
-        <scm>1.0.0.66</scm>
+        <scm>1.0.0.72</scm>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/dsm_manual/zh-CN/web/globalToken</loc>
         <loc>https://semi.design/dsm_manual/zh-CN/web/globalToken</loc>
-        <lastmod>2023-10-30T13:34:20.217Z</lastmod>
+        <lastmod>2024-01-18T06:20:35.990Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
-        <scm>1.0.0.66</scm>
+        <scm>1.0.0.72</scm>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/dsm_manual/zh-CN/web/use</loc>
         <loc>https://semi.design/dsm_manual/zh-CN/web/use</loc>
-        <lastmod>2023-10-30T13:34:20.072Z</lastmod>
+        <lastmod>2024-01-18T06:20:36.121Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
-        <scm>1.0.0.66</scm>
+        <scm>1.0.0.72</scm>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/dsm_manual/zh-CN/web/web_publish</loc>
         <loc>https://semi.design/dsm_manual/zh-CN/web/web_publish</loc>
-        <lastmod>2023-10-30T13:34:19.997Z</lastmod>
+        <lastmod>2024-01-18T06:20:36.105Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
-        <scm>1.0.0.66</scm>
+        <scm>1.0.0.72</scm>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/dsm_manual/zh-CN/web/web_start</loc>
         <loc>https://semi.design/dsm_manual/zh-CN/web/web_start</loc>
-        <lastmod>2023-10-30T13:34:20.168Z</lastmod>
+        <lastmod>2024-01-18T06:20:36.435Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
-        <scm>1.0.0.66</scm>
+        <scm>1.0.0.72</scm>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/dsm/landing</loc>
         <loc>https://semi.design/dsm/landing</loc>
-        <lastmod>2023-11-17T09:16:45.265Z</lastmod>
+        <lastmod>2024-01-19T10:05:31.040Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
-        <scm>1.0.0.156</scm>
+        <scm>1.0.0.165</scm>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/basic/divider</loc>
         <loc>https://semi.design/en-US/basic/divider</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/basic/grid</loc>
         <loc>https://semi.design/en-US/basic/grid</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/basic/icon</loc>
         <loc>https://semi.design/en-US/basic/icon</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/basic/layout</loc>
         <loc>https://semi.design/en-US/basic/layout</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/basic/space</loc>
         <loc>https://semi.design/en-US/basic/space</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/basic/tokens</loc>
         <loc>https://semi.design/en-US/basic/tokens</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/basic/typography</loc>
         <loc>https://semi.design/en-US/basic/typography</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/feedback/banner</loc>
         <loc>https://semi.design/en-US/feedback/banner</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/feedback/notification</loc>
         <loc>https://semi.design/en-US/feedback/notification</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/feedback/popconfirm</loc>
         <loc>https://semi.design/en-US/feedback/popconfirm</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/feedback/progress</loc>
         <loc>https://semi.design/en-US/feedback/progress</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/feedback/skeleton</loc>
         <loc>https://semi.design/en-US/feedback/skeleton</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/feedback/spin</loc>
         <loc>https://semi.design/en-US/feedback/spin</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/feedback/toast</loc>
         <loc>https://semi.design/en-US/feedback/toast</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/input/autocomplete</loc>
         <loc>https://semi.design/en-US/input/autocomplete</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/input/button</loc>
         <loc>https://semi.design/en-US/input/button</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/input/cascader</loc>
         <loc>https://semi.design/en-US/input/cascader</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/input/checkbox</loc>
         <loc>https://semi.design/en-US/input/checkbox</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/input/datepicker</loc>
         <loc>https://semi.design/en-US/input/datepicker</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/input/form</loc>
         <loc>https://semi.design/en-US/input/form</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/input/input</loc>
         <loc>https://semi.design/en-US/input/input</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/input/inputnumber</loc>
         <loc>https://semi.design/en-US/input/inputnumber</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/input/radio</loc>
         <loc>https://semi.design/en-US/input/radio</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/input/rating</loc>
         <loc>https://semi.design/en-US/input/rating</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/input/select</loc>
         <loc>https://semi.design/en-US/input/select</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/input/slider</loc>
         <loc>https://semi.design/en-US/input/slider</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/input/switch</loc>
         <loc>https://semi.design/en-US/input/switch</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/input/taginput</loc>
         <loc>https://semi.design/en-US/input/taginput</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/input/timepicker</loc>
         <loc>https://semi.design/en-US/input/timepicker</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/input/transfer</loc>
         <loc>https://semi.design/en-US/input/transfer</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/input/treeselect</loc>
         <loc>https://semi.design/en-US/input/treeselect</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/input/upload</loc>
         <loc>https://semi.design/en-US/input/upload</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/navigation/anchor</loc>
         <loc>https://semi.design/en-US/navigation/anchor</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/navigation/backtop</loc>
         <loc>https://semi.design/en-US/navigation/backtop</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/navigation/breadcrumb</loc>
         <loc>https://semi.design/en-US/navigation/breadcrumb</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/navigation/navigation</loc>
         <loc>https://semi.design/en-US/navigation/navigation</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/navigation/pagination</loc>
         <loc>https://semi.design/en-US/navigation/pagination</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/navigation/steps</loc>
         <loc>https://semi.design/en-US/navigation/steps</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/navigation/tabs</loc>
         <loc>https://semi.design/en-US/navigation/tabs</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/navigation/tree</loc>
         <loc>https://semi.design/en-US/navigation/tree</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/other/configprovider</loc>
         <loc>https://semi.design/en-US/other/configprovider</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/other/locale</loc>
         <loc>https://semi.design/en-US/other/locale</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/show/avatar</loc>
         <loc>https://semi.design/en-US/show/avatar</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/show/badge</loc>
         <loc>https://semi.design/en-US/show/badge</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/show/calendar</loc>
         <loc>https://semi.design/en-US/show/calendar</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/show/card</loc>
         <loc>https://semi.design/en-US/show/card</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/show/carousel</loc>
         <loc>https://semi.design/en-US/show/carousel</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/show/collapse</loc>
         <loc>https://semi.design/en-US/show/collapse</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/show/collapsible</loc>
         <loc>https://semi.design/en-US/show/collapsible</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/show/descriptions</loc>
         <loc>https://semi.design/en-US/show/descriptions</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/show/dropdown</loc>
         <loc>https://semi.design/en-US/show/dropdown</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/show/empty</loc>
         <loc>https://semi.design/en-US/show/empty</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/show/highlight</loc>
         <loc>https://semi.design/en-US/show/highlight</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/show/image</loc>
         <loc>https://semi.design/en-US/show/image</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/show/list</loc>
         <loc>https://semi.design/en-US/show/list</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/show/modal</loc>
         <loc>https://semi.design/en-US/show/modal</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/show/overflowlist</loc>
         <loc>https://semi.design/en-US/show/overflowlist</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/show/popover</loc>
         <loc>https://semi.design/en-US/show/popover</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/show/scrolllist</loc>
         <loc>https://semi.design/en-US/show/scrolllist</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/show/sidesheet</loc>
         <loc>https://semi.design/en-US/show/sidesheet</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/show/table</loc>
         <loc>https://semi.design/en-US/show/table</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/show/tag</loc>
         <loc>https://semi.design/en-US/show/tag</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/show/timeline</loc>
         <loc>https://semi.design/en-US/show/timeline</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/show/tooltip</loc>
         <loc>https://semi.design/en-US/show/tooltip</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/start/accessibility</loc>
         <loc>https://semi.design/en-US/start/accessibility</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/start/changelog</loc>
         <loc>https://semi.design/en-US/start/changelog</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/start/customize-theme</loc>
         <loc>https://semi.design/en-US/start/customize-theme</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/start/dark-mode</loc>
         <loc>https://semi.design/en-US/start/dark-mode</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/start/faq</loc>
         <loc>https://semi.design/en-US/start/faq</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/start/getting-started</loc>
         <loc>https://semi.design/en-US/start/getting-started</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/start/introduction</loc>
         <loc>https://semi.design/en-US/start/introduction</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/start/overview</loc>
         <loc>https://semi.design/en-US/start/overview</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/en-US/start/update-to-v2</loc>
         <loc>https://semi.design/en-US/start/update-to-v2</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/basic/divider</loc>
         <loc>https://semi.design/zh-CN/basic/divider</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/basic/grid</loc>
         <loc>https://semi.design/zh-CN/basic/grid</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/basic/icon</loc>
         <loc>https://semi.design/zh-CN/basic/icon</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/basic/layout</loc>
         <loc>https://semi.design/zh-CN/basic/layout</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/basic/space</loc>
         <loc>https://semi.design/zh-CN/basic/space</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/basic/tokens</loc>
         <loc>https://semi.design/zh-CN/basic/tokens</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/basic/typography</loc>
         <loc>https://semi.design/zh-CN/basic/typography</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/feedback/banner</loc>
         <loc>https://semi.design/zh-CN/feedback/banner</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/feedback/notification</loc>
         <loc>https://semi.design/zh-CN/feedback/notification</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/feedback/popconfirm</loc>
         <loc>https://semi.design/zh-CN/feedback/popconfirm</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/feedback/progress</loc>
         <loc>https://semi.design/zh-CN/feedback/progress</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/feedback/skeleton</loc>
         <loc>https://semi.design/zh-CN/feedback/skeleton</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/feedback/spin</loc>
         <loc>https://semi.design/zh-CN/feedback/spin</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/feedback/toast</loc>
         <loc>https://semi.design/zh-CN/feedback/toast</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/input/autocomplete</loc>
         <loc>https://semi.design/zh-CN/input/autocomplete</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/input/button</loc>
         <loc>https://semi.design/zh-CN/input/button</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/input/cascader</loc>
         <loc>https://semi.design/zh-CN/input/cascader</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/input/checkbox</loc>
         <loc>https://semi.design/zh-CN/input/checkbox</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/input/datepicker</loc>
         <loc>https://semi.design/zh-CN/input/datepicker</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/input/form</loc>
         <loc>https://semi.design/zh-CN/input/form</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/input/input</loc>
         <loc>https://semi.design/zh-CN/input/input</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/input/inputnumber</loc>
         <loc>https://semi.design/zh-CN/input/inputnumber</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/input/radio</loc>
         <loc>https://semi.design/zh-CN/input/radio</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/input/rating</loc>
         <loc>https://semi.design/zh-CN/input/rating</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/input/select</loc>
         <loc>https://semi.design/zh-CN/input/select</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/input/slider</loc>
         <loc>https://semi.design/zh-CN/input/slider</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/input/switch</loc>
         <loc>https://semi.design/zh-CN/input/switch</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/input/taginput</loc>
         <loc>https://semi.design/zh-CN/input/taginput</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/input/timepicker</loc>
         <loc>https://semi.design/zh-CN/input/timepicker</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/input/transfer</loc>
         <loc>https://semi.design/zh-CN/input/transfer</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/input/treeselect</loc>
         <loc>https://semi.design/zh-CN/input/treeselect</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/input/upload</loc>
         <loc>https://semi.design/zh-CN/input/upload</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/navigation/anchor</loc>
         <loc>https://semi.design/zh-CN/navigation/anchor</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/navigation/backtop</loc>
         <loc>https://semi.design/zh-CN/navigation/backtop</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/navigation/breadcrumb</loc>
         <loc>https://semi.design/zh-CN/navigation/breadcrumb</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/navigation/navigation</loc>
         <loc>https://semi.design/zh-CN/navigation/navigation</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/navigation/pagination</loc>
         <loc>https://semi.design/zh-CN/navigation/pagination</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/navigation/steps</loc>
         <loc>https://semi.design/zh-CN/navigation/steps</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/navigation/tabs</loc>
         <loc>https://semi.design/zh-CN/navigation/tabs</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/navigation/tree</loc>
         <loc>https://semi.design/zh-CN/navigation/tree</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/other/configprovider</loc>
         <loc>https://semi.design/zh-CN/other/configprovider</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/other/locale</loc>
         <loc>https://semi.design/zh-CN/other/locale</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/show/avatar</loc>
         <loc>https://semi.design/zh-CN/show/avatar</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/show/badge</loc>
         <loc>https://semi.design/zh-CN/show/badge</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/show/calendar</loc>
         <loc>https://semi.design/zh-CN/show/calendar</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/show/card</loc>
         <loc>https://semi.design/zh-CN/show/card</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/show/carousel</loc>
         <loc>https://semi.design/zh-CN/show/carousel</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/show/collapse</loc>
         <loc>https://semi.design/zh-CN/show/collapse</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/show/collapsible</loc>
         <loc>https://semi.design/zh-CN/show/collapsible</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/show/descriptions</loc>
         <loc>https://semi.design/zh-CN/show/descriptions</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/show/dropdown</loc>
         <loc>https://semi.design/zh-CN/show/dropdown</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/show/empty</loc>
         <loc>https://semi.design/zh-CN/show/empty</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/show/highlight</loc>
         <loc>https://semi.design/zh-CN/show/highlight</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/show/image</loc>
         <loc>https://semi.design/zh-CN/show/image</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/show/list</loc>
         <loc>https://semi.design/zh-CN/show/list</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/show/modal</loc>
         <loc>https://semi.design/zh-CN/show/modal</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/show/overflowlist</loc>
         <loc>https://semi.design/zh-CN/show/overflowlist</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/show/popover</loc>
         <loc>https://semi.design/zh-CN/show/popover</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/show/scrolllist</loc>
         <loc>https://semi.design/zh-CN/show/scrolllist</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/show/sidesheet</loc>
         <loc>https://semi.design/zh-CN/show/sidesheet</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/show/table</loc>
         <loc>https://semi.design/zh-CN/show/table</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/show/tag</loc>
         <loc>https://semi.design/zh-CN/show/tag</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/show/timeline</loc>
         <loc>https://semi.design/zh-CN/show/timeline</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/show/tooltip</loc>
         <loc>https://semi.design/zh-CN/show/tooltip</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/start/accessibility</loc>
         <loc>https://semi.design/zh-CN/start/accessibility</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/start/changelog</loc>
         <loc>https://semi.design/zh-CN/start/changelog</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/start/customize-theme</loc>
         <loc>https://semi.design/zh-CN/start/customize-theme</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/start/dark-mode</loc>
         <loc>https://semi.design/zh-CN/start/dark-mode</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/start/faq</loc>
         <loc>https://semi.design/zh-CN/start/faq</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/start/getting-started</loc>
         <loc>https://semi.design/zh-CN/start/getting-started</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/start/introduction</loc>
         <loc>https://semi.design/zh-CN/start/introduction</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/start/overview</loc>
         <loc>https://semi.design/zh-CN/start/overview</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
     <url>
     <url>
         <loc>https://semi.design/zh-CN/start/update-to-v2</loc>
         <loc>https://semi.design/zh-CN/start/update-to-v2</loc>
-        <lastmod>2023-12-11T11:19:27.000Z</lastmod>
+        <lastmod>2024-01-19T09:54:35.000Z</lastmod>
         <changefreq>weekly</changefreq>
         <changefreq>weekly</changefreq>
     </url>
     </url>
 </urlset>
 </urlset>

+ 1 - 1
src/sitePages/newHome/components/banner/banner.jsx

@@ -38,7 +38,7 @@ function Banner() {
                             </defs>
                             </defs>
                         </svg>
                         </svg>
                         <a style={{ position: 'absolute', height: 'fit-content', left: 224, top: -26 }} href={"https://www.rspack.dev"} aria-label={"rspack"} target={"_blank"} rel="noreferrer">
                         <a style={{ position: 'absolute', height: 'fit-content', left: 224, top: -26 }} href={"https://www.rspack.dev"} aria-label={"rspack"} target={"_blank"} rel="noreferrer">
-                            <img style={{ width: "60px", position: "relative", left: "-18px" }} src={"https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/rspack.png"}/>
+                            <img style={{ width: "60px", position: "relative", left: "-18px" }} alt='rspack logo' src={"https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/rspack.png"}/>
                         </a>
                         </a>
                         <svg aria-label={"remix"} style={{ position: 'relative', top: "-16px", left: "304px", transform: 'scale(1.3)' }} height="24" viewBox="0 0 350 165" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><title>Remix Logo</title>
                         <svg aria-label={"remix"} style={{ position: 'relative', top: "-16px", left: "304px", transform: 'scale(1.3)' }} height="24" viewBox="0 0 350 165" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><title>Remix Logo</title>
                             <path fillRule="evenodd" clipRule="evenodd" d="M133.85 124.16C135.3 142.762 135.3 151.482 135.3 161H92.2283C92.2283 158.927 92.2653 157.03 92.3028 155.107C92.4195 149.128 92.5411 142.894 91.5717 130.304C90.2905 111.872 82.3473 107.776 67.7419 107.776H54.8021H0V74.24H69.7918C88.2407 74.24 97.4651 68.632 97.4651 53.784C97.4651 40.728 88.2407 32.816 69.7918 32.816H0V0H77.4788C119.245 0 140 19.712 140 51.2C140 74.752 125.395 90.112 105.665 92.672C122.32 96 132.057 105.472 133.85 124.16Z" fill="currentColor"></path>
                             <path fillRule="evenodd" clipRule="evenodd" d="M133.85 124.16C135.3 142.762 135.3 151.482 135.3 161H92.2283C92.2283 158.927 92.2653 157.03 92.3028 155.107C92.4195 149.128 92.5411 142.894 91.5717 130.304C90.2905 111.872 82.3473 107.776 67.7419 107.776H54.8021H0V74.24H69.7918C88.2407 74.24 97.4651 68.632 97.4651 53.784C97.4651 40.728 88.2407 32.816 69.7918 32.816H0V0H77.4788C119.245 0 140 19.712 140 51.2C140 74.752 125.395 90.112 105.665 92.672C122.32 96 132.057 105.472 133.85 124.16Z" fill="currentColor"></path>

+ 23 - 23
src/sitePages/newHome/components/comments/comments.jsx

@@ -40,7 +40,7 @@ function numberAnimation(number, s, dom) {
     requestAnimationFrame(fn);
     requestAnimationFrame(fn);
 }
 }
 
 
-const realNumber = [7100, 560, 5000000, 100];
+const realNumber = [7600, 560, 5000000, 100];
 
 
 function Comments(props) {
 function Comments(props) {
     useEffect(()=> {
     useEffect(()=> {
@@ -96,24 +96,24 @@ function Comments(props) {
                 <span key='chromatic'>
                 <span key='chromatic'>
                     <img
                     <img
                         src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/chromatic.png"
                         src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/chromatic.png"
-                        alt="semi application demo"
+                        alt="chromatic logo"
                         className={styles.group3736} 
                         className={styles.group3736} 
                     />
                     />
                     <img
                     <img
                         src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/chromatic-dark.png"
                         src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/chromatic-dark.png"
-                        alt="semi application demo"
+                        alt="chromatic logo"
                         className={`${styles.group3736dark}`} 
                         className={`${styles.group3736dark}`} 
                     />
                     />
                 </span>
                 </span>
                 <span key='cypress'>
                 <span key='cypress'>
                     <img
                     <img
                         src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/cypress.png"
                         src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/cypress.png"
-                        alt="semi application demo"
+                        alt="cypress logo"
                         className={styles.group3736} 
                         className={styles.group3736} 
                     />
                     />
                     <img
                     <img
                         src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/cypress-dark.png"
                         src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/cypress-dark.png"
-                        alt="semi application demo"
+                        alt="cypress logo"
                         className={`${styles.group3736dark}`} 
                         className={`${styles.group3736dark}`} 
                     />
                     />
                 </span>
                 </span>
@@ -122,10 +122,10 @@ function Comments(props) {
                 <div className={styles.autoWrapper}>
                 <div className={styles.autoWrapper}>
                     <div className={styles.testimonial1}>
                     <div className={styles.testimonial1}>
                         {/* eslint-disable-next-line jsx-a11y/alt-text */}
                         {/* eslint-disable-next-line jsx-a11y/alt-text */}
-                        <img src="https://lf9-static.semi.design/obj/semi-tos/images/7e1756c0-321a-11ec-adec-e911cea4cf98.png" className={styles.mColorCN} />
+                        <img src="https://lf9-static.semi.design/obj/semi-tos/images/7e1756c0-321a-11ec-adec-e911cea4cf98.png" className={styles.mColorCN} alt="user avatar" />
                         <div className={styles.frame4569}>
                         <div className={styles.frame4569}>
                             {/* eslint-disable-next-line jsx-a11y/alt-text */}
                             {/* eslint-disable-next-line jsx-a11y/alt-text */}
-                            <img src="https://lf9-static.semi.design/obj/semi-tos/images/7e19c7c0-321a-11ec-b393-ab4adc2e449f.svg" className={styles.quoteMark} />
+                            <img src="https://lf9-static.semi.design/obj/semi-tos/images/7e19c7c0-321a-11ec-b393-ab4adc2e449f.svg" className={styles.quoteMark} alt="quote icon" />
                             <div className={styles.feedbackPersonDetail}>
                             <div className={styles.feedbackPersonDetail}>
                                 <p className={styles.feedback}><span className={styles.feedback_3a905c13}>{_t("access_is_simple_and_easy_to_use", { }, "接入简单易上手;")}</span></p>
                                 <p className={styles.feedback}><span className={styles.feedback_3a905c13}>{_t("access_is_simple_and_easy_to_use", { }, "接入简单易上手;")}</span></p>
                                 <div className={styles.personDetails}>
                                 <div className={styles.personDetails}>
@@ -139,13 +139,13 @@ function Comments(props) {
                         <div className={styles.mColorCN_beba3295}>
                         <div className={styles.mColorCN_beba3295}>
                             <div className={styles.autoWrapper_4fa00029}>
                             <div className={styles.autoWrapper_4fa00029}>
                                 {/* eslint-disable-next-line jsx-a11y/alt-text */}
                                 {/* eslint-disable-next-line jsx-a11y/alt-text */}
-                                <img src="https://lf9-static.semi.design/obj/semi-tos/images/7e17a4e1-321a-11ec-9c23-a9f1bde3758e.svg" className={styles.autoWrapper_4fa00029} />
+                                <img src="https://lf9-static.semi.design/obj/semi-tos/images/7e17a4e1-321a-11ec-9c23-a9f1bde3758e.svg" className={styles.autoWrapper_4fa00029} alt="user avatar" />
                                 <p className={styles.text_b1d6cd66}>C</p>
                                 <p className={styles.text_b1d6cd66}>C</p>
                             </div>
                             </div>
                         </div>
                         </div>
                         <div className={styles.frame4569}>
                         <div className={styles.frame4569}>
                             {/* eslint-disable-next-line jsx-a11y/alt-text */}
                             {/* eslint-disable-next-line jsx-a11y/alt-text */}
-                            <img src="https://lf9-static.semi.design/obj/semi-tos/images/7e190470-321a-11ec-b008-15e09471f238.svg" className={styles.quoteMark} />
+                            <img src="https://lf9-static.semi.design/obj/semi-tos/images/7e190470-321a-11ec-b008-15e09471f238.svg" className={styles.quoteMark} alt="quote icon" />
                             <div className={styles.feedbackPersonDetail}>
                             <div className={styles.feedbackPersonDetail}>
                                 <p className={styles.feedback}>{_t("the_components_are_quite_complete__covering_a_wide_range_and_the_overall_style_i_e10d9214b403886d249f00b8c4dbb975", { }, "组件挺全的,覆盖的比较广泛,整体风格也不错。")}</p>
                                 <p className={styles.feedback}>{_t("the_components_are_quite_complete__covering_a_wide_range_and_the_overall_style_i_e10d9214b403886d249f00b8c4dbb975", { }, "组件挺全的,覆盖的比较广泛,整体风格也不错。")}</p>
                                 <div className={styles.personDetails}>
                                 <div className={styles.personDetails}>
@@ -159,13 +159,13 @@ function Comments(props) {
                         <div className={styles.mColorCN_beba3295}>
                         <div className={styles.mColorCN_beba3295}>
                             <div className={styles.autoWrapper_4fa00029}>
                             <div className={styles.autoWrapper_4fa00029}>
                                 {/* eslint-disable-next-line jsx-a11y/alt-text */}
                                 {/* eslint-disable-next-line jsx-a11y/alt-text */}
-                                <img src="https://lf9-static.semi.design/obj/semi-tos/images/7e1ab220-321a-11ec-ab65-77a60c02a0b5.svg" className={styles.autoWrapper_4fa00029} />
+                                <img src="https://lf9-static.semi.design/obj/semi-tos/images/7e1ab220-321a-11ec-ab65-77a60c02a0b5.svg" className={styles.autoWrapper_4fa00029} alt="user avatar" />
                                 <p className={styles.text_11043f46}>M</p>
                                 <p className={styles.text_11043f46}>M</p>
                             </div>
                             </div>
                         </div>
                         </div>
                         <div className={styles.frame4569}>
                         <div className={styles.frame4569}>
                             {/* eslint-disable-next-line jsx-a11y/alt-text */}
                             {/* eslint-disable-next-line jsx-a11y/alt-text */}
-                            <img src="https://lf9-static.semi.design/obj/semi-tos/images/7e1ad930-321a-11ec-ab65-77a60c02a0b5.svg" className={styles.quoteMark} />
+                            <img src="https://lf9-static.semi.design/obj/semi-tos/images/7e1ad930-321a-11ec-ab65-77a60c02a0b5.svg" className={styles.quoteMark} alt="quote icon" />
                             <div className={styles.feedbackPersonDetail}>
                             <div className={styles.feedbackPersonDetail}>
                                 <p className={styles.feedback_daa8760d}>{_t("design_resources_are_obviously_helpful_to_improve_efficiency_", { }, "设计资源对提效有明显帮助。")}</p>
                                 <p className={styles.feedback_daa8760d}>{_t("design_resources_are_obviously_helpful_to_improve_efficiency_", { }, "设计资源对提效有明显帮助。")}</p>
                                 <div className={styles.personDetails}>
                                 <div className={styles.personDetails}>
@@ -181,13 +181,13 @@ function Comments(props) {
                         <div className={styles.mColorCN_beba3295}>
                         <div className={styles.mColorCN_beba3295}>
                             <div className={styles.autoWrapper_4fa00029}>
                             <div className={styles.autoWrapper_4fa00029}>
                                 {/* eslint-disable-next-line jsx-a11y/alt-text */}
                                 {/* eslint-disable-next-line jsx-a11y/alt-text */}
-                                <img src="https://lf9-static.semi.design/obj/semi-tos/images/7e190470-321a-11ec-8b14-8fb159794ae4.svg" className={styles.autoWrapper_4fa00029} />
+                                <img src="https://lf9-static.semi.design/obj/semi-tos/images/7e190470-321a-11ec-8b14-8fb159794ae4.svg" className={styles.autoWrapper_4fa00029} alt="user avatar" />
                                 <p className={styles.text_f8842908}>Y</p>
                                 <p className={styles.text_f8842908}>Y</p>
                             </div>
                             </div>
                         </div>
                         </div>
                         <div className={styles.frame4569}>
                         <div className={styles.frame4569}>
                             {/* eslint-disable-next-line jsx-a11y/alt-text */}
                             {/* eslint-disable-next-line jsx-a11y/alt-text */}
-                            <img src="https://lf9-static.semi.design/obj/semi-tos/images/7e1b0040-321a-11ec-ab65-77a60c02a0b5.svg" className={styles.quoteMark} />
+                            <img src="https://lf9-static.semi.design/obj/semi-tos/images/7e1b0040-321a-11ec-ab65-77a60c02a0b5.svg" className={styles.quoteMark} alt="quote icon" />
                             <div className={styles.feedbackPersonDetail}>
                             <div className={styles.feedbackPersonDetail}>
                                 <p className={styles.feedback}>{_t("there_are_many_other_business_uses_within_the_company__there_are_more_sample_ref_c5fe7051d5fbf1a547084c91f7c4fd8e", { }, "有很多公司内的其他业务使用,有比较多的样例参考,我们依托")}</p>
                                 <p className={styles.feedback}>{_t("there_are_many_other_business_uses_within_the_company__there_are_more_sample_ref_c5fe7051d5fbf1a547084c91f7c4fd8e", { }, "有很多公司内的其他业务使用,有比较多的样例参考,我们依托")}</p>
                                 <div className={styles.personDetails_53392045}>
                                 <div className={styles.personDetails_53392045}>
@@ -199,10 +199,10 @@ function Comments(props) {
                     </div>
                     </div>
                     <div className={styles.testimonial1}>
                     <div className={styles.testimonial1}>
                         {/* eslint-disable-next-line jsx-a11y/alt-text */}
                         {/* eslint-disable-next-line jsx-a11y/alt-text */}
-                        <img src="https://lf9-static.semi.design/obj/semi-tos/images/7e190471-321a-11ec-b008-15e09471f238.png" className={styles.mColorCN} />
+                        <img src="https://lf9-static.semi.design/obj/semi-tos/images/7e190471-321a-11ec-b008-15e09471f238.png" className={styles.mColorCN} alt="user avatar" />
                         <div className={styles.frame4569}>
                         <div className={styles.frame4569}>
                             {/* eslint-disable-next-line jsx-a11y/alt-text */}
                             {/* eslint-disable-next-line jsx-a11y/alt-text */}
-                            <img src="https://lf9-static.semi.design/obj/semi-tos/images/7e1a15e0-321a-11ec-b393-ab4adc2e449f.svg" className={styles.quoteMark} />
+                            <img src="https://lf9-static.semi.design/obj/semi-tos/images/7e1a15e0-321a-11ec-b393-ab4adc2e449f.svg" className={styles.quoteMark} alt="quote icon" />
                             <div className={styles.feedbackPersonDetail}>
                             <div className={styles.feedbackPersonDetail}>
                                 <p className={styles.feedback}>{_t("super_good!_strong_push_", { }, "超级好用!强推。")}</p>
                                 <p className={styles.feedback}>{_t("super_good!_strong_push_", { }, "超级好用!强推。")}</p>
                                 <div className={styles.personDetails}>
                                 <div className={styles.personDetails}>
@@ -214,10 +214,10 @@ function Comments(props) {
                     </div>
                     </div>
                     <div className={styles.testimonial7}>
                     <div className={styles.testimonial7}>
                         {/* eslint-disable-next-line jsx-a11y/alt-text */}
                         {/* eslint-disable-next-line jsx-a11y/alt-text */}
-                        <img src="https://lf9-static.semi.design/obj/semi-tos/images/7e192b80-321a-11ec-8b14-8fb159794ae4.png" className={styles.mColorCN} />
+                        <img src="https://lf9-static.semi.design/obj/semi-tos/images/7e192b80-321a-11ec-8b14-8fb159794ae4.png" className={styles.mColorCN} alt="user avatar" />
                         <div className={styles.frame4569}>
                         <div className={styles.frame4569}>
                             {/* eslint-disable-next-line jsx-a11y/alt-text */}
                             {/* eslint-disable-next-line jsx-a11y/alt-text */}
-                            <img src="https://lf9-static.semi.design/obj/semi-tos/images/7e1979a0-321a-11ec-adec-e911cea4cf98.svg" className={styles.quoteMark} />
+                            <img src="https://lf9-static.semi.design/obj/semi-tos/images/7e1979a0-321a-11ec-adec-e911cea4cf98.svg" className={styles.quoteMark} alt="quote icon" />
                             <div className={styles.feedbackPersonDetail}>
                             <div className={styles.feedbackPersonDetail}>
                                 <p className={styles.feedback}>{_t("as_an_excellent_benchmarking_industry", { }, "作为对标业界优秀的")}</p>
                                 <p className={styles.feedback}>{_t("as_an_excellent_benchmarking_industry", { }, "作为对标业界优秀的")}</p>
                                 <div className={styles.personDetails}>
                                 <div className={styles.personDetails}>
@@ -231,10 +231,10 @@ function Comments(props) {
                 <div className={styles.frame4571}>
                 <div className={styles.frame4571}>
                     <div className={styles.testimonial3}>
                     <div className={styles.testimonial3}>
                         {/* eslint-disable-next-line jsx-a11y/alt-text */}
                         {/* eslint-disable-next-line jsx-a11y/alt-text */}
-                        <img src="https://lf9-static.semi.design/obj/semi-tos/images/7e1b2750-321a-11ec-ab65-77a60c02a0b5.png" className={styles.mColorCN} />
+                        <img src="https://lf9-static.semi.design/obj/semi-tos/images/7e1b2750-321a-11ec-ab65-77a60c02a0b5.png" className={styles.mColorCN} alt="user avatar" />
                         <div className={styles.frame4569}>
                         <div className={styles.frame4569}>
                             {/* eslint-disable-next-line jsx-a11y/alt-text */}
                             {/* eslint-disable-next-line jsx-a11y/alt-text */}
-                            <img src="https://lf9-static.semi.design/obj/semi-tos/images/7e1a3cf0-321a-11ec-b393-ab4adc2e449f.svg" className={styles.quoteMark} />
+                            <img src="https://lf9-static.semi.design/obj/semi-tos/images/7e1a3cf0-321a-11ec-b393-ab4adc2e449f.svg" className={styles.quoteMark} alt="quote icon" />
                             <div className={styles.feedbackPersonDetail}>
                             <div className={styles.feedbackPersonDetail}>
                                 <p className={styles.feedback}>{_t("easy_to_use__beautiful_style_", { }, "使用方便,样式美观。")}</p>
                                 <p className={styles.feedback}>{_t("easy_to_use__beautiful_style_", { }, "使用方便,样式美观。")}</p>
                                 <div className={styles.personDetails}>
                                 <div className={styles.personDetails}>
@@ -248,13 +248,13 @@ function Comments(props) {
                         <div className={styles.mColorCN_beba3295}>
                         <div className={styles.mColorCN_beba3295}>
                             <div className={styles.autoWrapper_4fa00029}>
                             <div className={styles.autoWrapper_4fa00029}>
                                 {/* eslint-disable-next-line jsx-a11y/alt-text */}
                                 {/* eslint-disable-next-line jsx-a11y/alt-text */}
-                                <img src="https://lf9-static.semi.design/obj/semi-tos/images/7e1b9c80-321a-11ec-ab65-77a60c02a0b5.svg" className={styles.autoWrapper_4fa00029} />
+                                <img src="https://lf9-static.semi.design/obj/semi-tos/images/7e1b9c80-321a-11ec-ab65-77a60c02a0b5.svg" className={styles.autoWrapper_4fa00029} alt="user avatar" />
                                 <p className={styles.text_b1d6cd66}>G</p>
                                 <p className={styles.text_b1d6cd66}>G</p>
                             </div>
                             </div>
                         </div>
                         </div>
                         <div className={styles.frame4569}>
                         <div className={styles.frame4569}>
                             {/* eslint-disable-next-line jsx-a11y/alt-text */}
                             {/* eslint-disable-next-line jsx-a11y/alt-text */}
-                            <img src="https://lf9-static.semi.design/obj/semi-tos/images/7e19a0b0-321a-11ec-9c23-a9f1bde3758e.svg" className={styles.quoteMark} />
+                            <img src="https://lf9-static.semi.design/obj/semi-tos/images/7e19a0b0-321a-11ec-9c23-a9f1bde3758e.svg" className={styles.quoteMark} alt="quote icon" />
                             <div className={styles.feedbackPersonDetail}>
                             <div className={styles.feedbackPersonDetail}>
                                 <p className={styles.feedback}>{_t("uniform_style_and_high_fidelity_prototype_facilitate_communication_with_front_en_95d0c0ccece05c104b98ac0dae9fb53b", { }, "统一的样式,高保真的原型便于与前端同学进行沟通。")}</p>
                                 <p className={styles.feedback}>{_t("uniform_style_and_high_fidelity_prototype_facilitate_communication_with_front_en_95d0c0ccece05c104b98ac0dae9fb53b", { }, "统一的样式,高保真的原型便于与前端同学进行沟通。")}</p>
                                 <div className={styles.personDetails}>
                                 <div className={styles.personDetails}>
@@ -266,10 +266,10 @@ function Comments(props) {
                     </div>
                     </div>
                     <div className={styles.testimonial7}>
                     <div className={styles.testimonial7}>
                         {/* eslint-disable-next-line jsx-a11y/alt-text */}
                         {/* eslint-disable-next-line jsx-a11y/alt-text */}
-                        <img src="https://lf9-static.semi.design/obj/semi-tos/images/7e1979a1-321a-11ec-adec-e911cea4cf98.png" className={styles.mColorCN} />
+                        <img src="https://lf9-static.semi.design/obj/semi-tos/images/7e1979a1-321a-11ec-adec-e911cea4cf98.png" className={styles.mColorCN} alt="user avatar" />
                         <div className={styles.frame4569}>
                         <div className={styles.frame4569}>
                             {/* eslint-disable-next-line jsx-a11y/alt-text */}
                             {/* eslint-disable-next-line jsx-a11y/alt-text */}
-                            <img src="https://lf9-static.semi.design/obj/semi-tos/images/7e19c7c0-321a-11ec-9c23-a9f1bde3758e.svg" className={styles.quoteMark} />
+                            <img src="https://lf9-static.semi.design/obj/semi-tos/images/7e19c7c0-321a-11ec-9c23-a9f1bde3758e.svg" className={styles.quoteMark} alt="quote icon" />
                             <div className={styles.feedbackPersonDetail}>
                             <div className={styles.feedbackPersonDetail}>
                                 <p className={styles.feedback_daa8760d}>{_t("the_documentation_is_very_detailed_and_the_details_of_the_components_are_well_th_aadc51a1122c41cf69ebd4b15e83e864", { }, "文档非常详细,对组件的细节思考非常充足。")}</p>
                                 <p className={styles.feedback_daa8760d}>{_t("the_documentation_is_very_detailed_and_the_details_of_the_components_are_well_th_aadc51a1122c41cf69ebd4b15e83e864", { }, "文档非常详细,对组件的细节思考非常充足。")}</p>
                                 <div className={styles.personDetails}>
                                 <div className={styles.personDetails}>

+ 8 - 7
src/sitePages/newHome/components/feature/feature.jsx

@@ -2,6 +2,7 @@
 import { _t } from "../../../../utils/locale";
 import { _t } from "../../../../utils/locale";
 import React from 'react';
 import React from 'react';
 import styles from "./feature.module.scss";
 import styles from "./feature.module.scss";
+import { IconSkeleton } from '@douyinfe/semi-icons-lab';
 
 
 function Feature(props) {
 function Feature(props) {
 
 
@@ -12,7 +13,7 @@ function Feature(props) {
             <div className={styles.featuresList}>
             <div className={styles.featuresList}>
                 <div className={styles.row1}>
                 <div className={styles.row1}>
                     <div className={styles.iconDetails}>
                     <div className={styles.iconDetails}>
-                        <img className={styles.icon} src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/d2c-code.png" />
+                        <img className={styles.icon} src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/d2c-code.png" alt="d2c icon" />
                         <div className={styles.details}>
                         <div className={styles.details}>
                             <p className={styles.headline}>{_t("feature_D2C")}</p> 
                             <p className={styles.headline}>{_t("feature_D2C")}</p> 
                             <p className={styles.description}>
                             <p className={styles.description}>
@@ -21,7 +22,7 @@ function Feature(props) {
                         </div>
                         </div>
                     </div>
                     </div>
                     <div className={styles.iconDetails}>
                     <div className={styles.iconDetails}>
-                        <img className={styles.icon} src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/a11y-icon.png" />
+                        <img className={styles.icon} src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/a11y-icon.png" alt="a11y icon" />
                         <div className={styles.details}>
                         <div className={styles.details}>
                             <p className={styles.headline}>{_t("feature_a11y")}</p>
                             <p className={styles.headline}>{_t("feature_a11y")}</p>
                             <p className={styles.description}>
                             <p className={styles.description}>
@@ -30,7 +31,7 @@ function Feature(props) {
                         </div>
                         </div>
                     </div>
                     </div>
                     <div className={styles.iconDetails}>
                     <div className={styles.iconDetails}>
-                        <img className={styles.icon} src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/language-icon.png" />
+                        <img className={styles.icon} src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/language-icon.png" alt="i18n icon" />
                         <div className={styles.details}>
                         <div className={styles.details}>
                             <p className={styles.headline}>{_t("feature_language")}</p>
                             <p className={styles.headline}>{_t("feature_language")}</p>
                             <p className={styles.description}>
                             <p className={styles.description}>
@@ -41,7 +42,7 @@ function Feature(props) {
                 </div>
                 </div>
                 <div className={styles.row1}>
                 <div className={styles.row1}>
                     <div className={styles.iconDetails}>
                     <div className={styles.iconDetails}>
-                        <img className={styles.icon} src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/livecode-icon.png" />
+                        <img className={styles.icon} src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/livecode-icon.png" alt="live code icon" />
                         <div className={styles.details}>
                         <div className={styles.details}>
                             <p className={styles.headline}>{_t("feature_live_code")}</p> 
                             <p className={styles.headline}>{_t("feature_live_code")}</p> 
                             <p className={styles.description}>
                             <p className={styles.description}>
@@ -50,7 +51,7 @@ function Feature(props) {
                         </div>
                         </div>
                     </div>
                     </div>
                     <div className={styles.iconDetails}>
                     <div className={styles.iconDetails}>
-                        <img className={styles.table} src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/ssr-icon.png" />
+                        <img className={styles.table} src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/ssr-icon.png" alt="auto test icon" />
                         <div className={styles.details}>
                         <div className={styles.details}>
                             <p className={styles.headline}>{_t("feature_test")}</p>
                             <p className={styles.headline}>{_t("feature_test")}</p>
                             <p className={styles.description}>
                             <p className={styles.description}>
@@ -59,7 +60,7 @@ function Feature(props) {
                         </div>
                         </div>
                     </div>
                     </div>
                     <div className={styles.iconDetails}>
                     <div className={styles.iconDetails}>
-                        <img className={styles.table} src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/a11y-icon.png" />
+                        <IconSkeleton style={{ fontSize: "28px" }} />
                         <div className={styles.details}>
                         <div className={styles.details}>
                             <p className={styles.headline}>{_t("feature_SSR")}</p>
                             <p className={styles.headline}>{_t("feature_SSR")}</p>
                             <p className={styles.description}>
                             <p className={styles.description}>
@@ -70,7 +71,7 @@ function Feature(props) {
                 </div>
                 </div>
                 <div className={styles.row1} style={{ width: "100%" }}>
                 <div className={styles.row1} style={{ width: "100%" }}>
                     <div className={styles.iconDetails}>
                     <div className={styles.iconDetails}>
-                        <img className={styles.icon} src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/fa-icon.png" />
+                        <img className={styles.icon} src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/fa-icon.png" alt="developer friendly" />
                         <div className={styles.details}>
                         <div className={styles.details}>
                             <p className={styles.headline}>{_t("feature_FA")}</p>
                             <p className={styles.headline}>{_t("feature_FA")}</p>
                             <p className={styles.description}>
                             <p className={styles.description}>

+ 1 - 1
src/sitePages/newHome/components/operateButton/operateButton.jsx

@@ -32,7 +32,7 @@ function OperateButton() {
         >
         >
             <span style={{ display: 'flex' }}>
             <span style={{ display: 'flex' }}>
                 GitHub
                 GitHub
-                <span className={styles.badge}>7.3k</span>
+                <span className={styles.badge}>7.6k</span>
             </span>
             </span>
         </Button>
         </Button>
     </div>);
     </div>);

+ 3 - 0
src/sitePages/newHome/components/pro/pro.jsx

@@ -48,6 +48,7 @@ function Pro(props) {
                 <img
                 <img
                     src="https://lf9-static.semi.design/obj/semi-tos/images/homepage-pro-code.jpg"
                     src="https://lf9-static.semi.design/obj/semi-tos/images/homepage-pro-code.jpg"
                     className={styles.syntaxHighlighter}
                     className={styles.syntaxHighlighter}
+                    alt="d2c demo code"
                 />
                 />
                 <div className={styles.rectangle1080}></div>
                 <div className={styles.rectangle1080}></div>
                 <div className={styles.frame14295}>
                 <div className={styles.frame14295}>
@@ -56,11 +57,13 @@ function Pro(props) {
                         <img
                         <img
                             src="https://lf9-static.semi.design/obj/semi-tos/images/5de23960-3242-11ec-8b14-8fb159794ae4.png"
                             src="https://lf9-static.semi.design/obj/semi-tos/images/5de23960-3242-11ec-8b14-8fb159794ae4.png"
                             className={styles.chromeStandart}
                             className={styles.chromeStandart}
+                            alt="figma design file demo"
                         />
                         />
                         {/* eslint-disable-next-line */}
                         {/* eslint-disable-next-line */}
                         <img
                         <img
                             src="https://lf9-static.semi.design/obj/semi-tos/images/5ddb0d70-3242-11ec-adec-e911cea4cf98.png"
                             src="https://lf9-static.semi.design/obj/semi-tos/images/5ddb0d70-3242-11ec-adec-e911cea4cf98.png"
                             className={styles.chromeStandart_2167fd7e}
                             className={styles.chromeStandart_2167fd7e}
+                            alt="figma design file demo"
                         />
                         />
                         <div className={styles.chromeStandart_07210c83}>
                         <div className={styles.chromeStandart_07210c83}>
                             <Component></Component>
                             <Component></Component>

+ 5 - 5
src/sitePages/newHome/components/products/products.jsx

@@ -11,15 +11,15 @@ function Products(props) {
             <p className={styles.text_ff23e7f4}>{_t("now_serving_100_000", { }, "现已服务 10 万")}</p>
             <p className={styles.text_ff23e7f4}>{_t("now_serving_100_000", { }, "现已服务 10 万")}</p>
             <div className={styles.frame14369}>
             <div className={styles.frame14369}>
                 <div key='douyinCreator'>
                 <div key='douyinCreator'>
-                    <img src="https://lf9-static.semi.design/obj/semi-tos/images/16cf36e0-321a-11ec-b393-ab4adc2e449f.png" className={classnames(styles.image42, styles.hideInDark)} />          
-                    <img className={classForDarkImage} src="https://lf9-static.semi.design/obj/semi-tos/images/a50bd6f0-3474-11ec-b008-15e09471f238.png" style={{ width: 155, height: 36 }} />              
+                    <img src="https://lf9-static.semi.design/obj/semi-tos/images/16cf36e0-321a-11ec-b393-ab4adc2e449f.png" className={classnames(styles.image42, styles.hideInDark)} alt="douyin logo" />          
+                    <img className={classForDarkImage} src="https://lf9-static.semi.design/obj/semi-tos/images/a50bd6f0-3474-11ec-b008-15e09471f238.png" style={{ width: 155, height: 36 }} alt="douyin logo" />              
                 </div>
                 </div>
                 <div key="lark" className={classnames(styles.group720)}>
                 <div key="lark" className={classnames(styles.group720)}>
-                    <img src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/lark.png" className={styles.logo_lark} />
+                    <img src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/lark.png" className={styles.logo_lark} alt="larkprogram logo" />
                     <LarkProgramSvg />
                     <LarkProgramSvg />
                 </div>
                 </div>
                 <div key="byteHi" className={classnames(styles.group720)}>
                 <div key="byteHi" className={classnames(styles.group720)}>
-                    <img src="https://lf9-static.semi.design/obj/semi-tos/images/16cec1b0-321a-11ec-adec-e911cea4cf98.png" className={styles.logo_bytehi} />
+                    <img src="https://lf9-static.semi.design/obj/semi-tos/images/16cec1b0-321a-11ec-adec-e911cea4cf98.png" className={styles.logo_bytehi} alt="bytehi logo"/>
                     <ByteHiSvg />
                     <ByteHiSvg />
                 </div>
                 </div>
                 <div key="starRiver" className={classnames(styles.group720)}>
                 <div key="starRiver" className={classnames(styles.group720)}>
@@ -29,7 +29,7 @@ function Products(props) {
                     <AnyWebSvg />
                     <AnyWebSvg />
                 </div>
                 </div>
                 <div className={styles.frame4144}>
                 <div className={styles.frame4144}>
-                    <img src="https://lf9-static.semi.design/obj/semi-tos/images/16d06f60-321a-11ec-9c23-a9f1bde3758e.png" className={styles.logo_sso} />
+                    <img src="https://lf9-static.semi.design/obj/semi-tos/images/16d06f60-321a-11ec-9c23-a9f1bde3758e.png" className={styles.logo_sso} alt="bytedance sso logo" />
                     <p className={styles.developer_11777484}>Bytedance SSO</p>
                     <p className={styles.developer_11777484}>Bytedance SSO</p>
                 </div>
                 </div>
                 <div key="capcut" className={classnames(styles.group720)}>
                 <div key="capcut" className={classnames(styles.group720)}>

+ 2 - 2
src/sitePages/newHome/components/resource/resource.jsx

@@ -30,7 +30,7 @@ function Resource(props) {
                             <span className={styles.text_70c95f84}>{_t("home.resource.rd.desc")}</span>
                             <span className={styles.text_70c95f84}>{_t("home.resource.rd.desc")}</span>
                         </p>
                         </p>
                         <p onClick={goComponentsOverview} className={styles.text_0aedd7ef}>{_t("component_documentation", { }, "组件文档")}</p>
                         <p onClick={goComponentsOverview} className={styles.text_0aedd7ef}>{_t("component_documentation", { }, "组件文档")}</p>
-                    </div><img src="https://lf9-static.semi.design/obj/semi-tos/images/homepage-code.png" className={styles.frame} />
+                    </div><img src="https://lf9-static.semi.design/obj/semi-tos/images/homepage-code.png" className={styles.frame} alt="demo code" />
                 </div>
                 </div>
                 <div className={styles.frame23}>
                 <div className={styles.frame23}>
                     <div className={styles.group20}>
                     <div className={styles.group20}>
@@ -39,7 +39,7 @@ function Resource(props) {
                             <span className={styles.text_70c95f84}>{_t("home.resource.design.desc")}</span>
                             <span className={styles.text_70c95f84}>{_t("home.resource.design.desc")}</span>
                         </p>
                         </p>
                         <p onClick={goFigma} className={styles.figmaUIKit}>Figma UIKit</p>
                         <p onClick={goFigma} className={styles.figmaUIKit}>Figma UIKit</p>
-                    </div><img src="https://lf9-static.semi.design/obj/semi-tos/images/a05515c0-323c-11ec-9c23-a9f1bde3758e.png" className={styles.frame4573} />
+                    </div><img src="https://lf9-static.semi.design/obj/semi-tos/images/a05515c0-323c-11ec-9c23-a9f1bde3758e.png" className={styles.frame4573} alt="figma source demo" />
                 </div>
                 </div>
             </div>
             </div>
         </div>
         </div>

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov