Browse Source

Merge branch 'release' of https://github.com/DouyinFE/semi-design into release

走鹃 3 years ago
parent
commit
6527962c7c

+ 1 - 1
README.md

@@ -22,7 +22,7 @@
 [license-url]: https://github.com/DouyinFE/semi-design/blob/main/LICENSE
 [codecov-badge]: https://img.shields.io/codecov/c/gh/DouyinFE/semi-design
 [codecov-url]: https://app.codecov.io/gh/DouyinFE/semi-design
-[chromatic-badge]: https://img.shields.io/badge/test-chromatic-f52
+[chromatic-badge]: https://img.shields.io/badge/test-chromatic-brightgreen
 [chromatic-url]: https://www.chromatic.com/
 [cypress-badge]: https://img.shields.io/endpoint?url=https://dashboard.cypress.io/badge/simple/k83u7j&style=flat&logo=cypress
 [cypress-url]: https://dashboard.cypress.io/projects/k83u7j/runs

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

@@ -272,6 +272,163 @@ class Demo extends React.Component {
 }
 ```
 
+After setting the `filterTreeNode` property to enable search, you can customize the rendering method of the search box by setting `searchRender`. When set to `false`, the search box can be hidden.
+```jsx live=true
+import React from 'react';
+import { Tree } from '@douyinfe/semi-ui';
+
+() => {
+  const treeData = [
+            {
+                label: 'Asia',
+                value: 'Asia',
+                key: '0',
+                children: [
+                    {
+                        label: 'China',
+                        value: 'China',
+                        key: '0-0',
+                        children: [
+                            {
+                                label: 'Beijing',
+                                value: 'Beijing',
+                                key: '0-0-0',
+                            },
+                            {
+                                label: 'Shanghai',
+                                value: 'Shanghai',
+                                key: '0-0-1',
+                            },
+                        ],
+                    },
+                    {
+                        label: 'Japan',
+                        value: 'Japan',
+                        key: '0-1',
+                        children: [
+                            {
+                                label: 'Osaka',
+                                value: 'Osaka',
+                                key: '0-1-0'
+                            }
+                        ]
+                    },
+                ],
+            },
+            {
+                label: 'North America',
+                value: 'North America',
+                key: '1',
+                children: [
+                    {
+                        label: 'United States',
+                        value: 'United States',
+                        key: '1-0'
+                    },
+                    {
+                        label: 'Canada',
+                        value: 'Canada',
+                        key: '1-1'
+                    }
+                ]
+            }
+        ];
+
+  return (
+    <Tree
+      filterTreeNode
+      searchRender={({ prefix, ...restProps }) => (
+        <Input
+          prefix='Search'
+          {...restProps}
+        />
+      )}
+      treeData={treeData}
+    />
+  );
+};
+
+```
+
+### Trigger search manually
+Use ref to get tree instance,you can call `search` method of tree to trigger search manually. Note that you need to set `filterTreeNode` to enable search at the same time.If the search box is outside the tree, you can hide the search box inside the tree by setting `searchRender=false`.
+```jsx live=true
+import React from 'react';
+import { Tree } from '@douyinfe/semi-ui';
+
+() => {
+  const ref = useRef();
+  const treeData = [
+    {
+      label: 'Asia',
+      value: 'Asia',
+      key: '0',
+      children: [
+        {
+          label: 'China',
+          value: 'China',
+          key: '0-0',
+          children: [
+            {
+              label: 'Beijing',
+              value: 'Beijing',
+              key: '0-0-0',
+            },
+            {
+              label: 'Shanghai',
+              value: 'Shanghai',
+              key: '0-0-1',
+            },
+          ],
+        },
+        {
+          label: 'Japan',
+          value: 'Japan',
+          key: '0-1',
+          children: [
+            {
+              label: 'Osaka',
+              value: 'Osaka',
+              key: '0-1-0',
+            },
+          ],
+        },
+      ],
+    },
+    {
+      label: 'North America',
+      value: 'North America',
+      key: '1',
+      children: [
+        {
+          label: 'United States',
+          value: 'United States',
+          key: '1-0',
+        },
+        {
+          label: 'Canada',
+          value: 'Canada',
+          key: '1-1',
+        },
+      ],
+    },
+  ];
+  return (
+    <div>
+      <Input aria-label='filter tree' prefix="Search" showClear onChange={v => ref.current.search(v)} />
+      <div style={{ marginTop: 20}}>search result:</div>
+      <Tree
+        ref={ref}
+        filterTreeNode
+        searchRender={false}
+        treeData={treeData}
+        blockNode={false}
+      />
+    </div>
+  );
+};
+```
+
 ### JSON TreeData
 
 You could use `treeDataSimpleJson` to pass in `treeNodes` data in JSON format. In this case, key will be used as `key` and `label`, and value will be used as `value` correspondingly. Return value includes JSON data in selected nodes.
@@ -2033,8 +2190,10 @@ import { IconFixedStroked, IconSectionStroked, IconAbsoluteStroked, IconInnerSec
 | itemSize | Height for each line of treeNode, required | number | - |
 | width | Width | number\|string | '100%' |
 
-### Ref Method
-- search(sugInput) => void
+### Methods
+|Name | Description | Type 
+|----|----|----|
+| search | Trigger search manually | (value: string) => void |
 
 
 ## Accessibility

+ 162 - 2
content/navigation/tree/index.md

@@ -259,6 +259,163 @@ class Demo extends React.Component {
 }
 ```
 
+设置 `filterTreeNode` 属性开启搜索后,可以通过设置 `searchRender` 自定义搜索框的渲染方法,设置为`false`时可以隐藏搜索框。
+```jsx live=true
+import React from 'react';
+import { Tree } from '@douyinfe/semi-ui';
+
+() => {
+  const treeData = [
+            {
+                label: 'Asia',
+                value: 'Asia',
+                key: '0',
+                children: [
+                    {
+                        label: 'China',
+                        value: 'China',
+                        key: '0-0',
+                        children: [
+                            {
+                                label: 'Beijing',
+                                value: 'Beijing',
+                                key: '0-0-0',
+                            },
+                            {
+                                label: 'Shanghai',
+                                value: 'Shanghai',
+                                key: '0-0-1',
+                            },
+                        ],
+                    },
+                    {
+                        label: 'Japan',
+                        value: 'Japan',
+                        key: '0-1',
+                        children: [
+                            {
+                                label: 'Osaka',
+                                value: 'Osaka',
+                                key: '0-1-0'
+                            }
+                        ]
+                    },
+                ],
+            },
+            {
+                label: 'North America',
+                value: 'North America',
+                key: '1',
+                children: [
+                    {
+                        label: 'United States',
+                        value: 'United States',
+                        key: '1-0'
+                    },
+                    {
+                        label: 'Canada',
+                        value: 'Canada',
+                        key: '1-1'
+                    }
+                ]
+            }
+        ];
+
+  return (
+    <Tree
+      filterTreeNode
+      searchRender={({ prefix, ...restProps }) => (
+        <Input
+          prefix='Search'
+          {...restProps}
+        />
+      )}
+      treeData={treeData}
+    />
+  );
+};
+
+```
+
+### 手动触发搜索
+可以通过ref的方式获取tree的实例,调用tree的`search`方法进行搜索。注意需要同时设置`filterTreeNode`开启搜索,如果搜索框在tree外部,可以通过设置`searchRender=false`隐藏tree内部的搜索框。
+```jsx live=true
+import React from 'react';
+import { Tree } from '@douyinfe/semi-ui';
+
+() => {
+  const ref = useRef();
+  const treeData = [
+    {
+      label: 'Asia',
+      value: 'Asia',
+      key: '0',
+      children: [
+        {
+          label: 'China',
+          value: 'China',
+          key: '0-0',
+          children: [
+            {
+              label: 'Beijing',
+              value: 'Beijing',
+              key: '0-0-0',
+            },
+            {
+              label: 'Shanghai',
+              value: 'Shanghai',
+              key: '0-0-1',
+            },
+          ],
+        },
+        {
+          label: 'Japan',
+          value: 'Japan',
+          key: '0-1',
+          children: [
+            {
+              label: 'Osaka',
+              value: 'Osaka',
+              key: '0-1-0',
+            },
+          ],
+        },
+      ],
+    },
+    {
+      label: 'North America',
+      value: 'North America',
+      key: '1',
+      children: [
+        {
+          label: 'United States',
+          value: 'United States',
+          key: '1-0',
+        },
+        {
+          label: 'Canada',
+          value: 'Canada',
+          key: '1-1',
+        },
+      ],
+    },
+  ];
+  return (
+    <div>
+      <Input aria-label='filter tree' prefix="Search" showClear onChange={v => ref.current.search(v)} />
+      <div style={{ marginTop: 20}}>搜索结果如下:</div>
+      <Tree
+        ref={ref}
+        filterTreeNode
+        searchRender={false}
+        treeData={treeData}
+        blockNode={false}
+      />
+    </div>
+  );
+};
+```
+
 ### 简单 JSON 格式的数据
 可以通过 `treeDataSimpleJson` 传入 JSON 形式的 `treeNodes` 数据。此时 key-value 键值对中的 key 值将作为 `treeNode` 的 `key` 和 `label`,`value` 值将作为 `treeNode` 的 `value`。返回值为包含选中节点的 JSON 数据。
 
@@ -2027,8 +2184,11 @@ import { IconFixedStroked, IconSectionStroked, IconAbsoluteStroked, IconInnerSec
 | itemSize | 每行的treeNode的高度,必传 | number | - |
 | width | 宽度值 | number\|string | '100%' |
 
-### Ref 方法
-- search(sugInput) => void
+### Methods
+
+|名称 | 描述 | 类型
+|----|----|----|
+| search | 手动触发搜索 | (value: string) => void |
 
 ## Accessibility
 

+ 2 - 2
content/start/getting-started/index-en-US.md

@@ -154,5 +154,5 @@ Introduce the full amount of semi css in `global.css`. Currently, on-demand impo
 You need to replace the path of the import statement in Step3, and replace the default theme CSS product with the CSS product in your customized theme package, for example, the theme package is `@semi-bot/semi-theme-nyx-c`
 ```css
 /* styles/globals.css */
-@import '~@semi-bot/semi-theme-nyx-c/semi.min.css'';
-```
+@import '~@semi-bot/semi-theme-nyx-c/semi.min.css';
+```

+ 3 - 3
content/start/getting-started/index.md

@@ -78,18 +78,18 @@ module.exports = semi({
 
 ### Step3
 
-在 `global.css` 中引入全量的 semi css。目前不支持按需引入。
+在 `global.css` 中引入全量的 semi css。目前在 Next.js 中不支持按需引入。
 
 ```css
 /* styles/globals.css */
 @import '~@douyinfe/semi-ui/dist/css/semi.min.css';
 ```
 
-**如何在 nextjs 中使用主题包**  
+**如何在 Next.js 中使用主题包**  
 你需要更换 Step3 中 import 语句的路径,将默认主题 CSS 产物更换为你定制的主题包中的 CSS 产物,例如主题包为 `@semi-bot/semi-theme-nyx-c`
 ```css
 /* styles/globals.css */
-@import '~@semi-bot/semi-theme-nyx-c/semi.min.css'';
+@import '~@semi-bot/semi-theme-nyx-c/semi.min.css';
 ```
 
 ## 4、UMD 方式使用组件

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

@@ -8,6 +8,7 @@ $module: #{$prefix}-modal;
     position: relative;
     // width: 600px;
     margin: $spacing-modal-marginY $spacing-modal-marginX;
+    color: $color-modal_main-text;
     
     &-mask {
         position: fixed;

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

@@ -422,10 +422,10 @@ $module: #{$prefix}-tabs;
     &-pane {
         width: 100%;
         overflow: hidden;
+        color: $color-tabs_tab-pane-text-default;
         // position: absolute;
         // flex-shrink: 0;
         // position: absolute;
-
         &:focus-visible {
             outline: $width-tabs-outline solid $color-tabs_tab-outline-focus;
         }

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

@@ -46,6 +46,7 @@ $color-tabs_tab_selected-icon-default: var(--semi-color-primary); // 页签图
 
 $color-tabs_tab-outline-focus: var(--semi-color-primary-light-active); // 页签轮廓 - 聚焦
 
+$color-tabs_tab-pane-text-default: var(--semi-color-text-0); // 标签页内容文本颜色 - 默认
 
 $font-tabs_tab-fontWeight: $font-weight-regular; // 页签文本字重 - 默认
 $font-tabs_tab_active-fontWeight: $font-weight-bold; // 页签文本字重 - 选中

+ 9 - 1
packages/semi-foundation/timePicker/timePicker.scss

@@ -48,9 +48,17 @@ $module-list: #{$prefix}-scrolllist;
                 border: $width-timePicker_range_panel-border solid $color-timePicker_range_panel-border;
                 border-radius: $radius-timePicker_range_panel;
 
+                // left
+                .#{$prefix}-scrolllist:first-of-type {
+                    border-radius: $radius-timePicker_range_panel 0 0 $radius-timePicker_range_panel;
+                }
+                // right
+                .#{$prefix}-scrolllist:last-of-type {
+                    border-radius: 0 $radius-timePicker_range_panel $radius-timePicker_range_panel 0;
+                }
+
                 & > .#{$prefix}-scrolllist:not(:last-child) {
                     .#{$prefix}-scrolllist {
-
                         &-body {
                             border-right: $width-timePicker_range_panel_scrolllist_body-border solid $color-timePicker_range_picker_panel_split-border;
                         }

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

@@ -542,11 +542,25 @@ $module: #{$prefix}-upload;
             cursor: pointer;
             @include font-size-regular;
             margin-bottom: $spacing-upload_drag_area_main_text-marginBottom;
+            color: $color-upload_drag_area_main-text-default;
+            &:hover {
+                color: $color-upload_drag_area_main-text-hover;
+            }
+            &:active {
+                color: $color-upload_drag_area_main-text-active;
+            }
         }
 
         &-sub-text {
             cursor: pointer;
             @include font-size-small;
+            color: $color-upload_drag_area_sub-text-default;
+            &:hover {
+                color: $color-upload_drag_area_sub-text-hover;
+            }
+            &:active {
+                color: $color-upload_drag_area_sub-text-active;
+            }
         }
 
         &-tips {

+ 8 - 0
packages/semi-foundation/upload/variables.scss

@@ -13,6 +13,14 @@ $color-upload_drag_area_disabled-text: var(--semi-color-disabled-text); // 上
 $color-upload_drag_area-bg: var(--semi-color-tertiary-light-default); // 上传可拖拽区域背景颜色 - 默认
 $color-upload_drag_area_icon: var(--semi-color-primary); // 上传可拖拽区域图标颜色
 $color-upload_drag_area_tips-text: var(--semi-color-primary); // 上传可拖拽区域背景颜色 - 悬浮
+
+$color-upload_drag_area_main-text-default: var(--semi-color-text-0); // 上传可拖拽区主要提示文本颜色 - 默认
+$color-upload_drag_area_main-text-hover: var(--semi-color-text-0); // 上传可拖拽区主要提示文本颜色 - 悬浮
+$color-upload_drag_area_main-text-active: var(--semi-color-text-0); // 上传可拖拽区主要提示文本颜色 - 按下
+$color-upload_drag_area_sub-text-default: var(--semi-color-text-0); // 上传可拖拽区次要提示文本颜色 - 默认
+$color-upload_drag_area_sub-text-hover: var(--semi-color-text-0); // 上传可拖拽区次要提示文本颜色 - 悬浮
+$color-upload_drag_area_sub-text-active: var(--semi-color-text-0); // 上传可拖拽区次要提示文本颜色 - 按下
+
 $color-upload_file_card_fail_info-text: var(--semi-color-danger); // 上传文件卡片失败提示信息文本颜色
 $color-upload_file_card_preview_placeholder-bg: rgba(var(--semi-grey-3), 1); // 文件卡片默认预览背景颜色
 $color-upload_file_card_preview_placeholder-text: rgba(var(--semi-white), 1); // 文件卡片默认预览图颜色

+ 4 - 2
packages/semi-ui/cascader/index.tsx

@@ -412,13 +412,15 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
                             realValue as SimpleValueType[][] :
                             [realValue] as SimpleValueType[][];
                     } else {
-                        normallizedValue = [[realValue]];
+                        if (realValue !==  undefined) {
+                            normallizedValue = [[realValue]];
+                        }
                     }
                     // formatValuePath is used to save value of valuePath
                     const formatValuePath: (string | number)[][] = [];
                     normallizedValue.forEach((valueItem: SimpleValueType[]) => {
                         const formatItem: (string | number)[] = onChangeWithObject ?
-                            (valueItem as CascaderData[]).map(i => i.value) :
+                            (valueItem as CascaderData[]).map(i => i?.value) :
                             valueItem as (string | number)[];
                         formatValuePath.push(formatItem);
                     });

+ 5 - 5
packages/semi-ui/gulpfile.js

@@ -73,14 +73,14 @@ gulp.task('compileScss', function compileScss() {
             }
         ))
         .pipe(sass({
-            importer: (url, prev) => {
+            importer: (url, prev, done) => {
                 const rootPath = path.join(__dirname, '../../');
                 let realUrl = url;
                 if (/~@douyinfe\/semi-foundation/.test(url)) {
                     const semiUIPath = path.join(rootPath, 'packages/semi-foundation');
                     realUrl = url.replace(/~@douyinfe\/semi-foundation/, semiUIPath);
                 }
-                return { url: realUrl };
+                done({ file:realUrl });
             },
             charset: false
         }).on('error', sass.logError))
@@ -104,11 +104,11 @@ gulp.task('moveScssForCJS', function moveScssForCJS() {
     return moveScss(false);
 });
 
-gulp.task('compileLib', 
+gulp.task('compileLib',
     gulp.series(
         [
-            'cleanLib', 
-            'compileScss', 
+            'cleanLib',
+            'compileScss',
             gulp.parallel('moveScssForESM', 'moveScssForCJS'),
             gulp.parallel('compileTSXForESM', 'compileTSXForCJS')
         ]

+ 3 - 0
packages/semi-ui/table/_story/v2/FixedOnHeaderRow/index.jsx

@@ -3,6 +3,9 @@ import { Table, Avatar, Toast } from '@douyinfe/semi-ui';
 import * as dateFns from 'date-fns';
 
 App.storyName = 'fix onHeaderRow';
+App.parameters = {
+    chromatic: { disableSnapshot: true },
+};
 
 /**
  * test with cypress

+ 9 - 11
packages/semi-ui/tagInput/index.tsx

@@ -333,7 +333,7 @@ class TagInput extends BaseComponent<TagInputProps, TagInputState> {
         const typoCls = cls(`${prefixCls}-wrapper-typo`, {
             [`${prefixCls}-wrapper-typo-disabled`]: disabled
         });
-        const spanNotWithPopoverCls = cls(`${prefixCls}-wrapper-n`, {
+        const restTagsCls = cls(`${prefixCls}-wrapper-n`, {
             [`${prefixCls}-wrapper-n-disabled`]: disabled
         });
         const restTags: Array<React.ReactNode> = [];
@@ -372,13 +372,18 @@ class TagInput extends BaseComponent<TagInputProps, TagInputState> {
                 tags.push(item);
             }
         });
+
+        const restTagsContent = (
+            <span className={restTagsCls}>+{tagsArray.length - maxTagCount}</span>
+        );
+
         return (
             <>
                 {tags}
                 {
                     restTags.length > 0 &&
                     (
-                        showRestTagsPopover && !disabled ?
+                        showRestTagsPopover ?
                             (
                                 <Popover
                                     content={restTags}
@@ -388,16 +393,9 @@ class TagInput extends BaseComponent<TagInputProps, TagInputState> {
                                     autoAdjustOverflow
                                     {...restTagsPopoverProps}
                                 >
-                                    <span className={cls(`${prefixCls}-wrapper-n`)}>
-                                        +{tagsArray.length - maxTagCount}
-                                    </span>
+                                    {restTagsContent}
                                 </Popover>
-                            ) :
-                            (
-                                <span className={spanNotWithPopoverCls}>
-                                    {`+${tagsArray.length - maxTagCount}`}
-                                </span>
-                            )
+                            ) : restTagsContent
                     )
                 }
             </>