Skip to content

Commit 8234174

Browse files
committed
chore: fix input logic
1 parent 370a165 commit 8234174

File tree

6 files changed

+117
-75
lines changed

6 files changed

+117
-75
lines changed

assets/patch.less

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@
6969

7070
// ============================ Multiple ============================
7171
&-multiple {
72-
.@{select-prefix}-item {
72+
.@{select-prefix}-selection-item {
7373
background: rgba(0, 0, 0, 0.1);
7474
border-radius: 8px;
7575
margin-right: 4px;

src/BaseSelect/index.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import { useEvent } from '@rc-component/util';
2929
import type { SelectInputRef } from '../SelectInput';
3030
import SelectInput from '../SelectInput';
3131
import type { ComponentsConfig } from '../hooks/useComponents';
32+
import useComponents from '../hooks/useComponents';
3233
export type BaseSelectSemanticName = 'prefix' | 'suffix' | 'input' | 'clear';
3334

3435
/**
@@ -313,7 +314,7 @@ const BaseSelect = React.forwardRef<BaseSelectRef, BaseSelectProps>((props, ref)
313314
onMouseDown,
314315

315316
// Components
316-
components = {},
317+
components,
317318

318319
// Rest Props
319320
...restProps
@@ -366,6 +367,9 @@ const BaseSelect = React.forwardRef<BaseSelectRef, BaseSelectProps>((props, ref)
366367
selectorRef.current?.nativeElement,
367368
}));
368369

370+
// =========================== Components ===========================
371+
const mergedComponents = useComponents(components, getInputElement, getRawInputElement);
372+
369373
// ========================== Search Value ==========================
370374
const mergedSearchValue = React.useMemo(() => {
371375
if (mode !== 'combobox') {
@@ -927,7 +931,7 @@ const BaseSelect = React.forwardRef<BaseSelectRef, BaseSelectProps>((props, ref)
927931
// Open
928932
onMouseDown={onInternalMouseDown}
929933
// Components
930-
components={components}
934+
components={mergedComponents}
931935
/>
932936
);
933937

src/SelectInput/Input.tsx

Lines changed: 62 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import clsx from 'clsx';
33
import { useSelectInputContext } from './context';
44
import useLayoutEffect from '@rc-component/util/lib/hooks/useLayoutEffect';
55
import useBaseProps from '../hooks/useBaseProps';
6+
import { composeRef } from '@rc-component/util/lib/ref';
67

78
export interface InputProps {
89
id?: string;
@@ -151,41 +152,68 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>((props, ref) => {
151152
}, [syncWidth, value]);
152153

153154
// ============================= Render =============================
154-
return (
155-
<InputComponent
156-
id={id}
157-
type={mode === 'combobox' ? 'text' : 'search'}
158-
{...restProps}
159-
ref={inputRef}
160-
style={
161-
{
162-
...styles?.input,
163-
...style,
164-
'--select-input-width': widthCssVar,
165-
} as React.CSSProperties
155+
// Extract shared input props
156+
const sharedInputProps = {
157+
id,
158+
type: mode === 'combobox' ? 'text' : 'search',
159+
...restProps,
160+
ref: inputRef as React.Ref<HTMLInputElement>,
161+
style: {
162+
...styles?.input,
163+
...style,
164+
'--select-input-width': widthCssVar,
165+
} as React.CSSProperties,
166+
autoFocus,
167+
autoComplete: autoComplete || 'off',
168+
className: inputCls,
169+
disabled,
170+
value: value || '',
171+
onChange: handleChange,
172+
onKeyDown: handleKeyDown,
173+
onBlur: handleBlur,
174+
onPaste: handlePaste,
175+
onCompositionStart: handleCompositionStart,
176+
onCompositionEnd: handleCompositionEnd,
177+
// Accessibility attributes
178+
role: role || 'combobox',
179+
'aria-expanded': open || false,
180+
'aria-haspopup': 'listbox' as const,
181+
'aria-owns': `${id}_list`,
182+
'aria-autocomplete': 'list' as const,
183+
'aria-controls': `${id}_list`,
184+
'aria-activedescendant': open ? activeDescendantId : undefined,
185+
};
186+
187+
// Handle different InputComponent types
188+
if (React.isValidElement(InputComponent)) {
189+
// If InputComponent is a ReactElement, use cloneElement with merged props
190+
const existingProps: any = InputComponent.props || {};
191+
192+
// Start with shared props as base
193+
const mergedProps = { ...sharedInputProps, ...existingProps };
194+
195+
// Batch update function calls
196+
Object.keys(existingProps).forEach((key) => {
197+
const existingValue = (existingProps as any)[key];
198+
199+
if (typeof existingValue === 'function') {
200+
// Merge event handlers
201+
(mergedProps as any)[key] = (...args: any[]) => {
202+
existingValue(...args);
203+
(sharedInputProps as any)[key]?.(...args);
204+
};
166205
}
167-
autoFocus={autoFocus}
168-
autoComplete={autoComplete || 'off'}
169-
className={inputCls}
170-
disabled={disabled}
171-
value={value || ''}
172-
onChange={handleChange}
173-
onKeyDown={handleKeyDown}
174-
onBlur={handleBlur}
175-
onPaste={handlePaste}
176-
onCompositionStart={handleCompositionStart}
177-
onCompositionEnd={handleCompositionEnd}
178-
// Accessibility attributes
179-
role={role || 'combobox'}
180-
aria-expanded={open || false}
181-
aria-haspopup="listbox"
182-
aria-owns={`${id}_list`}
183-
aria-autocomplete="list"
184-
aria-controls={`${id}_list`}
185-
aria-activedescendant={open ? activeDescendantId : undefined}
186-
// onMouseDown={onMouseDown}
187-
/>
188-
);
206+
});
207+
208+
// Update ref
209+
mergedProps.ref = composeRef((InputComponent as any).ref, sharedInputProps.ref);
210+
211+
return React.cloneElement(InputComponent, mergedProps);
212+
}
213+
214+
// If InputComponent is a component type, render normally
215+
const Component = InputComponent as React.ComponentType<any>;
216+
return <Component {...sharedInputProps} />;
189217
});
190218

191219
export default Input;

src/hooks/useComponents.ts

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import * as React from 'react';
22
import type { SelectInputRef, SelectInputProps } from '../SelectInput';
3+
import type { BaseSelectProps } from '../BaseSelect';
34

45
export interface ComponentsConfig {
56
root?: React.ComponentType<any> | string | React.ReactElement;
6-
input?: React.ComponentType<any> | string;
7+
input?: React.ComponentType<any> | string | React.ReactElement;
78
}
89

910
export interface FilledComponentsConfig {
@@ -15,10 +16,27 @@ export interface FilledComponentsConfig {
1516
>;
1617
}
1718

18-
export default function useComponents(components?: ComponentsConfig) {
19+
export default function useComponents(
20+
components?: ComponentsConfig,
21+
getInputElement?: BaseSelectProps['getInputElement'],
22+
getRawInputElement?: BaseSelectProps['getRawInputElement'],
23+
): ComponentsConfig {
1924
return React.useMemo(() => {
20-
const { root: RootComponent, input: InputComponent } = components || {};
25+
let { root, input } = components || {};
2126

22-
return { root: RootComponent, input: InputComponent } as FilledComponentsConfig;
23-
}, [components]);
27+
// root: getRawInputElement
28+
if (getRawInputElement) {
29+
root = getRawInputElement();
30+
}
31+
32+
// input: getInputElement
33+
if (getInputElement) {
34+
input = getInputElement();
35+
}
36+
37+
return {
38+
root,
39+
input,
40+
};
41+
}, [components, getInputElement, getRawInputElement]);
2442
}

tests/Select.test.tsx

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,7 @@ describe('Select.Basic', () => {
456456
</Select>,
457457
);
458458

459-
expect(container.firstChild).toMatchSnapshot();
459+
expect(container.querySelector('input')).toHaveAttribute('readonly');
460460
});
461461

462462
it('should contain falsy children', () => {
@@ -2256,15 +2256,15 @@ describe('Select.Basic', () => {
22562256
/>,
22572257
);
22582258

2259-
expect(container.querySelectorAll('span.rc-select-item')[0].getAttribute('title')).toEqual(
2260-
'TitleBamboo',
2261-
);
2262-
expect(container.querySelectorAll('span.rc-select-item')[1].getAttribute('title')).toEqual(
2263-
'little',
2264-
);
2265-
expect(container.querySelectorAll('span.rc-select-item')[2].getAttribute('title')).toEqual(
2266-
'+ 1 ...',
2267-
);
2259+
expect(
2260+
container.querySelectorAll('span.rc-select-selection-item')[0].getAttribute('title'),
2261+
).toEqual('TitleBamboo');
2262+
expect(
2263+
container.querySelectorAll('span.rc-select-selection-item')[1].getAttribute('title'),
2264+
).toEqual('little');
2265+
expect(
2266+
container.querySelectorAll('span.rc-select-selection-item')[2].getAttribute('title'),
2267+
).toEqual('+ 1 ...');
22682268
});
22692269
});
22702270

@@ -2424,7 +2424,6 @@ describe('Select.Basic', () => {
24242424
const ref = React.useRef<HTMLInputElement>(null);
24252425
const onSelect = () => {
24262426
ref.current!.blur();
2427-
fireEvent.blur(ref.current);
24282427
};
24292428
const getInputElement = () => {
24302429
return <input ref={ref} onBlur={onBlur} />;

tests/__snapshots__/Select.test.tsx.snap

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -106,28 +106,6 @@ exports[`Select.Basic filterOption could be true as described in default value 1
106106
</div>
107107
`;
108108

109-
exports[`Select.Basic no search 1`] = `
110-
<div
111-
class="rc-select rc-select-single"
112-
>
113-
<div
114-
class="rc-select-content"
115-
>
116-
<div
117-
class="rc-select-content-value"
118-
style="visibility: visible;"
119-
>
120-
1
121-
</div>
122-
<input
123-
class="rc-select-input"
124-
readonly=""
125-
value=""
126-
/>
127-
</div>
128-
</div>
129-
`;
130-
131109
exports[`Select.Basic render renders aria-attributes correctly 1`] = `
132110
<div
133111
aria-label="some-label"
@@ -183,8 +161,15 @@ exports[`Select.Basic render renders correctly 1`] = `
183161
2
184162
</div>
185163
<input
164+
aria-autocomplete="list"
165+
aria-controls="test-id_list"
166+
aria-expanded="false"
167+
aria-haspopup="listbox"
168+
aria-owns="test-id_list"
169+
autocomplete="off"
186170
class="antd-input"
187171
id="test-id"
172+
role="combobox"
188173
type="search"
189174
value=""
190175
/>
@@ -250,8 +235,16 @@ exports[`Select.Basic render renders disabled select correctly 1`] = `
250235
2
251236
</div>
252237
<input
238+
aria-autocomplete="list"
239+
aria-controls="test-id_list"
240+
aria-expanded="false"
241+
aria-haspopup="listbox"
242+
aria-owns="test-id_list"
243+
autocomplete="off"
253244
class="antd-input"
245+
disabled=""
254246
id="test-id"
247+
role="combobox"
255248
type="search"
256249
value=""
257250
/>

0 commit comments

Comments
 (0)