Browse Source

Merge remote-tracking branch 'semi/release' into feat/KeyboardShortCut

yanzhuoran 1 year ago
parent
commit
68320fe534
61 changed files with 996 additions and 612 deletions
  1. 1 0
      .eslintrc.js
  2. 5 5
      .github/workflows/cypress.yml
  3. 45 4
      content/navigation/tabs/index-en-US.md
  4. 47 6
      content/navigation/tabs/index.md
  5. 40 1
      content/other/configprovider/index-en-US.md
  6. 42 0
      content/other/configprovider/index.md
  7. 1 1
      content/show/avatar/index-en-US.md
  8. 1 1
      content/show/avatar/index.md
  9. 16 0
      content/start/changelog/index-en-US.md
  10. 17 0
      content/start/changelog/index.md
  11. 1 1
      content/start/design-to-code/index-en-US.md
  12. 1 1
      content/start/design-to-code/index.md
  13. 5 5
      cypress/e2e/tabs.spec.js
  14. 1 1
      gatsby-node.js
  15. 2 1
      jest.config.js
  16. 1 1
      lerna.json
  17. 1 0
      package.json
  18. 3 3
      packages/semi-animation-react/package.json
  19. 1 1
      packages/semi-animation-styled/package.json
  20. 1 1
      packages/semi-animation/package.json
  21. 1 1
      packages/semi-eslint-plugin/package.json
  22. 4 1
      packages/semi-foundation/chat/chat.scss
  23. 2 0
      packages/semi-foundation/chat/variables.scss
  24. 3 4
      packages/semi-foundation/overflowList/foundation.ts
  25. 2 2
      packages/semi-foundation/package.json
  26. 2 1
      packages/semi-foundation/tabs/constants.ts
  27. 42 0
      packages/semi-foundation/tabs/tabs.scss
  28. 12 0
      packages/semi-foundation/tabs/variables.scss
  29. 18 14
      packages/semi-foundation/tooltip/foundation.ts
  30. 2 0
      packages/semi-foundation/upload/upload.scss
  31. 1 1
      packages/semi-icons-lab/package.json
  32. 1 1
      packages/semi-icons/package.json
  33. 1 1
      packages/semi-illustrations/package.json
  34. 2 2
      packages/semi-next/package.json
  35. 1 1
      packages/semi-rspack/package.json
  36. 1 1
      packages/semi-scss-compile/package.json
  37. 1 1
      packages/semi-theme-default/package.json
  38. 11 0
      packages/semi-ui/avatar/_story/avatar.stories.tsx
  39. 2 2
      packages/semi-ui/avatar/interface.ts
  40. 13 3
      packages/semi-ui/cascader/index.tsx
  41. 7 1
      packages/semi-ui/chat/_story/constant.js
  42. 18 12
      packages/semi-ui/chat/chatBox/chatBoxContent.tsx
  43. 11 1
      packages/semi-ui/chat/index.tsx
  44. 2 0
      packages/semi-ui/configProvider/index.tsx
  45. 1 1
      packages/semi-ui/dropdown/index.tsx
  46. 7 7
      packages/semi-ui/hotKeys/__test__/hotkeys.test.js
  47. 1 0
      packages/semi-ui/index.ts
  48. 8 7
      packages/semi-ui/package.json
  49. 9 4
      packages/semi-ui/tabs/TabBar.tsx
  50. 1 1
      packages/semi-ui/tabs/TabItem.tsx
  51. 91 6
      packages/semi-ui/tabs/_story/tabs.stories.jsx
  52. 4 1
      packages/semi-ui/tabs/index.tsx
  53. 9 4
      packages/semi-ui/tabs/interface.ts
  54. 2 2
      packages/semi-ui/tooltip/__test__/tooltip.test.js
  55. 6 3
      packages/semi-ui/tooltip/index.tsx
  56. 14 1
      packages/semi-ui/upload/_story/upload.stories.jsx
  57. 1 1
      packages/semi-webpack/package.json
  58. 148 148
      sitemap.xml
  59. 20 0
      syncRegistry.sh
  60. 2 1
      test/setup.js
  61. 280 342
      yarn.lock

+ 1 - 0
.eslintrc.js

@@ -62,6 +62,7 @@ module.exports = {
             plugins: ['react', 'jest', 'react-hooks', 'import', '@typescript-eslint', 'semi-design'],
             rules: {
                 // 因为历史原因,现有项目基本全部是4个空格
+                "arrow-spacing": ["error", { "before": true, "after": true }],
                 indent: 'off',
                 'comma-spacing': ["error", {"before": false, "after": true}],
                 'no-multi-spaces': ["error", {ignoreEOLComments: true}],

+ 5 - 5
.github/workflows/cypress.yml

@@ -23,8 +23,8 @@ jobs:
     install:
         runs-on: ubuntu-latest
         container:
-            # cypress-docker-images/browsers at master · cypress-io/cypress-docker-images
-            image: cypress/browsers:node-20.14.0-chrome-125.0.6422.141-1-ff-126.0.1-edge-125.0.2535.85-1
+            # https://github.com/cypress-io/cypress-docker-images/tree/master/browsers
+            image: cypress/browsers:node-20.17.0-chrome-128.0.6613.113-1-ff-129.0.2-edge-128.0.2739.42-1
         if: ${{ github.repository_owner == 'DouyinFE' }}
         steps:
             - name: Checkout
@@ -44,8 +44,8 @@ jobs:
                   name: storybook-static
                   if-no-files-found: error
                   path: storybook
-            - name: Reclaim cache directory
-              run: chown -R 1001:1001 /github/home/.cache && echo "pwn dat cache"
+            # - name: Reclaim cache directory
+            #   run: chown -R 1001:1001 /github/home/.cache && echo "pwn dat cache"
             - name: Cypress install
               uses: cypress-io/github-action@v6
               with:
@@ -54,7 +54,7 @@ jobs:
     chrome-tests:
         runs-on: ubuntu-latest
         container:
-            image: cypress/browsers:node-20.14.0-chrome-125.0.6422.141-1-ff-126.0.1-edge-125.0.2535.85-1
+            image: cypress/browsers:node-20.17.0-chrome-128.0.6613.113-1-ff-129.0.2-edge-128.0.2739.42-1
             options: --user 1001
         needs: install
         steps:

+ 45 - 4
content/navigation/tabs/index-en-US.md

@@ -18,7 +18,7 @@ import { Tabs, TabPane } from '@douyinfe/semi-ui';
 
 ### Basic Usage
 
-Tbs supports three types of styles: `line`, `button`, and `card`. By default, the first tab is selected.
+Tbs supports three types of styles: `line`, `button`, `card`, and `slash`. By default, the first tab is selected.
 
 Tabs supports two declare ways, and the rendering process of the two is different:
 
@@ -168,6 +168,44 @@ class TabDemo extends React.Component {
 }
 ```
 
+```jsx live=true
+import React from 'react';
+import { Tabs } from '@douyinfe/semi-ui';
+
+class TabDemo extends React.Component {
+    constructor() {
+        super();
+        this.state = { key: '1' };
+        this.onTabClick = this.onTabClick.bind(this);
+    }
+
+    onTabClick(key, type) {
+        this.setState({ [type]: key });
+    }
+
+    render() {
+        // eslint-disable-next-line react/jsx-key
+        const contentList = [<div>Document</div>, <div>Quick Start</div>, <div>Help</div>];
+        const tabList = [
+            { tab: 'Document', itemKey: '1' },
+            { tab: 'Quick Start', itemKey: '2' },
+            { tab: 'Help', itemKey: '3' },
+        ];
+        return (
+            <Tabs
+                type="slash"
+                tabList={tabList}
+                onChange={key => {
+                    this.onTabClick(key, 'key');
+                }}
+            >
+                {contentList[this.state.key - 1]}
+            </Tabs>
+        );
+    }
+}
+```
+
 ### With Icon
 
 ```jsx live=true
@@ -274,7 +312,7 @@ function Demo() {
 
 ### Vertical mode
 
-Support two positions: `tabPosition='left|top'`
+When `type` is `line`, `card`, or `button`, horizontal and vertical modes are supported, `tabPosition='left|top'`,default is top. When `type` is `slash`, only horizontal mode is supported.
 
 ```jsx live=true
 import React from 'react';
@@ -381,7 +419,9 @@ class App extends React.Component {
 
 **Modify the scrolling rendering Arrow**
 
-`renderArrow` modifies the Arrow, with the input parameters being the overflowed items and position
+`renderArrow` modifies the Arrow, with the input parameters being the overflowed items, position, click function, and defaultNode.
+ 
+**Attention**: The first three parameters of renderArrow are supported since 2.61.0,while defaultNode parameter is supported since 2.66.0.
 
 ```jsx live=true dir="column"
 import React from 'react';
@@ -701,6 +741,7 @@ class App extends React.Component {
 | activeKey | The itemKey value of the currently active tab page | string | None |
 | className | class name | string | None |
 | collapsible | collapsed Tabs, **>=1.1.0** | boolean | false |
+| dropdownProps | In collapsible mode, It is used to transparently transmit parameters to the Dropdown component of the drop-down menu, support since 2.66.0 | DropDownProps | { start: DropdownProps, end: DropdownProps } |
 | visibleTabsStyle | Overall scrolling area style **>=2.61.0** | style: CSSProperties | None |
 | contentStyle | The outer style object of the content area | CSSProperties | None |
 | defaultActiveKey | Initialize the key value of the selected tab page | string | '1' |
@@ -708,7 +749,7 @@ class App extends React.Component {
 | lazyRender | Lazy rendering, only when the panel is activated will it be rendered in the DOM tree, **>=1.0.0** | boolean | false |
 | more | Render a portion of the Tab into a drop-down menu ** >= 2.59.0** | number \| {count:number,render:()=>ReactNode,dropdownProps:DropDownProps} | - |
 | renderTabBar | Used for secondary packaging tab bar | (tabBarProps: object, defaultTabBar: React.ComponentType) => ReactNode | None |
-| renderArrow | Customize how overflow items indicator are rendered externally. By default, the overflow items are expanded when the arrow button is hovered. **>=2.61.0** | (items: OverflowItem[],pos:"start"\|"end", handleArrowClick:()=>void)=> ReactNode | None |
+| renderArrow | Customize how overflow items indicator are rendered externally. By default, the overflow items are expanded when the arrow button is hovered. The first three parameters of renderArrow are supported since **>=2.61.0**, defaultNode is supported since **>=2.66.0** | (items: OverflowItem[],pos:"start"\|"end", handleArrowClick:()=>void, defaultNode: ReactNode)=> ReactNode | None |
 | 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 |
 | showRestInDropdown | Whether to display the collapsed Tab in the drop-down menu (only effective when collapsible is true) **>= 2.61.0** | boolean | true |
 | size | Size, providing three types of `large`, `medium`, and `small`, **>=1.11.0, currently only supports linear Tabs** | string | `large` |

+ 47 - 6
content/navigation/tabs/index.md

@@ -17,7 +17,7 @@ import { Tabs, TabPane } from '@douyinfe/semi-ui';
 
 ### 基本用法
 
-标签栏支持三种样式的显示:线条式,按钮式,卡片式。默认选中第一项。  
+标签栏支持三种样式的显示:线条式,按钮式,卡片式,斜线式。默认选中第一项。  
 标签页支持两种传入方式,两者渲染流程上有所区别:
 
 -   通过 `tabList` 传入标签页对象的数组,当使用 `tabList` 时每次只渲染当前传入的节点
@@ -153,6 +153,44 @@ class TabDemo extends React.Component {
 }
 ```
 
+```jsx live=true
+import React from 'react';
+import { Tabs } from '@douyinfe/semi-ui';
+
+class TabDemo extends React.Component {
+    constructor() {
+        super();
+        this.state = { key: '1' };
+        this.onTabClick = this.onTabClick.bind(this);
+    }
+
+    onTabClick(key, type) {
+        this.setState({ [type]: key });
+    }
+
+    render() {
+        // eslint-disable-next-line react/jsx-key
+        const contentList = [<div>文档</div>, <div>快速起步</div>, <div>帮助</div>];
+        const tabList = [
+            { tab: '文档', itemKey: '1' },
+            { tab: '快速起步', itemKey: '2' },
+            { tab: '帮助', itemKey: '3' },
+        ];
+        return (
+            <Tabs
+                type="slash"
+                tabList={tabList}
+                onChange={key => {
+                    this.onTabClick(key, 'key');
+                }}
+            >
+                {contentList[this.state.key - 1]}
+            </Tabs>
+        );
+    }
+}
+```
+
 ### 带图标的
 
 有图标的标签栏。
@@ -257,7 +295,7 @@ function Demo() {
 
 ### 垂直的标签栏
 
-支持水平和垂直两种模式, `tabPosition='left|top'`
+`type` 为 `line`, `card`, `button` 支持水平和垂直两种模式,`tabPosition='left|top'`, 默认为 `top`。`type` 为 `slash` 仅支持水平模式,无需设置。
 
 ```jsx live=true
 import React from 'react';
@@ -404,7 +442,9 @@ class App extends React.Component {
 
 **自定义滚动箭头渲染**
 
-通过 renderArrow 修改滚动折叠模式下,左右切换箭头的渲染,入参为溢出的 items 和 位置
+通过 renderArrow 修改滚动折叠模式下,左右切换箭头的渲染,入参为溢出的 items 和 位置, 点击处理函数,以及 defaultNode。
+
+**注**:renderArrow 的前三个参数自 2.61.0 支持,defaultNode 自 2.66.0 支持。
 
 ```jsx live=true dir="column"
 import React from 'react';
@@ -412,7 +452,7 @@ import { Tabs, TabPane, Dropdown } from '@douyinfe/semi-ui';
 
 () => {
     const [activeKey, setActiveKey] = useState('Tab-0');
-    const renderArrow = (items, pos, handleArrowClick) => {
+    const renderArrow = (items, pos, handleArrowClick, defaultNode) => {
         const style = {
             width: 32,
             height: 32,
@@ -718,6 +758,7 @@ class App extends React.Component {
 | arrowPosition | 折叠模式下,左右切换箭头渲染位置 **>=2.61.0** | "start" "end" "both" | 无 |
 | className | 类名 | string | 无 |
 | collapsible | 折叠的 Tabs,**>=1.1.0** | boolean | false |
+| dropdownProps | 用于在折叠模式下透传参数到下拉菜单的 Dropdown 组件 | { start: DropdownProps, end: DropdownProps } | 无 |
 | visibleTabsStyle | 整体滚动区域 Style **>=2.61.0** | style: CSSProperties | 无 |
 | contentStyle | 内容区域外层样式对象 | CSSProperties | 无 |
 | defaultActiveKey | 初始化选中的 tab 页的 key 值 | string | '1' |
@@ -725,7 +766,7 @@ class App extends React.Component {
 | lazyRender | 懒渲染,仅当面板激活过才被渲染在 DOM 树中  | boolean | false |
 | more | 将一部分 Tab 渲染到下拉菜单中 ** >= 2.59.0** | number \| {count:number,render:()=>ReactNode,dropdownProps:DropDownProps} | - |
 | renderTabBar | 用于二次封装标签栏 | (tabBarProps: object, defaultTabBar: React.ComponentType) => ReactNode | 无 |
-| renderArrow | 折叠滚动模式下,自定义左右切换箭头如何渲染,默认为箭头按钮 hover 时展开溢出项 **>=2.61.0** | (items: OverflowItem[],pos:"start"\|"end", handleArrowClick:()=>void)=> ReactNode | 无 |
+| renderArrow | 折叠滚动模式下,自定义左右切换箭头如何渲染,默认为箭头按钮 hover 时展开溢出项。前三个参数自 **>=2.61.0** 支持,defaultNode 参数自 **>=2.66.0** 支持| (items: OverflowItem[],pos:"start"\|"end", handleArrowClick:()=>void, defaultNode: ReactNode)=> ReactNode | 无 |
 | preventScroll | 指示浏览器是否应滚动文档以显示新聚焦的元素,作用于组件内的 focus 方法 | boolean |  |  |
 | showRestInDropdown | 是否将收起的 Tab 展示在下拉菜单中(仅当 collapsible 为 true 时生效) **>= 2.61.0** | boolean | true |
 | size | 大小,提供 `large`、`medium`、`small` 三种类型,**>=1.11.0,目前仅支持线性 Tabs** | string | `large` |
@@ -734,7 +775,7 @@ class App extends React.Component {
 | tabList | 标签页对象组成的数组,该对象支持 itemKey(对应 activeKey,tab(标签页文字)及 icon(标签页图标) | TabPane[] | 无 |
 | tabPaneMotion | 是否使用动画切换 tabs | boolean | true |
 | tabPosition | tab 的位置,支持`top`(水平), `left`(垂直) | string | `top` |
-| type | 标签栏的样式,可选`line`、 `card`、 `button` | string | `line` |
+| type | 标签栏的样式,可选`line`、 `card`、 `button`、`slash` | string | `line` |
 | onChange | 切换 tab 页时的回调函数 | function(activeKey: string) | 无 |
 | onTabClick | 单击事件 | function(key: string, e: Event) | 无 |
 | onTabClose | 关闭 tab 页时的回调函数 **>=2.1.0** | function(tabKey: string) | 无 |

+ 40 - 1
content/other/configprovider/index-en-US.md

@@ -74,6 +74,45 @@ function Demo(props = {}) {
 }
 ```
 
+### Manually obtain values
+Usually, the value of ConfigProvider is automatically obtained and consumed within the component, so you don't need to worry about it. However, in some special scenarios, you may need to manually obtain the value to perform other operations.
+
+Use ConfigConsumer to obtain the value of ConfigProvider
+
+```jsx live=true dir="column" hideInDSM
+import React, { useMemo, useState } from 'react';
+import { ConfigProvider, ConfigConsumer, Select, DatePicker, TimePicker, Typography } from '@douyinfe/semi-ui';
+
+function Demo(props = {}) {
+  const [timeZone, setTimeZone] = useState('GMT+08:00');
+  const defaultTimestamp = 1581599305265;
+  const gmtList = useMemo(() => {
+    const list = [];
+    for (let hourOffset = -11; hourOffset <= 14; hourOffset++) {
+      const prefix = hourOffset >= 0 ? '+' : '-';
+      const hOffset = Math.abs(parseInt(hourOffset, 10));
+      list.push(`GMT${prefix}${String(hOffset).padStart(2, '0')}:00`);
+    }
+    return list;
+  }, []);
+
+  return (
+          <ConfigProvider timeZone={timeZone}>
+            {/*...*/}
+            <ConfigConsumer>
+              {(value) => {
+                return <Typography.Text ellipsis={{ showTooltip: {opts:{style:{minWidth:"1200px"}} }}}  style={{ width: 600 }}>
+                  {JSON.stringify(value)}
+                </Typography.Text>
+              }}
+            </ConfigConsumer>
+            {/*...*/}
+          </ConfigProvider>
+  );
+}
+
+```
+
 ### RTL/LTR
 Global configuration `direction` can change the text direction of components。`rtl` means right to left (similar to Hebrew or Arabic), `ltr` means left to right (similar to most languages such as English)
 
@@ -454,4 +493,4 @@ semiGlobal.config.overrideDefaultProps = {
 };
 
 
-```
+```

+ 42 - 0
content/other/configprovider/index.md

@@ -77,6 +77,48 @@ function Demo(props = {}) {
 }
 ```
 
+### 手动获取值
+通常情况下,组件内部会自动获取 ConfigProvider 的值自动消费,无需关心。但是一些特殊场景,你可能需要手动获取值来进行其他操作。
+
+使用 ConfigConsumer 获取 ConfigProvider 的值
+
+```jsx live=true dir="column" hideInDSM
+import React, { useMemo, useState } from 'react';
+import { ConfigProvider, ConfigConsumer, Select, DatePicker, TimePicker, Typography } from '@douyinfe/semi-ui';
+
+function Demo(props = {}) {
+  const [timeZone, setTimeZone] = useState('GMT+08:00');
+  const defaultTimestamp = 1581599305265;
+  const gmtList = useMemo(() => {
+    const list = [];
+    for (let hourOffset = -11; hourOffset <= 14; hourOffset++) {
+      const prefix = hourOffset >= 0 ? '+' : '-';
+      const hOffset = Math.abs(parseInt(hourOffset, 10));
+      list.push(`GMT${prefix}${String(hOffset).padStart(2, '0')}:00`);
+    }
+    return list;
+  }, []);
+
+  return (
+          <ConfigProvider timeZone={timeZone}>
+            {/*...*/}
+            <ConfigConsumer>
+              {(value) => {
+                return <Typography.Text ellipsis={{ showTooltip: {opts:{style:{minWidth:"1200px"}} }}}  style={{ width: 600 }}>
+                  {JSON.stringify(value)}
+                </Typography.Text>
+             }}
+            </ConfigConsumer>
+            {/*...*/}
+          </ConfigProvider>
+          );
+}
+
+```
+
+
+
+
 ### RTL/LTR
 全局配置 `direction` 可以改变组件的文本方向(1.8.0)。
 

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

@@ -456,7 +456,7 @@ import { Avatar, AvatarGroup } from '@douyinfe/semi-ui';
 | overlapFrom | Set the coverage direction of the avatars, one of `start`, `end` | string | `start` |
 | renderMore | Customize the more tag  | (restNumber: number, restAvatars: ReactNode[]) => ReactNode | - |
 | shape      | Shape of the avatar, one of `circle`, `square`                                      | string | `circle` |
-| size       | Size of the avatar, one of `extra-extra-small`, `extra-small`, `small`, `default`, `medium`, `large`, `extra-large` | string | `medium` |
+| size       | Size of the avatar, one of `extra-extra-small`, `extra-small`, `small`, `default`, `medium`, `large`, `extra-large` and valid value like "10px" | string | `medium` |
 
 ## Accessibility
 

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

@@ -452,7 +452,7 @@ import { AvatarGroup, Avatar } from '@douyinfe/semi-ui';
 | overlapFrom | 设置头像覆盖方向,支持 `start`, `end` | string | `start` |
 | renderMore | 自定义渲染 more 标签 | (restNumber: number, restAvatars: ReactNode[]) => ReactNode | - |
 | shape | 指定头像的形状,支持`circle`、`square` | string | `circle` |
-| size | 设置头像的大小,支持 `extra-extra-small`, `extra-small`、`small`、`default`、`medium`、`large`、`extra-large` | string | `medium` |
+| size | 设置头像的大小,支持 `extra-extra-small`, `extra-small`、`small`、`default`、`medium`、`large`、`extra-large` 和合法的 width 属性值例,如 "10px"| string | `medium` |
 
 ## Accessibility
 

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

@@ -16,6 +16,22 @@ Version:Major.Minor.Patch (follow the **Semver** specification)
 
 ---
 
+#### 🎉 2.66.0-beta.0 (2024-09-02)
+- 【Fix】
+    - Fixed the issue that the error style was blocked in Form.Upload image wall mode
+    - Fixed the issue that Collapse Tabs crashes when the tab is set to jsx (affected range: 2.65.0 )
+    - Fixed the issue that Dropdown onVisibleChange reported an error when it was not defined in some scenarios
+    - Fixed SyntaxError when parsing unescaped characters in Chat component message box
+    - Fixed the issue where the Chat component scrolls the message list while the message is being updated streaming. The streaming update of message will cause the list to unexpectedly scroll to the bottom.
+- 【Feat】
+    - Tabs add slash type
+    - renderArrow of Tabs support defaultNode param
+    - All types of Tabs support closable (previously only the card type supported closable)
+    - Tabs supports setting dropdown parameters in collapsible mode through dropdownProps API
+    - create KeyboardShortCut,user can define shortcut key combinations and trigger callbacks. [@Nathon2Y](https://github.com/Nathon2Y)
+- 【Chore】
+    - The size API type of Avatar and AvatarGroup has been changed to string #2443  [#2446 ](https://github.com/DouyinFE/semi-design/issues/2446)
+
 #### 🎉 2.65.0 (2024-08-23)
 - 【Fix】
     - Fixed the problem that when Slider is in range controlled mode, dragging one handle may cause another handle to shake [#2438](https://github.com/DouyinFE/semi-design/issues/2438)

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

@@ -12,6 +12,23 @@ Semi 版本号遵循 **Semver** 规范(主版本号-次版本号-修订版本
 -   次版本号(minor):Semi 固定每两周发布一个 minor 版本,包括以下类型变更:添加了新组件/新 feature,或者设计规范样式更新,或者不合理交互的变更,但不会对组件 API 做删减或功能变更。
 -   修订版本号(patch):仅会进行 bugfix,发布时间不限
 -   不同版本间的详细关系,可查阅 [FAQ](/zh-CN/start/faq)
+-   
+
+#### 🎉 2.66.0-beta.0 (2024-09-02)
+- 【Fix】
+    - 修复 Form.Upload 图片墙模式下 error 样式被遮挡问题 [#2449](https://github.com/DouyinFE/semi-design/pull/2449)
+    - 修复 Collapse Tabs 在 tab 设置为 jsx 情况下会崩溃问题(影响范围:2.65.0 ) [#2464](https://github.com/DouyinFE/semi-design/pull/2464)
+    - 修复 Dropdown onVisibleChange 在一些场景未定义时报错的问题 [#2454](https://github.com/DouyinFE/semi-design/pull/2454)
+    - 修复 Chat 组件内容显示部分解析未转义字符时候的 SyntaxError [#2452](https://github.com/DouyinFE/semi-design/pull/2452)
+    - 修复 Chat 组件在消息流式更新的同时,滚动消息列表,消息流式更新会导致列表意外滚动到底部问题 [#2451](https://github.com/DouyinFE/semi-design/pull/2451)
+- 【Feat】
+    - Tabs 增加 slash 类型 [#2416](https://github.com/DouyinFE/semi-design/pull/2416)
+    - Tabs 的 renderArrow 支持 defaultNode 参数 [#2416](https://github.com/DouyinFE/semi-design/pull/2416)
+    - Tabs 的所有类型支持 closable (此前仅 card 类型支持 closable) [#2416](https://github.com/DouyinFE/semi-design/pull/2416)
+    - Tabs 支持通过dropdownProps API 设置滚动折叠模式下的 dropdown 参数  [#2416](https://github.com/DouyinFE/semi-design/pull/2416)
+    - 添加快捷键组件,支持用户自定义快捷键组合并触发回调 [@Nathon2Y](https://github.com/Nathon2Y) [#2418](https://github.com/DouyinFE/semi-design/pull/2418)
+- 【Chore】
+    - Avatar,AvatarGroup 的 size API 类型修改为 string #2443  [#2446 ](https://github.com/DouyinFE/semi-design/issues/2446) [#2459](https://github.com/DouyinFE/semi-design/pull/2459)
 
 #### 🎉 2.65.0 (2024-08-23)
 - 【Fix】

+ 1 - 1
content/start/design-to-code/index-en-US.md

@@ -100,7 +100,7 @@ Here is a link to the Figma example mockup and its corresponding Codesandbox tra
 |------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------|
 | <a href='https://www.figma.com/file/TlLeWouyImYUexTmhdLiIn/D2C-Getting-Start-Demo?node-id=5%3A2092' target="_blank" rel="noreferrer noopener"><img src='https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/semi-linker/simple-demo-1.jpg' style={{ width:  400 }} /></a>                                               | A module with simple content without components                                                   | Can be used to quickly restore layout and content                                                   | <a href='https://codesandbox.io/s/w1z9yx' target="_blank" rel="noreferrer noopener">Link</a> |
 | <a href='https://www.figma.com/file/TlLeWouyImYUexTmhdLiIn/D2C-Getting-Start-Demo?node-id=1%3A275' target="_blank" rel="noreferrer noopener"><img src='https://lf3-files.qingfuwucdn.net/obj/inspirecloud-file/baas/tt38q7/2468f1c4f1756bc0_1676603194364.png' style={{ width:  400 }} /></a>                                                  | Modules that do not contain components, have more content, or have a slightly more complex layout | Can be used to quickly restore layout and content                                                   | <a href='https://codesandbox.io/s/905ncn' target="_blank" rel="noreferrer noopener">Link</a> |
-| <a href='https://www.figma.com/file/TlLeWouyImYUexTmhdLiIn/D2C-Getting-Start-Demo%EF%BC%88Figma-Community%EF%BC%89?node-id=419%3A90854&t=PMnGQ3VQIoGQZZPl-4' target="_blank"><img src='https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/semi-linker/semi-code-site/Simple Form.png' style={{ width:  400 }}/></a>    | Module with Semi Form Components                                                                  | Can be used to quickly restore the layout and content, and identify the Props of the Semi component | <a href='https://codesandbox.io/s/nzsf0j' target="_blank">Link</a>                           |
+| <a href='https://www.figma.com/file/TlLeWouyImYUexTmhdLiIn/D2C-Getting-Start-Demo%EF%BC%88Figma-Community%EF%BC%89?node-id=419%3A90854&t=PMnGQ3VQIoGQZZPl-4' target="_blank"><img src='https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/semi-linker/semi-code-site/Simple Form.png' style={{ width:  400 }}/></a>    | Module with Semi Form Components                                                                  | Can be used to quickly restore the layout and content, and identify the Props of the Semi component | <a href='https://codesandbox.io/p/sandbox/simple-form-9gq7fw' target="_blank">Link</a>                           |
 | <a href='https://www.figma.com/file/TlLeWouyImYUexTmhdLiIn/D2C-Getting-Start-Demo%EF%BC%88Figma-Community%EF%BC%89?node-id=419%3A128959&t=PMnGQ3VQIoGQZZPl-4' target="_blank"><img src='https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/semi-linker/semi-code-site/Simple Table.png' style={{ width:  400 }} /></a> | Module with Semi Table Components                                                                 | Can be used to quickly identify table columns, create Table                                         | <a href='https://codesandbox.io/s/happy-browser-dt34sr' target="_blank">Link</a>             |
 | <a href='https://www.figma.com/file/TlLeWouyImYUexTmhdLiIn/D2C-Getting-Start-Demo?node-id=1%3A276' target="_blank" rel="noreferrer noopener"><img src='https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/semi-linker/d2c-landing-example.png' style={{ width:  400 }} /></a>                                          | Full landing page                                                                                 | Can be used to quickly restore layout and content                                                   | <a href='https://codesandbox.io/s/cvhhqt' target="_blank" rel="noreferrer noopener">Link</a> |
 

+ 1 - 1
content/start/design-to-code/index.md

@@ -103,7 +103,7 @@ Design to code(简称D2C) 是 Semi Design 提供的设计稿转代码功能
 |------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------|---------------------------------------------------|----------------------------------------------------------------------------------------------|
 | <a href='https://www.figma.com/file/TlLeWouyImYUexTmhdLiIn/D2C-Getting-Start-Demo?node-id=5%3A2092' target="_blank" rel="noreferrer noopener"><img src='https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/semi-linker/simple-demo-1.jpg' style={{ width:  400 }} /></a>                                               | 不含组件,内容较简单的模块           | 可用于快速还原布局及内容                            | <a href='https://codesandbox.io/s/w1z9yx' target="_blank" rel="noreferrer noopener">Link</a> |
 | <a href='https://www.figma.com/file/TlLeWouyImYUexTmhdLiIn/D2C-Getting-Start-Demo?node-id=1%3A275' target="_blank" rel="noreferrer noopener"><img src='https://lf3-files.qingfuwucdn.net/obj/inspirecloud-file/baas/tt38q7/2468f1c4f1756bc0_1676603194364.png' style={{ width:  400 }} /></a>                                                  | 不含组件,内容较多或布局稍复杂的模块 | 可用于快速还原布局及内容                            | <a href='https://codesandbox.io/s/905ncn' target="_blank" rel="noreferrer noopener">Link</a> |
-| <a href='https://www.figma.com/file/TlLeWouyImYUexTmhdLiIn/D2C-Getting-Start-Demo%EF%BC%88Figma-Community%EF%BC%89?node-id=419%3A90854&t=PMnGQ3VQIoGQZZPl-4' target="_blank"><img src='https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/semi-linker/semi-code-site/Simple Form.png' style={{ width:  400 }}/></a>    | 含 Semi 表单组件的模块              | 可用于快速还原布局及内容,并识别出 Semi 组件的 Props | <a href='https://codesandbox.io/s/nzsf0j' target="_blank">Link</a>                           |
+| <a href='https://www.figma.com/file/TlLeWouyImYUexTmhdLiIn/D2C-Getting-Start-Demo%EF%BC%88Figma-Community%EF%BC%89?node-id=419%3A90854&t=PMnGQ3VQIoGQZZPl-4' target="_blank"><img src='https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/semi-linker/semi-code-site/Simple Form.png' style={{ width:  400 }}/></a>    | 含 Semi 表单组件的模块              | 可用于快速还原布局及内容,并识别出 Semi 组件的 Props | <a href='https://codesandbox.io/p/sandbox/simple-form-9gq7fw' target="_blank">Link</a>                           |
 | <a href='https://www.figma.com/file/TlLeWouyImYUexTmhdLiIn/D2C-Getting-Start-Demo%EF%BC%88Figma-Community%EF%BC%89?node-id=419%3A128959&t=PMnGQ3VQIoGQZZPl-4' target="_blank"><img src='https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/semi-linker/semi-code-site/Simple Table.png' style={{ width:  400 }} /></a> | 含 Semi Table 组件                  | 可用于快速识别表格列、创建 Table                     | <a href='https://codesandbox.io/s/happy-browser-dt34sr' target="_blank">Link</a>             |
 | <a href='https://www.figma.com/file/TlLeWouyImYUexTmhdLiIn/D2C-Getting-Start-Demo?node-id=1%3A276' target="_blank" rel="noreferrer noopener"><img src='https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/semi-linker/d2c-landing-example.png' style={{ width:  400 }} /></a>                                          | 整页 Landing Page                   | 可用于快速还原布局及内容                            | <a href='https://codesandbox.io/s/cvhhqt' target="_blank" rel="noreferrer noopener">Link</a> |
 

+ 5 - 5
cypress/e2e/tabs.spec.js

@@ -74,13 +74,13 @@ describe('tabs', () => {
         cy.get('[id=semiTab1]').should('be.focused');
     });
 
-    it('keyboard test when the tabs is closable', () => {
+    it.only('keyboard test when the tabs is closable', () => {
         cy.visit('http://127.0.0.1:6006/iframe.html?id=tabs--tab-closable&args=&viewMode=story');
-        cy.get('[id=semiTab1]').click();
-        cy.get('[id=semiTab1]').should('be.focused');
+        cy.get('[data-tabkey=semiTab1]').eq(0).click();
+        cy.get('[data-tabkey=semiTab1]').eq(0).should('be.focused');
 
-        cy.get('[id=semiTab1]').type('{backspace}');
-        cy.get('[id=semiTab1]').should('not.exist');
+        cy.get('[data-tabkey=semiTab1]').eq(0).type('{backspace}');
+        cy.get('[data-tabkey=semiTab1]').should('not.exist');
     });
 
     it('collapsible', () => {

+ 1 - 1
gatsby-node.js

@@ -106,7 +106,7 @@ exports.onCreateWebpackConfig = ({ stage, rules, loaders, plugins, actions }) =>
                 "#minpath": isSSR ? "vfile/lib/minpath.js" : "vfile/lib/minpath.browser.js",
                 "#minproc": isSSR ? "vfile/lib/minproc.js" : "vfile/lib/minproc.browser.js",
                 "#minurl": isSSR ? "vfile/lib/minurl.js" : "vfile/lib/minurl.browser.js",
-                "estree-util-visit/do-not-use-color": isSSR ? "estree-util-visit/lib/color.node.js":"estree-util-visit/lib/color.js",
+                "estree-util-visit/do-not-use-color": isSSR ? "estree-util-visit/lib/color.node.js":"estree-util-visit/lib/color.default.js",
                 "devlop":"devlop/lib/default.js",
                 "unist-util-visit-parents/do-not-use-color": isSSR?"unist-util-visit-parents/lib/color.node.js":"unist-util-visit-parents/lib/color.js",
                 'semi-site-header': process.env.SEMI_SITE_HEADER || '@douyinfe/semi-site-header',

+ 2 - 1
jest.config.js

@@ -58,7 +58,8 @@ let config = {
         
         '@mdx-js/mdx': '<rootDir>/test/__mocks__/mdx-3.0.1-cjs.js',
         'remark-gfm': '<rootDir>/test/__mocks__/remark-gfm-4.0.0-cjs.js',
-
+        "@testing-library/react": "<rootDir>/node_modules/@testing-library/react",
+        "@testing-library/dom": "<rootDir>/node_modules/@testing-library/dom",
         '@douyinfe/semi-ui(.*)$': '<rootDir>/packages/semi-ui/$1',
         '@douyinfe/semi-foundation(.*)$': '<rootDir>/packages/semi-foundation/$1',
         '@douyinfe/semi-illustrations(.*)$': '<rootDir>/packages/semi-illustrations/src/$1',

+ 1 - 1
lerna.json

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

+ 1 - 0
package.json

@@ -170,6 +170,7 @@
         "enzyme": "^3.11.0",
         "enzyme-adapter-react-16": "^1.15.6",
         "enzyme-to-json": "^3.6.2",
+        "@testing-library/react": "^12",
         "esbuild": "^0.14.47",
         "esbuild-loader": "^2.14.0",
         "eslint": "^7.32.0",

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

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

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

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

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

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

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

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

+ 4 - 1
packages/semi-foundation/chat/chat.scss

@@ -233,6 +233,7 @@ $module: #{$prefix}-chat;
             .#{$module}-attachment-file, .#{$module}-attachment-img  {
                 margin-top: $spacing-chat_chatBox_content_attachment-marginY;
                 margin-bottom: $spacing-chat_chatBox_content_attachment-marginY;
+                margin-right: $spacing-chat_chatBox_content_attachment-marginRight;
             }
         
             &-user {
@@ -457,6 +458,8 @@ $module: #{$prefix}-chat;
         flex-wrap: wrap;
         column-gap: $spacing-chat_attachment-columnGap;
         row-gap: $spacing-chat_attachment-RowGap;
+        margin-left: $spacing-chat_attachment-marginX;
+        margin-right: $spacing-chat_attachment-marginX;
 
         &-item {
             position: relative;
@@ -493,7 +496,7 @@ $module: #{$prefix}-chat;
         }
 
         &-file {
-            display: flex;
+            display: inline-flex;
             flex-direction: row;
             align-items: center;
             height: $width-chat_attachment_file;

+ 2 - 0
packages/semi-foundation/chat/variables.scss

@@ -67,6 +67,7 @@ $spacing-chat_inputBox_inner-columnGap: 4px; // 输入框容器列间距
 $spacing-chat_inputBox-marginY: 4px;
 $spacing-chat_attachment-columnGap: 10px; // 附件列间距
 $spacing-chat_attachment-RowGap: 5px; // 附件行间距
+$spacing-chat_attachment-marginX: 12px; // 附件左右外边距
 $spacing-chat_attachment_clear-top: 8px;  // 附件清除图标顶部间距
 $spacing-chat_attachment_clear-right: 8px;  // 附件清除图标右内边距
 $spacing-chat_attachment_file-columnGap: 5px; // 文件附件列间距
@@ -74,6 +75,7 @@ $spacing-chat_attachment_file-padding: 5px;  // 文件附件内边距
 $spacing-chat_chatBox_loading_item-gap: 15px; // 聊天内容加载图标间距 
 $spacing-chat_divider-marginY: 12px; // 分割线上下外边距
 $spacing-chat_chatBox_content_attachment-marginY: 4px; // 聊天框内容文件/图片上下外间距
+$spacing-chat_chatBox_content_attachment-marginRight: 4px; //聊天框内容文件/图片上下右间距
 $spacing-chat_chatBox_content_code_topSlot-paddingX: 5px; // 聊天框代码块顶部上下内边距
 $spacing-chat_chatBox_content_code_topSlot-paddingY: 8px; // 聊天框代码块顶部左右内边距
 $spacing-chat_chatBox_content_code_topSlot_copy-columnGap: 5px; // 聊天框代码块顶部复制按钮列间距: 

+ 3 - 4
packages/semi-foundation/overflowList/foundation.ts

@@ -33,15 +33,14 @@ class OverflowListFoundation extends BaseFoundation<OverflowListAdapter> {
             return overflow;
         }
 
-        const cloneItems = copy(items);
 
-        const visibleStateArr = cloneItems.map(({ key }: { key: string }) => Boolean(visibleState.get(key)));
+        const visibleStateArr = items.map(({ key }: { key: string }) => Boolean(visibleState.get(key)));
         const visibleStart = visibleStateArr.indexOf(true);
         const visibleEnd = visibleStateArr.lastIndexOf(true);
 
         const overflowList = [];
-        overflowList[0] = visibleStart >= 0 ? cloneItems.slice(0, visibleStart) : [];
-        overflowList[1] = visibleEnd >= 0 ? cloneItems.slice(visibleEnd + 1, cloneItems.length) : cloneItems;
+        overflowList[0] = visibleStart >= 0 ? items.slice(0, visibleStart) : [];
+        overflowList[1] = visibleEnd >= 0 ? items.slice(visibleEnd + 1, items.length) : items.slice();
         return overflowList;
     }
 

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

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

+ 2 - 1
packages/semi-foundation/tabs/constants.ts

@@ -6,6 +6,7 @@ const cssClasses = {
     TABS_BAR_LINE: `${BASE_CLASS_PREFIX}-tabs-bar-line`,
     TABS_BAR_CARD: `${BASE_CLASS_PREFIX}-tabs-bar-card`,
     TABS_BAR_BUTTON: `${BASE_CLASS_PREFIX}-tabs-bar-button`,
+    TABS_BAR_SLASH: `${BASE_CLASS_PREFIX}-tabs-bar-slash`,
     TABS_BAR_EXTRA: `${BASE_CLASS_PREFIX}-tabs-bar-extra`,
     TABS_TAB: `${BASE_CLASS_PREFIX}-tabs-tab`,
     TABS_TAB_ACTIVE: `${BASE_CLASS_PREFIX}-tabs-tab-active`,
@@ -29,7 +30,7 @@ const numbers = {
 };
 
 const strings = {
-    TYPE_MAP: ['line', 'card', 'button'],
+    TYPE_MAP: ['line', 'card', 'button', 'slash'],
     SIZE: ['small', 'medium', 'large'],
     POSITION_MAP: ['top', 'left']
 };

+ 42 - 0
packages/semi-foundation/tabs/tabs.scss

@@ -174,6 +174,10 @@ $ignoreIcon: '.#{$prefix}-icon-checkbox_tick, .#{$prefix}-icon-radio, .#{$prefix
                 color: var(--semi-color-text-2);
                 margin-left: 10px;
                 cursor: pointer;
+
+                &.#{$prefix}-icon-close:hover {
+                    color: var(--semi-color-text-0);
+                }
             }
 
             &:hover {
@@ -182,6 +186,10 @@ $ignoreIcon: '.#{$prefix}-icon-checkbox_tick, .#{$prefix}-icon-radio, .#{$prefix
                 .#{$prefix}-icon:not(#{$ignoreIcon}) {
                     color: $color-tabs_tab-icon-hover;
                 }
+
+                .#{$prefix}-icon.#{$module}-tab-icon-close {
+                    color: var(--semi-color-text-2);
+                }
             }
 
             &:active {
@@ -190,6 +198,10 @@ $ignoreIcon: '.#{$prefix}-icon-checkbox_tick, .#{$prefix}-icon-radio, .#{$prefix
                 .#{$prefix}-icon:not(#{$ignoreIcon}) {
                     color: $color-tabs_tab-icon-active;
                 }
+
+                .#{$prefix}-icon.#{$module}-tab-icon-close {
+                    color: var(--semi-color-text-2);
+                }
             }
         }
 
@@ -583,6 +595,36 @@ $ignoreIcon: '.#{$prefix}-icon-checkbox_tick, .#{$prefix}-icon-radio, .#{$prefix
         }
     }
 
+    &-bar-slash {
+
+        .#{$module}-tab {
+            padding: $spacing-tabs_bar_slash_tab-paddingY $spacing-tabs_bar_slash_tab-paddingX;
+
+            &:nth-of-type(1) {
+                padding-left: 0;
+            }  
+
+            &:not(:last-of-type) {
+                margin-right: $spacing-tabs_bar_slash-marginRight;
+
+                &:after {  
+                    content: "";
+                    margin-left: $spacing-tabs_bar_slash_line_marginLeft;
+                    display: inline-block;
+                    height: $height-tabs_tab_slash_line;
+                    width: $width-tabs_tab_slash_line;
+                    margin-top: $spacing-tabs_bar_slash_line_marginTop;
+                    margin-bottom: $spacing-tabs_bar_slash_line_marginBottom;
+                    vertical-align: bottom;
+                    // Get diagonal slash
+                    background: linear-gradient(to bottom right, transparent 0%, 
+                        transparent calc(50% - 1px), $color-tabs_tab_slash_line 50%,
+                        transparent calc(50% + 1px), transparent 100%);
+                }
+            }
+        }
+    }
+
     &-content {
         width: 100%;
         padding: $spacing-tabs_content-paddingY $spacing-tabs_content-paddingX;

+ 12 - 0
packages/semi-foundation/tabs/variables.scss

@@ -65,6 +65,8 @@ $color-tabs_tab-pane_arrow_disabled-bg-hover:  transparent;
 $color-tabs_tab-pane_arrow_disabled-text-default: var(--semi-color-disabled-text);
 $color-tabs_tab-pane_arrow_disabled-text-hover:  var(--semi-color-disabled-text);
 
+$color-tabs_tab_slash_line: var(--semi-color-text-2); //斜线式页签分割线颜色
+
 $font-tabs_tab-fontWeight: $font-weight-regular; // 页签文本字重 - 默认
 $font-tabs_tab_active-fontWeight: $font-weight-bold; // 页签文本字重 - 选中
 
@@ -79,6 +81,9 @@ $width-tabs-outline-offset: -2px; // 聚焦轮廓偏移宽度
 $width-tabs_bar_line-outline-offset: -1px; // 线条式页签聚焦轮廓偏移宽度
 $width-tabs_tab-pane_arrow-border:0px; // 滚动折叠箭头边框宽度
 
+$width-tabs_tab_slash_line: 8px; // 斜线式页签分割线宽度
+$height-tabs_tab_slash_line: 14px; // 斜线式页签分割线高度
+
 $height-tabs_bar_extra_large: 50px; // 大尺寸页签高度
 $font-tabs_bar_extra_large-lineHeight: $height-tabs_bar_extra_large; // 大尺寸页签文字行高
 
@@ -118,6 +123,13 @@ $spacing-tabs_bar_line_tab_left-padding: 12px; // 垂直线条式页签左侧内
 $spacing-tabs_bar_line_tab_left_small-padding: $spacing-tight - 2px;  // 小尺寸垂直线条式页签左侧内边距
 $spacing-tabs_bar_line_tab_left_medium-padding: $spacing-base-tight - 2px; // 中等尺寸垂直线条式页签左侧内边距
 
+$spacing-tabs_bar_slash_tab-paddingY: 12px; // 斜线式页签上下内边距
+$spacing-tabs_bar_slash_tab-paddingX: 0px; // 斜线式页签水平内边距
+$spacing-tabs_bar_slash-marginRight: 16px; // 斜线式页签右侧外边距
+$spacing-tabs_bar_slash_line_marginLeft: 16px; // 斜线式页签斜线左侧外边距
+$spacing-tabs_bar_slash_line_marginTop: 3px; // 斜线式页签斜线顶部外边距
+$spacing-tabs_bar_slash_line_marginBottom: 3px; // 斜线式页签斜线底部外边距
+
 $spacing-tabs_content-paddingY: 5px; // 页签内容区垂直方向内边距
 $spacing-tabs_content-paddingX: 0; // 页签内容区水平方向内边距
 

+ 18 - 14
packages/semi-foundation/tooltip/foundation.ts

@@ -67,7 +67,8 @@ export interface TooltipAdapter<P = Record<string, any>, S = Record<string, any>
     notifyEscKeydown(event: any): void;
     getTriggerNode(): any;
     setId(): void;
-    getTriggerDOM(): HTMLElement|null
+    getTriggerDOM(): HTMLElement|null;
+    getAnimatingState(): boolean
 }
 
 export type Position = ArrayElement<typeof strings.POSITION_SET>;
@@ -180,7 +181,7 @@ export default class Tooltip<P = Record<string, any>, S = Record<string, any>> e
     _reducePos(position = '') {
         // if cur position consists of two directions, remove the last position
         const found = ['Top', 'Bottom', 'Left', 'Right'].find(pos => position.endsWith(pos));
-        return found ? position.replace(found, ''): position;
+        return found ? position.replace(found, '') : position;
     }
 
     clearDelayTimer() {
@@ -311,6 +312,9 @@ export default class Tooltip<P = Record<string, any>, S = Record<string, any>> e
     };
 
     show = () => {
+        if (this._adapter.getAnimatingState()) {
+            return;
+        }
         const content = this.getProp('content');
         const trigger = this.getProp('trigger');
 
@@ -334,7 +338,7 @@ export default class Tooltip<P = Record<string, any>, S = Record<string, any>> e
             this.calcPosition();
         });
 
-        if (trigger==="hover") {
+        if (trigger === "hover") {
             const checkTriggerIsHover = () => {
                 const triggerDOM = this._adapter.getTriggerDOM();
                 if (trigger && !triggerDOM?.matches?.(":hover")) {
@@ -474,13 +478,13 @@ export default class Tooltip<P = Record<string, any>, S = Record<string, any>> e
         const isWrapperWidthOverflow = wrapperRect.width > innerWidth;
         const scaled = Math.abs(wrapperRect?.width - this._adapter.getContainer()?.clientWidth) > 1;
         if (scaled) {
-            SPACING = SPACING * wrapperRect.width/this._adapter.getContainer().clientWidth;
+            SPACING = SPACING * wrapperRect.width / this._adapter.getContainer().clientWidth;
         }
         switch (position) {
             case 'top':
                 // left = middleX;
                 // top = triggerRect.top - SPACING;
-                left = isWidthOverFlow ? (isTriggerNearLeft ? containerRect.left + wrapperRect.width / 2 : containerRect.right - wrapperRect.width / 2 + offsetWidth): middleX + ANO_SPACING;
+                left = isWidthOverFlow ? (isTriggerNearLeft ? containerRect.left + wrapperRect.width / 2 : containerRect.right - wrapperRect.width / 2 + offsetWidth) : middleX + ANO_SPACING;
                 top = isHeightOverFlow ? containerRect.bottom + offsetHeight : triggerRect.top - SPACING;
                 translateX = -0.5;
                 translateY = -1;
@@ -505,7 +509,7 @@ export default class Tooltip<P = Record<string, any>, S = Record<string, any>> e
                 // top = middleY;
                 // left = isWidthOverFlow? containerRect.right - SPACING : triggerRect.left - SPACING;
                 left = isWidthOverFlow ? containerRect.right + offsetWidth - SPACING + offsetXWithArrow : triggerRect.left - SPACING;
-                top = isHeightOverFlow ? (isTriggerNearTop ? containerRect.top + wrapperRect.height / 2 : containerRect.bottom - wrapperRect.height / 2 + offsetHeight): middleY + ANO_SPACING;
+                top = isHeightOverFlow ? (isTriggerNearTop ? containerRect.top + wrapperRect.height / 2 : containerRect.bottom - wrapperRect.height / 2 + offsetHeight) : middleY + ANO_SPACING;
                 translateX = -1;
                 translateY = -0.5;
                 break;
@@ -519,22 +523,22 @@ export default class Tooltip<P = Record<string, any>, S = Record<string, any>> e
             case 'leftBottom':
                 // left = triggerRect.left - SPACING;
                 // top = pointAtCenter ? middleY + offsetYWithArrow : triggerRect.bottom;
-                left = isWidthOverFlow ? containerRect.right + offsetWidth - SPACING + offsetXWithArrow: triggerRect.left - SPACING;
-                top = isHeightOverFlow ? containerRect.bottom + offsetHeight: (pointAtCenter ? middleY + offsetYWithArrow + ANO_SPACING : triggerRect.bottom + ANO_SPACING);
+                left = isWidthOverFlow ? containerRect.right + offsetWidth - SPACING + offsetXWithArrow : triggerRect.left - SPACING;
+                top = isHeightOverFlow ? containerRect.bottom + offsetHeight : (pointAtCenter ? middleY + offsetYWithArrow + ANO_SPACING : triggerRect.bottom + ANO_SPACING);
                 translateX = -1;
                 translateY = -1;
                 break;
             case 'bottom':
                 // left = middleX;
                 // top = triggerRect.top + triggerRect.height + SPACING;
-                left = isWidthOverFlow ? (isTriggerNearLeft ? containerRect.left + wrapperRect.width / 2 : containerRect.right - wrapperRect.width / 2 + offsetWidth): middleX + ANO_SPACING;
-                top = isHeightOverFlow ? containerRect.top + offsetYWithArrow - SPACING: triggerRect.top + triggerRect.height + SPACING;
+                left = isWidthOverFlow ? (isTriggerNearLeft ? containerRect.left + wrapperRect.width / 2 : containerRect.right - wrapperRect.width / 2 + offsetWidth) : middleX + ANO_SPACING;
+                top = isHeightOverFlow ? containerRect.top + offsetYWithArrow - SPACING : triggerRect.top + triggerRect.height + SPACING;
                 translateX = -0.5;
                 break;
             case 'bottomLeft':
                 // left = pointAtCenter ? middleX - offsetXWithArrow : triggerRect.left;
                 // top = triggerRect.bottom + SPACING;
-                left = isWidthOverFlow ? (isWrapperWidthOverflow ? containerRect.left : containerRect.right - wrapperRect.width ) : (pointAtCenter ? middleX - offsetXWithArrow + ANO_SPACING: triggerRect.left + ANO_SPACING);
+                left = isWidthOverFlow ? (isWrapperWidthOverflow ? containerRect.left : containerRect.right - wrapperRect.width ) : (pointAtCenter ? middleX - offsetXWithArrow + ANO_SPACING : triggerRect.left + ANO_SPACING);
                 top = isHeightOverFlow ? containerRect.top + offsetYWithArrow - SPACING : triggerRect.top + triggerRect.height + SPACING;
                 break;
             case 'bottomRight':
@@ -596,11 +600,11 @@ export default class Tooltip<P = Record<string, any>, S = Record<string, any>> e
         top = top - containerRect.top;
 
         if (scaled) {
-            left /= wrapperRect.width/this._adapter.getContainer().clientWidth;
+            left /= wrapperRect.width / this._adapter.getContainer().clientWidth;
         }
 
         if (scaled) {
-            top /= wrapperRect.height/this._adapter.getContainer().clientHeight;
+            top /= wrapperRect.height / this._adapter.getContainer().clientHeight;
         }
 
         /**
@@ -820,7 +824,7 @@ export default class Tooltip<P = Record<string, any>, S = Record<string, any>> e
             const shouldViewReverseLeft = clientLeft - marginLeft < wrapperRect.width + spacing && restClientRight - marginRight > wrapperRect.width + spacing;
             const shouldViewReverseBottom = restClientBottom - marginBottom < wrapperRect.height + spacing && clientTop - marginTop > wrapperRect.height + spacing;
             const shouldViewReverseRight = restClientRight - marginRight < wrapperRect.width + spacing && clientLeft - marginLeft > wrapperRect.width + spacing;
-            const shouldViewReverseTopOver = restClientTop - marginBottom< wrapperRect.height + spacing && clientBottom - marginTop> wrapperRect.height + spacing;
+            const shouldViewReverseTopOver = restClientTop - marginBottom < wrapperRect.height + spacing && clientBottom - marginTop > wrapperRect.height + spacing;
             const shouldViewReverseBottomOver = clientBottom - marginTop < wrapperRect.height + spacing && restClientTop - marginBottom > wrapperRect.height + spacing;
 
             const shouldViewReverseTopSide = restClientTop < wrapperRect.height + ano_spacing && clientBottom > wrapperRect.height + ano_spacing;

+ 2 - 0
packages/semi-foundation/upload/upload.scss

@@ -347,6 +347,7 @@ $module: #{$prefix}-upload;
             height: $height-upload_file_pic_card;
             width: $width-upload_file_pic_card;
             border-radius: $radius-upload_picture_file_card_img;
+            box-sizing: border-box;
             position: relative;
             overflow: hidden;
 
@@ -474,6 +475,7 @@ $module: #{$prefix}-upload;
             }
 
             &-error {
+                border: 1px solid $color-upload_picture_file_card_error-border;
                 outline: 1px solid $color-upload_picture_file_card_error-border;
             }
 

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

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

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

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

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

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

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

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

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

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

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

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

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

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

+ 11 - 0
packages/semi-ui/avatar/_story/avatar.stories.tsx

@@ -1,7 +1,18 @@
 import * as React from 'react';
 import { storiesOf } from '@storybook/react';
 import Demo from './Demo';
+import Avatar from '../index';
+import AvatarGroup from '../avatarGroup';
 
 const stories = storiesOf('Avatar', module);
 
 stories.add('Avatar', () => <Demo />);
+
+stories.add('Avatar', () => <>
+    <Avatar size={'6rem'} />
+    <Avatar size="small" />
+    <AvatarGroup size="6rem">
+        <Avatar color="red" alt='Lisa LeBlanc'>LL</Avatar>
+        <Avatar alt='Caroline Xiao'>CX</Avatar>
+    </AvatarGroup>
+</>);

+ 2 - 2
packages/semi-ui/avatar/interface.ts

@@ -25,7 +25,7 @@ export interface AvatarProps extends BaseProps {
     children?: React.ReactNode;
     color?: AvatarColor;
     shape?: AvatarShape;
-    size?: AvatarSize;
+    size?: string;
     hoverMask?: React.ReactNode;
     src?: string;
     srcSet?: string;
@@ -68,7 +68,7 @@ export type AvatarGroupOverlapFrom = 'start' | 'end';
 export interface AvatarGroupProps {
     children?: React.ReactNode;
     shape?: AvatarGroupShape;
-    size?: AvatarGroupSize;
+    size?: string;
     overlapFrom?: AvatarGroupOverlapFrom;
     maxCount?: number;
     renderMore?: (restNumber?: number, restAvatars?: React.ReactNode[]) => React.ReactNode

+ 13 - 3
packages/semi-ui/cascader/index.tsx

@@ -378,9 +378,19 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
                 if (loadData) {
                     new Promise<void>(resolve => {
                         loadData(selectedOpt).then(() => {
-                            callback();
-                            this.setState({ loading: false });
-                            resolve();
+                            /** Why update loading status & call callback function in setTimeout?
+                             *  loadData func will update treeData, treeData change may trigger 
+                             *  selectedKeys & activeKeys change. For Loading data asynchronously,
+                             *  activeKeys should not change, Its implementation depends on loading 
+                             *  & loadedKeys. The update time of Loading & loadedKeys(in callback func)
+                             *  should be later than the update time of treeData(in loaData func) 
+                             *  In React 18, we need to use setTimeout to ensure the above time requirements.
+                             * */ 
+                            setTimeout(() => {
+                                callback();
+                                this.setState({ loading: false });
+                                resolve();
+                            })
                         });
                     });
                 }

+ 7 - 1
packages/semi-ui/chat/_story/constant.js

@@ -69,7 +69,13 @@ const infoWithAttachment = [
             {
                 type: 'image_url',
                 image_url: {
-                    url: 'https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/edit-bag.jpeg'
+                    url: 'https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/edit-bag.jpeg',
+                },
+            },
+            {
+                type: 'image_url',
+                image_url: {
+                    url: 'https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/SemiLogo.jpg'
                 },
             }
         ],

+ 18 - 12
packages/semi-ui/chat/chatBox/chatBoxContent.tsx

@@ -47,28 +47,34 @@ const ChatBoxContent = (props: ChatBoxContentProps) => {
                 <span className={`${PREFIX_CHAT_BOX}-content-loading-item`} />
             </span>;
         } else {
-            let realContent = '';
+            let realContent;
             if (typeof content === 'string') {
-                realContent = content;
+                realContent = <MarkdownRender
+                    format='md'
+                    raw={content}
+                    components={markdownComponents as any}
+                />;
             } else if (Array.isArray(content)) {
-                realContent = content.map((item)=> {
+                realContent = content.map((item, index)=> {
                     if (item.type === 'text') {
-                        return item.text;
+                        return <MarkdownRender
+                            key={`index`}
+                            format='md'
+                            raw={item.text}
+                            components={markdownComponents as any}
+                        />;
                     } else if (item.type === 'image_url') {
-                        return `![image](${item.image_url.url})`;
+                        return <ImageAttachment key={`index`} src={item.image_url.url} />;
                     } else if (item.type === 'file_url') {
                         const { name, size, url, type } = item.file_url;
                         const realType = name.split('.').pop() ?? type?.split('/').pop();
-                        return `<SemiFile url={'${url}'} name={'${name}'} size={'${size}'} type={'${realType}'}></SemiFile>`;
+                        return <FileAttachment key={`index`} url={name} name={name} size={size} type={realType}></FileAttachment>;
                     }
-                    return '';
-                }).join('\n\n');
+                    return null;
+                });
             }
             return (<>
-                <MarkdownRender
-                    raw={realContent}
-                    components={markdownComponents as any}
-                />
+                {realContent}
             </>);
         }
     }, [status, content]);

+ 11 - 1
packages/semi-ui/chat/index.tsx

@@ -29,6 +29,7 @@ class Chat extends BaseComponent<ChatProps, ChatState> {
     foundation: ChatFoundation;
     uploadRef: React.RefObject<Upload>;
     dropAreaRef: React.RefObject<HTMLDivElement>;
+    scrollTargetRef: React.RefObject<HTMLElement>;
 
     static propTypes = {
         className: PropTypes.string,
@@ -80,6 +81,7 @@ class Chat extends BaseComponent<ChatProps, ChatState> {
         this.dropAreaRef = React.createRef();
         this.wheelEventHandler = null;
         this.foundation = new ChatFoundation(this.adapter);
+        this.scrollTargetRef = React.createRef();
 
         this.state = {
             backBottomVisible: false,
@@ -144,7 +146,14 @@ class Chat extends BaseComponent<ChatProps, ChatState> {
                     return ;
                 }
                 this.wheelEventHandler = (e: any) => {
-                    if (e.target !== containerElement) {
+                    /**
+                     * Why use this.scrollTargetRef.current and wheel's currentTarget target comparison?
+                     * Both scroll and wheel events are on the container
+                     * his.scrollTargetRef.current is the object where scrolling actually occurs
+                     * wheel's currentTarget is the container,
+                     * Only when the wheel event occurs and there is scroll, the following logic(show scroll bar) needs to be executed
+                     */
+                    if (this.scrollTargetRef?.current !== e.currentTarget) {
                         return;
                     }
                     this.adapter.setWheelScroll(true);
@@ -261,6 +270,7 @@ class Chat extends BaseComponent<ChatProps, ChatState> {
     }
 
     containerScroll = (e: React.UIEvent<HTMLDivElement>) => {
+        (this.scrollTargetRef as any).current = e.target as HTMLElement;
         if (e.target !== e.currentTarget) {
             return;
         }

+ 2 - 0
packages/semi-ui/configProvider/index.tsx

@@ -6,6 +6,8 @@ import Context, { ContextValue } from './context';
 
 export interface ConfigProviderProps extends ContextValue {}
 
+export const ConfigConsumer = Context.Consumer;
+
 export default class ConfigProvider extends React.Component<ConfigProviderProps> {
 
     constructor(props: ConfigProviderProps) {

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

@@ -134,7 +134,7 @@ class Dropdown extends BaseComponent<DropdownProps, DropdownState> {
         return {
             ...super.adapter,
             setPopVisible: (popVisible: boolean) => this.setState({ popVisible }),
-            notifyVisibleChange: (visible: boolean) => this.props.onVisibleChange(visible),
+            notifyVisibleChange: (visible: boolean) => this.props.onVisibleChange?.(visible),
             getPopupId: () => this.tooltipRef.current.getPopupId()
         };
     }

+ 7 - 7
packages/semi-ui/hotKeys/__test__/hotkeys.test.js

@@ -4,10 +4,9 @@ import { noop, drop } from 'lodash';
 import { BASE_CLASS_PREFIX } from '../../../semi-foundation/base/constants';
 import {sleep} from "../../_test_/utils";
 
-function getHK(props) {
-    return mount(<HotKeys {...props}></HotKeys>, {
-        attachTo: document.getElementById('container'),
-    });
+function mount(props) {
+    const container = document.getElementById('container');
+    return testRender(<HotKeys {...props} id={"test"}></HotKeys>, container);
 }
 
 describe('HotKeys', () => {
@@ -34,8 +33,9 @@ describe('HotKeys', () => {
             },
             hotKeys: ['r']
         };
-        const hotkeys = getHK(props);
-        expect(hotkeys.exists(`.${BASE_CLASS_PREFIX}-hotKeys.test`)).toEqual(true);
-        expect(hotkeys.find(`.${BASE_CLASS_PREFIX}-hotKeys`)).toHaveStyle('color', 'red');
+        mount(props);
+
+        expect(Boolean(document.querySelector(`.${BASE_CLASS_PREFIX}-hotKeys.test`))).toEqual(true);
+        expect(document.querySelector(`.${BASE_CLASS_PREFIX}-hotKeys`).style['color']==="red").toEqual(true);
     });
 });

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

@@ -21,6 +21,7 @@ export { default as CheckboxGroup } from './checkbox/checkboxGroup';
 export { default as Collapse } from './collapse';
 export { default as Collapsible } from './collapsible';
 export { default as ConfigProvider } from './configProvider';
+export { ConfigConsumer } from "./configProvider";
 export { default as DatePicker } from './datePicker';
 export { default as Descriptions } from './descriptions';
 export { default as Divider } from './divider';

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

@@ -1,6 +1,6 @@
 {
     "name": "@douyinfe/semi-ui",
-    "version": "2.65.0",
+    "version": "2.66.0-beta.0",
     "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",
     "module": "lib/es/index.js",
@@ -20,11 +20,11 @@
         "@dnd-kit/core": "^6.0.8",
         "@dnd-kit/sortable": "^7.0.2",
         "@dnd-kit/utilities": "^3.2.1",
-        "@douyinfe/semi-animation": "2.65.0",
-        "@douyinfe/semi-animation-react": "2.65.0",
-        "@douyinfe/semi-foundation": "2.65.0",
-        "@douyinfe/semi-icons": "2.65.0",
-        "@douyinfe/semi-illustrations": "2.65.0",
+        "@douyinfe/semi-animation": "2.66.0-beta.0",
+        "@douyinfe/semi-animation-react": "2.66.0-beta.0",
+        "@douyinfe/semi-foundation": "2.66.0-beta.0",
+        "@douyinfe/semi-icons": "2.66.0-beta.0",
+        "@douyinfe/semi-illustrations": "2.66.0-beta.0",
         "@douyinfe/semi-theme-default": "2.61.0",
         "async-validator": "^3.5.0",
         "classnames": "^2.2.6",
@@ -113,6 +113,7 @@
         "through2": "^4.0.2",
         "ts-loader": "^5.4.5",
         "webpack": "^5.77.0",
-        "webpackbar": "^5.0.0-3"
+        "webpackbar": "^5.0.0-3",
+        "@testing-library/react": "^12"
     }
 }

+ 9 - 4
packages/semi-ui/tabs/TabBar.tsx

@@ -161,7 +161,7 @@ class TabBar extends React.Component<TabBarProps, TabBarState> {
                 </div>
             );
         }
-        const { dropdownClassName, dropdownStyle, showRestInDropdown } = this.props;
+        const { dropdownClassName, dropdownStyle, showRestInDropdown, dropdownProps } = this.props;
         const { rePosKey } = this.state;
         const disabled = !items.length;
         const menu = (
@@ -197,6 +197,8 @@ class TabBar extends React.Component<TabBarProps, TabBarState> {
             [`${cssClasses.TABS_BAR}-dropdown`]: true,
         });
 
+        const customDropdownProps = dropdownProps?.[pos] ?? {};
+
         return (
             <>
                 {showRestInDropdown ? (
@@ -211,6 +213,7 @@ class TabBar extends React.Component<TabBarProps, TabBarState> {
                         style={dropdownStyle}
                         trigger={'hover'}
                         disableFocusListener // prevent the panel from popping up again after clicking
+                        {...customDropdownProps}
                     >
                         {button}
                     </Dropdown>
@@ -221,11 +224,12 @@ class TabBar extends React.Component<TabBarProps, TabBarState> {
 
     renderOverflow = (items: any[]): Array<ReactNode> => items.map((item, index) => {
         const pos = index === 0 ? 'start' : 'end';
+        const icon = index === 0 ? <IconChevronLeft/> : <IconChevronRight/>;
+        const overflowNode = this.renderCollapse(item, icon, pos);
         if (this.props.renderArrow) {
-            return this.props.renderArrow(item, pos, ()=>this.handleArrowClick(item, pos));
+            return this.props.renderArrow(item, pos, ()=>this.handleArrowClick(item, pos), overflowNode);
         }
-        const icon = index === 0 ? <IconChevronLeft/> : <IconChevronRight/>;
-        return this.renderCollapse(item, icon, pos);
+        return overflowNode;
     });
 
 
@@ -318,6 +322,7 @@ class TabBar extends React.Component<TabBarProps, TabBarState> {
             [cssClasses.TABS_BAR_LINE]: type === 'line',
             [cssClasses.TABS_BAR_CARD]: type === 'card',
             [cssClasses.TABS_BAR_BUTTON]: type === 'button',
+            [cssClasses.TABS_BAR_SLASH]: type === 'slash',
             [`${cssClasses.TABS_BAR}-${tabPosition}`]: tabPosition,
             [`${cssClasses.TABS_BAR}-collapse`]: collapsible,
         });

+ 1 - 1
packages/semi-ui/tabs/TabItem.tsx

@@ -37,7 +37,7 @@ const TabItem = (props: TabItemProps, ref: LegacyRef<HTMLDivElement>) => {
     } = props;
 
     const closableIcon = useMemo(() => {
-        return (type === 'card' && closable) ?
+        return closable ?
             <IconClose 
                 aria-label="Close" 
                 role="button" 

+ 91 - 6
packages/semi-ui/tabs/_story/tabs.stories.jsx

@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import React, { useState, useCallback } from 'react';
 import Tabs from '../index';
 import Button from '@douyinfe/semi-ui/button/index';
 import Typography from '@douyinfe/semi-ui/typography/index';
@@ -363,12 +363,40 @@ Level2Card.story = {
   name: 'Level 2-卡片Tab',
 };
 
+export const SlashTab = () => {
+  return (
+  <>
+    <Tabs defaultActiveKey="1" type="slash">
+      <TabPane tab="文档" itemKey="1">文档</TabPane>
+      <TabPane tab="快速起步" itemKey="2" disabled>快速起步</TabPane>
+      <TabPane tab="帮助" itemKey="3">帮助</TabPane>
+      <TabPane tab="关于" itemKey="4">关于</TabPane>
+      <TabPane tab="资源工具" itemKey="5">资源工具</TabPane>
+    </Tabs>
+    <br />
+    <br />
+    <Tabs defaultActiveKey="1" type="slash">
+      <TabPane tab={<span><IconFile />文档</span>} itemKey="1">文档</TabPane>
+      <TabPane tab={<span><IconGlobe />快速起步</span>} itemKey="2" disabled>快速起步</TabPane>
+      <TabPane tab={<span><IconHelpCircle />帮助</span>} itemKey="3">帮助</TabPane>
+    </Tabs>
+    <br />
+    <Tabs style={{ width: '400px'}} type="slash" collapsible dropdownProps={{ start: { showTick: false}, end: { showTick: false}}}>
+          {['文档', "快速起步", "帮助", "关于", "资源工具", "主页"].map((i, index) => (
+              <TabPane tab={i} itemKey={i} key={i} >
+                  Content of card tab {i}
+              </TabPane>
+          ))}
+    </Tabs>
+  </>)
+}
+
 export const Level3ButtonTab = () => (
   <Tabs style={style} defaultActiveKey="1" type="button">
     <TabPane tab="文档" itemKey="1">
       文档
     </TabPane>
-    <TabPane tab="快速起步" itemKey="2">
+    <TabPane tab="快速起步" itemKey="2" disabled>
       快速起步
     </TabPane>
     <TabPane tab="帮助" itemKey="3">
@@ -889,11 +917,35 @@ class TabClosableDemo extends React.Component {
 
   render() {
     return (
-      <Tabs type="card" defaultActiveKey="1" onTabClose={this.close.bind(this)}>
+      <>
+        <br />
+        <Tabs type="card" defaultActiveKey="1" onTabClose={this.close.bind(this)}>
           {
-            this.state.tabList.map(t=><TabPane closable={t.closable} tab={t.tab} itemKey={t.itemKey} key={t.itemKey}>{t.text}</TabPane>)
+            this.state.tabList.map(t=><TabPane closable={t.closable} tab={t.tab} itemKey={t.itemKey} key={t.itemKey} >{t.text}</TabPane>)
           }
-      </Tabs>
+        </Tabs>
+        <br />
+        <br />
+        <Tabs type="line" defaultActiveKey="1" onTabClose={this.close.bind(this)}>
+          {
+            this.state.tabList.map(t=><TabPane closable={t.closable} tab={t.tab} itemKey={t.itemKey} key={t.itemKey} >{t.text}</TabPane>)
+          }
+        </Tabs>
+        <br />
+        <br />
+        <Tabs type="button" defaultActiveKey="1" onTabClose={this.close.bind(this)}>
+          {
+            this.state.tabList.map(t=><TabPane closable={t.closable} tab={t.tab} itemKey={t.itemKey} key={t.itemKey} >{t.text}</TabPane>)
+          }
+        </Tabs>
+        <br />
+        <br />
+        <Tabs type="slash" defaultActiveKey="1" onTabClose={this.close.bind(this)}>
+          {
+            this.state.tabList.map(t=><TabPane  closable={t.closable} tab={t.tab} itemKey={t.itemKey} key={t.itemKey} >{t.text}</TabPane>)
+          }
+        </Tabs>
+      </>
     );
   }
 }
@@ -1070,4 +1122,37 @@ export const Fix2415 = () => {
         ))}    
     </Tabs>
   )
-}
+}
+export const DynamicShowArrow = () => {
+  const [hidden, setHidden] = useState(true);
+  const renderArrow = (items, pos, handleArrowClick, defaultNode) => {
+      const style = { visibility: hidden ? 'hidden': 'visible'};
+      return <span style={style}>
+        {defaultNode}
+      </span>
+  };
+  const onVisibleTabsChange = useCallback((visibleState) => {
+      let values = Object.values(Object.fromEntries(visibleState));
+      if (values.includes(false)) {
+          setHidden(false);
+      } else {
+          setHidden(true);
+      }
+  }, []);
+  return (
+      <Tabs
+          renderArrow={renderArrow}
+          style={{ margin: '20px' }}
+          type="line"
+          arrowPosition={"end"}
+          collapsible
+          onVisibleTabsChange={onVisibleTabsChange}
+      >
+          {[0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(i => (
+              <TabPane tab={`Tab-${i}`} itemKey={`Tab-${i}`} key={i}>
+                  Content of card tab {i}
+              </TabPane>
+          ))}
+      </Tabs>
+  );
+};

+ 4 - 1
packages/semi-ui/tabs/index.tsx

@@ -56,6 +56,7 @@ class Tabs extends BaseComponent<TabsProps, TabsState> {
         more: PropTypes.oneOfType([PropTypes.number, PropTypes.object]),
         arrowPosition: PropTypes.string,
         renderArrow: PropTypes.func,
+        dropdownProps: PropTypes.object,
     };
     static __SemiComponentName__ = "Tabs";
     static defaultProps: TabsProps = getDefaultPropsFromGlobalConfig(Tabs.__SemiComponentName__, {
@@ -265,6 +266,7 @@ class Tabs extends BaseComponent<TabsProps, TabsState> {
             visibleTabsStyle,
             arrowPosition,
             renderArrow,
+            dropdownProps,
             ...restProps
         } = this.props;
         const { panes, activeKey } = this.state;
@@ -296,7 +298,8 @@ class Tabs extends BaseComponent<TabsProps, TabsState> {
             onVisibleTabsChange,
             visibleTabsStyle,
             arrowPosition,
-            renderArrow
+            renderArrow,
+            dropdownProps,
         } as TabBarProps;
 
         const tabBar = renderTabBar ? renderTabBar(tabBarProps, TabBar) : <TabBar {...tabBarProps} />;

+ 9 - 4
packages/semi-ui/tabs/interface.ts

@@ -4,7 +4,7 @@ import TabBar, { OverflowItem } from './TabBar';
 import { DropdownProps } from "../dropdown";
 import { OverflowListProps } from "../overflowList";
 
-export type TabType = 'line' | 'card' | 'button';
+export type TabType = 'line' | 'card' | 'button' | 'slash';
 export type TabSize = 'small' | 'medium' | 'large';
 export type TabPosition = 'top' | 'left';
 
@@ -16,6 +16,10 @@ export interface PlainTab {
     closable?: boolean
 }
 
+interface TabsDropDownProps {
+    start: DropdownProps;
+    end: DropdownProps
+}
 
 export interface TabsProps {
     activeKey?: string;
@@ -45,7 +49,8 @@ export interface TabsProps {
     onVisibleTabsChange?: TabBarProps["onVisibleTabsChange"];
     visibleTabsStyle?: TabBarProps['visibleTabsStyle'];
     arrowPosition?: TabBarProps['arrowPosition'];
-    renderArrow?: TabBarProps['renderArrow']
+    renderArrow?: TabBarProps['renderArrow'];
+    dropdownProps?: TabsDropDownProps
 }
 
 export interface TabBarProps {
@@ -69,8 +74,8 @@ export interface TabBarProps {
     onVisibleTabsChange?: (visibleState: Map<string, boolean>) => void;
     visibleTabsStyle?: CSSProperties;
     arrowPosition?: OverflowListProps['overflowRenderDirection'];
-    renderArrow?: (items: OverflowItem[], pos: "start"|"end", handleArrowClick: () => void) => ReactNode
-
+    renderArrow?: (items: OverflowItem[], pos: "start"|"end", handleArrowClick: () => void, defaultNode: ReactNode) => ReactNode;
+    dropdownProps?: TabsDropDownProps
 }
 
 export interface TabPaneProps {

+ 2 - 2
packages/semi-ui/tooltip/__test__/tooltip.test.js

@@ -295,14 +295,14 @@ describe(`Tooltip`, () => {
     });
 
   it(`test click outside handler`, async () => {
-    const containerId = `container`;
-
+    const containerId = `container`
     const demo = mount(
       <div style={{ height: 480, width: 320 }}>
         <div id={containerId}>Hello Semi</div>
         <Tooltip
           content='Content'
           trigger='click'
+          motion={false}
         >
           <Button >Click here</Button>
         </Tooltip>

+ 6 - 3
packages/semi-ui/tooltip/index.tsx

@@ -198,7 +198,7 @@ export default class Tooltip extends BaseComponent<TooltipProps, TooltipState> {
     containerPosition: string;
     foundation: TooltipFoundation;
     context: ContextValue;
-
+    isAnimating: boolean = false;
     constructor(props: TooltipProps) {
         super(props);
         this.state = {
@@ -240,6 +240,7 @@ export default class Tooltip extends BaseComponent<TooltipProps, TooltipState> {
             on: (...args: any[]) => this.eventManager.on(...args),
             // @ts-ignore
             off: (...args: any[]) => this.eventManager.off(...args),
+            getAnimatingState: () => this.isAnimating,
             insertPortal: (content: TooltipProps['content'], { position, ...containerStyle }: { position: Position }) => {
                 this.setState(
                     {
@@ -458,7 +459,7 @@ export default class Tooltip extends BaseComponent<TooltipProps, TooltipState> {
             setId: () => {
                 this.setState({ id: getUuidShort() });
             },
-            getTriggerDOM: ()=>{
+            getTriggerDOM: () => {
                 if (this.triggerEl.current) {
                     return ReactDOM.findDOMNode(this.triggerEl.current as ReactInstance) as HTMLElement;
                 } else {
@@ -473,7 +474,7 @@ export default class Tooltip extends BaseComponent<TooltipProps, TooltipState> {
         this.mounted = true;
         this.getPopupContainer = this.props.getPopupContainer || this.context.getPopupContainer || defaultGetContainer;
         this.foundation.init();
-        runAfterTicks(()=>{
+        runAfterTicks(() => {
             let triggerEle = this.triggerEl.current;
             if (triggerEle) {
                 if (!(triggerEle instanceof HTMLElement)) {
@@ -652,8 +653,10 @@ export default class Tooltip extends BaseComponent<TooltipProps, TooltipState> {
                 animationState={transitionState as "enter" | "leave"}
                 motion={motion && isPositionUpdated}
                 startClassName={transitionState === 'enter' ? `${prefix}-animation-show` : `${prefix}-animation-hide`}
+                onAnimationStart={() => this.isAnimating = true}
                 onAnimationEnd={() => {
                     if (transitionState === 'leave') {
+                        this.isAnimating = false;
                         this.didLeave();
                         this.props.afterClose?.();
                     }

+ 14 - 1
packages/semi-ui/upload/_story/upload.stories.jsx

@@ -1323,4 +1323,17 @@ export const Unmount = () => {
             <button onClick={toggle}>toggle upload mount</button>
         </>
     );
-};
+};
+
+export const fix2448 = () => {
+  let action = 'http://xxx';
+    return (
+        <>
+          <Form>
+            <Form.Upload action={action} listType="picture" accept="image/*" multiple >
+              <IconPlus size="extra-large" />
+            </Form.Upload>
+          </Form>
+        </>
+    );
+}

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

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

+ 148 - 148
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">
     <url>
         <loc>https://juejin.cn/post/7267418854124699702</loc>
-        <lastmod>2024-08-23T10:54:30.076Z</lastmod>
+        <lastmod>2024-09-02T09:53:28.292Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://medium.com/front-end-weekly/how-we-test-semi-design-component-libraries-64b854f63b65</loc>
-        <lastmod>2024-08-23T10:54:29.367Z</lastmod>
+        <lastmod>2024-09-02T09:53:26.514Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://mp.weixin.qq.com/s/noHoWRuA25PgqFNcurhIUA</loc>
-        <lastmod>2024-08-23T10:54:32.871Z</lastmod>
+        <lastmod>2024-09-02T09:53:28.468Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://mp.weixin.qq.com/s/O3js-SZDNPEOjGxh-aAkbw</loc>
-        <lastmod>2024-08-23T10:54:32.852Z</lastmod>
+        <lastmod>2024-09-02T09:53:29.571Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
@@ -790,77 +790,77 @@
     </url>
     <url>
         <loc>https://semi.design/en-US/basic/divider</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/basic/grid</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/basic/icon</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/basic/layout</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/basic/space</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/basic/tokens</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/basic/typography</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/feedback/banner</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/feedback/notification</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/feedback/popconfirm</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/feedback/progress</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/feedback/skeleton</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/feedback/spin</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/feedback/toast</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/input/autocomplete</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
@@ -870,362 +870,362 @@
     </url>
     <url>
         <loc>https://semi.design/en-US/input/cascader</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/input/checkbox</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/input/datepicker</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/input/form</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/input/input</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/input/inputnumber</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/input/radio</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/input/rating</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/input/select</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/input/slider</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/input/switch</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/input/taginput</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/input/timepicker</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/input/transfer</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/input/treeselect</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/input/upload</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/navigation/anchor</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/navigation/backtop</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/navigation/breadcrumb</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/navigation/navigation</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/navigation/pagination</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/navigation/steps</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/navigation/tabs</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/navigation/tree</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/other/configprovider</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/other/locale</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/show/avatar</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/show/badge</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/show/calendar</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/show/card</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/show/carousel</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/show/collapse</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/show/collapsible</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/show/descriptions</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/show/dropdown</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/show/empty</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/show/highlight</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/show/image</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/show/list</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/show/modal</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/show/overflowlist</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/show/popover</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/show/scrolllist</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/show/sidesheet</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/show/table</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/show/tag</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/show/timeline</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/show/tooltip</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/start/accessibility</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/start/changelog</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/start/customize-theme</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/start/dark-mode</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/start/faq</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/start/getting-started</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/start/introduction</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/start/overview</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/en-US/start/update-to-v2</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/basic/divider</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/basic/grid</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/basic/icon</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/basic/layout</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/basic/space</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/basic/tokens</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/basic/typography</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/feedback/banner</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/feedback/notification</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/feedback/popconfirm</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/feedback/progress</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/feedback/skeleton</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/feedback/spin</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/feedback/toast</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/input/autocomplete</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
@@ -1235,287 +1235,287 @@
     </url>
     <url>
         <loc>https://semi.design/zh-CN/input/cascader</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/input/checkbox</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/input/datepicker</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/input/form</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/input/input</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/input/inputnumber</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/input/radio</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/input/rating</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/input/select</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/input/slider</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/input/switch</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/input/taginput</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/input/timepicker</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/input/transfer</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/input/treeselect</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/input/upload</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/navigation/anchor</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/navigation/backtop</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/navigation/breadcrumb</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/navigation/navigation</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/navigation/pagination</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/navigation/steps</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/navigation/tabs</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/navigation/tree</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/other/configprovider</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/other/locale</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/show/avatar</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/show/badge</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/show/calendar</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/show/card</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/show/carousel</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/show/collapse</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/show/collapsible</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/show/descriptions</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/show/dropdown</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/show/empty</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/show/highlight</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/show/image</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/show/list</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/show/modal</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/show/overflowlist</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/show/popover</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/show/scrolllist</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/show/sidesheet</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/show/table</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/show/tag</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/show/timeline</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/show/tooltip</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/start/accessibility</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/start/changelog</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/start/customize-theme</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/start/dark-mode</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/start/faq</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/start/getting-started</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/start/introduction</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/start/overview</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
     <url>
         <loc>https://semi.design/zh-CN/start/update-to-v2</loc>
-        <lastmod>2024-08-23T10:43:56.000Z</lastmod>
+        <lastmod>2024-09-02T09:38:49.000Z</lastmod>
         <changefreq>weekly</changefreq>
     </url>
 </urlset>

+ 20 - 0
syncRegistry.sh

@@ -0,0 +1,20 @@
+#!/bin/bash
+
+## 提示用户输入URL
+read -p "请输入同步的源(例如: registry.npmjs.org): " url
+#
+## 使用python -m webbrowser访问输入的URL
+python -m webbrowser https://$url/sync/@douyinfe/semi-ui
+python -m webbrowser https://$url/sync/@douyinfe/semi-foundation
+python -m webbrowser https://$url/sync/@douyinfe/semi-animation
+python -m webbrowser https://$url/sync/@douyinfe/semi-animation-react
+python -m webbrowser https://$url/sync/@douyinfe/semi-animation-styled
+python -m webbrowser https://$url/sync/@douyinfe/semi-icons
+python -m webbrowser https://$url/sync/@douyinfe/semi-icons-lab
+python -m webbrowser https://$url/sync/@douyinfe/semi-illustrations
+python -m webbrowser https://$url/sync/@douyinfe/semi-next
+python -m webbrowser https://$url/sync/@douyinfe/semi-rspack-plugin
+python -m webbrowser https://$url/sync/@douyinfe/semi-scss-compile
+python -m webbrowser https://$url/sync/@douyinfe/semi-theme-default
+python -m webbrowser https://$url/sync/@douyinfe/semi-webpack-plugin
+

+ 2 - 1
test/setup.js

@@ -4,7 +4,7 @@ import React from 'react';
 import sinon from 'sinon';
 import enzymeToJson from 'enzyme-to-json';
 import jest from 'jest';
-
+import { render as testRender } from '@testing-library/react';
 import jsdom from 'jsdom';
 import crypto from 'crypto';
 import { advanceBy, advanceTo, clear } from 'jest-date-mock';
@@ -42,6 +42,7 @@ global.shallow = shallow;
 global.render = render;
 global.mount = mount;
 global.sinon = sinon;
+global.testRender = testRender
 
 Object.defineProperty(global.self, 'crypto', {
     value: {

File diff suppressed because it is too large
+ 280 - 342
yarn.lock


Some files were not shown because too many files changed in this diff