Procházet zdrojové kódy

fix: fix click dropdown make screen scroll after tooltip add off screen render, #1254 (#1260)

* fix: fix click dropdown make screen scroll after tooltip add off screen render

* fix: fix click dropdown make screen scroll after tooltip add off screen render

* fix: fix click dropdown make screen scroll after tooltip add off screen render
YannLynn před 2 roky
rodič
revize
7cf21e374c

+ 16 - 9
packages/semi-foundation/dropdown/foundation.ts

@@ -3,33 +3,40 @@ import { handlePrevent, setFocusToFirstItem, setFocusToLastItem } from '../utils
 
 export interface DropdownAdapter extends Partial<DefaultAdapter> {
     setPopVisible(visible: boolean): void;
-    notifyVisibleChange(visible: boolean): void
+    notifyVisibleChange(visible: boolean): void;
+    getPopupId(): string
 }
 
 export default class DropdownFoundation extends BaseFoundation<DropdownAdapter> {
     handleVisibleChange(visible: boolean) {
         this._adapter.setPopVisible(visible);
         this._adapter.notifyVisibleChange(visible);
+
+        const { trigger } = this.getProps();
+        if (visible && trigger === "click"){
+            const popupId = this._adapter.getPopupId();
+            this.setFocusToFirstMenuItem(popupId);
+        }
     }
 
-    getMenuItemNodes(target: any): HTMLElement[] {
-        const id = target.attributes['data-popupid'].value;
+    getMenuItemNodes(id: string): HTMLElement[] {
         const menuWrapper = document.getElementById(id);
         // if has dropdown item, the item must wrapped by li
         return menuWrapper ? Array.from(menuWrapper.getElementsByTagName('li')).filter(item => item.ariaDisabled === "false") : null;
     }
 
-    setFocusToFirstMenuItem(target: any): void {
-        const menuItemNodes = this.getMenuItemNodes(target);
+    setFocusToFirstMenuItem(id: string): void {
+        const menuItemNodes = this.getMenuItemNodes(id);
         menuItemNodes && setFocusToFirstItem(menuItemNodes);
     }
 
-    setFocusToLastMenuItem(target: any): void {
-        const menuItemNodes = this.getMenuItemNodes(target);
+    setFocusToLastMenuItem(id: string): void {
+        const menuItemNodes = this.getMenuItemNodes(id);
         menuItemNodes && setFocusToLastItem(menuItemNodes);
     }
 
     handleKeyDown(event: any): void {
+        const id = event.target?.attributes['data-popupid']?.value;
         switch (event.key) {
             case ' ':
             case 'Enter':
@@ -38,11 +45,11 @@ export default class DropdownFoundation extends BaseFoundation<DropdownAdapter>
                 // handlePrevent(event);
                 break;
             case 'ArrowDown':
-                this.setFocusToFirstMenuItem(event.target);
+                this.setFocusToFirstMenuItem(id);
                 handlePrevent(event);
                 break;
             case 'ArrowUp':
-                this.setFocusToLastMenuItem(event.target);
+                this.setFocusToLastMenuItem(id);
                 handlePrevent(event);
                 break;
             default:

+ 1 - 12
packages/semi-foundation/dropdown/menuFoundation.ts

@@ -1,22 +1,11 @@
 
 import BaseFoundation, { DefaultAdapter } from '../base/foundation';
-import { handlePrevent, isPrintableCharacter, findIndexByCharacter, getAncestorNodeByRole, getMenuButton, setFocusToFirstItem, setFocusToItem, setFocusToNextMenuitem, setFocusToPreviousMenuItem } from '../utils/a11y';
-
+import { handlePrevent, isPrintableCharacter, findIndexByCharacter, getAncestorNodeByRole, getMenuButton, setFocusToItem, setFocusToNextMenuitem, setFocusToPreviousMenuItem } from '../utils/a11y';
 
 export default class DropdownMenuFoundation extends BaseFoundation<Partial<DefaultAdapter>> {
     menuItemNodes: HTMLElement[] = null;
     firstChars: string[] = [];
 
-    // if trigger is click, auto focus to the first menu item
-    autoFocus(ulElement: any): void {
-        const trigger = this._adapter.getContext('trigger');
-        if (trigger === 'click'){
-            // find all non-disabled li under this menu and set focus to the first menu
-            this.menuItemNodes = [...ulElement.getElementsByTagName('li')].filter(item => item.ariaDisabled !== "true");
-            setFocusToFirstItem(this.menuItemNodes);
-        }
-    }
-
     handleEscape(menu: Element): void {
         const trigger = this._adapter.getContext('trigger');
         if (trigger === 'custom'){

+ 5 - 1
packages/semi-foundation/tooltip/foundation.ts

@@ -294,6 +294,10 @@ export default class Tooltip<P = Record<string, any>, S = Record<string, any>> e
         const content = this.getProp('content');
         const trigger = this.getProp('trigger');
         const clickTriggerToHide = this.getProp('clickTriggerToHide');
+        const { visible } = this.getStates();
+        if (visible) {
+            return ;
+        }
 
         this.clearDelayTimer();
 
@@ -310,7 +314,7 @@ export default class Tooltip<P = Record<string, any>, S = Record<string, any>> e
             this._togglePortalVisible(true);
         });
 
-        this._adapter.insertPortal(content, { left: -9990, top: -9999 }); // offscreen rendering
+        this._adapter.insertPortal(content, { left: -9999, top: -9999 }); // offscreen rendering
 
         if (trigger === 'custom') {
             // eslint-disable-next-line

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

@@ -170,7 +170,6 @@ class YearAndMonth extends BaseComponent<YearAndMonthProps, YearAndMonthState> {
     renderColMonth() {
         const { months, currentMonth, currentYear } = this.state;
         const { locale, localeCode, monthCycled, disabledDate, yearAndMonthOpts } = this.props;
-        console.log('yearAndMonthOpts', yearAndMonthOpts);
         let transform = (val: string) => val;
         const currentDate = setYear(Date.now(), currentYear);
         if (localeCode === 'zh-CN' || localeCode === 'zh-TW') {

+ 1 - 7
packages/semi-ui/dropdown/dropdownMenu.tsx

@@ -19,12 +19,10 @@ class DropdownMenu extends BaseComponent<DropdownMenuProps> {
 
     static contextType = DropdownContext;
 
-    menuRef: React.RefObject<HTMLUListElement>
 
     constructor(props: DropdownMenuProps) {
         super(props);
 
-        this.menuRef = React.createRef();
         this.foundation = new Foundation(this.adapter);
     }
 
@@ -34,14 +32,10 @@ class DropdownMenu extends BaseComponent<DropdownMenuProps> {
         };
     }
 
-    componentDidMount() {
-        this.foundation.autoFocus(this.menuRef.current);
-    }
-
     render() {
         const { children, className, style, ...rest } = this.props;
         return (
-            <ul role="menu" aria-orientation="vertical" ref={this.menuRef} {...rest} className={classnames(`${prefixCls}-menu`, className)} style={style} onKeyDown={e => this.foundation.onMenuKeydown(e)}>
+            <ul role="menu" aria-orientation="vertical" {...rest} className={classnames(`${prefixCls}-menu`, className)} style={style} onKeyDown={e => this.foundation.onMenuKeydown(e)}>
                 {children}
             </ul>
         );

+ 5 - 0
packages/semi-ui/dropdown/index.tsx

@@ -111,6 +111,8 @@ class Dropdown extends BaseComponent<DropdownProps, DropdownState> {
         onEscKeyDown: noop,
     };
 
+    tooltipRef: React.RefObject<Tooltip>
+
     constructor(props: DropdownProps) {
         super(props);
 
@@ -119,6 +121,7 @@ class Dropdown extends BaseComponent<DropdownProps, DropdownState> {
         };
 
         this.foundation = new Foundation(this.adapter);
+        this.tooltipRef = React.createRef();
     }
 
     context: DropdownContextType;
@@ -128,6 +131,7 @@ class Dropdown extends BaseComponent<DropdownProps, DropdownState> {
             ...super.adapter,
             setPopVisible: (popVisible: boolean) => this.setState({ popVisible }),
             notifyVisibleChange: (visible: boolean) => this.props.onVisibleChange(visible),
+            getPopupId: () => this.tooltipRef.current.getPopupId()
         };
     }
 
@@ -237,6 +241,7 @@ class Dropdown extends BaseComponent<DropdownProps, DropdownState> {
                 onVisibleChange={this.handleVisibleChange}
                 showArrow={false}
                 returnFocusOnClose={true}
+                ref={this.tooltipRef}
                 {...attr}
             >
                 {React.isValidElement(children) ?

+ 4 - 0
packages/semi-ui/tooltip/index.tsx

@@ -652,6 +652,10 @@ export default class Tooltip extends BaseComponent<TooltipProps, TooltipState> {
         return mergedEvents;
     };
 
+    getPopupId = () => {
+        return this.state.id;
+    }
+
     render() {
         const { isInsert, triggerEventSet, visible, id } = this.state;
         const { wrapWhenSpecial, role, trigger } = this.props;