diff --git a/package.json b/package.json index 75ad891d..3cf7898f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@rc-component/util", - "version": "1.3.1", + "version": "1.4.0", "description": "Common Utils For React Component", "keywords": [ "react", @@ -56,7 +56,7 @@ "cross-env": "^7.0.2", "dumi": "^2.1.3", "eslint": "^8.54.0", - "eslint-plugin-jest": "^28.2.0", + "eslint-plugin-jest": "^29.0.1", "eslint-plugin-unicorn": "^56.0.1", "father": "^4.1.3", "glob": "^11.0.3", diff --git a/src/Dom/focus.ts b/src/Dom/focus.ts index a6654841..6b182463 100644 --- a/src/Dom/focus.ts +++ b/src/Dom/focus.ts @@ -97,3 +97,43 @@ export function limitTabRange(node: HTMLElement, e: KeyboardEvent) { } } } + +export interface InputFocusOptions extends FocusOptions { + cursor?: 'start' | 'end' | 'all'; +} + +// Used for `rc-input` `rc-textarea` `rc-input-number` +/** + * Focus element and set cursor position for input/textarea elements. + */ +export function triggerFocus( + element?: HTMLElement, + option?: InputFocusOptions, +) { + if (!element) return; + + element.focus(option); + + // Selection content + const { cursor } = option || {}; + if ( + cursor && + (element instanceof HTMLInputElement || + element instanceof HTMLTextAreaElement) + ) { + const len = element.value.length; + + switch (cursor) { + case 'start': + element.setSelectionRange(0, 0); + break; + + case 'end': + element.setSelectionRange(len, len); + break; + + default: + element.setSelectionRange(0, len); + } + } +} diff --git a/tests/focus.test.ts b/tests/focus.test.ts index 795e2e71..1c835bf9 100644 --- a/tests/focus.test.ts +++ b/tests/focus.test.ts @@ -1,6 +1,6 @@ /* eslint-disable class-methods-use-this */ import { spyElementPrototype } from '../src/test/domHook'; -import { getFocusNodeList } from '../src/Dom/focus'; +import { getFocusNodeList, triggerFocus } from '../src/Dom/focus'; describe('focus', () => { beforeAll(() => { @@ -31,4 +31,29 @@ describe('focus', () => { const tabFocusList = getFocusNodeList(div, true); expect(tabFocusList).toHaveLength(5); }); + + it('triggerFocus should set cursor position for textarea', () => { + const textarea = document.createElement('textarea'); + textarea.value = 'test content'; + + const focusSpy = jest.spyOn(textarea, 'focus'); + const setSelectionRangeSpy = jest.spyOn(textarea, 'setSelectionRange'); + + // Test cursor: 'start' + triggerFocus(textarea, { cursor: 'start' }); + expect(setSelectionRangeSpy).toHaveBeenCalledWith(0, 0); + + // Test cursor: 'end' + triggerFocus(textarea, { cursor: 'end' }); + expect(setSelectionRangeSpy).toHaveBeenCalledWith(12, 12); // 'test content'.length = 12 + + // Test cursor: 'all' + triggerFocus(textarea, { cursor: 'all' }); + expect(setSelectionRangeSpy).toHaveBeenCalledWith(0, 12); // select all text + + expect(focusSpy).toHaveBeenCalledTimes(3); + + focusSpy.mockRestore(); + setSelectionRangeSpy.mockRestore(); + }); });