Skip to content

Commit 5028dfd

Browse files
authored
feat: support nativeElement (#68)
* feat: support nativeElement * chore: update
1 parent 0f81074 commit 5028dfd

5 files changed

Lines changed: 67 additions & 6 deletions

File tree

src/BaseInput.tsx

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
import clsx from 'classnames';
2-
import type { FC, ReactElement, ReactNode } from 'react';
2+
import type { ReactElement, ReactNode } from 'react';
33
import React, { cloneElement, useRef } from 'react';
44
import type { BaseInputProps } from './interface';
55
import { hasAddon, hasPrefixSuffix } from './utils/commonUtils';
66

7-
const BaseInput: FC<BaseInputProps> = (props) => {
7+
export interface HolderRef {
8+
/** Provider holder ref. Will return `null` if not wrap anything */
9+
nativeElement: HTMLElement | null;
10+
}
11+
12+
const BaseInput = React.forwardRef<HolderRef, BaseInputProps>((props, ref) => {
813
const {
914
inputElement: inputEl,
1015
children,
@@ -54,6 +59,13 @@ const BaseInput: FC<BaseInputProps> = (props) => {
5459
null,
5560
});
5661

62+
// ======================== Ref ======================== //
63+
const groupRef = useRef<HTMLDivElement>(null);
64+
65+
React.useImperativeHandle(ref, () => ({
66+
nativeElement: groupRef.current || containerRef.current,
67+
}));
68+
5769
// ================== Prefix & Suffix ================== //
5870
if (hasAffix) {
5971
// ================== Clear Icon ================== //
@@ -157,7 +169,7 @@ const BaseInput: FC<BaseInputProps> = (props) => {
157169
// Need another wrapper for changing display:table to display:inline-block
158170
// and put style prop in wrapper
159171
element = (
160-
<GroupWrapperComponent className={mergedGroupClassName}>
172+
<GroupWrapperComponent className={mergedGroupClassName} ref={groupRef}>
161173
<WrapperComponent className={mergedWrapperClassName}>
162174
{addonBefore && (
163175
<GroupAddonComponent className={addonCls}>
@@ -184,6 +196,6 @@ const BaseInput: FC<BaseInputProps> = (props) => {
184196
},
185197
hidden,
186198
});
187-
};
199+
});
188200

189201
export default BaseInput;

src/Input.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import React, {
88
useRef,
99
useState,
1010
} from 'react';
11-
import BaseInput from './BaseInput';
11+
import BaseInput, { HolderRef } from './BaseInput';
1212
import useCount from './hooks/useCount';
1313
import type { ChangeEventInfo, InputProps, InputRef } from './interface';
1414
import type { InputFocusOptions } from './utils/commonUtils';
@@ -43,6 +43,7 @@ const Input = forwardRef<InputRef, InputProps>((props, ref) => {
4343
const compositionRef = useRef(false);
4444

4545
const inputRef = useRef<HTMLInputElement>(null);
46+
const holderRef = useRef<HolderRef>(null);
4647

4748
const focus = (option?: InputFocusOptions) => {
4849
if (inputRef.current) {
@@ -86,6 +87,7 @@ const Input = forwardRef<InputRef, InputProps>((props, ref) => {
8687
inputRef.current?.select();
8788
},
8889
input: inputRef.current,
90+
nativeElement: holderRef.current?.nativeElement || inputRef.current,
8991
}));
9092

9193
useEffect(() => {

src/interface.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ export interface InputRef {
148148
) => void;
149149
select: () => void;
150150
input: HTMLInputElement | null;
151+
nativeElement: HTMLElement | null;
151152
}
152153

153154
export interface ChangeEventInfo {

tests/BaseInput.test.tsx

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { fireEvent, render } from '@testing-library/react';
22
import type { ChangeEvent, FC } from 'react';
33
import React, { useState } from 'react';
4-
import BaseInput from '../src/BaseInput';
4+
import BaseInput, { type HolderRef } from '../src/BaseInput';
55

66
describe('BaseInput', () => {
77
it('should render perfectly', () => {
@@ -267,4 +267,49 @@ describe('BaseInput', () => {
267267
expect(container.querySelector('.rc-input-affix-wrapper')).toBeFalsy();
268268
expect(container.querySelector('input')).toHaveClass('test-variant');
269269
});
270+
271+
describe('ref', () => {
272+
it('prefix', () => {
273+
const holderRef = React.createRef<HolderRef>();
274+
const { container } = render(
275+
<BaseInput prefixCls="rc-input" prefix="prefix" ref={holderRef}>
276+
<input />
277+
</BaseInput>,
278+
);
279+
expect(holderRef.current?.nativeElement).toBe(
280+
container.querySelector('.rc-input-affix-wrapper'),
281+
);
282+
});
283+
284+
it('addon', () => {
285+
const holderRef = React.createRef<HolderRef>();
286+
const { container } = render(
287+
<BaseInput prefixCls="rc-input" addonAfter="after" ref={holderRef}>
288+
<input />
289+
</BaseInput>,
290+
);
291+
292+
expect(holderRef.current?.nativeElement).toBe(
293+
container.querySelector('.rc-input-group-wrapper'),
294+
);
295+
});
296+
297+
it('mix', () => {
298+
const holderRef = React.createRef<HolderRef>();
299+
const { container } = render(
300+
<BaseInput
301+
prefixCls="rc-input"
302+
suffix="suffix"
303+
addonAfter="after"
304+
ref={holderRef}
305+
>
306+
<input />
307+
</BaseInput>,
308+
);
309+
310+
expect(holderRef.current?.nativeElement).toBe(
311+
container.querySelector('.rc-input-group-wrapper'),
312+
);
313+
});
314+
});
270315
});

tests/index.test.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,7 @@ describe('Input ref', () => {
382382
const { container } = render(<Input ref={ref} defaultValue="light" />);
383383
const inputEl = container.querySelector('input')!;
384384
expect(ref.current?.input).toBe(inputEl);
385+
expect(ref.current?.nativeElement).toBe(inputEl);
385386
});
386387
});
387388

0 commit comments

Comments
 (0)