Skip to content

Commit b21639e

Browse files
committed
Merge remote-tracking branch 'origin' into feat-item-button-with-actions
2 parents 54abe1c + feb33ec commit b21639e

File tree

22 files changed

+3258
-179
lines changed

22 files changed

+3258
-179
lines changed

.changeset/proud-dolls-punch.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

CHANGELOG.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,27 @@
11
# @cube-dev/ui-kit
22

3+
## 0.84.0
4+
5+
### Minor Changes
6+
7+
- [#817](https://github.com/cube-js/cube-ui-kit/pull/817) [`bb56ca5a`](https://github.com/cube-js/cube-ui-kit/commit/bb56ca5a8a4b08379685a7d32a797ea65019c12d) Thanks [@tenphi](https://github.com/tenphi)! - Add Picker component as a more advanced version of Select.
8+
9+
## 0.83.3
10+
11+
### Patch Changes
12+
13+
- [#838](https://github.com/cube-js/cube-ui-kit/pull/838) [`17518277`](https://github.com/cube-js/cube-ui-kit/commit/17518277e6bda8b495c0e74b884f6c97096760e3) Thanks [@tenphi](https://github.com/tenphi)! - Add ProgressBarIcon.
14+
15+
- [#840](https://github.com/cube-js/cube-ui-kit/pull/840) [`5fb963f0`](https://github.com/cube-js/cube-ui-kit/commit/5fb963f040f1c1ec59bd63c6918cb5f6f6b7a210) Thanks [@tenphi](https://github.com/tenphi)! - Fix RadioGroup base layout.
16+
17+
## 0.83.2
18+
19+
### Patch Changes
20+
21+
- [#835](https://github.com/cube-js/cube-ui-kit/pull/835) [`97925cab`](https://github.com/cube-js/cube-ui-kit/commit/97925cabf6babdfc546436cb59d24967a826fb74) Thanks [@tenphi](https://github.com/tenphi)! - Fix qa prop in Radio component.
22+
23+
- [#837](https://github.com/cube-js/cube-ui-kit/pull/837) [`f80593b8`](https://github.com/cube-js/cube-ui-kit/commit/f80593b89bba6c638d8cfd795e9ad5b02609e75a) Thanks [@tenphi](https://github.com/tenphi)! - Fix qa prop on TextInputBase.
24+
325
## 0.83.1
426

527
### Patch Changes

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@cube-dev/ui-kit",
3-
"version": "0.83.1",
3+
"version": "0.84.0",
44
"type": "module",
55
"description": "UIKit for Cube Projects",
66
"repository": {
@@ -10,7 +10,7 @@
1010
"module": "dist/es/index.js",
1111
"types": "dist/types/index.d.ts",
1212
"sideEffects": false,
13-
"packageManager": "pnpm@10.14.0",
13+
"packageManager": "pnpm@10.19.0",
1414
"exports": {
1515
".": {
1616
"import": "./dist/es/index.js",

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useState } from 'react';
1+
import { useMemo, useState } from 'react';
22
import { userEvent, within } from 'storybook/test';
33

44
import { baseProps } from '../../../stories/lists/baseProps';
@@ -772,13 +772,13 @@ export const ShowAllOnNoResults: StoryObj<typeof ComboBox> = {
772772
};
773773

774774
export const VirtualizedList = () => {
775+
const [selected, setSelected] = useState<string | null>(null);
776+
775777
interface Item {
776778
key: string;
777779
name: string;
778780
}
779781

780-
const [selected, setSelected] = useState<string | null>(null);
781-
782782
// Generate a large list of items with varying content to test virtualization
783783
const items: Item[] = Array.from({ length: 1000 }, (_, i) => ({
784784
key: `item-${i}`,

src/components/fields/ComboBox/ComboBox.test.tsx

Lines changed: 133 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,7 @@ describe('<ComboBox />', () => {
463463
});
464464
});
465465

466-
it('should clear selection on blur when clearOnBlur is true', async () => {
466+
it('should clear invalid input on blur when clearOnBlur is true', async () => {
467467
const onSelectionChange = jest.fn();
468468

469469
const { getByRole, getAllByRole, queryByRole } = renderWithRoot(
@@ -493,12 +493,18 @@ describe('<ComboBox />', () => {
493493
expect(combobox).toHaveValue('Red');
494494
});
495495

496+
onSelectionChange.mockClear();
497+
498+
// Type invalid text to make input invalid
499+
await userEvent.clear(combobox);
500+
await userEvent.type(combobox, 'xyz');
501+
496502
// Blur the input
497503
await act(async () => {
498504
combobox.blur();
499505
});
500506

501-
// Should clear selection on blur
507+
// Should clear selection on blur because input is invalid
502508
await waitFor(() => {
503509
expect(onSelectionChange).toHaveBeenCalledWith(null);
504510
expect(combobox).toHaveValue('');
@@ -585,6 +591,131 @@ describe('<ComboBox />', () => {
585591
});
586592
});
587593

594+
it('should auto-select when there is exactly one filtered result on blur', async () => {
595+
const onSelectionChange = jest.fn();
596+
597+
const { getByRole } = renderWithRoot(
598+
<ComboBox label="test" onSelectionChange={onSelectionChange}>
599+
{items.map((item) => (
600+
<ComboBox.Item key={item.key}>{item.children}</ComboBox.Item>
601+
))}
602+
</ComboBox>,
603+
);
604+
605+
const combobox = getByRole('combobox');
606+
607+
// Type partial match that results in one item (Violet is unique with 'vio')
608+
await userEvent.type(combobox, 'vio');
609+
610+
// Blur the input
611+
await act(async () => {
612+
combobox.blur();
613+
});
614+
615+
// Should auto-select the single matching item
616+
await waitFor(() => {
617+
expect(onSelectionChange).toHaveBeenCalledWith('violet');
618+
expect(combobox).toHaveValue('Violet');
619+
});
620+
});
621+
622+
it('should reset to selected value on blur when clearOnBlur is false and input is invalid', async () => {
623+
const onSelectionChange = jest.fn();
624+
625+
const { getByRole, getAllByRole, queryByRole } = renderWithRoot(
626+
<ComboBox label="test" onSelectionChange={onSelectionChange}>
627+
{items.map((item) => (
628+
<ComboBox.Item key={item.key}>{item.children}</ComboBox.Item>
629+
))}
630+
</ComboBox>,
631+
);
632+
633+
const combobox = getByRole('combobox');
634+
635+
// Type to filter and open popover
636+
await userEvent.type(combobox, 're');
637+
638+
await waitFor(() => {
639+
expect(queryByRole('listbox')).toBeInTheDocument();
640+
});
641+
642+
// Click on first option (Red)
643+
const options = getAllByRole('option');
644+
await userEvent.click(options[0]);
645+
646+
// Verify selection was made
647+
await waitFor(() => {
648+
expect(onSelectionChange).toHaveBeenCalledWith('red');
649+
expect(combobox).toHaveValue('Red');
650+
});
651+
652+
onSelectionChange.mockClear();
653+
654+
// Type invalid text to make input invalid
655+
await userEvent.clear(combobox);
656+
await userEvent.type(combobox, 'xyz');
657+
658+
// Blur the input
659+
await act(async () => {
660+
combobox.blur();
661+
});
662+
663+
// Should reset input to selected value (Red) since clearOnBlur is false
664+
await waitFor(() => {
665+
expect(combobox).toHaveValue('Red');
666+
});
667+
668+
// Selection should not change
669+
expect(onSelectionChange).not.toHaveBeenCalled();
670+
});
671+
672+
it('should clear selection when input is empty on blur even with clearOnBlur false', async () => {
673+
const onSelectionChange = jest.fn();
674+
675+
const { getByRole, getAllByRole, queryByRole } = renderWithRoot(
676+
<ComboBox label="test" onSelectionChange={onSelectionChange}>
677+
{items.map((item) => (
678+
<ComboBox.Item key={item.key}>{item.children}</ComboBox.Item>
679+
))}
680+
</ComboBox>,
681+
);
682+
683+
const combobox = getByRole('combobox');
684+
685+
// Type to filter and open popover
686+
await userEvent.type(combobox, 're');
687+
688+
await waitFor(() => {
689+
expect(queryByRole('listbox')).toBeInTheDocument();
690+
});
691+
692+
// Click on first option (Red)
693+
const options = getAllByRole('option');
694+
await userEvent.click(options[0]);
695+
696+
// Verify selection was made
697+
await waitFor(() => {
698+
expect(onSelectionChange).toHaveBeenCalledWith('red');
699+
expect(combobox).toHaveValue('Red');
700+
});
701+
702+
onSelectionChange.mockClear();
703+
704+
// Clear the input completely
705+
await userEvent.clear(combobox);
706+
707+
// Blur the input
708+
await act(async () => {
709+
combobox.blur();
710+
});
711+
712+
// Should clear selection even though clearOnBlur is false
713+
await waitFor(() => {
714+
expect(onSelectionChange).toHaveBeenCalledWith(null);
715+
expect(combobox).toHaveValue('');
716+
});
717+
});
718+
588719
it('should show all items when opening with no results', async () => {
589720
const { getByRole, getAllByRole, queryByRole, getByTestId } =
590721
renderWithRoot(

0 commit comments

Comments
 (0)