Browse Source

Merge branch 'release' into main

linyan 2 years ago
parent
commit
06e5e0cc39
98 changed files with 1261 additions and 234 deletions
  1. 1 1
      content/feedback/banner/index-en-US.md
  2. 1 1
      content/feedback/banner/index.md
  3. 1 1
      content/feedback/notification/index-en-US.md
  4. 1 1
      content/feedback/notification/index.md
  5. 1 1
      content/feedback/popconfirm/index-en-US.md
  6. 1 1
      content/feedback/popconfirm/index.md
  7. 1 1
      content/feedback/progress/index-en-US.md
  8. 1 1
      content/feedback/progress/index.md
  9. 1 1
      content/feedback/skeleton/index-en-US.md
  10. 1 1
      content/feedback/skeleton/index.md
  11. 1 1
      content/feedback/spin/index-en-US.md
  12. 1 1
      content/feedback/spin/index.md
  13. 1 1
      content/feedback/toast/index-en-US.md
  14. 1 1
      content/feedback/toast/index.md
  15. 3 3
      content/input/form/index-en-US.md
  16. 1 1
      content/input/form/index.md
  17. 46 2
      content/navigation/navigation/index-en-US.md
  18. 95 47
      content/navigation/navigation/index.md
  19. 1 0
      content/order.js
  20. 1 1
      content/other/configprovider/index-en-US.md
  21. 1 1
      content/other/configprovider/index.md
  22. 1 1
      content/other/locale/index-en-US.md
  23. 1 1
      content/other/locale/index.md
  24. 109 0
      content/show/highlight/index-en-US.md
  25. 127 0
      content/show/highlight/index.md
  26. 1 1
      content/show/image/index-en-US.md
  27. 2 1
      content/show/image/index.md
  28. 1 1
      content/show/list/index-en-US.md
  29. 1 1
      content/show/list/index.md
  30. 1 1
      content/show/modal/index-en-US.md
  31. 1 1
      content/show/modal/index.md
  32. 1 1
      content/show/overflowlist/index-en-US.md
  33. 1 1
      content/show/overflowlist/index.md
  34. 1 1
      content/show/popover/index-en-US.md
  35. 1 1
      content/show/popover/index.md
  36. 1 1
      content/show/scrolllist/index-en-US.md
  37. 1 1
      content/show/scrolllist/index.md
  38. 1 1
      content/show/sidesheet/index-en-US.md
  39. 1 1
      content/show/sidesheet/index.md
  40. 1 1
      content/show/table/index-en-US.md
  41. 1 1
      content/show/table/index.md
  42. 1 1
      content/show/tag/index-en-US.md
  43. 1 1
      content/show/tag/index.md
  44. 1 1
      content/show/timeline/index-en-US.md
  45. 1 1
      content/show/timeline/index.md
  46. 1 1
      content/show/tooltip/index-en-US.md
  47. 1 1
      content/show/tooltip/index.md
  48. 22 0
      content/start/changelog/index-en-US.md
  49. 22 0
      content/start/changelog/index.md
  50. 7 6
      content/start/dark-mode/index-en-US.md
  51. 5 3
      content/start/dark-mode/index.md
  52. 2 1
      content/start/overview/index-en-US.md
  53. 2 1
      content/start/overview/index.md
  54. 124 26
      gatsby-node.js
  55. 2 2
      lerna.json
  56. 2 2
      packages/semi-animation-react/package.json
  57. 2 2
      packages/semi-animation-styled/package.json
  58. 2 2
      packages/semi-animation/package.json
  59. 2 2
      packages/semi-eslint-plugin/package.json
  60. 7 0
      packages/semi-foundation/highlight/constants.ts
  61. 11 0
      packages/semi-foundation/highlight/highlight.scss
  62. 5 0
      packages/semi-foundation/highlight/variables.scss
  63. 9 5
      packages/semi-foundation/image/previewInnerFoundation.ts
  64. 2 2
      packages/semi-foundation/package.json
  65. 2 2
      packages/semi-icons/package.json
  66. 2 2
      packages/semi-illustrations/package.json
  67. 2 2
      packages/semi-next/package.json
  68. 2 2
      packages/semi-scss-compile/package.json
  69. 2 2
      packages/semi-theme-default/package.json
  70. 4 0
      packages/semi-theme-default/scss/global.scss
  71. 2 2
      packages/semi-ui/_utils/index.tsx
  72. 159 0
      packages/semi-ui/form/_story/FieldProps/name.jsx
  73. 7 0
      packages/semi-ui/form/_story/form.stories.jsx
  74. 8 4
      packages/semi-ui/form/hoc/withField.tsx
  75. 41 0
      packages/semi-ui/highlight/_story/highlight.stories.jsx
  76. 20 0
      packages/semi-ui/highlight/_story/highlight.stories.tsx
  77. 1 0
      packages/semi-ui/highlight/index-en-US.md
  78. 1 0
      packages/semi-ui/highlight/index.md
  79. 70 0
      packages/semi-ui/highlight/index.tsx
  80. 43 0
      packages/semi-ui/image/__test__/imagePreview.test.js
  81. 2 1
      packages/semi-ui/image/image.tsx
  82. 1 0
      packages/semi-ui/image/index.tsx
  83. 2 0
      packages/semi-ui/image/interface.tsx
  84. 2 1
      packages/semi-ui/image/previewImage.tsx
  85. 63 23
      packages/semi-ui/image/previewInner.tsx
  86. 1 1
      packages/semi-ui/index.ts
  87. 5 5
      packages/semi-ui/modal/Modal.tsx
  88. 11 1
      packages/semi-ui/navigation/Item.tsx
  89. 5 1
      packages/semi-ui/navigation/SubNav.tsx
  90. 40 0
      packages/semi-ui/navigation/_story/Popup/index.jsx
  91. 6 0
      packages/semi-ui/navigation/_story/navigation.stories.jsx
  92. 12 5
      packages/semi-ui/navigation/index.tsx
  93. 6 2
      packages/semi-ui/navigation/nav-context.ts
  94. 8 8
      packages/semi-ui/package.json
  95. 0 21
      packages/semi-ui/select/_story/select.stories.jsx
  96. 2 2
      packages/semi-webpack/package.json
  97. 4 0
      src/images/docIcons/doc-highlight.svg
  98. 74 0
      yarn.lock

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

@@ -1,6 +1,6 @@
 ---
 localeCode: en-US
-order: 65
+order: 66
 category: Feedback
 title:  Banner
 subTitle: Banner

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

@@ -1,6 +1,6 @@
 ---
 localeCode: zh-CN
-order: 65
+order: 66
 category: 反馈类
 title:  Banner 通知横幅
 icon: doc-banner

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

@@ -1,6 +1,6 @@
 ---
 localeCode: en-US
-order: 66
+order: 67
 category: Feedback
 title:  Notification
 subTitle: Notification

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

@@ -1,6 +1,6 @@
 ---
 localeCode: zh-CN
-order: 66
+order: 67
 category: 反馈类
 title: Notification 通知
 icon: doc-notification

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

@@ -1,6 +1,6 @@
 ---
 localeCode: en-US
-order: 67
+order: 68
 category: Feedback
 title:  Popconfirm
 subTitle: Popconfirm

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

@@ -1,6 +1,6 @@
 ---
 localeCode: zh-CN
-order: 67
+order: 68
 category: 反馈类
 title:  Popconfirm 气泡确认框
 icon: doc-popconfirm

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

@@ -1,6 +1,6 @@
 ---
 localeCode: en-US
-order: 68
+order: 69
 category: Feedback
 title: Progress
 subTitle: Progress

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

@@ -1,6 +1,6 @@
 ---
 localeCode: zh-CN
-order: 68
+order: 69
 category: 反馈类
 title: Progress 进度条
 icon: doc-progress

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

@@ -1,6 +1,6 @@
 ---
 localeCode: en-US
-order: 69
+order: 70
 category: Feedback
 title: Skeleton
 subTitle: Skeleton

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

@@ -1,6 +1,6 @@
 ---
 localeCode: zh-CN
-order: 69
+order: 70
 category: 反馈类
 title: Skeleton 骨架屏
 icon: doc-skeleton

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

@@ -1,6 +1,6 @@
 ---
 localeCode: en-US
-order: 70
+order: 71
 category: Feedback
 title: Spin
 subTitle: Spin

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

@@ -1,6 +1,6 @@
 ---
 localeCode: zh-CN
-order: 70
+order: 71
 category: 反馈类
 title: Spin 加载器
 icon: doc-spin

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

@@ -1,6 +1,6 @@
 ---
 localeCode: en-US
-order: 71
+order: 72
 category: Feedback
 title: Toast
 subTitle: Toast

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

@@ -1,6 +1,6 @@
 ---
 localeCode: zh-CN
-order: 71
+order: 72
 category: 反馈类
 title: Toast 提示
 icon: doc-toast

+ 3 - 3
content/input/form/index-en-US.md

@@ -1726,18 +1726,18 @@ import { Form, Button } from '@douyinfe/semi-ui';
 | labelAlign            | Text-align of the label text of this field                                                                                                                                                                                               | string                                 |           |
 | labelWidth            | The width of the label text of this field                                                                                                                                                                                                | string\|number                         |           |
 | noLabel               | When you don't need to add label automatically, you can set this value to true                                                                                                                                                           | boolean                                |           |
-| name                  | Field name. When passed in, the corresponding className will be automatically added to the corresponding field div, such as: money => '.semi-form-field-money'                                                                           | string                                 |           |
+| name                  | Field name. When passed in, the corresponding className will be automatically added to the field wrapper div, such as: money => '.semi-form-field-money'. After v2.24, the name will also be transparently transmitted to the underlying component for consumption. For example, you can configure the name attribute of input                                                                           | string                                 |           |
 | fieldClassName        | The className of the entire fieldWrapper is the same as the name parameter, except that the prefix is ​​not automatically appended                                                                                                       | string                                 |           |
 | fieldStyle            | The inline style of the entire fieldWrapper <br/>**since v1.9.0**                                                                                                      | object                                 |           |
 | initValue             | The initial value of the field (consumed only once when Field mounted, subsequent updates are invalid), it has higher priority than the values ​​in Form's initValues ​​                                                                 | any(type depends on current component) |           |
 | validate              | The custom validation function for this form control. Supports synchronous and asynchronous verification. <br/> Rules does not take effect when validate is set                                                                           | function(fieldValue, values)           |           | (fieldValue) => fieldValue.length>5? 'error balabala': ''          |
 | rules                 | validation rules, validation library based on [async-validator](https://github.com/yiminghe/async-validator)                                                                                                                             | array                                  |           | const rules = \[{type:' string ', message:' invalidate string'} \] |
 | validateStatus        | The validation result status of this form control, optional: `success` / `error` / `warning` / `default`                                                                                                                                 | string                                 | 'default' |
-| trigger               | The timing of triggering the verification, optional: `blur` / `change` / `custom` / `mount` <br/> 1. When set to custom, only formApi will trigger the verification <br/> 2mount (triggered once when mounting)                          | string                                 | 'change'  |
+| trigger               | The timing of triggering the verification, optional: `blur` / `change` / `custom` / `mount` <br/> 1. When set to custom, only formApi will trigger the verification <br/> 2.mount (triggered once when mounting)                          | string                                 | 'change'  |
 | onChange              | Callback invoked when this field value changes                                                                                                                                                                                           |
 | transform             | transform field values before validation                                                                                                                                                                                                 | function(fieldValue)                   |           | (value) => Number(value)                                           |
 | allowEmptyString      | Whether to allow values to be empty strings. <br/>When the value is '' by default, the key corresponding to this field will be removed from `values`. <br/>If you want to keep the key, you need to set allowEmptyString to true           | boolean                                |           | false                                                              |
-| convert               | After the field value changes, before rerender, update the value of filed                                                                                                                                                                | function(fieldValue)                   |           | (value) => newValue(value)                                         |
+| convert               | After the field value changes, before rerender, update the value of filed                                                                                                                                                                | function(fieldValue)                   |           | (value) => newValue                                        |
 | stopValidateWithError | When it is true, the rules check is used. After encountering the first rule that fails the check, it will no longer trigger the check of subsequent rules<br/>**since v0.35.0**                                                          | boolean                                |           | false                                                              |
 | helpText              | Custom prompt information, which is displayed in the same block as the verification information. When both have values, the verification information is displayed first<br/>**since v1.0.0**                                             | ReactNode                              |           |                                                                    |
 | extraText             | Additional prompt information, you can use this when both error information and prompt copy are required, after helpText/errorMessage<br/>**since v1.0.0**                                                                               | ReactNode                              |           |                                                                    |

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

@@ -2048,7 +2048,7 @@ import { Form, Button } from '@douyinfe/semi-ui';
 | labelWidth            | 该表单控件的 label 文本的 width。在Form与Field上同时传入时,以Field props为准                                                                                                                         | string\|number                                                                                |
 | noLabel               | 当你不需要自动添加 label 时,可以将该值置为 true                                                                                                                                                                    | boolean                                                                                       |
 | noErrorMessage        | 当你不需要自动添加 ErrorMessage 模块时,可以将该值置为 true,注意此时 helpText 也不会被展示                                                                                                                         | boolean                                                                                       |
-| name                  | 控件名称,传入时会自动在对应 field 的 div 中追加对应的 className,如:abc => '.semi-form-field-abc'                                                                                                             | string                                                                                        |
+| name                  | 控件名称,传入时会自动在对应 field wrapper div 追加对应的 className,如:abc => '.semi-form-field-abc' v2.24 后,还会将 name 透传至底层组件消费,例如你可以用于配置 input的name属性                                                                                                            | string                                                                                        |
 | fieldClassName        | 整个 fieldWrapper 的 className,作用与 name 参数一致,区别是不会自动追加前缀                                                                                                                                        | string                                                                                        |
 | fieldStyle            | 整个 fieldWrapper 的 内联样式<br/> **v1.15.0开始提供**                                                                                                                                        | object                                                                                        |
 | initValue             | 该表单控件的初始值(仅在 Field mounted 时消费一次,后续更新无效),相比 Form 的 initValues 中的值,它的优先级更高                                                                                                   | any(类型取决于当前组件,详细见各组件的 api)                                                 |

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

@@ -227,6 +227,47 @@ class NavApp extends React.Component {
 
 ```
 
+### Use react-router like router lib
+
+In order to use routing components such as react-router, NavItem can be wrapped in the Link or NavLink provided by the routing component to let users click NavItem to trigger the routing component. We need to customize rendering.
+
+Use renderWrapper to customize navigation components in each navigation item. [See CodeSandBox demo](https://codesandbox.io/s/semi-navigation-with-react-router-9kk9dm?file=/src/App.js)
+```jsx
+import { Link } from "react-router-dom";
+
+()=>{
+    return <Nav
+        renderWrapper={({ itemElement, isSubNav, isInSubNav, props }) => {
+            const routerMap = {
+                Home: "/",
+                About: "/about",
+                Dashboard: "/dashboard",
+                "Nothing Here": "/nothing-here"
+            };
+            return (
+                <Link
+                    style={{ textDecoration: "none" }}
+                    to={routerMap[props.itemKey]}
+                >
+                    {itemElement}
+                </Link>
+            );
+        }}
+        items={[
+            { itemKey: "Home", text: "Home" },
+            { itemKey: "About", text: "About" },
+            {
+                text: "Sub",
+
+                itemKey: "Sub",
+                items: ["Dashboard", "Nothing Here"]
+            }
+        ]}
+    ></Nav>
+}
+```
+
+
 ### Navigation Direction
 
 Navigation currently offers navigation in two directions:
@@ -688,22 +729,25 @@ function NavApp (props = {}) {
 ### Nav
 
 | Properties          | Type                                                                                                                                                                                       | Description                                                                                                                      | Default    |
-| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------- | ---------- |
+| ------------------- |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -------------------------------------------------------------------------------------------------------------------------------- | ---------- |
 | bodyStyle           | Custom style for navigation item list                                                                                                                                                      | object                                                                                                                           |            |
 | className           | Style name of outermost element                                                                                                                                                            | boolean                                                                                                                          |            |
 | defaultIsCollapsed  | Whether the default is put away, valid only when `mode = "vertical"`                                                                                                                       | boolean                                                                                                                          | false      |
 | defaultOpenKeys     | Initially open sub navigation `itemKey` array, valid only `mode = "vertical"`and the sidebar is in an expanded state                                                                       | string[]                                                                                                                         | []         |
 | defaultSelectedKeys | Originally selected navigation item `itemKey` array                                                                                                                                        | string[]                                                                                                                         | []         |
 | footer              | The bottom area configure objects or elements, see [Nav.Footer](#Nav.Footer)                                                                                                               | object\|ReactNode                                                                                                                |            |
+| getPopupContainer   | Dropdown's getPopupContainer config of vertical collapsed Nav or horizontal Nav. >= v2.24     | Function |                      |
 | header              | Head area configuration objects or elements, see [Nav.Header](#Nav.Header)                                                                                                                 | object\|ReactNode                                                                                                                |            |
 | isCollapsed         | A controlled attribute of whether it is in a put-away state, valid only when `mode = "vertical"`                                                                                           | boolean                                                                                                                          |            |
 | items               | Navigate the list of items, each item can continue with the items property. If it is a string array, each item is taken as text and itemKey                                                | object\|string[]\|[Item](#Nav.Item)[]\|[Sub](#Nav.Sub)[]                                                                         |            |
-| mode                | Navigation type, currently supports horizontal and vertical, optional value: `vertical`\|`horizontal`                                                                                      | string                                                                                                                           | `vertical` |
+| mode                | Navigation type, currently supports horizontal and vertical, optional value: `vertical`\                                                                                                   |`horizontal`                                                                                      | string                                                                                                                           | `vertical` |
 | onClick             | Trigger when clicking on any navigation item                                                                                                                                               | ({ itemKey: string, domEvent: MouseEvent, isOpen: boolean }) => void                                                             | () = > {}  |
 | onCollapseChange    | The callback when the state changes.                                                                                                                                                       | (is Collapsed: boolean) => void                                                                                                  | () = > {}  |
 | onOpenChange        | Triggers when switching the hidden state of a sub navigation project                                                                                                                       | ({ itemKey: string, openKeys: string[], domEvent: MouseEvent, isOpen: boolean }) => void                                         | () = > {}  |
 | onSelect            | Triggers the first time you select an optional navigation project, where the selected Items field version > = 0.17.0 is supported                                                          | ({ itemKey: string, selectedKeys: string[], selectedItems: [Item](#Nav.Item)[], domEvent: MouseEvent, isOpen: boolean }) => void | () = > {}  |
 | openKeys            | Controlled open sub navigation `itemKey` array, expanded with `onOpenChange` callback control sub navigation items, valid only `mode = "vertical"`and the sidebar is in an unfolding state | string[]                                                                                                                         |            |
+| renderWrapper       | Custom navigation item outer component  >=2.24.0                                                                                                                                           | (data:{ itemElement:ReactElement, isSubNav:boolean, isInSubNav:boolean, props:SubNavProps\| ItemProps })=>ReactNode | |
+| prefixCls           | classsname prefix                                                                                                                                                                          | string                                                                                                                                                              | `semi`                  |
 | selectedKeys        | Controlled navigation item `itemKey` array, with `onSelect` callback control navigation item selection                                                                                     | string[]                                                                                                                         |            |
 | style               | Custom styles for outermost elements                                                                                                                                                       | object                                                                                                                           |            |
 | subNavCloseDelay    | Delay of sub navigation floating layer closure. Effective when the limit is true or mode is "limit" in MS                                                                                  | number                                                                                                                           | 100        |

+ 95 - 47
content/navigation/navigation/index.md

@@ -113,7 +113,7 @@ class NavApp extends React.Component {
 ```jsx live=true dir="column"
 import React from 'react';
 import { Nav } from '@douyinfe/semi-ui';
-import { IconUser, IconStar, IconSetting } from '@douyinfe/semi-icons';
+import { IconUser, IconStar, IconSetting, IconSemiLogo } from '@douyinfe/semi-icons';
 
 class NavApp extends React.Component {
     render() {
@@ -133,7 +133,7 @@ class NavApp extends React.Component {
                 ]}
                 onSelect={key => console.log(key)}
                 header={{
-                    logo: <img src="https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/webcast_logo.svg" />,
+                    logo: <IconSemiLogo style={{ height: '36px', fontSize: 36 }} />,
                     text: 'Semi 运营后台'
                 }}
                 footer={{
@@ -154,7 +154,7 @@ Navigation 目前提供了个两个参数用于定义导航样式:`style` 和
 ```jsx live=true dir="column"
 import React from 'react';
 import { Nav } from '@douyinfe/semi-ui';
-import { IconUser, IconStar, IconSetting, IconFolder } from '@douyinfe/semi-icons';
+import { IconUser, IconStar, IconSetting, IconFolder, IconSemiLogo } from '@douyinfe/semi-icons';
 
 class NavApp extends React.Component {
     render() {
@@ -181,7 +181,7 @@ class NavApp extends React.Component {
                 ]}
                 onSelect={key => console.log(key)}
                 header={{
-                    logo: <img src="https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/webcast_logo.svg" />,
+                    logo: <IconSemiLogo style={{ height: '36px', fontSize: 36 }} />,
                     text: 'Semi 运营后台'
                 }}
                 footer={{
@@ -200,7 +200,7 @@ class NavApp extends React.Component {
 ```jsx live=true dir="column"
 import React from 'react';
 import { Nav } from '@douyinfe/semi-ui';
-import { IconStar, IconUser, IconUserGroup } from '@douyinfe/semi-icons';
+import { IconStar, IconUser, IconUserGroup, IconSemiLogo } from '@douyinfe/semi-icons';
 
 class NavApp extends React.Component {
     render() {
@@ -211,7 +211,7 @@ class NavApp extends React.Component {
                 onSelect={data => console.log('trigger onSelect: ', data)}
                 onClick={data => console.log('trigger onClick: ', data)}
             >
-                <Nav.Header logo={<img src="https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/webcast_logo.svg" />} text={'Semi 运营后台'} />
+                <Nav.Header logo={<IconSemiLogo style={{ height: '36px', fontSize: 36 }} />} text={'Semi 运营后台'} />
                 <Nav.Item itemKey={'union'} text={'活动管理'} icon={<IconStar />} />
                 <Nav.Sub itemKey={'user'} text="用户管理" icon={<IconUser />}>
                     <Nav.Item itemKey={'active'} text={'活跃用户'} />
@@ -230,6 +230,52 @@ class NavApp extends React.Component {
 
 ```
 
+###  配合 react-router 等路由组件
+
+为了在使用 react-router 等路由组件时,能将 NavItem 包裹在路由组件提供的 Link 或者 NavLink 中来让用户点击 NavItem 时候触发路由组件的点击事件, 我们需要自定义渲染。
+
+使用 renderWrapper 在每个导航项外包裹自定义导航组件 [查看此 CodeSandBox](https://codesandbox.io/s/semi-navigation-with-react-router-9kk9dm?file=/src/App.js)
+
+```jsx
+import { Link } from "react-router-dom";
+import React from 'react';
+import { Nav } from '@douyinfe/semi-ui';
+
+() => {
+    return (
+        <Nav
+            renderWrapper={({ itemElement, isSubNav, isInSubNav, props }) => {
+                const routerMap = {
+                    Home: "/",
+                    About: "/about",
+                    Dashboard: "/dashboard",
+                    "Nothing Here": "/nothing-here"
+                };
+                return (
+                    <Link
+                        style={{ textDecoration: "none" }}
+                        to={routerMap[props.itemKey]}
+                    >
+                        {itemElement}
+                    </Link>
+                );
+            }}
+            items={[
+                { itemKey: "Home", text: "Home" },
+                { itemKey: "About", text: "About" },
+                {
+                    text: "Sub",
+                    itemKey: "Sub",
+                    items: ["Dashboard", "Nothing Here"]
+                }
+            ]}
+        ></Nav>
+    );
+}
+```
+
+
+
 ### 导航方向
 
 Navigation 目前提供两种方向的导航:
@@ -249,7 +295,7 @@ Navigation 目前提供两种方向的导航:
 ```jsx live=true dir="column"
 import React from 'react';
 import { Nav } from '@douyinfe/semi-ui';
-import { IconStar, IconUser, IconUserGroup, IconSetting } from '@douyinfe/semi-icons';
+import { IconStar, IconUser, IconUserGroup, IconSetting, IconSemiLogo } from '@douyinfe/semi-icons';
 
 class NavApp extends React.Component {
     render() {
@@ -275,7 +321,7 @@ class NavApp extends React.Component {
                     ]}
                     onSelect={key => console.log(key)}
                     header={{
-                        logo: <img src="https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/webcast_logo.svg" />,
+                        logo: <IconSemiLogo style={{ height: '36px', fontSize: 36 }} />,
                         text: 'Semi 运营后台'
                     }}
                     footer={{
@@ -293,7 +339,7 @@ class NavApp extends React.Component {
 ```jsx live=true dir="column"
 import React from 'react';
 import { Nav, Avatar, Dropdown } from '@douyinfe/semi-ui';
-import { IconStar, IconUser, IconUserGroup, IconSetting, IconEdit } from '@douyinfe/semi-icons';
+import { IconStar, IconUser, IconUserGroup, IconSetting, IconEdit, IconSemiLogo } from '@douyinfe/semi-icons';
 
 class NavApp extends React.Component {
     render() {
@@ -329,7 +375,7 @@ class NavApp extends React.Component {
                     ]}
                     onSelect={key => console.log(key)}
                     header={{
-                        logo: <img src="https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/webcast_logo.svg" />,
+                        logo: <IconSemiLogo style={{ height: '36px', fontSize: 36 }} />,
                         text: 'Semi 运营后台'
                     }}
                     footer={
@@ -360,7 +406,7 @@ class NavApp extends React.Component {
 ```jsx live=true dir="column"
 import React from 'react';
 import { Nav, Avatar, Dropdown, Select, Button } from '@douyinfe/semi-ui';
-import { IconStar, IconUser, IconUserGroup, IconSetting, IconEdit, IconLanguage } from '@douyinfe/semi-icons';
+import { IconStar, IconUser, IconUserGroup, IconSetting, IconEdit, IconLanguage, IconSemiLogo } from '@douyinfe/semi-icons';
 
 class NavApp extends React.Component {
     constructor() {
@@ -407,7 +453,7 @@ class NavApp extends React.Component {
                 mode={'horizontal'}
                 onSelect={key => console.log(key)}
                 header={{
-                    logo: <img src="https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/webcast_logo.svg" />,
+                    logo: <IconSemiLogo style={{ height: '36px', fontSize: 36 }} />,
                     text: 'Semi 运营后台'
                 }}
                 footer={
@@ -468,7 +514,7 @@ class NavApp extends React.Component {
 ```jsx live=true dir=column
 import React from 'react';
 import { Nav } from '@douyinfe/semi-ui';
-import { IconUser, IconStar, IconSetting } from '@douyinfe/semi-icons';
+import { IconUser, IconStar, IconSetting, IconSemiLogo } from '@douyinfe/semi-icons';
 
 class NavApp extends React.Component {
     render() {
@@ -489,7 +535,7 @@ class NavApp extends React.Component {
                 ]}
                 onSelect={key => console.log(key)}
                 header={{
-                    logo: <img src="https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/webcast_logo.svg" />,
+                    logo: <IconSemiLogo style={{ height: '36px', fontSize: 36 }} />,
                     text: 'Semi 运营后台'
                 }}
                 footer={{
@@ -513,7 +559,7 @@ limitIndent 只在 竖直方向生效
 ```jsx live=true dir=column
 import React from 'react';
 import { Nav } from '@douyinfe/semi-ui';
-import { IconUser, IconStar, IconSetting } from '@douyinfe/semi-icons';
+import { IconUser, IconStar, IconSetting, IconSemiLogo } from '@douyinfe/semi-icons';
 
 class NavApp extends React.Component {
     render() {
@@ -545,7 +591,7 @@ class NavApp extends React.Component {
                 ]}
                 onSelect={key => console.log(key)}
                 header={{
-                    logo: <img src="https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/webcast_logo.svg" />,
+                    logo: <IconSemiLogo style={{ height: '36px', fontSize: 36 }} />,
                     text: 'Semi 运营后台'
                 }}
                 footer={{
@@ -569,7 +615,7 @@ class NavApp extends React.Component {
 ```jsx live=true dir="column"
 import React from 'react';
 import { Nav } from '@douyinfe/semi-ui';
-import { IconUser, IconStar, IconUserGroup, IconSetting } from '@douyinfe/semi-icons';
+import { IconUser, IconStar, IconUserGroup, IconSetting, IconSemiLogo } from '@douyinfe/semi-icons';
 
 class NavApp extends React.Component {
     render() {
@@ -596,7 +642,7 @@ class NavApp extends React.Component {
                     },
                 ]}
                 header={{
-                    logo: <img src="https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/webcast_logo.svg" />,
+                    logo: <IconSemiLogo style={{ height: '36px', fontSize: 36 }} />,
                     text: 'Semi 运营后台'
                 }}
                 footer={{
@@ -628,7 +674,7 @@ Navigation 组件提供了几个受控属性,配合各种回调,可以很轻
 ```jsx live=true dir="column"
 import React, { useMemo, useState } from 'react';
 import { Nav } from '@douyinfe/semi-ui';
-import { IconUser, IconStar, IconUserGroup, IconSetting } from '@douyinfe/semi-icons';
+import { IconUser, IconStar, IconUserGroup, IconSetting, IconSemiLogo } from '@douyinfe/semi-icons';
 
 function NavApp (props = {}) {
     const [openKeys, setOpenKeys] = useState(['union-management', 'job']);
@@ -673,7 +719,7 @@ function NavApp (props = {}) {
             bodyStyle={{ height: 360 }}
             items={items}
             header={{
-                logo: <img src="https://sf6-cdn-tos.douyinstatic.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/webcast_logo.svg" />,
+                logo: <IconSemiLogo style={{ height: '36px', fontSize: 36 }} />,
                 text: 'Semi 运营后台'
             }}
             footer={{
@@ -691,33 +737,35 @@ function NavApp (props = {}) {
 
 ### Nav
 
-| 属性                | 描述                                                                                                                             | 类型                                                                                                                           | 默认值     |
-| ------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | ---------- |
-| bodyStyle           | 导航项列表的自定义样式                                                                             | CSSProperties                                                                                                                           |           |
-| className           | 最外层元素的样式名                                                                               | string                                                                                                                          |           |
-| defaultIsCollapsed  | 默认是否处于收起状态,仅 `mode = "vertical"` 时有效                                                    | boolean                                                                                                                          | false     |
-| defaultOpenKeys     | 初始打开的子导航 `itemKey` 数组,仅 `mode = "vertical"` 且侧边栏处于展开状态时有效                               | string[]                                                                                                                         | []        |
-| defaultSelectedKeys | 初始选中的导航项 `itemKey` 数组                                                                   | string[]                                                                                                                         | []        |
-| footer              | 底部区域配置对象或元素,详见 [Nav.Footer](#Nav.Footer)                                                | object\| ReactNode |                      |
-| header              | 头部区域配置对象或元素,详见 [Nav.Header](#Nav.Header)                                                | object\| ReactNode |                      |
-| isCollapsed         | 是否处于收起状态的受控属性,仅 `mode = "vertical"` 时有效                                                 | boolean                                                                                                                          |           |
-| items               | 导航项目列表,每一项可以继续带有 items 属性。如果为 string 数组,则会取每一项作为 text 和 itemKey                         | object\| string[] \| [Item](#Nav.Item)[] \| [Sub](#Nav.Sub)[] |  |
-| limitIndent         | 解除缩进限制,可使用 level 自定义导航项缩进,水平模式只能为true >=1.27.0                                          | boolean                                                                                                                          | true      |
-| mode                | 导航类型,目前支持横向与竖直,可选值:`vertical`/| `horizontal`                                                                                                                     | string    | `vertical`           |
-| openKeys            | 受控的打开的子导航 `itemKey` 数组,配合 `onOpenChange` 回调控制子导航项展开,仅 `mode = "vertical"` 且侧边栏处于展开状态时有效 | string[]                                                                                                                         |           |
-| prefixCls           | 类名前缀                                                                                    | string                                                                                                                           | `semi`    |
-| selectedKeys        | 受控的导航项 `itemKey` 数组,配合 `onSelect` 回调控制导航项选择                                             | string[]                                                                                                                         |           |
-| style               | 最外层元素的自定义样式                                                                             |         CSSProperties                                                                                                                         |           |
-| subNavCloseDelay    | 子导航浮层关闭的延迟。collapse 为 true 或 mode 为 "horizontal" 时有效,单位为 ms                             | number                                                                                                                           | 100       |
-| subNavMotion        | 子导航折叠动画                                                                                 | boolean                                                                                                                          | true      |
-| subNavOpenDelay     | 子导航浮层显示的延迟。collapse 为 true 或 mode 为 "horizontal" 时有效,单位为 ms                             | number                                                                                                                           | 0         |
-| toggleIconPosition  | 带有子导航项的的父级导航项箭头位置 >=1.27.0                                                              | 'left' \| 'right'   | 'right'              |
-| tooltipHideDelay    | tooltip 隐藏的延迟,collapse 为 true 时有效,单位为 ms                                                | number                                                                                                                           | 100       |
-| tooltipShowDelay    | tooltip 显示的延迟,collapse 为 true 时有效,单位为 ms                                                | number                                                                                                                           | 0         |
-| onClick             | 点击任意导航项时触发                                                                              |<ApiType detail='({ itemKey: string, domEvent: MouseEvent, isOpen: boolean }) => void'>(itemKey, event, isOpen)=> void </ApiType>                                                                | () => {}  |
-| onCollapseChange    | 收起状态变化时的回调                                                                              |<ApiType detail='(isCollapsed: boolean) => void'>(isCollapsed)=>{} </ApiType>                                                                                                     | () => {}  |
-| onOpenChange        | 切换某个子导航项目显隐状态时触发                                                                    | <ApiType detail='({ itemKey: string, openKeys: string[], domEvent: MouseEvent, isOpen: boolean }) => void'> ({itemKey, openKeys, event, isOpen})=>{}</ApiType>                                      | () => {}  |
-| onSelect            | 第一次选中某个可选中导航项目时触发,其中 selectedItems 这个字段版本 >= 0.17.0 后才支持 | <ApiType detail='({ itemKey: string, selectedKeys: string[], selectedItems: Item[], domEvent: MouseEvent, isOpen: boolean }) => void'>(onSelectProps)=>{}</ApiType> | () => {}  |
+| 属性                  | 描述                                                                                      | 类型                                                                                                                                                                  | 默认值                     |
+|---------------------|-----------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------|
+| bodyStyle           | 导航项列表的自定义样式                                                                             | CSSProperties                                                                                                                                                       |                         |
+| className           | 最外层元素的样式名                                                                               | string                                                                                                                                                              |                         |
+| defaultIsCollapsed  | 默认是否处于收起状态,仅 `mode = "vertical"` 时有效                                                    | boolean                                                                                                                                                             | false                   |
+| defaultOpenKeys     | 初始打开的子导航 `itemKey` 数组,仅 `mode = "vertical"` 且侧边栏处于展开状态时有效                               | string[]                                                                                                                                                            | []                      |
+| defaultSelectedKeys | 初始选中的导航项 `itemKey` 数组                                                                   | string[]                                                                                                                                                            | []                      |
+| footer              | 底部区域配置对象或元素,详见 [Nav.Footer](#Nav.Footer)                                                | object\                                                                                                                                                             | ReactNode               |                      |
+| getPopupContainer   | 垂直 Nav 折叠或 水平 Nav中 Dropdown 的 getPopupContainer 配置,可指定弹出层容器, >=2.24.0                        | Function |                      |
+| header              | 头部区域配置对象或元素,详见 [Nav.Header](#Nav.Header)                                                | object\                                                                                                                                                             | ReactNode               |                      |
+| isCollapsed         | 是否处于收起状态的受控属性,仅 `mode = "vertical"` 时有效                                                 | boolean                                                                                                                                                             |                         |
+| items               | 导航项目列表,每一项可以继续带有 items 属性。如果为 string 数组,则会取每一项作为 text 和 itemKey                         | object\                                                                                                                                                             | string[] \              | [Item](#Nav.Item)[] \| [Sub](#Nav.Sub)[] |  |
+| limitIndent         | 解除缩进限制,可使用 level 自定义导航项缩进,水平模式只能为true >=1.27.0                                          | boolean                                                                                                                                                             | true                    |
+| mode                | 导航类型,目前支持横向与竖直,可选值:`vertical`/                                                          | `horizontal`                                                                                                                                                        | string                  | `vertical`           |
+| openKeys            | 受控的打开的子导航 `itemKey` 数组,配合 `onOpenChange` 回调控制子导航项展开,仅 `mode = "vertical"` 且侧边栏处于展开状态时有效 | string[]                                                                                                                                                            |                         |
+| prefixCls           | 类名前缀                                                                                    | string                                                                                                                                                              | `semi`                  |
+| renderWrapper       | 自定义导航项外层组件  >=2.24.0                                                                    | (data:{ itemElement:ReactElement, isSubNav:boolean, isInSubNav:boolean, props:SubNavProps\| ItemProps })=>ReactNode | |
+| selectedKeys        | 受控的导航项 `itemKey` 数组,配合 `onSelect` 回调控制导航项选择                                             | string[]                                                                                                                                                            |                         |
+| style               | 最外层元素的自定义样式                                                                             | CSSProperties                                                                                                                                                       |                         |
+| subNavCloseDelay    | 子导航浮层关闭的延迟。collapse 为 true 或 mode 为 "horizontal" 时有效,单位为 ms                             | number                                                                                                                                                              | 100                     |
+| subNavMotion        | 子导航折叠动画                                                                                 | boolean                                                                                                                                                             | true                    |
+| subNavOpenDelay     | 子导航浮层显示的延迟。collapse 为 true 或 mode 为 "horizontal" 时有效,单位为 ms                             | number                                                                                                                                                              | 0                       |
+| toggleIconPosition  | 带有子导航项的的父级导航项箭头位置 >=1.27.0                                                              | 'left' \                                                                                                                                                            | 'right'                 | 'right'              |
+| tooltipHideDelay    | tooltip 隐藏的延迟,collapse 为 true 时有效,单位为 ms                                                | number                                                                                                                                                              | 100                     |
+| tooltipShowDelay    | tooltip 显示的延迟,collapse 为 true 时有效,单位为 ms                                                | number                                                                                                                                                              | 0                       |
+| onClick             | 点击任意导航项时触发                                                                              | <ApiType detail='({ itemKey: string, domEvent: MouseEvent, isOpen: boolean }) => void'>(itemKey, event, isOpen)=> void </ApiType>                                   | () => {}                |
+| onCollapseChange    | 收起状态变化时的回调                                                                              | <ApiType detail='(isCollapsed: boolean) => void'>(isCollapsed)=>{} </ApiType>                                                                                       | () => {}                |
+| onOpenChange        | 切换某个子导航项目显隐状态时触发                                                                        | <ApiType detail='({ itemKey: string, openKeys: string[], domEvent: MouseEvent, isOpen: boolean }) => void'> ({itemKey, openKeys, event, isOpen})=>{}</ApiType>      | () => {}                |
+| onSelect            | 第一次选中某个可选中导航项目时触发,其中 selectedItems 这个字段版本 >= 0.17.0 后才支持                                | <ApiType detail='({ itemKey: string, selectedKeys: string[], selectedItems: Item[], domEvent: MouseEvent, isOpen: boolean }) => void'>(onSelectProps)=>{}</ApiType> | () => {}                |
 
 ### Nav.Item
 

+ 1 - 0
content/order.js

@@ -52,6 +52,7 @@ const order = [
     'descriptions',
     'dropdown',
     'empty',
+    'highlight',
     'image',
     'list',
     'modal',

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

@@ -1,6 +1,6 @@
 ---
 localeCode: en-US
-order: 72
+order: 73
 category: Other
 title: ConfigProvider
 icon: doc-configprovider

+ 1 - 1
content/other/configprovider/index.md

@@ -1,6 +1,6 @@
 ---
 localeCode: zh-CN
-order: 72
+order: 73
 category: 其他
 title:  ConfigProvider 全局配置
 icon: doc-configprovider

+ 1 - 1
content/other/locale/index-en-US.md

@@ -1,6 +1,6 @@
 ---
 localeCode: en-US
-order: 73
+order: 74
 category: Other
 title: LocaleProvider
 subTitle: LocaleProvider

+ 1 - 1
content/other/locale/index.md

@@ -1,6 +1,6 @@
 ---
 localeCode: zh-CN
-order: 73
+order: 74
 category: 其他
 title:  LocaleProvider 多语言
 icon: doc-i18n

+ 109 - 0
content/show/highlight/index-en-US.md

@@ -0,0 +1,109 @@
+---
+localeCode: en-US
+order: 54
+category: Show
+title: Highlight 
+icon: doc-highlight
+dir: column
+noInline: true
+brief: highlight specific content
+---
+
+## code demo
+
+### How to import
+
+Semi support `Highlight` component since v2.24.0
+
+```jsx import
+import { Highlight } from '@douyinfe/semi-ui';
+```
+
+
+### Basic usage
+
+You can specify keywords to be highlighted with `searchWords` and source text with `sourceString`
+
+
+```jsx live=true dir="column"
+import React from 'react';
+import { Highlight } from '@douyinfe/semi-ui';
+
+() => {
+    const sourceString = 'From Semi Design,To Any Design. Quickly define your design system and apply it to design drafts and code';
+    const searchWords = ['Any Design', 'Semi Design'];
+    
+    return (<h2>
+        <Highlight sourceString={sourceString} searchWords={searchWords} />
+    </h2>);
+};
+```
+
+### Specify highlight style
+
+By default, the highlighted text will have its own text style, the text color is black, and the background color is `--semi-yellow-4`.  
+In dark mode, the text color is white, and the background color is `--semi-yellow-2`.  
+When you need to customize different highlight styles, you can specify them through `highlightClassName`, `highlightStyle`
+
+```jsx live=true dir="column"
+import React from 'react';
+import { Highlight } from '@douyinfe/semi-ui';
+
+() => {
+    const sourceString = 'From Semi Design,To Any Design. Quickly define your design system and apply it to design drafts and code';
+    const searchWords = ['Any Design', 'Semi Design'];
+    
+    return (<h2>
+        <Highlight
+            sourceString={sourceString}
+            searchWords={searchWords}
+            highlightStyle={{
+                borderRadius: 6,
+                marginLeft: 4,
+                marginRight: 4,
+                paddingLeft: 4,
+                paddingRight: 4,
+                backgroundColor: 'rgba(var(--semi-teal-5), 1)',
+                color: 'rgba(var(--semi-white), 1)'
+            }}
+        />
+    </h2>);
+};
+```
+
+
+### Specify the highlight tag
+
+Semi will wrap the text matching searchWords in sourceString with mark tag by default, you can also re-specify the tag through `component`
+
+```jsx live=true dir="column"
+import React from 'react';
+import { Highlight } from '@douyinfe/semi-ui';
+
+() => {
+    const sourceString = 'From Semi Design,To Any Design. Quickly define your design system and apply it to design drafts and code';
+    const searchWords = ['Any Design', 'Semi Design'];
+    
+    return (<h2>
+        <Highlight
+            sourceString={sourceString}
+            searchWords={searchWords}
+            component='strong'
+        />
+    </h2>);
+};
+```
+
+## API Reference
+
+### Highlight
+
+| property | description | type | default value |
+| ------------ | ------------------------------------ -------------------- | ----------------------------- --- | ---------- |
+| searchWords | expected highlighted text | string[] | '' |
+| sourceString | source text | string | |
+| component | Highlight label | string | `mark` |
+| highlightClassName | The style class name of the highlight tag | ReactNode | - |
+| highlightStyle | Inline style for highlight tags | ReactNode | - |
+| caseSensitive | Is case sensitive | false | - |
+| autoEscape | Whether to automatically escape | true | - |

+ 127 - 0
content/show/highlight/index.md

@@ -0,0 +1,127 @@
+---
+localeCode: zh-CN
+order: 54
+category: 展示类
+title: Highlight 高亮文本
+icon: doc-highlight
+dir: column
+noInline: true
+brief: 高亮特定内容
+---
+
+## 代码演示
+
+### 如何引入
+
+Highlight 从 v2.24.0 版本开始支持
+
+```jsx import
+import { Highlight } from '@douyinfe/semi-ui';
+```
+
+### 基本用法
+
+你可以通过 `searchWords` 指定需要高亮的关键字,通过 `sourceString` 指定源文本
+
+
+```jsx live=true dir="column"
+import React from 'react';
+import { Highlight } from '@douyinfe/semi-ui';
+
+() => {
+    const sourceString = '从 Semi Design 到 Any Design  快速定义你的设计系统,并应用在设计稿和代码中';
+    const searchWords = ['设计系统', 'Semi Design'];
+    
+    return (<h2>
+        <Highlight sourceString={sourceString} searchWords={searchWords} />
+    </h2>);
+};
+```
+
+### 指定高亮样式
+
+默认情况下,高亮文本会自带文本样式,背景颜色 --semi-yellow-4, 文本颜色为黑色  
+暗色模式下,背景颜色为 --semi-yellow-2,文本颜色为白色   
+当你需要自定义不同的高亮样式时,你可以通过 `highlightClassName`, `highlightStyle`来指定 
+
+```jsx live=true dir="column"
+import React from 'react';
+import { Highlight } from '@douyinfe/semi-ui';
+
+() => {
+    const sourceString = '从 Semi Design 到 Any Design 快速定义你的设计系统,并应用在设计稿和代码中';
+    const searchWords = ['设计系统', 'Semi Design'];
+    
+    return (
+        <>
+            <h2>
+                <Highlight
+                    sourceString={sourceString}
+                    searchWords={searchWords}
+                    highlightStyle={{
+                        borderRadius: 6,
+                        marginLeft: 4,
+                        marginRight: 4,
+                        paddingLeft: 4,
+                        paddingRight: 4,
+                        backgroundColor: 'rgba(var(--semi-teal-5), 1)',
+                        color: 'rgba(var(--semi-white), 1)'
+                    }}
+                />
+            </h2>
+            <h2>
+                <Highlight
+                    sourceString={sourceString}
+                    searchWords={searchWords}
+                    highlightStyle={{
+                        borderRadius: 6,
+                        marginLeft: 4,
+                        marginRight: 4,
+                        paddingLeft: 4,
+                        paddingRight: 4,
+                        backgroundColor: 'var(--semi-color-primary)',
+                        color: 'rgba(var(--semi-white), 1)'
+                    }}
+                />
+            </h2>
+        </>
+    );
+};
+```
+
+
+### 指定高亮标签
+
+Semi 默认会将 sourceString 中与 searchWords 匹配的文本用 mark 标签包裹,你也可以通过 `component` 重新指定标签
+
+```jsx live=true dir="column"
+import React from 'react';
+import { Highlight } from '@douyinfe/semi-ui';
+
+() => {
+    const sourceString = '从 Semi Design 到 Any Design  快速定义你的设计系统,并应用在设计稿和代码中';
+    const searchWords = ['设计系统', 'Semi Design'];
+    
+    return (<h2>
+        <Highlight
+            sourceString={sourceString}
+            searchWords={searchWords}
+            component='strong'
+        />
+    </h2>);
+};
+```
+
+## API 参考
+
+### Highlight
+
+| 属性         | 说明                                                     | 类型                             | 默认值     |
+| ------------ | -------------------------------------------------------- | -------------------------------- | ---------- |
+| searchWords  | 期望高亮显示的文本                                          | string[]                          | ''   |
+| sourceString | 源文本                                      | string                           |           |
+| component   | 高亮标签                                              | string                           | `mark`          |
+| highlightClassName | 高亮标签的样式类名                                         | ReactNode                        | -          |
+| highlightStyle   | 高亮标签的内联样式                                                 | ReactNode                        | -          |
+| caseSensitive    | 是否大小写敏感                                            | false  | -          |
+| autoEscape       | 是否自动转义                                                | true                        | -          |

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

@@ -1,6 +1,6 @@
 ---
 localeCode: en-US
-order: 54
+order: 55
 category: Show
 title: Image
 icon: doc-image

+ 2 - 1
content/show/image/index.md

@@ -1,6 +1,6 @@
 ---
 localeCode: zh-CN
-order: 54
+order: 55
 category: 展示类
 title: Image 图片
 icon: doc-image
@@ -444,6 +444,7 @@ import { Image, ImagePreview } from '@douyinfe/semi-ui';
 | className         | 自定义样式类名            | string           | - | |
 | closable          | 是否显示关闭按钮           | boolean        | true | |
 | closeOnEsc        | 点击 esc 关闭预览         | boolean        | true | |
+| crossOrigin       | 透传给预览图片的原生 img 标签的 crossorigin  | 'anonymous'|'use-credentials'| - | |
 | currentIndex      | 受控属性,当前预览图片下标  | number               | - | |
 | defaultCurrentIndex | 首次展示图片下标        | number             | - | |
 | defaultVisible    | 首次是否开启预览           | boolean         | - | |

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

@@ -1,6 +1,6 @@
 ---
 localeCode: en-US
-order: 55
+order: 56
 category: Show
 title: List
 subTitle: List

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

@@ -1,6 +1,6 @@
 ---
 localeCode: zh-CN
-order: 55
+order: 56
 category: 展示类
 title: List 列表
 icon: doc-list

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

@@ -1,6 +1,6 @@
 ---
 localeCode: en-US
-order: 56
+order: 57
 category: Show
 title:  Modal
 subTitle: Modal

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

@@ -1,6 +1,6 @@
 ---
 localeCode: zh-CN
-order: 56
+order: 57
 category: 展示类
 title: Modal 模态对话框
 icon: doc-modal

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

@@ -1,6 +1,6 @@
 ---
 localeCode: en-US
-order: 57
+order: 58
 category: Show
 title: OverflowList
 subTitle: OverflowList

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

@@ -1,6 +1,6 @@
 ---
 localeCode: zh-CN
-order: 57
+order: 58
 category: 展示类
 title: OverflowList 折叠列表
 icon: doc-overflowList

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

@@ -1,6 +1,6 @@
 ---
 localeCode: en-US
-order: 58
+order: 59
 category: Show
 title: Popover
 subTitle: Popover

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

@@ -1,6 +1,6 @@
 ---
 localeCode: zh-CN
-order: 58
+order: 59
 category: 展示类
 title: Popover 气泡卡片
 icon: doc-popover

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

@@ -1,6 +1,6 @@
 ---
 localeCode: en-US
-order: 59
+order: 60
 category: Show
 title:  ScrollList
 subTitle: ScrollList

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

@@ -1,6 +1,6 @@
 ---
 localeCode: zh-CN
-order: 59
+order: 60
 category: 展示类
 title: ScrollList 滚动列表
 icon: doc-scrolllist

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

@@ -1,6 +1,6 @@
 ---
 localeCode: en-US
-order: 60
+order: 61
 category: Show
 title: SideSheet
 subTitle: SideSheet

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

@@ -1,6 +1,6 @@
 ---
 localeCode: zh-CN
-order: 60
+order: 61
 category: 展示类
 title: SideSheet 滑动侧边栏
 icon: doc-sidesheet

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

@@ -1,6 +1,6 @@
 ---
 localeCode: en-US
-order: 61
+order: 62
 category: Show
 title: Table
 subTitle: Table

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

@@ -1,6 +1,6 @@
 ---
 localeCode: zh-CN
-order: 61
+order: 62
 category: 展示类
 title: Table 表格
 icon: doc-table

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

@@ -1,6 +1,6 @@
 ---
 localeCode: en-US
-order: 62
+order: 63
 category: Show
 title: Tag
 subTitle: Tag

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

@@ -1,6 +1,6 @@
 ---
 localeCode: zh-CN
-order: 62
+order: 63
 category: 展示类
 title: Tag 标签
 icon: doc-tag

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

@@ -1,6 +1,6 @@
 ---
 localeCode: en-US
-order: 63
+order: 64
 category: Show
 title:  Timeline
 subTitle: Timeline

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

@@ -1,6 +1,6 @@
 ---
 localeCode: zh-CN
-order: 63
+order: 64
 category: 展示类
 title: Timeline 时间轴
 icon: doc-timeline

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

@@ -1,6 +1,6 @@
 ---
 localeCode: en-US
-order: 64
+order: 65
 category: Show
 title: Tooltip
 subTitle: Tooltip

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

@@ -1,6 +1,6 @@
 ---
 localeCode: zh-CN
-order: 64
+order: 65
 category: 展示类
 title: Tooltip 工具提示
 icon: doc-tooltip

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

@@ -23,6 +23,28 @@ Version:Major.Minor.Patch (follow the **Semver** specification)
 - 【Fix】
     - Fix the problem when trigger be blocked the wrapper did not offset in Tooltip
 
+#### 🎉 2.24.0-beta.1 (2022-11-22)
+- 【Style】
+    - Adjust Highlight style, default highlight background
+    - Design Token : `@douyinfe/semi-theme-default` add global design Token `--semi-color-highlight-bg`、`--semi-color-highlight`
+
+#### 🎉 2.24.0-beta.0 (2022-11-21)
+- 【New Component】
+    - Add Highlight Component [#1281](https://github.com/DouyinFE/semi-design/pull/1281)
+- 【Feat】
+    - Nav add getPopupContainer, can be used to specify a popover container in partial dark mode [#1277 ](https://github.com/DouyinFE/semi-design/issues/1277)
+    - ImagePreview added crossOrigin parameter  [#1284 ](https://github.com/DouyinFE/semi-design/issues/1284)
+    - The Form Field component transparently transmitting props.name to the underlying component for consumption, and no longer intercepts. The original influence on the field wrapper classname remains  [#1266](https://github.com/DouyinFE/semi-design/issues/1266)
+    - Navigation adds renderWrapper API for easier use of routing libraries such as react-router [#1249](https://github.com/DouyinFE/semi-design/pull/1249)
+- 【Perf】
+    - Cache the FieldComponent component in the withField HOC to avoid repeated calculation of components in the default shouldMemo scenario and reduce repeated performance consumption in complex form scenarios [#1228](https://github.com/DouyinFE/semi-design/pull/1228)
+- 【Style】
+    - Modify the style of TagInput used in Cascader/TreeSelect [#1278](https://github.com/DouyinFE/semi-design/pull/1278)
+- 【Fix】
+    - Fix the problem that when the Image component is previewing the image, the mouse wheel event will penetrate the popup layer, causing the content scrolling problem under the popup layer [#1289](https://github.com/DouyinFE/semi-design/pull/1289) [@edc-hui](https://github.com/edc-hui)
+    - Remove TimePicker console.log [@jukrb0x](https://github.com/jukrb0x)
+    - Fix the issue that in the Select radio mode, when the filter is enabled, when you click to select to close the list, it will flash once  [#1207](https://github.com/DouyinFE/semi-design/issues/1207)
+
 #### 🎉 2.23.3 (2022-11-15)
 - 【Style】
     - Form Design Token is updated,`$spacing-form_label_extra_posBottom-marginTop`、`$spacing-form_label_extra_posMid-marginBottom`、`$spacing-form_label_extra_posMid-marginTop` is corrected to more semantically `$spacing-form_extra_posBottom-marginTop`、`$spacing-form_extra_posMid-marginBottom`、`$spacing-form_extra_posMid-marginTop` [#1272](https://github.com/DouyinFE/semi-design/pull/1272)

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

@@ -23,6 +23,28 @@ Semi 版本号遵循 **Semver** 规范(主版本号-次版本号-修订版本
 - 【Fix】
     - 修复 Tooltip trigger 被遮挡时弹层也被遮挡问题
 
+#### 🎉 2.24.0-beta.1 (2022-11-22)
+- 【Style】
+    - 调整 Highlight 样式, 默认背景高亮
+    - Design Token 调整,@douyinfe/semi-theme-default 新增全局Token `--semi-color-highlight-bg`、`--semi-color-highlight`
+
+#### 🎉 2.24.0-beta.0 (2022-11-21)
+- 【New Component】
+    - 新增 Highlight 组件 [#1281](https://github.com/DouyinFE/semi-design/pull/1281)
+- 【Feat】
+    - Nav 支持透传 getPopupContainer,可用于局部暗色模式下指定弹出层容器,  [#1277](https://github.com/DouyinFE/semi-design/issues/1277)
+    - ImagePreview 新增 crossOrigin 参数  [#1284 ](https://github.com/DouyinFE/semi-design/issues/1284)
+    - Form Field 组件增加将 props.name 透传至底层组件消费的功能,不再进行拦截(可影响 Form.Input、Form.Upload、Form.CheckboxGroup、Form.RadioGroup 及其他用 withField 封装的自定义组件)。原有对 field wrapper classname 的影响依然保留  [#1266](https://github.com/DouyinFE/semi-design/issues/1266)
+    - Navigation 新增 renderWrapper API 用于更便捷地与 react-router、next、gatsby 等路由库结合 [#1249](https://github.com/DouyinFE/semi-design/pull/1249)
+- 【Perf】
+    - 缓存 withField HOC 中的 FieldComponent 组件,在默认 shouldMemo 场景下避免组件重复计算,降低复杂表单场景下带来的重复性能消耗 [#1228](https://github.com/DouyinFE/semi-design/pull/1228)
+- 【Style】
+    - 修改 Cascader/TreeSelect 中用到的 TagInput 的样式 [#1278](https://github.com/DouyinFE/semi-design/pull/1278)
+- 【Fix】
+    - 修复 Image 组件在预览图片的时候,鼠标滚轮事件会穿透弹层,导致弹层之下的内容滚动问题 [#1289](https://github.com/DouyinFE/semi-design/pull/1289) [@edc-hui](https://github.com/edc-hui)
+    - TimePicker 在生产环境输出 console log [@jukrb0x](https://github.com/jukrb0x)
+    - 修复 Select 单选模式下,filter 开启情况下,点击选择收起列表时,会闪烁一次的问题 [#1207](https://github.com/DouyinFE/semi-design/issues/1207)
+
 #### 🎉 2.23.3 (2022-11-15)
 - 【Style】
     - Form 组件 Design Token 修正,`$spacing-form_label_extra_posBottom-marginTop`、`$spacing-form_label_extra_posMid-marginBottom`、`$spacing-form_label_extra_posMid-marginTop`更正为更符合语义的 `$spacing-form_extra_posBottom-marginTop`、`$spacing-form_extra_posMid-marginBottom`、`$spacing-form_extra_posMid-marginTop`,并更正相关文档描述 [#1272](https://github.com/DouyinFE/semi-design/pull/1272)

+ 7 - 6
content/start/dark-mode/index-en-US.md

@@ -53,7 +53,7 @@ function Demo() {
             // Notify our site to update current mode
             window.setMode('dark');
         }
-    }
+    };
 
     return (
         <Button
@@ -100,9 +100,8 @@ Semi 2.0 natively supports block dark/bright color mode, and you can add `.semi-
 
 ```jsx live=true dir="column" hideInDSM
 import React from 'react';
-import { Layout, Nav, Button, Breadcrumb, Skeleton, Avatar } from '@douyinfe/semi-ui';
-import { IconSemiLogo, IconBell, IconHelpCircle, IconBytedanceLogo, IconHome, IconHistogram, IconLive, IconSetting } from '@douyinfe/semi-icons';
-
+import { Layout, Nav, Button, Breadcrumb, Avatar, Steps, Pagination, Row, Badge, Tag, Rating, Tooltip, Timeline, Popover } from '@douyinfe/semi-ui';
+import { IconSemiLogo, IconCamera, IconBell, IconHelpCircle, IconBytedanceLogo, IconHome, IconHistogram, IconLive, IconSetting, IconEdit, IconList } from '@douyinfe/semi-icons';
 () => {
     const { Header, Footer, Sider, Content } = Layout;
     const [mode, setMode] = useState('semi-always-dark');
@@ -210,8 +209,10 @@ import { IconSemiLogo, IconBell, IconHelpCircle, IconBytedanceLogo, IconHome, Ic
                             }}
                         >
                             <Row style={rowStyle}>
+                                <div id='popup-layer'></div>
                                 <Nav
                                     mode={'horizontal'}
+                                    getPopupContainer={() => document.querySelector('#popup-layer')}
                                     items={[
                                         { itemKey: 'user', text: 'Option1', icon: <IconEdit /> },
                                         { itemKey: 'union', text: 'Option2', icon: <IconCamera /> },
@@ -330,6 +331,6 @@ import { IconSemiLogo, IconBell, IconHelpCircle, IconBytedanceLogo, IconHome, Ic
                 </Footer>
             </Layout>
         </>
-    )
-}
+    );
+};
 ```

+ 5 - 3
content/start/dark-mode/index.md

@@ -51,7 +51,7 @@ function Demo() {
             body.setAttribute('theme-mode', 'dark');
             window.setMode('dark');
         }
-    }
+    };
 
     return (
         <Button
@@ -99,8 +99,8 @@ Semi 2.0 原生支持局部暗色/亮色模式。使用时,在顶级元素上
 
 ```jsx live=true dir="column" hideInDSM
 import React from 'react';
-import { Layout, Nav, Button, Breadcrumb, Avatar } from '@douyinfe/semi-ui';
-import { IconSemiLogo, IconBell, IconHelpCircle, IconBytedanceLogo, IconHome, IconHistogram, IconLive, IconSetting } from '@douyinfe/semi-icons';
+import { Layout, Nav, Button, Breadcrumb, Avatar, Steps, Pagination, Row, Badge, Tag, Rating, Tooltip, Timeline, Popover } from '@douyinfe/semi-ui';
+import { IconSemiLogo, IconCamera, IconBell, IconHelpCircle, IconBytedanceLogo, IconHome, IconHistogram, IconLive, IconSetting, IconEdit, IconList } from '@douyinfe/semi-icons';
 
 () => {
     const { Header, Footer, Sider, Content } = Layout;
@@ -214,8 +214,10 @@ import { IconSemiLogo, IconBell, IconHelpCircle, IconBytedanceLogo, IconHome, Ic
                             }}
                         >
                             <Row style={rowStyle}>
+                                <div id='popup-layer'></div>
                                 <Nav
                                     mode={'horizontal'}
+                                    getPopupContainer={() => document.querySelector('#popup-layer')}
                                     items={[
                                         { itemKey: 'user', text: 'Option1', icon: <IconEdit /> },
                                         { itemKey: 'union', text: 'Option2', icon: <IconCamera /> },

+ 2 - 1
content/start/overview/index-en-US.md

@@ -76,7 +76,8 @@ SideSheet,
 Table,
 Tag,
 Timeline,
-Tooltip
+Tooltip,
+Highlight
 ```
 
 ## Feedback

+ 2 - 1
content/start/overview/index.md

@@ -77,7 +77,8 @@ SideSheet 滑动侧边栏,
 Table 表格,
 Tag 标签,
 Timeline 时间轴,
-Tooltip 工具提示
+Tooltip 工具提示,
+Highlight 高亮文本
 ```
 
 ## 反馈类

+ 124 - 26
gatsby-node.js

@@ -11,6 +11,7 @@ const fs = require('fs');
 const items = ['basic', 'chart'];
 const sha1 = require('sha1');
 const hash = sha1(`${new Date().getTime()}${Math.random()}`);
+const numHash = Math.round(Math.random()*1000000);
 const glob = require('glob');
 
 
@@ -110,7 +111,7 @@ exports.onCreateWebpackConfig = ({ stage, rules, loaders, plugins, actions }) =>
                 'context': resolve('src/context'),
                 'components': resolve('src/components'),
                 'locale': resolve('src/locale'),
-                'src':resolve('src')
+                'src': resolve('src')
             },
         },
         module: {
@@ -162,12 +163,12 @@ exports.onCreateWebpackConfig = ({ stage, rules, loaders, plugins, actions }) =>
                 }
             ],
         },
-        plugins: [plugins.extractText(),plugins.define({
-            "THEME_SWITCHER_URL":JSON.stringify(process.env['THEME_SWITCHER_URL']),
-            "SEMI_SEARCH_URL":JSON.stringify(process.env['SEMI_SEARCH_URL']),
-            "DSM_URL":JSON.stringify(process.env['DSM_URL']),
-            'process.env.SEMI_SITE_HEADER':JSON.stringify(process.env.SEMI_SITE_HEADER),
-            'process.env.SEMI_SITE_BANNER':JSON.stringify(process.env.SEMI_SITE_BANNER),
+        plugins: [plugins.extractText(), plugins.define({
+            "THEME_SWITCHER_URL": JSON.stringify(process.env['THEME_SWITCHER_URL']),
+            "SEMI_SEARCH_URL": JSON.stringify(process.env['SEMI_SEARCH_URL']),
+            "DSM_URL": JSON.stringify(process.env['DSM_URL']),
+            'process.env.SEMI_SITE_HEADER': JSON.stringify(process.env.SEMI_SITE_HEADER),
+            'process.env.SEMI_SITE_BANNER': JSON.stringify(process.env.SEMI_SITE_BANNER),
             'process.env.D2C_URL': JSON.stringify(process.env.D2C_URL),
         })],
     });
@@ -287,37 +288,134 @@ exports.createPages = async ({ actions, graphql, reporter }) => {
 
 exports.onPostBuild = async () => {
     const publicPath = path.join(__dirname, 'public');
-
-    const pageDataFiles = glob.sync(`${publicPath}/page-data/**/page-data.json`);
+    const replacedNameSet = new Set();
+    const pageDataFiles = glob.sync(`${publicPath}/page-data/**/*.json`);
     for (let file of pageDataFiles) {
-        console.log(file);
-        const newFilename = file.replace(`page-data.json`, `page-data.${hash}.json`);
-        fs.renameSync(file, newFilename);
-    }
-
-    const appDataFiles = glob.sync(`${publicPath}/page-data/**/app-data.json`);
-    for (let file of appDataFiles) {
-        console.log(file);
-        const newFilename = file.replace(`app-data.json`, `app-data.${hash}.json`);
+        const newFilename = file.replace(/([a-zA-Z0-9\-]+)\.json/g, (_, p1)=> {
+            replacedNameSet.add(p1);
+            return `${p1}${/^\d+$/.test(p1)?numHash:`.${hash}`}.json`;
+        });
         fs.renameSync(file, newFilename);
     }
-
+    
     const htmlAndJSFiles = glob.sync(`${publicPath}/**/*.{html,js}`);
     for (let file of htmlAndJSFiles) {
         const stats = fs.statSync(file);
         if (stats.isFile()) {
-            console.log(`Adding version to page-data.json app-data.json designToken.json in ${file}..`);
+            if (file.includes("public/editor")){
+                continue;
+            }
             let content = fs.readFileSync(file, 'utf8');
-            const result = content.replace(
-                /page-data.json(\?v=[a-f0-9]*)?/g,
-                `page-data.${hash}.json`
-            ).replace(/app-data.json(\?v=[a-f0-9]*)?/g,
-                `app-data.${hash}.json`
-            ).replace(/designToken.json(\?v=[a-f0-9]*)?/g,
+            let result = content.replace(/([a-zA-Z0-9\-]+)\.json/g, (_, p1)=>{
+                if (replacedNameSet.has(p1) && !/^\d+$/.test(p1)){
+                    const newFileName = `${p1}.${hash}.json`;
+                    console.log(`Add hash to json in ${file} from ${p1}.json to ${newFileName} ..`);
+                    return newFileName;
+                } else {
+                    return `${p1}.json`;
+                }
+            });
+            result=result.replace(/designToken.json(\?v=[a-f0-9]*)?/g,
+                `designToken.json?v=${hash}`);
+            fs.writeFileSync(file, result, 'utf8');
+        }
+    }
+
+    console.log("Num json set ", Array.from(replacedNameSet));
+
+    //only match nav json (only number)
+    const jsonFiles = glob.sync(`${publicPath}/**/*.{js,html,json}`);
+    for (let file of jsonFiles) {
+        if (file.includes("public/editor")){
+            continue;
+        }
+        const stats = fs.statSync(file);
+        if (stats.isFile()) {
+            console.log("Notice: Add Hash to JSON File "+ file);
+            if (file.includes("public/editor")){
+                continue;
+            }
+            let result = fs.readFileSync(file, 'utf8');
+
+            for (let name of replacedNameSet){
+                if (/^\d+$/.test(name)){
+                    result = result.replaceAll(name, `${name}${numHash}`);
+                }
+
+            }
+            result=result.replace(/designToken.json(\?v=[a-f0-9]*)?/g,
                 `designToken.json?v=${hash}`);
             fs.writeFileSync(file, result, 'utf8');
         }
     }
 
+    (()=>{
+        const jsFiles = glob.sync(`${publicPath}/*.js`);
+
+        const replaceNames = {};
+        for (let file of jsFiles) {
+            const filename = path.basename(file);
+            const fileNameWithoutExt = filename.split('.')[0];
+            const originHash = fileNameWithoutExt.split('-').at(-1);
+
+            if (originHash && originHash!==fileNameWithoutExt){
+                let fileNameWithoutExtWithHash = fileNameWithoutExt.replace(originHash, `${originHash}${numHash}`);
+                replaceNames[originHash] = `${originHash}${numHash}`;
+                fs.renameSync(file, path.join(path.dirname(file), `${fileNameWithoutExtWithHash}.js`));
+            } else {
+                let finalFileName = `${fileNameWithoutExt}${numHash}.js`;
+                replaceNames[filename] = finalFileName;
+                fs.renameSync(file, path.join(path.dirname(file), finalFileName));
+            }
+        }
+        const allFiles = glob.sync(`${publicPath}/**/*.{js,html,json}`);
+        for (let file of allFiles) {
+            const stats = fs.statSync(file);
+            if (stats.isFile()) {
+                let result = fs.readFileSync(file, 'utf8');
+                for (let [oldName, newName] of Object.entries(replaceNames)) {
+                    result = result.replaceAll(oldName, newName);
+                }
+                fs.writeFileSync(file, result, 'utf8');
+            }
+        }
+    })();
+
+
+
+    (()=>{
+        const cssFiles = glob.sync(`${publicPath}/*.css`);
+
+        const replaceNames = {};
+        for (let file of cssFiles) {
+            const { base: filename, name: fileNameWithoutExt } = path.parse(file);
+            const originHash = fileNameWithoutExt.split('.').at(-1);
+
+
+            if (originHash && originHash!==fileNameWithoutExt){
+                let fileNameWithoutExtWithHash = fileNameWithoutExt.replace(originHash, `${originHash}${numHash}`);
+                replaceNames[originHash] = `${originHash}${numHash}`;
+                fs.renameSync(file, path.join(path.dirname(file), `${fileNameWithoutExtWithHash}.css`));
+            } else {
+                let finalFileName = `${fileNameWithoutExt}${numHash}.css`;
+                replaceNames[filename] = finalFileName;
+                fs.renameSync(file, path.join(path.dirname(file), finalFileName));
+            }
+
+        }
+        const allFiles = glob.sync(`${publicPath}/**/*.{js,html,json}`);
+        for (let file of allFiles) {
+            const stats = fs.statSync(file);
+            if (stats.isFile()) {
+                let result = fs.readFileSync(file, 'utf8');
+                for (let [oldName, newName] of Object.entries(replaceNames)) {
+                    result = result.replaceAll(oldName, newName);
+                }
+                fs.writeFileSync(file, result, 'utf8');
+            }
+        }
+    })();
+
+
 
 };

+ 2 - 2
lerna.json

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

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

@@ -1,6 +1,6 @@
 {
   "name": "@douyinfe/semi-animation-react",
-  "version": "2.23.7",
+  "version": "2.24.0-beta.1",
   "description": "motion library for semi-ui-react",
   "keywords": [
     "motion",
@@ -44,4 +44,4 @@
     "react-storybook-addon-props-combinations": "^1.1.0"
   },
   "gitHead": "eb34a4f25f002bb4cbcfa51f3df93bed868c831a"
-}
+}

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

@@ -1,6 +1,6 @@
 {
   "name": "@douyinfe/semi-animation-styled",
-  "version": "2.23.7",
+  "version": "2.24.0-beta.1",
   "description": "semi styled animation",
   "keywords": [
     "semi",
@@ -40,4 +40,4 @@
     "merge2": "^1.4.1"
   },
   "gitHead": "eb34a4f25f002bb4cbcfa51f3df93bed868c831a"
-}
+}

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

@@ -1,6 +1,6 @@
 {
   "name": "@douyinfe/semi-animation",
-  "version": "2.23.7",
+  "version": "2.24.0-beta.1",
   "description": "animation base library for semi-ui",
   "keywords": [
     "animation",
@@ -43,4 +43,4 @@
     "react-storybook-addon-props-combinations": "^1.1.0"
   },
   "gitHead": "eb34a4f25f002bb4cbcfa51f3df93bed868c831a"
-}
+}

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

@@ -1,6 +1,6 @@
 {
   "name": "eslint-plugin-semi-design",
-  "version": "2.23.7",
+  "version": "2.24.0-beta.1",
   "description": "semi ui eslint plugin",
   "keywords": [
     "semi",
@@ -40,4 +40,4 @@
   "bugs": {
     "url": "https://github.com/DouyinFE/semi-design/issues"
   }
-}
+}

+ 7 - 0
packages/semi-foundation/highlight/constants.ts

@@ -0,0 +1,7 @@
+import { BASE_CLASS_PREFIX } from "../base/constants";
+
+const cssClasses = {
+    PREFIX: `${BASE_CLASS_PREFIX}-highlight`,
+} as const;
+
+export { cssClasses };

+ 11 - 0
packages/semi-foundation/highlight/highlight.scss

@@ -0,0 +1,11 @@
+//@import '../theme/variables.scss';
+@import "./variables.scss";
+
+$highlight: #{$prefix}-highlight;
+$tag: #{$prefix}-highlight-tag;
+
+.#{$tag} {
+    color: $color-highlight-text-default;
+    background-color: $color-highlight-text-bg-default;
+    font-weight: $font-highlight-text-fontWeight;
+}

+ 5 - 0
packages/semi-foundation/highlight/variables.scss

@@ -0,0 +1,5 @@
+
+$color-highlight-text-default: var(--semi-color-highlight); // 高亮文字颜色
+$color-highlight-text-bg-default:  var(--semi-color-highlight-bg); // 高亮文字背景颜色
+
+$font-highlight-text-fontWeight: 600; // 高亮文字字重

+ 9 - 5
packages/semi-foundation/image/previewInnerFoundation.ts

@@ -18,7 +18,9 @@ export interface PreviewInnerAdapter<P = Record<string, any>, S = Record<string,
     setStopTiming: (value: boolean) => void;
     getStartMouseDown: () => {x: number; y: number};
     setStartMouseDown: (x: number, y: number) => void;
-    setMouseActiveTime: (time: number) => void
+    setMouseActiveTime: (time: number) => void;
+    disabledBodyScroll: () => void;
+    enabledBodyScroll: () => void
 }
 
 const NOT_CLOSE_TARGETS = ["icon", "footer"];
@@ -31,10 +33,12 @@ export default class PreviewInnerFoundation<P = Record<string, any>, S = Record<
 
     beforeShow() {
         this._adapter.registerKeyDownListener();
+        this._adapter.disabledBodyScroll();
     }
 
     afterHide() {
         this._adapter.unregisterKeyDownListener();
+        this._adapter.enabledBodyScroll();
     }
 
     handleRatio(type: string) {
@@ -125,7 +129,7 @@ export default class PreviewInnerFoundation<P = Record<string, any>, S = Record<
             rotation: 0,
         } as any);
         this._adapter.notifyRotateChange(0);
-    }  
+    }
 
     handleDownload = () => {
         const { currentIndex, imgSrc } = this.getStates();
@@ -194,7 +198,7 @@ export default class PreviewInnerFoundation<P = Record<string, any>, S = Record<
             callback(e);
         };
         Img.onerror = callback;
-        Img.src = preloadImages[0];  
+        Img.src = preloadImages[0];
     }
 
     // 在切换左右图片时,当被切换图片完成加载后,根据方向决定下一个预加载的图片
@@ -260,5 +264,5 @@ export default class PreviewInnerFoundation<P = Record<string, any>, S = Record<
         } else {
             this.preloadSingleImage();
         }
-    }   
-}
+    }
+}

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

@@ -1,6 +1,6 @@
 {
     "name": "@douyinfe/semi-foundation",
-    "version": "2.23.7",
+    "version": "2.24.0-beta.1",
     "description": "",
     "scripts": {
         "build:lib": "node ./scripts/compileLib.js",
@@ -38,4 +38,4 @@
         "merge2": "^1.4.1",
         "through2": "^4.0.2"
     }
-}
+}

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

@@ -1,6 +1,6 @@
 {
   "name": "@douyinfe/semi-icons",
-  "version": "2.23.7",
+  "version": "2.24.0-beta.1",
   "description": "semi icons",
   "keywords": [
     "semi",
@@ -60,4 +60,4 @@
     "*"
   ],
   "gitHead": "eb34a4f25f002bb4cbcfa51f3df93bed868c831a"
-}
+}

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

@@ -1,6 +1,6 @@
 {
   "name": "@douyinfe/semi-illustrations",
-  "version": "2.23.7",
+  "version": "2.24.0-beta.1",
   "description": "semi illustrations",
   "keywords": [
     "semi",
@@ -45,4 +45,4 @@
     "prepublishOnly": "npm run clean && npm run build:js"
   },
   "gitHead": "eb34a4f25f002bb4cbcfa51f3df93bed868c831a"
-}
+}

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

@@ -1,6 +1,6 @@
 {
     "name": "@douyinfe/semi-next",
-    "version": "2.23.7",
+    "version": "2.24.0-beta.1",
     "description": "Plugin that support Semi Design in Next.js",
     "author": "伍浩威 <[email protected]>",
     "homepage": "",
@@ -26,4 +26,4 @@
         "@douyinfe/semi-webpack-plugin": "2.23.2"
     },
     "gitHead": "eb34a4f25f002bb4cbcfa51f3df93bed868c831a"
-}
+}

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

@@ -1,6 +1,6 @@
 {
   "name": "@douyinfe/semi-scss-compile",
-  "version": "2.23.7",
+  "version": "2.24.0-beta.1",
   "description": "compile semi scss to css",
   "author": "[email protected]",
   "license": "MIT",
@@ -33,4 +33,4 @@
     "typescript": "^4.4.4"
   },
   "gitHead": "eb34a4f25f002bb4cbcfa51f3df93bed868c831a"
-}
+}

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

@@ -1,6 +1,6 @@
 {
     "name": "@douyinfe/semi-theme-default",
-    "version": "2.23.7",
+    "version": "2.24.0-beta.1",
     "description": "semi-theme-default",
     "keywords": [
         "semi-theme",
@@ -21,4 +21,4 @@
     "devDependencies": {
         "path": "^0.12.7"
     }
-}
+}

+ 4 - 0
packages/semi-theme-default/scss/global.scss

@@ -101,6 +101,8 @@ body, body[theme-mode="dark"] .semi-always-light {
     --semi-border-radius-large: 12px; // 大圆角, 用于 modal
     --semi-border-radius-circle: 50%; // 全圆角, 用于 avatar, badge 等组件
     --semi-border-radius-full: 9999px; // 用于创建全尺寸圆角,如胶囊标签等
+    --semi-color-highlight-bg: rgba(var(--semi-yellow-4), 1); // 高亮文本背景色
+    --semi-color-highlight: rgba(var(--semi-black), 1); // 高亮文本色
 }
 
 body[theme-mode="dark"], body .semi-always-dark {
@@ -189,4 +191,6 @@ body[theme-mode="dark"], body .semi-always-dark {
     --semi-border-radius-large: 12px;
     --semi-border-radius-circle: 50%;
     --semi-border-radius-full: 9999px;
+    --semi-color-highlight-bg: rgba(var(--semi-yellow-2), 1); // 高亮文本背景色
+    --semi-color-highlight: rgba(var(--semi-white), 1); // 高亮文本色
 }

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

@@ -141,14 +141,14 @@ export const registerMediaQuery = (media: string, { match, unmatch, callInInit =
 };
 export interface GetHighLightTextHTMLProps {
     sourceString?: string;
-    searchWords?: any[];
+    searchWords?: string[];
     option: HighLightTextHTMLOption
 }
 
 export interface HighLightTextHTMLOption {
     highlightTag?: string;
     highlightClassName?: string;
-    highlightStyle?: Record<string, any>;
+    highlightStyle?: React.CSSProperties;
     caseSensitive: boolean;
     autoEscape: boolean
 }

+ 159 - 0
packages/semi-ui/form/_story/FieldProps/name.jsx

@@ -0,0 +1,159 @@
+/* eslint-disable no-unused-vars */
+import React, { useState, useLayoutEffect, useEffect, useRef } from 'react';
+import { storiesOf } from '@storybook/react';
+import { Button, Modal, TreeSelect, Row, Col, Avatar, Tabs, TabPane, Badge } from '@douyinfe/semi-ui';
+import {
+    Form,
+    useFormState,
+    useFormApi,
+    useFieldApi,
+    useFieldState,
+    withFormState,
+    withFormApi,
+    withField,
+    ArrayField
+} from '../../index';
+
+import {
+    UseFormApiDemo,
+    UseFormStateDemo,
+    UseFieldApiDemo,
+    UseFieldStateDemo,
+    WithFormStateDemo,
+    WithFormApiDemo,
+    ComponentUsingFormState,
+    CustomStringify
+} from '../Hook/hookDemo';
+const { Input, Select, DatePicker, Switch, Slider, CheckboxGroup, Checkbox, RadioGroup, Radio, TimePicker } = Form;
+
+const NameDemo = () => {
+    const style = { width: '90%' };
+    const helpText = <span style={{ color: 'var(--semi-color-warning)' }}>密码强度:弱</span>;
+    return (
+        <Form extraTextPosition="middle">
+            <Form.Input
+                field="b"
+                name='test'
+            />
+            <Form.Input
+                field='name'
+                label="名称"
+                name='name'
+                // initValue={'mikeya'}
+                style={style}
+                trigger='blur'
+                rules={[
+                    { required: true, message: 'required error' },
+                    { type: 'string', message: 'type error' },
+                    { validator: (rule, value) => value === 'muji', message: 'not muji' }
+                ]}
+            />
+            <Form.DatePicker field="date" name='date' label='日期' style={style} placeholder='请选择生效日期' />
+            <Form.Select field="role" name='role' style={style} label='角色' placeholder='请选择你的角色'>
+                <Form.Select.Option value="operate">运营</Form.Select.Option>
+                <Form.Select.Option value="rd">开发</Form.Select.Option>
+                <Form.Select.Option value="pm">产品</Form.Select.Option>
+                <Form.Select.Option value="ued">设计</Form.Select.Option>
+            </Form.Select>
+            <Form.Select
+                field="business"
+                name='business'
+                multiple
+                style={style}
+                placeholder='请选择业务线'
+                label="业务线(多选)"
+            >
+                <Form.Select.Option value="dy">抖音</Form.Select.Option>
+                <Form.Select.Option value="hootsoon">火山小视频</Form.Select.Option>
+                <Form.Select.Option value="toutiao">今日头条</Form.Select.Option>
+            </Form.Select>
+            <Form.Cascader
+                placeholder="请选择所在地区"
+                field='area'
+                name='area'
+                label='地区(级联选择)'
+            >
+            </Form.Cascader>    
+            <Form.TreeSelect
+                field="tree"
+                name='tree'
+                style={style}
+                label='节点(树选择)'
+                placeholder='请选择服务节点'
+                filterTreeNode
+            >
+            </Form.TreeSelect>
+            <Form.TimePicker
+                field='time'
+                name='time'
+                helpText='原则上应当在 9:00 - 18:00 之间'
+                label='时间选择'
+            >
+            </Form.TimePicker>
+            <Form.AutoComplete
+                field='typeData'
+                label='类型选择'
+                name='typeData'
+                data={['1', '2', '3']}
+            >
+            </Form.AutoComplete>
+            <Form.TagInput
+                field='tags'
+                label='tags'
+                name='tags'
+            />
+            <Form.TextArea
+                style={style}
+                field='description'
+                name='description'
+                label='申请理由'
+                placeholder='请填写申请资源理由'
+            />
+            <Form.CheckboxGroup
+                field="type"
+                name='anotherType'
+                label='申请类型'
+                initValue={['user', 'admin']}
+                rules={[
+                    { required: true }
+                ]}
+            >
+                <Form.Checkbox value="admin">管理员admin</Form.Checkbox>
+                <Form.Checkbox value="user">用户user</Form.Checkbox>
+                <Form.Checkbox value="guest">访客guest</Form.Checkbox>
+                <Form.Checkbox value="root">根用户root</Form.Checkbox>
+            </Form.CheckboxGroup>
+            <Form.RadioGroup
+                name='anotherSource'
+                field="isMonopolize" label='是否独占资源' rules={[
+                    { type: 'boolean' },
+                    { required: true, message: '必须选择是否独占 ' }
+                ]}>
+                <Form.Radio value={true}>是</Form.Radio>
+                <Form.Radio value={false}>否</Form.Radio>
+            </Form.RadioGroup>
+            <Form.InputNumber field='number' name='number' label='申请数量' initValue={20} style={style}/>
+            <Form.Slider field="range" name='range' label='资源使用报警阈值(%)' initValue={10} style={{ width: '90%' }}/>
+            <Form.Rating field="rating" name='rating' label='满意度(Rating)' initValue={2} style={{ width: '90%' }}/>
+            <Form.Switch field='switch' name='switch' label='开关(Switch)'/>
+            <Form.CheckboxGroup field="cardCheckbox" label='卡片选择' style={{ width: '90%' }} type='card' initValue={['1', '3']} direction={'horizontal'} aria-label="CheckboxGroup 示例">
+                <Form.Checkbox value={'1'} disabled extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统' style={{ width: 280 }}>
+                    单选框标题
+                </Form.Checkbox>
+                <Form.Checkbox value={'2'} disabled extra='Semi Design 是由互娱社区前端团队与 UED 团队共同设计开发并维护的设计系统' style={{ width: 280 }}>
+                    单选框标题
+                </Form.Checkbox>
+            </Form.CheckboxGroup>
+            <Form.RadioGroup field='buttonRadio' type='button' buttonSize='middle' defaultValue={1} aria-label="单选组合示例">
+                <Radio value={1}>即时推送</Radio>
+                <Radio value={2}>定时推送</Radio>
+                <Radio value={3}>动态推送</Radio>
+            </Form.RadioGroup>
+            <Form.Checkbox value="false" field="agree" name='agree' useOutSideGroup={true} noLabel={true}>
+                我已阅读并清楚相关规定
+            </Form.Checkbox>
+        </Form>
+    );
+};
+
+export { NameDemo };

+ 7 - 0
packages/semi-ui/form/_story/form.stories.jsx

@@ -66,6 +66,7 @@ import {
 
 // field props
 import { ConvertDemo } from './FieldProps/convert';
+import { NameDemo } from './FieldProps/name';
 import { HelpAndExtra, ExtraPositionDemo } from './FieldProps/helpAndExtra';
 import { BigNumberFieldDemo } from './FieldProps/bigNumberFieldPath';
 import { UpdateDemo, RuleupdateDemo } from './FieldProps/rulesUpdateDemo';
@@ -323,6 +324,12 @@ FiledPropConvert.story = {
   name: 'Filed Prop-convert',
 };
 
+export const FieldPropsName = () => <NameDemo />;
+
+FieldPropsName.story = {
+  name: 'Filed Prop-name',
+};
+
 export const FiledPropHelpTextExtraTextExtraTextPosition = () => (
   <>
     <HelpAndExtra />

+ 8 - 4
packages/semi-ui/form/hoc/withField.tsx

@@ -434,7 +434,7 @@ function withField<
         const extraTextId = `${a11yId}-extraText`;
         const errorMessageId = `${a11yId}-errormessage`;
 
-        let FieldComponent = (() => {
+        const FieldComponent = () => {
             // prefer to use validateStatus which pass by user throught props
             let blockStatus = validateStatus ? validateStatus : status;
 
@@ -459,6 +459,10 @@ function withField<
                 'aria-labelledby': labelId,
             };
 
+            if (name) {
+                newProps['name'] = name;
+            }
+
             if (helpText) {
                 newProps['aria-describedby'] = extraText ? `${helpTextId} ${extraTextId}` : helpTextId;
             }
@@ -580,7 +584,7 @@ function withField<
                     )}
                 </div>
             );
-        })();
+        };
 
         // !important optimization
         const shouldUpdate = [
@@ -593,10 +597,10 @@ function withField<
         ];
         if (options.shouldMemo) {
             // eslint-disable-next-line react-hooks/exhaustive-deps
-            return useMemo(() => FieldComponent, [...shouldUpdate]);
+            return useMemo(FieldComponent, [...shouldUpdate]);
         } else {
             // Some Custom Component with inner state shouldn't be memo, otherwise the component will not updated when the internal state is updated
-            return FieldComponent;
+            return FieldComponent();
         }
     };
     SemiField = forwardRef(SemiField);

+ 41 - 0
packages/semi-ui/highlight/_story/highlight.stories.jsx

@@ -0,0 +1,41 @@
+import React from 'react';
+import ReactDOM from 'react-dom';
+
+import { Skeleton, Avatar, Button, ButtonGroup, Spin, Highlight } from '../../index';
+
+
+const searchWords = ['do', 'dollar'];
+const sourceString = 'aaa do dollar aaa';
+
+export default {
+  title: 'Highlight'
+}
+
+export const HighlightTag = () => (
+  <h2>
+    <Highlight
+        component='span'
+        sourceString='semi design connect designOps & devOps'
+        searchWords={['semi']}
+        />
+  </h2>
+);
+
+HighlightTag.story = {
+  name: 'different tag',
+};
+
+export const HighlightStyle = () => (
+  <h2>
+    <Highlight
+        component='span'
+        sourceString='semi design connect designOps & devOps'
+        searchWords={['semi', 'design']}
+        highlightStyle={{ backgroundColor: 'var(--semi-color-warning)', borderRadius: 4 }}
+    />
+  </h2>
+);
+
+HighlightStyle.story = {
+  name: 'custom style',
+};

+ 20 - 0
packages/semi-ui/highlight/_story/highlight.stories.tsx

@@ -0,0 +1,20 @@
+import React from 'react';
+import { storiesOf } from '@storybook/react';
+
+import { Skeleton, Avatar, Button, ButtonGroup, Spin, Highlight } from '../../index';
+
+const searchWords = ['do', 'dollar'];
+const sourceString = 'aaa do dollar aaa';
+const stories = storiesOf('Highlight', module);
+
+const HighlightTag = () => (
+    <h2>
+        <Highlight
+            component='span'
+            sourceString='semi design connect designOps & devOps'
+            searchWords={['semi']}
+        />
+    </h2>
+);
+
+stories.add('List', () => (<HighlightTag></HighlightTag>));

+ 1 - 0
packages/semi-ui/highlight/index-en-US.md

@@ -0,0 +1 @@
+../../../content/show/highlight/index-en-US.md

+ 1 - 0
packages/semi-ui/highlight/index.md

@@ -0,0 +1 @@
+../../../content/show/highlight/index.md

+ 70 - 0
packages/semi-ui/highlight/index.tsx

@@ -0,0 +1,70 @@
+import React, { PureComponent } from 'react';
+import cls from 'classnames';
+import PropTypes, { string } from 'prop-types';
+import { cssClasses } from '@douyinfe/semi-foundation/highlight/constants';
+import { getHighLightTextHTML } from '../_utils/index';
+import '@douyinfe/semi-foundation/highlight/highlight.scss';
+
+export interface HighlightProps {
+    autoEscape?: boolean;
+    caseSensitive?: boolean;
+    sourceString?: string;
+    searchWords?: Array<string>;
+    highlightStyle?: React.CSSProperties;
+    highlightClassName?: string;
+    component?: string
+}
+
+const prefixCls = cssClasses.PREFIX;
+
+class Highlight extends PureComponent<HighlightProps> {
+
+    static propTypes = {
+        style: PropTypes.object,
+        className: PropTypes.string,
+        autoEscape: PropTypes.bool,
+        caseSensitive: PropTypes.bool,
+        sourceString: PropTypes.string,
+        searchWords: PropTypes.arrayOf(PropTypes.string),
+        highlightStyle: PropTypes.object,
+        highlightClassName: PropTypes.string,
+        component: PropTypes.string
+    };
+
+    static defaultProps = {
+        component: 'mark',
+        autoEscape: true,
+        caseSensitive: false,
+        sourceString: '',
+    };
+
+    render() {
+        const {
+            searchWords,
+            sourceString,
+            component,
+            highlightClassName,
+            highlightStyle,
+            caseSensitive,
+            autoEscape,
+        } = this.props;
+
+        const tagCls = cls({
+            [`${prefixCls}-tag`]: true,
+        }, highlightClassName);
+
+        const option = {
+            highlightTag: component,
+            highlightClassName: tagCls,
+            highlightStyle,
+            caseSensitive,
+            autoEscape,
+        };
+
+        return (
+            getHighLightTextHTML({ sourceString, searchWords, option })
+        );
+    }
+}
+
+export default Highlight;

+ 43 - 0
packages/semi-ui/image/__test__/imagePreview.test.js

@@ -0,0 +1,43 @@
+import { Image, ImagePreview } from '../../index';
+import { BASE_CLASS_PREFIX } from '../../../semi-foundation/base/constants';
+
+function getImagePreview(imageProps) {
+    const props = imageProps ? imageProps : {};
+    const srcList = [
+        "https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/abstract.jpg",
+        "https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/sky.jpg",
+        "https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/greenleaf.jpg",
+        "https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/root-web-sites/colorful.jpg",
+    ];
+    return (
+        <ImagePreview {...props}>
+            {srcList.map((src, index) => {
+                return (
+                    <Image
+                        key={index}
+                        src={src}
+                        width={200}
+                        alt={`lamp${index + 1}`}
+                        style={{ marginRight: 5 }}
+                    />
+                );
+            })}
+        </ImagePreview>
+    )
+}
+
+describe('ImagePreview', () => {
+    it('visible', function () {
+        const imageComponent = getImagePreview();
+        const image = mount(imageComponent, { attachTo: document.getElementById('container') });
+        expect(image.exists(`div.${BASE_CLASS_PREFIX}-image-preview`)).toEqual(false);
+        image.setProps({ visible: true })
+        image.update();
+        expect(image.exists(`div.${BASE_CLASS_PREFIX}-image-preview`)).toEqual(true);
+        expect(document.body.style.overflow).toEqual('hidden');
+        image.setProps({ visible: false })
+        image.update();
+        expect(document.body.style.overflow).not.toEqual('hidden');
+        expect(document.querySelector(`div.${BASE_CLASS_PREFIX}-image-preview`)).toEqual(null);
+    });
+})

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

@@ -12,7 +12,7 @@ import { PreviewContext, PreviewContextProps } from "./previewContext";
 import ImageFoundation, { ImageAdapter } from "@douyinfe/semi-foundation/image/imageFoundation";
 import LocaleConsumer from "../locale/localeConsumer";
 import { Locale } from "../locale/interface";
-import { isBoolean, isObject } from "lodash";
+import { isBoolean, isObject, isUndefined } from "lodash";
 import Skeleton from "../skeleton";
 import "@douyinfe/semi-foundation/image/image.scss";
 
@@ -209,6 +209,7 @@ export default class Image extends BaseComponent<ImageProps, ImageStates> {
                         src={previewSrc}
                         visible={previewVisible}
                         onVisibleChange={this.handlePreviewVisibleChange}
+                        crossOrigin={!isUndefined(crossOrigin) ? crossOrigin : previewProps?.crossOrigin}
                     />
                 }
             </div>

+ 1 - 0
packages/semi-ui/image/index.tsx

@@ -13,4 +13,5 @@ export type {
     ImageProps,
     PreviewImageProps,
     PreviewProps,
+    MenuProps
 } from "./interface";

+ 2 - 0
packages/semi-ui/image/interface.tsx

@@ -52,6 +52,7 @@ export interface PreviewProps extends BaseProps {
     disableDownload?: boolean;
     zIndex?: number;
     children?: ReactNode;
+    crossOrigin?: "anonymous"| "use-credentials";
     renderHeader?: (info: any) => ReactNode;
     renderPreviewMenu?: (props: MenuProps) => ReactNode;
     getPopupContainer?: () => HTMLElement;
@@ -156,6 +157,7 @@ export interface PreviewImageProps {
     ratio?: RatioType;
     disableDownload?: boolean;
     clickZoom?: number;
+    crossOrigin?: "anonymous"| "use-credentials";
     setRatio?: (type: RatioType) => void;
     onZoom?: (zoom: number) => void;
     onLoad?: (src: string) => void;

+ 2 - 1
packages/semi-ui/image/previewImage.tsx

@@ -182,7 +182,7 @@ export default class PreviewImage extends BaseComponent<PreviewImageProps, Previ
     };
 
     render() {
-        const { src, rotation } = this.props;
+        const { src, rotation, crossOrigin } = this.props;
         const { loading, width, height, top, left } = this.state;
         const imgStyle = {
             position: "absolute",
@@ -213,6 +213,7 @@ export default class PreviewImage extends BaseComponent<PreviewImageProps, Previ
                     onLoad={this.handleLoad}
                     onError={this.handleError}
                     style={imgStyle as React.CSSProperties}
+                    crossOrigin={crossOrigin}
                 />
                 {loading && <Spin size={"large"} wrapperClassName={`${preViewImgPrefixCls}-spin`}/>}
             </div>

+ 63 - 23
packages/semi-ui/image/previewInner.tsx

@@ -25,7 +25,7 @@ let timer = null;
 
 export default class PreviewInner extends BaseComponent<PreviewInnerProps, PreviewInnerStates> {
     static contextType = PreviewContext;
-    
+
     static propTypes = {
         style: PropTypes.object,
         className: PropTypes.string,
@@ -74,17 +74,36 @@ export default class PreviewInner extends BaseComponent<PreviewInnerProps, Previ
         infinite: false,
         closeOnEsc: true,
         lazyLoad: false,
-        preLoad: true, 
+        preLoad: true,
         preLoadGap: 2,
         zIndex: 1000,
         maskClosable: true,
         viewerVisibleDelay: 10000,
     };
 
+    private bodyOverflow: string;
+    private scrollBarWidth: number;
+    private originBodyWidth: string;
+
     get adapter(): PreviewInnerAdapter<PreviewInnerProps, PreviewInnerStates> {
         return {
             ...super.adapter,
             getIsInGroup: () => this.isInGroup(),
+            disabledBodyScroll: () => {
+                const { getPopupContainer } = this.props;
+                this.bodyOverflow = document.body.style.overflow || '';
+                if (!getPopupContainer && this.bodyOverflow !== 'hidden') {
+                    document.body.style.overflow = 'hidden';
+                    document.body.style.width = `calc(${this.originBodyWidth || '100%'} - ${this.scrollBarWidth}px)`;
+                }
+            },
+            enabledBodyScroll: () => {
+                const { getPopupContainer } = this.props;
+                if (!getPopupContainer && this.bodyOverflow !== 'hidden') {
+                    document.body.style.overflow = this.bodyOverflow;
+                    document.body.style.width = this.originBodyWidth;
+                }
+            },
             notifyChange: (index: number, direction: string) => {
                 const { onChange, onPrev, onNext } = this.props;
                 isFunction(onChange) && onChange(index);
@@ -116,11 +135,11 @@ export default class PreviewInner extends BaseComponent<PreviewInnerProps, Previ
             },
             notifyRotateChange: (angle: number) => {
                 const { onRotateLeft } = this.props;
-                isFunction(onRotateLeft) && onRotateLeft(angle);   
+                isFunction(onRotateLeft) && onRotateLeft(angle);
             },
             notifyDownload: (src: string, index: number) => {
                 const { onDownload } = this.props;
-                isFunction(onDownload) && onDownload(src, index);  
+                isFunction(onDownload) && onDownload(src, index);
             },
             registerKeyDownListener: () => {
                 window && window.addEventListener("keydown", this.handleKeyDown);
@@ -147,7 +166,7 @@ export default class PreviewInner extends BaseComponent<PreviewInnerProps, Previ
                 mouseActiveTime = time;
             },
         };
-        
+
     }
 
     timer;
@@ -167,8 +186,11 @@ export default class PreviewInner extends BaseComponent<PreviewInnerProps, Previ
             visible: false,
             preloadAfterVisibleChange: true,
             direction: "",
-        }; 
+        };
         this.foundation = new PreviewInnerFoundation(this.adapter);
+        this.bodyOverflow = '';
+        this.originBodyWidth = '100%';
+        this.scrollBarWidth = 0;
     }
 
     static getDerivedStateFromProps(props: PreviewInnerProps, state: PreviewInnerStates) {
@@ -177,7 +199,7 @@ export default class PreviewInner extends BaseComponent<PreviewInnerProps, Previ
         if (props.visible) {
             // if src in props
             src = Array.isArray(props.src) ? props.src : [props.src];
-        } 
+        }
         if (!isEqual(src, state.imgSrc)) {
             willUpdateStates.imgSrc = src;
         }
@@ -193,6 +215,22 @@ export default class PreviewInner extends BaseComponent<PreviewInnerProps, Previ
         return willUpdateStates;
     }
 
+    static getScrollbarWidth() {
+        if (globalThis && Object.prototype.toString.call(globalThis) === '[object Window]') {
+            return window.innerWidth - document.documentElement.clientWidth;
+        }
+        return 0;
+    }
+
+    componentDidMount() {
+
+        this.scrollBarWidth = PreviewInner.getScrollbarWidth();
+        this.originBodyWidth = document.body.style.width;
+        if (this.props.visible) {
+            this.foundation.beforeShow();
+        }
+    }
+
     componentDidUpdate(prevProps: PreviewInnerProps, prevState: PreviewInnerStates) {
         if (prevState.visible !== this.props.visible && this.props.visible) {
             mouseActiveTime = new Date().getTime();
@@ -267,8 +305,8 @@ export default class PreviewInner extends BaseComponent<PreviewInnerProps, Previ
 
     onImageLoad = (src) => {
         this.foundation.onImageLoad(src);
-    }   
-    
+    }
+
     handleMouseDown = (e): void => {
         this.foundation.handleMouseDown(e);
     }
@@ -278,14 +316,15 @@ export default class PreviewInner extends BaseComponent<PreviewInnerProps, Previ
     }
 
     render() {
-        const { 
-            getPopupContainer, 
-            zIndex, 
-            visible, 
-            className, 
-            style, 
-            infinite, 
+        const {
+            getPopupContainer,
+            zIndex,
+            visible,
+            className,
+            style,
+            infinite,
             zoomStep,
+            crossOrigin,
             prevTip,
             nextTip,
             zoomInTip,
@@ -314,7 +353,7 @@ export default class PreviewInner extends BaseComponent<PreviewInnerProps, Previ
             };
         }
         const previewPrefixCls = `${prefixCls}-preview`;
-        const previewWrapperCls = cls(previewPrefixCls, 
+        const previewWrapperCls = cls(previewPrefixCls,
             {
                 [`${prefixCls}-hide`]: !visible,
                 [`${previewPrefixCls}-popup`]: getPopupContainer,
@@ -323,16 +362,16 @@ export default class PreviewInner extends BaseComponent<PreviewInnerProps, Previ
         );
         const hideViewerCls = !viewerVisible ? `${previewPrefixCls}-hide` : "";
         const total = imgSrc.length;
-        const showPrev = total !== 1 && (infinite || currentIndex !== 0); 
+        const showPrev = total !== 1 && (infinite || currentIndex !== 0);
         const showNext = total !== 1 && (infinite || currentIndex !== total - 1);
         return (
-            <Portal 
+            <Portal
                 getPopupContainer={getPopupContainer}
                 style={wrapperStyle}
             >
-                {visible && 
+                {visible &&
                 // eslint-disable-next-line jsx-a11y/mouse-events-have-key-events,jsx-a11y/no-static-element-interactions
-                <div 
+                <div
                     className={previewWrapperCls}
                     style={style}
                     onMouseDown={this.handleMouseDown}
@@ -342,7 +381,7 @@ export default class PreviewInner extends BaseComponent<PreviewInnerProps, Previ
                     onMouseOut={(e): void => this.handleMouseEvent(e.nativeEvent, "out")}
                 >
                     <Header className={cls(hideViewerCls)} onClose={this.handlePreviewClose} renderHeader={renderHeader}/>
-                    <PreviewImage 
+                    <PreviewImage
                         src={imgSrc[currentIndex]}
                         onZoom={this.handleZoomImage}
                         disableDownload={disableDownload}
@@ -351,6 +390,7 @@ export default class PreviewInner extends BaseComponent<PreviewInnerProps, Previ
                         ratio={ratio}
                         zoomStep={zoomStep}
                         rotation={rotation}
+                        crossOrigin={crossOrigin} 
                         onError={this.onImageError}
                         onLoad={this.onImageLoad}
                     />
@@ -404,4 +444,4 @@ export default class PreviewInner extends BaseComponent<PreviewInnerProps, Previ
             </Portal>
         );
     }
-}
+}

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

@@ -79,7 +79,7 @@ export { default as TreeSelect } from './treeSelect';
 export { default as Upload } from './upload';
 export { default as Typography } from './typography';
 export { default as Transfer } from './transfer';
-
+export { default as Highlight } from './highlight';
 
 export { default as LocaleProvider } from './locale/localeProvider';
 export { default as LocaleConsumer } from './locale/localeConsumer';

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

@@ -113,7 +113,7 @@ class Modal extends BaseComponent<ModalReactProps, ModalState> {
     private readonly modalRef: LegacyRef<ModalContent>;
     private bodyOverflow: string;
     private scrollBarWidth: number;
-    private originBodyWith: string;
+    private originBodyWidth: string;
     private _haveRendered: boolean;
 
     constructor(props: ModalReactProps) {
@@ -126,7 +126,7 @@ class Modal extends BaseComponent<ModalReactProps, ModalState> {
         this.modalRef = React.createRef();
         this.bodyOverflow = '';
         this.scrollBarWidth = 0;
-        this.originBodyWith = '100%';
+        this.originBodyWidth = '100%';
 
     }
 
@@ -139,14 +139,14 @@ class Modal extends BaseComponent<ModalReactProps, ModalState> {
                 this.bodyOverflow = document.body.style.overflow || '';
                 if (!getPopupContainer && this.bodyOverflow !== 'hidden') {
                     document.body.style.overflow = 'hidden';
-                    document.body.style.width = `calc(${this.originBodyWith || '100%'} - ${this.scrollBarWidth}px)`;
+                    document.body.style.width = `calc(${this.originBodyWidth || '100%'} - ${this.scrollBarWidth}px)`;
                 }
             },
             enabledBodyScroll: () => {
                 const { getPopupContainer } = this.props;
                 if (!getPopupContainer && this.bodyOverflow !== 'hidden') {
                     document.body.style.overflow = this.bodyOverflow;
-                    document.body.style.width = this.originBodyWith;
+                    document.body.style.width = this.originBodyWidth;
                 }
             },
             notifyCancel: (e: React.MouseEvent) => {
@@ -232,7 +232,7 @@ class Modal extends BaseComponent<ModalReactProps, ModalState> {
     componentDidMount() {
 
         this.scrollBarWidth = Modal.getScrollbarWidth();
-        this.originBodyWith = document.body.style.width;
+        this.originBodyWidth = document.body.style.width;
         if (this.props.visible) {
             this.foundation.beforeShow();
         }

+ 11 - 1
packages/semi-ui/navigation/Item.tsx

@@ -34,7 +34,9 @@ export interface NavItemProps extends ItemProps, BaseProps {
     text?: React.ReactNode;
     tooltipHideDelay?: number;
     tooltipShowDelay?: number;
+
     onClick?(clickItems: SelectedData): void;
+
     onMouseEnter?: React.MouseEventHandler<HTMLLIElement>;
     onMouseLeave?: React.MouseEventHandler<HTMLLIElement>
 }
@@ -85,6 +87,7 @@ export default class NavItem extends BaseComponent<NavItemProps, NavItemState> {
 
     foundation: ItemFoundation;
     context: NavContextType;
+
     constructor(props: NavItemProps) {
         super(props);
         this.state = {
@@ -295,7 +298,14 @@ export default class NavItem extends BaseComponent<NavItemProps, NavItemState> {
         if (isCollapsed && !isInSubNav && !isSubNav || isCollapsed && isSubNav && disabled) {
             itemDom = this.wrapTooltip(itemDom);
         }
-
+        if (typeof this.context.renderWrapper === 'function') {
+            return this.context.renderWrapper({
+                itemElement: itemDom,
+                isSubNav: isSubNav,
+                isInSubNav: isInSubNav,
+                props: this.props
+            });
+        }
         return itemDom;
     }
 }

+ 5 - 1
packages/semi-ui/navigation/SubNav.tsx

@@ -315,7 +315,7 @@ export default class SubNav extends BaseComponent<SubNavProps, SubNavState> {
         let _elem: React.ReactNode = elem;
         const { children, dropdownStyle, disabled } = this.props;
 
-        const { mode, isInSubNav, isCollapsed, subNavCloseDelay, subNavOpenDelay, prefixCls } = this.context;
+        const { mode, isInSubNav, isCollapsed, subNavCloseDelay, subNavOpenDelay, prefixCls, getPopupContainer } = this.context;
 
         const isOpen = this.adapter.getIsOpen();
         const openKeysIsControlled = this.adapter.getOpenKeysIsControlled();
@@ -334,6 +334,10 @@ export default class SubNav extends BaseComponent<SubNavProps, SubNavState> {
             dropdownProps.visible = isOpen;
         }
 
+        if (getPopupContainer) {
+            dropdownProps.getPopupContainer = getPopupContainer;
+        }
+
         if (isCollapsed || mode === strings.MODE_HORIZONTAL) {
             // Do not show dropdown when disabled
             _elem = !disabled ? (

+ 40 - 0
packages/semi-ui/navigation/_story/Popup/index.jsx

@@ -0,0 +1,40 @@
+import React from 'react';
+import { Nav } from '@douyinfe/semi-ui';
+import { IconUser, IconStar, IconUserGroup, IconEdit, IconApps, IconSetting } from '@douyinfe/semi-icons';
+
+export default function GetPopupNav() {
+    const items = [
+        { itemKey: 'user', text: '用户管理', icon: <IconUser />, disabled: true },
+        { itemKey: 'union', text: '公会中心', icon: <IconStar /> },
+        {
+            text: '任务平台',
+            icon: <IconSetting />,
+            itemKey: 'job',
+            disabled: true,
+            items: [{ itemKey: 'job_manage', text: '任务管理', disabled: true }, '用户任务查询'],
+        },
+        {
+            text: '收藏夹',
+            icon: <IconStar />,
+            itemKey: 'star',
+            items: [{ itemKey: 'like', text: '我的喜欢', disabled: true }, '点赞'],
+        },
+    ];
+
+    return (
+        <div>
+            <div id={'con'} style={{ position: 'relative ' }}>
+            </div>
+            <Nav
+                items={items}
+                mode={'horizontal'}
+                defaultOpenKeys={['job', 'star']}
+                getPopupContainer={() => document.querySelector('#con')}
+                defaultSelectedKeys={['user']}
+                footer={{
+                    collapseButton: true,
+                }}
+            />
+        </div>
+    );
+}

+ 6 - 0
packages/semi-ui/navigation/_story/navigation.stories.jsx

@@ -11,6 +11,7 @@ import WithChildren from './WithChildren';
 import ItemsChange from './ItemsChange';
 import DisabledNav from './DisabledNav';
 import Button from '../../button';
+import GetPopupNav from './Popup';
 
 import {
   IconMail,
@@ -328,3 +329,8 @@ export const DisabledNavDemo = () => <DisabledNav />;
 DisabledNavDemo.story = {
   name: 'disabled nav'
 }
+
+export const PopupDemo = () => <GetPopupNav />;
+PopupDemo.story = {
+  name: 'getPopupContainer'
+}

+ 12 - 5
packages/semi-ui/navigation/index.tsx

@@ -1,6 +1,6 @@
 /* eslint-disable max-lines-per-function */
 import BaseComponent, { BaseProps } from '../_base/baseComponent';
-import React, { Children } from 'react';
+import React, { Children, ReactElement, ReactNode } from 'react';
 import PropTypes from 'prop-types';
 import cls from 'classnames';
 import { noop, get, isEqual } from 'lodash';
@@ -63,11 +63,13 @@ export interface NavProps extends BaseProps {
     toggleIconPosition?: string;
     tooltipHideDelay?: number;
     tooltipShowDelay?: number;
+    getPopupContainer?: () => HTMLElement;
     onClick?: (data: { itemKey: React.ReactText; domEvent: MouseEvent; isOpen: boolean }) => void;
     onCollapseChange?: (isCollapse: boolean) => void;
     onDeselect?: (data?: any) => void;
     onOpenChange?: (data: { itemKey: (string | number); openKeys: (string | number)[]; domEvent: MouseEvent; isOpen: boolean }) => void;
-    onSelect?: (data: OnSelectedData) => void
+    onSelect?: (data: OnSelectedData) => void;
+    renderWrapper?: ({ itemElement, isSubNav, isInSubNav, props }: { itemElement: ReactElement;isInSubNav:boolean; isSubNav: boolean; props: NavItemProps | SubNavProps }) => ReactNode
 }
 
 export interface NavState {
@@ -146,7 +148,8 @@ class Nav extends BaseComponent<NavProps, NavState> {
         prefixCls: PropTypes.string,
         header: PropTypes.oneOfType([PropTypes.node, PropTypes.object]),
         footer: PropTypes.oneOfType([PropTypes.node, PropTypes.object]),
-        limitIndent: PropTypes.bool
+        limitIndent: PropTypes.bool,
+        getPopupContainer: PropTypes.func,
     };
 
     static defaultProps = {
@@ -299,7 +302,9 @@ class Nav extends BaseComponent<NavProps, NavState> {
             footer,
             header,
             toggleIconPosition,
-            limitIndent
+            limitIndent,
+            renderWrapper,
+            getPopupContainer
         } = this.props;
 
         const { selectedKeys, openKeys, items, isCollapsed } = this.state;
@@ -397,7 +402,9 @@ class Nav extends BaseComponent<NavProps, NavState> {
                             locale,
                             prefixCls,
                             toggleIconPosition,
-                            limitIndent
+                            limitIndent,
+                            renderWrapper,
+                            getPopupContainer
                         } as any}
                     >
                         <div className={finalCls} style={finalStyle}>

+ 6 - 2
packages/semi-ui/navigation/nav-context.ts

@@ -1,7 +1,9 @@
 import React from 'react';
 
-import { NavProps } from './index';
+import type { NavProps } from './index';
 import { Locale } from '../locale/interface';
+ 
+import type { DropdownProps } from '../dropdown';
 export interface NavContextType {
     isCollapsed?: boolean;
     mode?: NavProps['mode'];
@@ -18,7 +20,9 @@ export interface NavContextType {
     subNavMotion?: NavProps['subNavMotion'];
     subNavCloseDelay?: NavProps['subNavCloseDelay'];
     subNavOpenDelay?: NavProps['subNavOpenDelay'];
-    canUpdateOpenKeys?: boolean
+    canUpdateOpenKeys?: boolean;
+    renderWrapper?: NavProps['renderWrapper'];
+    getPopupContainer?: DropdownProps['getPopupContainer']
 }
 
 const NavContext = React.createContext<NavContextType>({

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

@@ -1,6 +1,6 @@
 {
     "name": "@douyinfe/semi-ui",
-    "version": "2.23.7",
+    "version": "2.24.0-beta.1",
     "description": "",
     "main": "lib/cjs/index.js",
     "module": "lib/es/index.js",
@@ -17,12 +17,12 @@
         "lib/*"
     ],
     "dependencies": {
-        "@douyinfe/semi-animation": "2.23.7",
-        "@douyinfe/semi-animation-react": "2.23.7",
-        "@douyinfe/semi-foundation": "2.23.7",
-        "@douyinfe/semi-icons": "2.23.7",
-        "@douyinfe/semi-illustrations": "2.23.7",
-        "@douyinfe/semi-theme-default": "2.23.7",
+        "@douyinfe/semi-animation": "2.24.0-beta.1",
+        "@douyinfe/semi-animation-react": "2.24.0-beta.1",
+        "@douyinfe/semi-foundation": "2.24.0-beta.1",
+        "@douyinfe/semi-icons": "2.24.0-beta.1",
+        "@douyinfe/semi-illustrations": "2.24.0-beta.1",
+        "@douyinfe/semi-theme-default": "2.24.0-beta.1",
         "async-validator": "^3.5.0",
         "classnames": "^2.2.6",
         "copy-text-to-clipboard": "^2.1.1",
@@ -110,4 +110,4 @@
         "webpack": "^4.46.0",
         "webpackbar": "^5.0.0-3"
     }
-}
+}

+ 0 - 21
packages/semi-ui/select/_story/select.stories.jsx

@@ -4,7 +4,6 @@ import './select.scss';
 import { Input, Select, Button, Icon, Avatar, Checkbox, Form, withField, Space, Tag } from '../../index';
 import CustomTrigger from './CustomTrigger';
 import classNames from 'classnames';
-import { getHighLightTextHTML } from '../../_utils/index';
 const Option = Select.Option;
 import { IconSearch, IconGift } from '@douyinfe/semi-icons';
 
@@ -2826,26 +2825,6 @@ Value0.story = {
   name: 'value=0',
 };
 
-const Highlight = () => {
-  const searchWords = ['do', 'dollar'];
-  const sourceString = 'aaa do dollar aaa';
-  const result = getHighLightTextHTML({
-    searchWords,
-    sourceString,
-  });
-  const result2 = getHighLightTextHTML({
-    searchWords: ['z'],
-    sourceString: 'aaazaaazaaa',
-  });
-  return result2;
-};
-
-export const _Highlight = () => <Highlight />;
-
-_Highlight.story = {
-  name: 'highlight',
-};
-
 export const ScrollIntoView = () => (
   <div>
       <p>single selection</p>

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

@@ -1,6 +1,6 @@
 {
     "name": "@douyinfe/semi-webpack-plugin",
-    "version": "2.23.7",
+    "version": "2.24.0-beta.1",
     "description": "",
     "author": "伍浩威 <[email protected]>",
     "homepage": "",
@@ -38,4 +38,4 @@
         "typescript": "^4"
     },
     "gitHead": "eb34a4f25f002bb4cbcfa51f3df93bed868c831a"
-}
+}

+ 4 - 0
src/images/docIcons/doc-highlight.svg

@@ -0,0 +1,4 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect x="3" y="8" width="18" height="8" rx="1" fill="#FAC800"/>
+<path d="M4.44342 4.44352C4.26265 4.62429 4.1611 4.86946 4.1611 5.12509V8.18065C4.1611 8.43629 4.26265 8.68146 4.44342 8.86222C4.62418 9.04299 4.86935 9.14454 5.12499 9.14454C5.38063 9.14454 5.6258 9.04299 5.80656 8.86222C5.98732 8.68146 6.08888 8.43629 6.08888 8.18065V6.08898H11.0361V17.9112H8.94443C8.68879 17.9112 8.44362 18.0128 8.26286 18.1935C8.0821 18.3743 7.98054 18.6195 7.98054 18.8751C7.98054 19.1307 8.0821 19.3759 8.26286 19.5567L8.40428 19.4152L8.26286 19.5567C8.44362 19.7374 8.68879 19.839 8.94443 19.839H15.0555C15.3112 19.839 15.5564 19.7374 15.7371 19.5567C15.9179 19.3759 16.0194 19.1307 16.0194 18.8751C16.0194 18.6195 15.9179 18.3743 15.7371 18.1935C15.5564 18.0128 15.3112 17.9112 15.0555 17.9112H12.9639V6.08898H17.9111V8.18065C17.9111 8.43629 18.0127 8.68146 18.1934 8.86222C18.3742 9.04299 18.6193 9.14454 18.875 9.14454C19.1306 9.14454 19.3758 9.04299 19.5566 8.86222C19.7373 8.68146 19.8389 8.43629 19.8389 8.18065V5.12509C19.8389 4.86946 19.7373 4.62429 19.5566 4.44352C19.3758 4.26276 19.1306 4.16121 18.875 4.16121H5.12499C4.86935 4.16121 4.62418 4.26276 4.44342 4.44352Z" fill="#6A6F7F" stroke="#6A6F7F" stroke-width="0.4"/>
+</svg>

+ 74 - 0
yarn.lock

@@ -1445,6 +1445,15 @@
   resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70"
   integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==
 
+"@douyinfe/[email protected]":
+  version "2.23.5"
+  resolved "https://registry.npmjs.org/@douyinfe/semi-animation-react/-/semi-animation-react-2.23.5.tgz#c106e869ddaa2f2fa4dd34381b601f42e4f83ed4"
+  integrity sha512-TIIUpcUGCRJDejkQxVMSEiogLM73P3vXZLuAxyxXg+cW5I/TK6ekynDswoE0M/pQf4hymrvuZPVq/MOD+ow6cA==
+  dependencies:
+    "@douyinfe/semi-animation" "2.12.0"
+    "@douyinfe/semi-animation-styled" "2.23.2"
+    classnames "^2.2.6"
+
 "@douyinfe/[email protected]":
   version "2.9.1"
   resolved "https://registry.yarnpkg.com/@douyinfe/semi-animation-react/-/semi-animation-react-2.9.1.tgz#f2e4c6ef7899729ee6145edf0579598ba195bfdd"
@@ -1475,6 +1484,13 @@
     "@babel/runtime-corejs3" "^7.15.4"
     bezier-easing "^2.1.0"
 
+"@douyinfe/[email protected]":
+  version "2.23.5"
+  resolved "https://registry.npmjs.org/@douyinfe/semi-animation/-/semi-animation-2.23.5.tgz#6d5bc3f3d86aecf0e80255c526f5afab95cadb9d"
+  integrity sha512-EEu4RWPTK1ksUB6SwTxmdgJ3qlDD0GaB9Azay4H93bknR/cV2lpbAhzes6nz3EiLua00MpJPQaLWQxs57nNWnw==
+  dependencies:
+    bezier-easing "^2.1.0"
+
 "@douyinfe/[email protected]":
   version "2.9.1"
   resolved "https://registry.yarnpkg.com/@douyinfe/semi-animation/-/semi-animation-2.9.1.tgz#4345fd86823b51e7c6fb5e9079d8f5c3ffe608f8"
@@ -1483,6 +1499,20 @@
     "@babel/runtime-corejs3" "^7.15.4"
     bezier-easing "^2.1.0"
 
+"@douyinfe/[email protected]":
+  version "2.23.5"
+  resolved "https://registry.npmjs.org/@douyinfe/semi-foundation/-/semi-foundation-2.23.5.tgz#b3a7cbfc6ce01644e852b19c91025cf03c75e51f"
+  integrity sha512-gEBhVzRlxedpxuCadX9uIHamOvFrNsyKUtFc/Jcr4WMOaJMrcHh3IgIHxmNK2RSvRLnX4/iUsLDNZGcSlh1mjQ==
+  dependencies:
+    "@douyinfe/semi-animation" "2.12.0"
+    async-validator "^3.5.0"
+    classnames "^2.2.6"
+    date-fns "^2.9.0"
+    date-fns-tz "^1.0.10"
+    lodash "^4.17.21"
+    memoize-one "^5.2.1"
+    scroll-into-view-if-needed "^2.2.24"
+
 "@douyinfe/[email protected]":
   version "2.9.1"
   resolved "https://registry.yarnpkg.com/@douyinfe/semi-foundation/-/semi-foundation-2.9.1.tgz#1300bb97d6ceb92274ca4c9e6c66c5c16dc284ea"
@@ -1498,6 +1528,13 @@
     memoize-one "^5.2.1"
     scroll-into-view-if-needed "^2.2.24"
 
+"@douyinfe/[email protected]", "@douyinfe/semi-icons@^2.0.0":
+  version "2.23.5"
+  resolved "https://registry.npmjs.org/@douyinfe/semi-icons/-/semi-icons-2.23.5.tgz#856180dd51b20986ac181fe6e849abda581efa6b"
+  integrity sha512-fknH7iCb9iIp35xWM4+MP/zbRicAp0Z4ijSt9UQAS6Xsza42sAAqKI3rswdmgiE4hPd2syg9fxnR9mb/JaiW+w==
+  dependencies:
+    classnames "^2.2.6"
+
 "@douyinfe/[email protected]", "@douyinfe/semi-icons@latest":
   version "2.9.1"
   resolved "https://registry.yarnpkg.com/@douyinfe/semi-icons/-/semi-icons-2.9.1.tgz#7a04e1a77070220b04f63e6f65aac30155ed8ddd"
@@ -1506,6 +1543,11 @@
     "@babel/runtime-corejs3" "^7.15.4"
     classnames "^2.2.6"
 
+"@douyinfe/[email protected]":
+  version "2.23.5"
+  resolved "https://registry.npmjs.org/@douyinfe/semi-illustrations/-/semi-illustrations-2.23.5.tgz#0336378b114b1be46a19331ab8b163b09055586a"
+  integrity sha512-hnx+WztfiZaqAR0zOsBreSSE+TRNxA2+fi9eW6dtwjRJDg6thA4VcW4T3bkhBv9il3oSNHV/He3w4I1NbRatsQ==
+
 "@douyinfe/[email protected]":
   version "2.9.1"
   resolved "https://registry.yarnpkg.com/@douyinfe/semi-illustrations/-/semi-illustrations-2.9.1.tgz#1a448d1854ee1beeba57ea612da052b549ea105f"
@@ -1579,6 +1621,13 @@
     monaco-themes "^0.3.3"
     react-live "^2.2.2"
 
+"@douyinfe/[email protected]":
+  version "2.23.5"
+  resolved "https://registry.npmjs.org/@douyinfe/semi-theme-default/-/semi-theme-default-2.23.5.tgz#54a2f99db79ff7e2fc6137f0d5bf82d3bffdbaca"
+  integrity sha512-zBTUB6aYMP6C3QctmFdg7ChN6wctgONKHvlbhvowMZ5M/YQrCPIYxu1LwUN+a2dSnbwY+1aKC+5t6firBMNThw==
+  dependencies:
+    glob "^7.1.6"
+
 "@douyinfe/[email protected]":
   version "2.9.1"
   resolved "https://registry.yarnpkg.com/@douyinfe/semi-theme-default/-/semi-theme-default-2.9.1.tgz#734113e9783ca58b69afe1769005e7e57e5a4da7"
@@ -1586,6 +1635,31 @@
   dependencies:
     glob "^7.1.6"
 
+"@douyinfe/semi-ui@^2.0.0":
+  version "2.23.5"
+  resolved "https://registry.npmjs.org/@douyinfe/semi-ui/-/semi-ui-2.23.5.tgz#06c5bd1ce868d9966412ed847293aed605292928"
+  integrity sha512-DOE8OPvX7VHapZ8AnXTr6sssQO9Ct/yHC+Ja56g5lL9hyq+UkSX6ENXocPA2+DDX/2jxL2UiiZtyp7hPtZpJsA==
+  dependencies:
+    "@douyinfe/semi-animation" "2.23.5"
+    "@douyinfe/semi-animation-react" "2.23.5"
+    "@douyinfe/semi-foundation" "2.23.5"
+    "@douyinfe/semi-icons" "2.23.5"
+    "@douyinfe/semi-illustrations" "2.23.5"
+    "@douyinfe/semi-theme-default" "2.23.5"
+    async-validator "^3.5.0"
+    classnames "^2.2.6"
+    copy-text-to-clipboard "^2.1.1"
+    date-fns "^2.9.0"
+    date-fns-tz "^1.0.10"
+    lodash "^4.17.21"
+    prop-types "^15.7.2"
+    react-resizable "^1.8.0"
+    react-sortable-hoc "^2.0.0"
+    react-window "^1.8.2"
+    resize-observer-polyfill "^1.5.1"
+    scroll-into-view-if-needed "^2.2.24"
+    utility-types "^3.10.0"
+
 "@douyinfe/semi-ui@latest":
   version "2.9.1"
   resolved "https://registry.yarnpkg.com/@douyinfe/semi-ui/-/semi-ui-2.9.1.tgz#505d4783ea1fa73d307b75f62091030f1fee9332"