소스 검색

fix: fixed autoFocus bug in Input and TextArea #2193

shijia.me 1 년 전
부모
커밋
97330590ff

+ 11 - 0
cypress/e2e/input.spec.js

@@ -65,4 +65,15 @@ describe('input', () => {
         cy.get('body').click();
         cy.get('.semi-input-wrapper').eq(2).children('input').should('not.be.focused');
     });
+
+    it('input autofocus should focus to text end', () => {
+        cy.visit('http://localhost:6006/iframe.html?args=&id=input--fix-input-auto-focus&viewMode=story');
+        cy.wait(300);
+        cy.window().then(window => {
+            const inputStr = window.document.body.querySelector('.semi-input').value.length;
+            const count = inputStr.length;
+            cy.get('div[data-cy=start]').should('contain.text', inputStr);
+            cy.get('div[data-cy=end]').should('contain.text', inputStr);
+        });
+    });
 });

+ 6 - 0
cypress/e2e/textarea.spec.js

@@ -110,4 +110,10 @@ describe('textarea', () => {
             expect(scrollHeight).eq(clientHeight);
         });
     });
+
+    it('textarea autofocus should focus to text end', () => {
+        cy.visit('http://localhost:6006/iframe.html?args=&id=input--fix-text-area-auto-focus&viewMode=story');
+        cy.get('div[data-cy=start]').should('contain.text', 0);
+        cy.get('div[data-cy=end]').should('contain.text', 0);
+    });
 });

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

@@ -40,10 +40,6 @@ class InputFoundation extends BaseFoundation<InputAdapter> {
         super({ ...InputFoundation.inputDefaultAdapter, ...adapter });
     }
 
-    init() {
-        this._setInitValue();
-    }
-
     destroy() {
         if (this._timer) {
             clearTimeout(this._timer);
@@ -53,16 +49,6 @@ class InputFoundation extends BaseFoundation<InputAdapter> {
 
     setDisable() {}
 
-    _setInitValue() {
-        const { defaultValue, value } = this.getProps();
-        let v = defaultValue;
-        if (this._isControlledComponent()) {
-            v = value;
-        }
-        this._adapter.setValue(v);
-    // this.checkAllowClear(v);
-    }
-
     setValue(value: any) {
         this._adapter.setValue(value);
     }

+ 0 - 16
packages/semi-foundation/input/textareaFoundation.ts

@@ -48,24 +48,8 @@ export default class TextAreaFoundation extends BaseFoundation<TextAreaAdapter>
         });
     }
 
-    init() {
-        this.setInitValue();
-    }
-
     destroy() { }
 
-    setInitValue() {
-        const {
-            defaultValue,
-            value
-        } = this.getProps();
-        let v = defaultValue;
-        if (this._isControlledComponent()) {
-            v = value;
-        }
-        this._adapter.setValue(v);
-    }
-
     handleValueChange(v: string) {
         this._adapter.setValue(v);
     }

+ 38 - 1
packages/semi-ui/input/_story/input.stories.jsx

@@ -1,4 +1,4 @@
-import React, { useState, useCallback, useRef } from 'react';
+import React, { useState, useCallback, useRef, useEffect } from 'react';
 import GraphemeSplitter from 'grapheme-splitter';
 import { isFunction, isString } from 'lodash';
 
@@ -1031,3 +1031,40 @@ export const TextAutoSizeResize = () => {
     </div>
   )
 };
+
+export const FixInputAutoFocus = () => {
+  const longStr = 'semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design';
+  const inputRef = useRef();
+  const [selection, setSelection] = useState();
+  useEffect(() => {
+    const start = inputRef.current.selectionStart;
+    const end = inputRef.current.selectionEnd;
+    setSelection({ start, end, length: longStr.length });
+  }, []);
+  return (
+    <div>
+      <Input ref={inputRef} style={{ width: 200 }} autoFocus defaultValue={longStr} />
+      <div data-cy="start">start: {selection?.start}</div>
+      <div data-cy="end">end: {selection?.end}</div>
+    </div>
+  )
+};
+
+export const FixTextAreaAutoFocus = () => {
+  const inputRef = useRef();
+  const [selection, setSelection] = useState();
+  useEffect(() => {
+    const start = inputRef.current.selectionStart;
+    const end = inputRef.current.selectionEnd;
+    setSelection({ start, end });
+  }, []);
+  const longStr = 'semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design semi design';
+  return (
+    <div>
+      <TextArea ref={inputRef} style={{ width: 200 }} autoFocus defaultValue={longStr} />
+      <div data-cy="start">start: {selection?.start}</div>
+      <div data-cy="end">end: {selection?.end}</div>
+    </div>
+  )
+};
+

+ 3 - 3
packages/semi-ui/input/index.tsx

@@ -157,9 +157,10 @@ class Input extends BaseComponent<InputProps, InputState> {
 
     constructor(props: InputProps) {
         super(props);
+        const initValue = 'value' in props ? props.value : props.defaultValue;
         this.state = {
-            value: '',
-            cachedValue: null, // Cache current props.value value
+            value: initValue,
+            cachedValue: props.value, // Cache current props.value value
             disabled: false,
             props: {},
             isFocus: false,
@@ -223,7 +224,6 @@ class Input extends BaseComponent<InputProps, InputState> {
     componentDidMount(): void {
         // autofocus is changed from the original support of input to the support of manually calling the focus method,
         // so that preventScroll can still take effect under the setting of autofocus
-        this.foundation.init();
         const { disabled, autoFocus, preventScroll } = this.props;
         if (!disabled && (autoFocus || this.props['autofocus'])) {
             this.inputRef.current.focus({ preventScroll });

+ 3 - 1
packages/semi-ui/input/textarea.tsx

@@ -113,12 +113,14 @@ class TextArea extends BaseComponent<TextAreaProps, TextAreaState> {
 
     constructor(props: TextAreaProps) {
         super(props);
+        const initValue = 'value' in props ? props.value : props.defaultValue;
         this.state = {
-            value: '',
+            value: initValue,
             isFocus: false,
             isHover: false,
             height: 0,
             minLength: props.minLength,
+            cachedValue: props.value,
         };
         this.focusing = false;
         this.foundation = new TextAreaFoundation(this.adapter);