Skip to content

Commit d06c017

Browse files
authored
fix(ComboBox): reset value on enter (#629)
1 parent ff5ab7c commit d06c017

File tree

3 files changed

+113
-5
lines changed

3 files changed

+113
-5
lines changed

.changeset/tough-pumpkins-sniff.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@cube-dev/ui-kit': patch
3+
---
4+
5+
Reset the value of the ComboBox on Enter press if it's not an option and custom input is not allowed.

src/components/fields/ComboBox/ComboBox.stories.tsx

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,59 @@ const TemplateForm: StoryFn<CubeComboBoxProps<any>> = (
8989
);
9090
};
9191

92+
const TemplateFormPropagation: StoryFn<CubeComboBoxProps<any>> = (
93+
args: CubeComboBoxProps<any>,
94+
) => {
95+
const [form] = Form.useForm();
96+
97+
return (
98+
<Flow gap="2x">
99+
<Form
100+
form={form}
101+
defaultValues={{ combobox: args.allowsCustomValue ? 'unknown' : 'red' }}
102+
onSubmit={(data) => console.log('! submit', data)}
103+
>
104+
<ComboBox
105+
name="combobox"
106+
{...args}
107+
rules={[
108+
{
109+
required: true,
110+
},
111+
{
112+
pattern: /^[A-Za-z_][A-Za-z0-9_]*$/,
113+
message: 'Please enter valid variable name',
114+
},
115+
]}
116+
>
117+
<ComboBox.Item key="red">
118+
{args.allowsCustomValue ? 'red' : 'Red'}
119+
</ComboBox.Item>
120+
<ComboBox.Item key="orange">
121+
{args.allowsCustomValue ? 'orange' : 'Orange'}
122+
</ComboBox.Item>
123+
<ComboBox.Item key="yellow">
124+
{args.allowsCustomValue ? 'yellow' : 'Yellow'}
125+
</ComboBox.Item>
126+
<ComboBox.Item key="green">
127+
{args.allowsCustomValue ? 'green' : 'Green'}
128+
</ComboBox.Item>
129+
<ComboBox.Item key="blue">
130+
{args.allowsCustomValue ? 'blue' : 'Blue'}
131+
</ComboBox.Item>
132+
<ComboBox.Item key="purple">
133+
{args.allowsCustomValue ? 'purple' : 'Purple'}
134+
</ComboBox.Item>
135+
<ComboBox.Item key="violet">
136+
{args.allowsCustomValue ? 'violet' : 'Violet'}
137+
</ComboBox.Item>
138+
</ComboBox>
139+
<Form.Submit>Submit</Form.Submit>
140+
</Form>
141+
</Flow>
142+
);
143+
};
144+
92145
const TemplateLegacyForm: StoryFn<CubeComboBoxProps<any>> = (
93146
args: CubeComboBoxProps<any>,
94147
) => {
@@ -264,3 +317,26 @@ WithinFormWithLegacyFieldAndCustomValue.args = {
264317
...TemplateForm.args,
265318
allowsCustomValue: true,
266319
};
320+
321+
export const WithinFormStopEnterPropagation = TemplateFormPropagation.bind({});
322+
WithinFormStopEnterPropagation.play = async ({ canvasElement }) => {
323+
const { getByTestId } = within(canvasElement);
324+
325+
const input = getByTestId('Input');
326+
327+
await userEvent.type(
328+
input,
329+
'{backspace}{backspace}{backspace}{backspace}{backspace}{backspace}{backspace}blurring{enter}',
330+
);
331+
};
332+
333+
export const WithinFormStopBlurPropagation = TemplateFormPropagation.bind({});
334+
WithinFormStopBlurPropagation.play = async ({ canvasElement }) => {
335+
const { getByTestId } = within(canvasElement);
336+
337+
const input = getByTestId('Input');
338+
339+
await userEvent.type(input, '!');
340+
const button = getByTestId('Button');
341+
await userEvent.click(button);
342+
};

src/components/fields/ComboBox/ComboBox.tsx

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -330,14 +330,26 @@ export const ComboBox = forwardRef(function ComboBox<T extends object>(
330330
// If input is not full and the user presses Enter, pick the first option.
331331
let onKeyPress = useEvent((e: KeyboardEvent) => {
332332
if (e.key === 'Enter') {
333-
if (!props.allowsCustomValue && state.isOpen) {
334-
const option = [...state.collection][0]?.key;
333+
if (!props.allowsCustomValue) {
334+
if (state.isOpen) {
335+
const option = [...state.collection][0]?.key;
335336

336-
if (option && selectedKey !== option) {
337-
props.onSelectionChange?.(option);
337+
if (option && selectedKey !== option) {
338+
props.onSelectionChange?.(option);
338339

339-
e.stopPropagation();
340+
e.stopPropagation();
341+
e.preventDefault();
342+
}
343+
} else if (
344+
inputRef.current?.value &&
345+
![...state.collection]
346+
.map((i) => i.textValue)
347+
.includes(inputRef.current?.value)
348+
) {
349+
// If the input value is not in the collection, we need to prevent the submitting of the form.
350+
// Also, we reset value manually.
340351
e.preventDefault();
352+
props.onSelectionChange?.(null);
341353
}
342354
// If a custom value is allowed, we need to check if the input value is in the collection.
343355
} else if (props.allowsCustomValue) {
@@ -354,11 +366,26 @@ export const ComboBox = forwardRef(function ComboBox<T extends object>(
354366
}
355367
});
356368

369+
let onBlur = useEvent((e: FocusEvent) => {
370+
// If the input value is not in the collection, we need to reset the value.
371+
if (
372+
!props.allowsCustomValue &&
373+
inputRef.current?.value &&
374+
![...state.collection]
375+
.map((i) => i.textValue)
376+
.includes(inputRef.current?.value)
377+
) {
378+
props.onSelectionChange?.(null);
379+
}
380+
});
381+
357382
useEffect(() => {
358383
inputRef.current?.addEventListener('keydown', onKeyPress, true);
384+
inputRef.current?.addEventListener('blur', onBlur, true);
359385

360386
return () => {
361387
inputRef.current?.removeEventListener('keydown', onKeyPress, true);
388+
inputRef.current?.removeEventListener('blur', onBlur, true);
362389
};
363390
}, []);
364391

0 commit comments

Comments
 (0)