Browse Source

fix: [Transfer] Fixed Transfer in Popover causing Popover to close when dragged, close #1149, #1226 (#1247)

YyumeiZhang 2 years ago
parent
commit
4cb9b86b77

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

@@ -20,6 +20,10 @@ $module: #{$prefix}-tagInput;
         &-item {
         &-item {
             display: flex;
             display: flex;
             align-items: center;
             align-items: center;
+
+            &-move {
+                z-index: $z-tagInput_drag_item_move;
+            }
         }
         }
 
 
         &-handler {
         &-handler {

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

@@ -47,3 +47,5 @@ $width-tagInput-border-hover: $width-tagInput-border-default; // 标签输入框
 $width-tagInput-border-focus: $border-thickness-control-focus; // 标签输入框描边宽度 - 选中态
 $width-tagInput-border-focus: $border-thickness-control-focus; // 标签输入框描边宽度 - 选中态
 
 
 $radius-tagInput: var(--semi-border-radius-small); // 标签输入框圆角
 $radius-tagInput: var(--semi-border-radius-small); // 标签输入框圆角
+
+$z-tagInput_drag_item_move: 2000 !default; // 标签输入框中正在拖拽元素的z-index

+ 9 - 3
packages/semi-foundation/transfer/transfer.scss

@@ -165,9 +165,15 @@ $module: #{$prefix}-transfer;
                 word-break: break-all;
                 word-break: break-all;
             }
             }
 
 
-            &-drag-handler {
-                margin-right: $spacing-transfer_right_item_drag_handler-marginRight;
-                flex-shrink: 0;
+            &-drag {
+                &-handler {
+                    margin-right: $spacing-transfer_right_item_drag_handler-marginRight;
+                    flex-shrink: 0;
+                }
+
+                &-item-move {
+                    z-index: $z-transfer_right_item_drag_item_move;
+                }            
             }
             }
         }
         }
 
 

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

@@ -53,3 +53,5 @@ $radius-transfer: var(--semi-border-radius-medium); // 穿梭框圆角
 
 
 // Font
 // Font
 $font-transfer_header_all-fontWeight: 600; // 穿梭框字重
 $font-transfer_header_all-fontWeight: 600; // 穿梭框字重
+
+$z-transfer_right_item_drag_item_move: 2000 !default; // 穿梭框右侧面板中正在拖拽元素的z-index

+ 3 - 0
packages/semi-theme-default/scss/variables.scss

@@ -45,6 +45,9 @@ $z-tooltip: 1060; // tooltip 组件 z-index
 $z-image_preview: 1070; // Image 组件预览层z-index
 $z-image_preview: 1070; // Image 组件预览层z-index
 $z-image_preview_header: 1; // Image 组件预览层中 header 部分 z-index
 $z-image_preview_header: 1; // Image 组件预览层中 header 部分 z-index
 
 
+// 正在拖拽中的元素的 z-index,需要高于所有的弹出层组件 z-index
+$z-transfer_right_item_drag_item_move: 2000; // 穿梭框右侧面板中正在拖拽元素的z-index
+$z-tagInput_drag_item_move: 2000; // 标签输入框中正在拖拽元素的z-index
 
 
 // font
 // font
 $font-family-regular: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI',
 $font-family-regular: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI',

+ 72 - 3
packages/semi-ui/tagInput/_story/tagInput.stories.jsx

@@ -1,6 +1,5 @@
-import React from 'react';
-import { Toast, Icon, Button, Avatar, Form } from '@douyinfe/semi-ui/';
-import TagInput from '../index';
+import React, { useState, useCallback } from 'react';
+import { Toast, Icon, Button, Avatar, Form, Popover, SideSheet, Modal, TagInput } from '../../index';
 import { IconGift, IconVigoLogo } from '@douyinfe/semi-icons';
 import { IconGift, IconVigoLogo } from '@douyinfe/semi-icons';
 const style = {
 const style = {
   width: 400,
   width: 400,
@@ -443,3 +442,73 @@ export const TagInputInForm = () => (
 PrefixSuffix.story = {
 PrefixSuffix.story = {
   name: 'TagInputInForm'
   name: 'TagInputInForm'
 };
 };
+
+export const TagInputInPopover = () => {
+  // 在弹出层中点击item,可拖拽item被遮挡问题:https://github.com/DouyinFE/semi-design/issues/1149
+  const [sideSheetVisible, setSideSheetVisible] = useState(false);
+  const [modalVisible, setModalVisible] = useState(false);
+  const sideSheetChange = useCallback(() => {
+    setSideSheetVisible(!sideSheetVisible);
+  }, [sideSheetVisible]);
+
+  const showDialog = () => {
+    setModalVisible(true);
+  };
+
+  const handleOk = () => {
+    setModalVisible(false);
+  };
+
+  const handleCancel = () => {
+    setModalVisible(false);
+  };
+
+  const data = Array.from({ length: 30 }, (v, i) => {
+    return {
+      label: `选项名称 ${i}`,
+      value: i,
+      disabled: false,
+      key: i
+    };
+  });
+
+  const tagInputNode = (<TagInput
+    draggable
+    allowDuplicates={false}
+    defaultValue={['抖音', '火山', '西瓜视频']}
+    placeholder='请输入...'
+    onChange={v => console.log(v)}
+  />);
+
+  return (
+    <div className="App">
+      <p>issues 1149: 在弹出层中点击item,可拖拽item被遮挡问题</p>
+      <Popover
+        trigger="click"
+        position='rightTop'
+        content={<div style={{ padding: 100 }}>{tagInputNode}</div>}
+      >
+        <Button>TagInput In Popover</Button>
+      </Popover>
+      <br /><br />
+       {/* 弹出层:sideSheet */}
+       <Button onClick={sideSheetChange}>TagInput In SideSheet</Button>
+        <SideSheet title="滑动侧边栏" visible={sideSheetVisible} onCancel={sideSheetChange} size="medium">
+          {tagInputNode}
+        </SideSheet>
+        <br /><br />
+        {/* 弹出层:Modal */}
+        <Button onClick={showDialog}>TagInput in Modal</Button>
+        <Modal
+          title="基本对话框"
+          visible={modalVisible}
+          onOk={handleOk}
+          onCancel={handleCancel}
+          closeOnEsc={true}
+        >
+          {tagInputNode}
+        </Modal>
+    </div>
+  );
+}
+

+ 2 - 1
packages/semi-ui/tagInput/index.tsx

@@ -484,8 +484,9 @@ class TagInput extends BaseComponent<TagInputProps, TagInputState> {
         }));
         }));
 
 
         if (active && draggable && sortableListItems.length > 0) {
         if (active && draggable && sortableListItems.length > 0) {
+            // helperClass:add styles to the helper(item being dragged) https://github.com/clauderic/react-sortable-hoc/issues/87
             // @ts-ignore skip SortableItem type check
             // @ts-ignore skip SortableItem type check
-            return <SortableList useDragHandle items={sortableListItems} onSortEnd={this.onSortEnd} axis={"xy"} />;
+            return <SortableList useDragHandle helperClass={`${prefixCls}-drag-item-move`} items={sortableListItems} onSortEnd={this.onSortEnd} axis={"xy"} />;
         } 
         } 
         return (
         return (
             <>
             <>

+ 50 - 7
packages/semi-ui/transfer/_story/transfer.stories.jsx

@@ -1,11 +1,5 @@
 import React, { useState, useRef } from 'react';
 import React, { useState, useRef } from 'react';
-import { Transfer, Button } from '../../index';
-import Table from '../../table';
-import Avatar from '../../avatar';
-import Checkbox from '../../checkbox';
-import Icon from '../../icons';
-import Tree from '../../tree';
-import Input from '../../input';
+import { Transfer, Button, Popover, SideSheet, Avatar, Checkbox, Tree, Input } from '../../index';
 import { omit, values } from 'lodash';
 import { omit, values } from 'lodash';
 import './transfer.scss';
 import './transfer.scss';
 import { SortableContainer, SortableElement, sortableHandle } from 'react-sortable-hoc';
 import { SortableContainer, SortableElement, sortableHandle } from 'react-sortable-hoc';
@@ -785,3 +779,52 @@ export const CustomRenderWithDragSort = () => <CustomRenderDragDemo />;
 CustomRenderWithDragSort.story = {
 CustomRenderWithDragSort.story = {
   name: 'customRender with drag sort',
   name: 'customRender with drag sort',
 };
 };
+
+export const TransferInPopover = () => {
+  // 点击可拖拽item,导致弹出层消失问题:https://github.com/DouyinFE/semi-design/issues/1226
+  // 在弹出层中点击item,导致可拖拽item被遮挡问题:https://github.com/DouyinFE/semi-design/issues/1149
+  const [visible, setVisible] = useState(false);
+  const change = () => {
+      setVisible(!visible);
+  };
+
+  const data = Array.from({ length: 30 }, (v, i) => {
+    return {
+      label: `选项名称 ${i}`,
+      value: i,
+      disabled: false,
+      key: i
+    };
+  });
+
+  const transferNode = (
+    <Transfer
+      style={{ width: 568, height: 416 }}
+      dataSource={data}
+      defaultValue={[2, 4]}
+      draggable
+      onChange={(values, items) => console.log(values, items)}
+    />
+  );
+
+  return (
+    <div className="App">
+      <>
+        {/* 弹出层:Popover */}
+        <Popover
+          trigger="click"
+          position='rightTop'
+          content={transferNode}
+        >
+          <Button>Transfer In Popover</Button>
+        </Popover>
+        {/* 弹出层:sideSheet */}
+        <br /><br />
+        <Button onClick={change}>Transfer In SideSheet</Button>
+        <SideSheet title="滑动侧边栏" visible={visible} onCancel={change} size="medium">
+          {transferNode}
+        </SideSheet>
+      </>
+    </div>
+  );
+}

+ 23 - 15
packages/semi-ui/transfer/index.tsx

@@ -152,6 +152,22 @@ export interface TransferProps {
 
 
 const prefixcls = cssClasses.PREFIX;
 const prefixcls = cssClasses.PREFIX;
 
 
+// SortableItem & SortableList should not be assigned inside of the render function
+const SortableItem = SortableElement((
+    (props: DraggableResolvedDataItem) => (props.item.node as React.FC<DraggableResolvedDataItem>)
+));
+
+const SortableList = SortableContainer(({ items }: { items: Array<ResolvedDataItem> }) => (
+    <div className={`${prefixcls}-right-list`} role="list" aria-label="Selected list">
+        {items.map((item, index: number) => (
+            // @ts-ignore skip SortableItem type check
+            <SortableItem key={item.label} index={index} item={item} />
+        ))}
+    </div>
+    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+    // @ts-ignore see reasons: https://github.com/clauderic/react-sortable-hoc/issues/206
+), { distance: 10 });
+
 class Transfer extends BaseComponent<TransferProps, TransferState> {
 class Transfer extends BaseComponent<TransferProps, TransferState> {
     static propTypes = {
     static propTypes = {
         style: PropTypes.object,
         style: PropTypes.object,
@@ -566,22 +582,14 @@ class Transfer extends BaseComponent<TransferProps, TransferState> {
     }
     }
 
 
     renderRightSortableList(selectedData: Array<ResolvedDataItem>) {
     renderRightSortableList(selectedData: Array<ResolvedDataItem>) {
-        // when choose some items && draggable is true
-        const SortableItem = SortableElement((
-            (props: DraggableResolvedDataItem) => this.renderRightItem(props.item)) as React.FC<DraggableResolvedDataItem>
-        );
-        const SortableList = SortableContainer(({ items }: { items: Array<ResolvedDataItem> }) => (
-            <div className={`${prefixcls}-right-list`} role="list" aria-label="Selected list">
-                {items.map((item, index: number) => (
-                    // @ts-ignore skip SortableItem type check
-                    <SortableItem key={item.label} index={index} item={item} />
-                ))}
-            </div>
-        // eslint-disable-next-line @typescript-eslint/ban-ts-comment
-        // @ts-ignore see reasons: https://github.com/clauderic/react-sortable-hoc/issues/206
-        ), { distance: 10 });
+        const sortableListItems = selectedData.map(item => ({
+            ...item,
+            node: this.renderRightItem(item)
+        }));
+
+        // helperClass:add styles to the helper(item being dragged) https://github.com/clauderic/react-sortable-hoc/issues/87
         // @ts-ignore skip SortableItem type check
         // @ts-ignore skip SortableItem type check
-        const sortList = <SortableList useDragHandle onSortEnd={this.onSortEnd} items={selectedData} />;
+        const sortList = <SortableList useDragHandle helperClass={`${prefixcls}-right-item-drag-item-move`} onSortEnd={this.onSortEnd} items={sortableListItems} />;
         return sortList;
         return sortList;
     }
     }