Browse Source

feat: tagInput prefix insetLabel (#883)

yykoypj 3 years ago
parent
commit
3022da6f99
2 changed files with 52 additions and 11 deletions
  1. 14 0
      packages/semi-foundation/tagInput/foundation.ts
  2. 38 11
      packages/semi-ui/tagInput/index.tsx

+ 14 - 0
packages/semi-foundation/tagInput/foundation.ts

@@ -18,6 +18,7 @@ export interface TagInputAdapter extends DefaultAdapter {
     setInputValue: (inputValue: string) => void;
     setTagsArray: (tagsArray: string[]) => void;
     setFocusing: (focusing: boolean) => void;
+    toggleFocusing(focused: boolean): void;
     setHovering: (hovering: boolean) => void;
     notifyBlur: (e: TagInputCursorEvent) => void;
     notifyFocus: (e: TagInputCursorEvent) => void;
@@ -183,6 +184,19 @@ class TagInputFoundation extends BaseFoundation<TagInputAdapter> {
         this._adapter.setHovering(false);
     }
 
+    handleClickPrefixOrSuffix(e: any) {
+        const { disabled } = this._adapter.getProps();
+        const { isFocus } = this._adapter.getStates();
+        if (!disabled && !isFocus) {
+            this._adapter.toggleFocusing(true);
+        }
+    }
+
+    handlePreventMouseDown(e: any) {
+        if (e && isFunction(e.preventDefault)) {
+            e.preventDefault();
+        }
+    }
     /**
      * handler of delete tag
      */

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

@@ -13,6 +13,7 @@ import { cssClasses, strings } from '@douyinfe/semi-foundation/tagInput/constant
 import '@douyinfe/semi-foundation/tagInput/tagInput.scss';
 import TagInputFoundation, { TagInputAdapter } from '@douyinfe/semi-foundation/tagInput/foundation';
 import { ArrayElement } from '../_base/base';
+import { isSemiIcon } from '../_utils';
 import BaseComponent from '../_base/baseComponent';
 import Tag from '../tag';
 import Input from '../input';
@@ -47,6 +48,8 @@ export interface TagInputProps {
     onKeyDown?: (e: React.MouseEvent<HTMLInputElement>) => void;
     onRemove?: (removedValue: string, idx: number) => void;
     placeholder?: string;
+    insetLabel?: React.ReactNode;
+    insetLabelId?: string;
     prefix?: React.ReactNode;
     renderTagItem?: (value: string, index: number) => React.ReactNode;
     separator?: string | string[] | null;
@@ -129,6 +132,8 @@ class TagInput extends BaseComponent<TagInputProps, TagInputState> {
     };
 
     inputRef: React.RefObject<HTMLInputElement>;
+    foundation: TagInputFoundation;
+
     constructor(props: TagInputProps) {
         super(props);
         this.foundation = new TagInputFoundation(this.adapter);
@@ -170,6 +175,15 @@ class TagInput extends BaseComponent<TagInputProps, TagInputState> {
             setFocusing: (focusing: boolean) => {
                 this.setState({ focusing });
             },
+            toggleFocusing: (isFocus: boolean) => {
+                const input = this.inputRef && this.inputRef.current;
+                if (isFocus) {
+                    input && input.focus();
+                } else {
+                    input && input.blur();
+                }
+                this.setState({ focusing: isFocus });
+            },
             setHovering: (hovering: boolean) => {
                 this.setState({ hovering });
             },
@@ -240,6 +254,15 @@ class TagInput extends BaseComponent<TagInputProps, TagInputState> {
         this.foundation.handleInputMouseEnter();
     };
 
+    handleClickPrefixOrSuffix = (e: React.MouseEvent<HTMLInputElement>) => {
+        this.foundation.handleClickPrefixOrSuffix(e);
+    };
+
+    handlePreventMouseDown = (e: React.MouseEvent<HTMLInputElement>) => {
+        this.foundation.handlePreventMouseDown(e);
+    };
+
+
     renderClearBtn() {
         const { hovering, tagsArray, inputValue } = this.state;
         const { showClear, disabled } = this.props;
@@ -248,11 +271,11 @@ class TagInput extends BaseComponent<TagInputProps, TagInputState> {
         });
         if (showClear) {
             return (
-                <div 
+                <div
                     role="button"
-                    tabIndex={0} 
-                    aria-label="Clear TagInput value" 
-                    className={clearCls} 
+                    tabIndex={0}
+                    aria-label="Clear TagInput value"
+                    className={clearCls}
                     onClick={e => this.handleClearBtn(e)}
                     onKeyPress={e => this.handleClearEnterPress(e)}
                 >
@@ -264,16 +287,19 @@ class TagInput extends BaseComponent<TagInputProps, TagInputState> {
     }
 
     renderPrefix() {
-        const { prefix } = this.props;
-        if (isNull(prefix) || isUndefined(prefix)) {
+        const { prefix, insetLabel, insetLabelId } = this.props;
+        const labelNode = prefix || insetLabel;
+        if (isNull(labelNode) || isUndefined(labelNode)) {
             return null;
         }
         const prefixWrapperCls = cls(`${prefixCls}-prefix`, {
-            [`${prefixCls}-prefix-text`]: prefix && isString(prefix),
+            [`${prefixCls}-inset-label`]: insetLabel,
+            [`${prefixCls}-prefix-text`]: labelNode && isString(labelNode),
             // eslint-disable-next-line max-len
-            [`${prefixCls}-prefix-icon`]: React.isValidElement(prefix) && !(prefix && isString(prefix)),
+            [`${prefixCls}-prefix-icon`]: isSemiIcon(labelNode),
         });
-        return <div className={prefixWrapperCls}>{prefix}</div>;
+        // eslint-disable-next-line jsx-a11y/no-static-element-interactions,jsx-a11y/click-events-have-key-events
+        return <div className={prefixWrapperCls} onMouseDown={this.handlePreventMouseDown} onClick={this.handleClickPrefixOrSuffix} id={insetLabelId}>{labelNode}</div>;
     }
 
     renderSuffix() {
@@ -284,9 +310,10 @@ class TagInput extends BaseComponent<TagInputProps, TagInputState> {
         const suffixWrapperCls = cls(`${prefixCls}-suffix`, {
             [`${prefixCls}-suffix-text`]: suffix && isString(suffix),
             // eslint-disable-next-line max-len
-            [`${prefixCls}-suffix-icon`]: React.isValidElement(suffix) && !(suffix && isString(suffix)),
+            [`${prefixCls}-suffix-icon`]: isSemiIcon(suffix),
         });
-        return <div className={suffixWrapperCls}>{suffix}</div>;
+        // eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions
+        return <div className={suffixWrapperCls} onMouseDown={this.handlePreventMouseDown} onClick={this.handleClickPrefixOrSuffix}>{suffix}</div>;
     }
 
     renderTags() {