Skip to content

Commit

Permalink
Merge pull request #2234 from epam/pickerInput-fix-emptyValue-prop
Browse files Browse the repository at this point in the history
[PickerInput]: fixed setting emptyValue in case of unselecting all picker items
  • Loading branch information
AlekseyManetov authored May 14, 2024
2 parents bb5c1c7 + 2852d56 commit 6ce8a1f
Show file tree
Hide file tree
Showing 12 changed files with 68 additions and 39 deletions.
4 changes: 0 additions & 4 deletions app/src/demo/tables/filteredTable/FilteredTable.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,6 @@
min-width: 0;
flex-grow: 1;
font-family: var(--uui-font);

.manager-cell {
font-family: var(--uui-font);
}
}

.icon-container {
Expand Down
3 changes: 1 addition & 2 deletions app/src/demo/tables/filteredTable/columns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import * as React from 'react';
import { Text, Badge, FlexRow, LinkButton, BadgeProps } from '@epam/uui';
import { DataColumnProps, getSeparatedValue } from '@epam/uui-core';
import { Person } from '@epam/uui-docs';
import css from './FilteredTable.module.scss';

export const personColumns: DataColumnProps<Person, number>[] = [
{
Expand Down Expand Up @@ -72,7 +71,7 @@ export const personColumns: DataColumnProps<Person, number>[] = [
{
key: 'managerName',
caption: 'Manager',
render: (p) => <LinkButton caption={ p.managerName } captionCX={ css.managerCell } href="#" />,
render: (p) => <LinkButton caption={ p.managerName } href="#" />,
grow: 0,
width: 150,
isSortable: true,
Expand Down
4 changes: 0 additions & 4 deletions app/src/demo/tables/masterDetailedTable/DemoTable.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,6 @@ body {
}
}
}

.manager-cell {
font-family: $font-sans;
}
}

.icon-container {
Expand Down
2 changes: 1 addition & 1 deletion app/src/demo/tables/masterDetailedTable/columns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export const personColumns: DataColumnProps<Person, PersonTableRecordId[], DataQ
}, {
key: 'managerName',
caption: 'Manager',
render: (p) => <LinkButton caption={ p.managerName } captionCX={ css.managerCell } href="#" />,
render: (p) => <LinkButton caption={ p.managerName } href="#" />,
width: 150,
isSortable: true,
isFilterActive: (f) => !!f.managerId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const languageLevels = [
{ id: 2, level: 'A1' }, { id: 3, level: 'A1+' }, { id: 4, level: 'A2' }, { id: 5, level: 'A2+' }, { id: 6, level: 'B1' }, { id: 7, level: 'B1+' }, { id: 8, level: 'B2' }, { id: 9, level: 'B2+' }, { id: 10, level: 'C1' }, { id: 11, level: 'C1+' }, { id: 12, level: 'C2' },
];

export default function LanguagesMultiPicker() {
export default function ArrayPickerInputExample() {
const [singlePickerValue, singleOnValueChange] = useState(null);
const [multiPickerValue, multiOnValueChange] = useState(null);

Expand Down
2 changes: 1 addition & 1 deletion app/src/sandbox/tablePaged/columns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export const personColumns = [
}, {
key: 'managerName',
caption: 'Manager',
render: (p) => <LinkButton caption={ p.managerName } captionCX={ css.managerCell } href="#" />,
render: (p) => <LinkButton caption={ p.managerName } href="#" />,
grow: 0,
shrink: 0,
width: 150,
Expand Down
23 changes: 7 additions & 16 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,15 @@

**What's New**

* [uui-core]: helpers cleanup
* Deprecated:
* `LazyLoadedMap` and related:
* `LazyLoadedMapLoadCallback`
* `UNKNOWN`
* `LOADING`
* `LOADED`
* `PENDING`
* `FAILED`
* `LoadingStatus`
* `browser` helper:
* `Browser`
* `getBrowser`
* [uui-core]: helpers cleanup, removed following helpers:
* `LazyLoadedMap`
* `browser'
* `Debouncer`
* `parseIconViewbox`
* `parseStringToCSSProperties`
* `getScreenSize`
* `urlParser`
* `batch` and related:
* `batch`
* `BatchPromiseOptions`
* `batch`

* [useTree]: useTree hook is added.
* [Features]:
Expand Down Expand Up @@ -71,6 +59,9 @@
* [PickerInput]: added property `renderTag` it's a callback for rendering custom Tags in selectionMode: `multi`.
* [PickerTogglerTag]: it's a new component, and we recommend it to use in the `renderTag` callback in the PickerInput.

**What's Fixed**
[PickerInput]: fixed setting emptyValue in case of unselecting all picker items

# 5.7.2 - 12.04.2024

**What's Fixed**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
]
},
{
"text": " ."
"text": "."
}
]
}
Expand Down
12 changes: 7 additions & 5 deletions uui-components/src/pickers/bindingHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,14 @@ interface PickerBindingHelper<TItem, TId> {
class ArrayBindingHelper<TItem, TId> implements PickerBindingHelper<TItem, TId> {
emptyValueArray: any[] = [];
dataSourceStateToValue(dsState: DataSourceState<any, TId>, props: PickerBaseProps<TId, TItem>, dataSource: IDataSource<TItem, TId, any>) {
if (props.valueType === 'entity') {
return dsState.checked?.map((id) => dataSource && dataSource.getById(id));
if (dsState && Array.isArray(dsState.checked) && dsState.checked && dsState.checked.length > 0) {
if (props.valueType === 'entity') {
return dsState.checked.map((id) => dataSource && dataSource.getById(id));
}
return dsState.checked;
} else {
return props.emptyValue;
}
return dsState.checked;
}

applyValueToDataSourceState(
Expand All @@ -48,7 +52,6 @@ class ArrayBindingHelper<TItem, TId> implements PickerBindingHelper<TItem, TId>

return {
...dsState,
selectedId: null,
checked: checked,
filter: props.filter || dsState.filter,
sorting: props.sorting ? [props.sorting] : dsState.sorting,
Expand Down Expand Up @@ -81,7 +84,6 @@ class ScalarBindingHelper<TItem, TId> implements PickerBindingHelper<TItem, TId>
return {
...dsState,
selectedId: selectedId,
checked: null,
filter: props.filter || dsState.filter,
sorting: props.sorting ? [props.sorting] : dsState.sorting,
};
Expand Down
2 changes: 1 addition & 1 deletion uui-components/src/pickers/hooks/usePicker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export function usePicker<TItem, TId, TProps extends PickerBaseProps<TItem, TId>

if ((!prevDataSourceState && (dataSourceState.checked?.length || dataSourceState.selectedId != null))
|| (prevDataSourceState && (
prevDataSourceState.checked !== dataSourceState.checked
!isEqual(prevDataSourceState.checked, dataSourceState.checked)
|| dataSourceState.selectedId !== prevDataSourceState.selectedId
))
) {
Expand Down
2 changes: 1 addition & 1 deletion uui-components/src/pickers/hooks/usePickerInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export function usePickerInput<TItem, TId, TProps>(props: UsePickerInputProps<TI
], []);

const pickerInputState = usePickerInputState({
dataSourceState: { visibleCount: initialRowsVisible },
dataSourceState: { visibleCount: initialRowsVisible, checked: [] },
});

const {
Expand Down
49 changes: 47 additions & 2 deletions uui/components/pickers/__tests__/PickerInput.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ async function setupPickerInputForTest<TItem = TestItemType, TId = number>(param
searchPosition: 'input',
getName: (item: TestItemType) => item.level,
value: params.value as TId,
selectionMode: 'single',
emptyValue: [],
searchDebounceDelay: 0,
}, params) as PickerInputComponentProps<TItem, TId>;
}
Expand Down Expand Up @@ -1362,7 +1362,33 @@ describe('PickerInput', () => {
});
});

it.each<[undefined | null | []]>([[[]]])
it.each<[undefined | null | []]>([[[]], [undefined], [null]])
('should not call onValueChange on edit search with emptyValue = %s; and return emptyValue = %s on check -> uncheck', async (emptyValue) => {
const { dom, mocks } = await setupPickerInputForTest<TestItemType, number>({
emptyValue: emptyValue,
value: emptyValue,
selectionMode: 'multi',
searchPosition: 'body',
});

fireEvent.click(dom.input);

const dialog = await screen.findByRole('dialog');
const bodyInput = await within(dialog).findByPlaceholderText('Search');
fireEvent.change(bodyInput, { target: { value: 'A' } });

expect(mocks.onValueChange).toHaveBeenCalledTimes(0);

// Test value after check -> uncheck
await PickerInputTestObject.clickOptionCheckbox('A1'); // check
await PickerInputTestObject.clickOptionCheckbox('A1'); // uncheck

await waitFor(async () => {
expect(mocks.onValueChange).toHaveBeenLastCalledWith(emptyValue);
});
});

it.each<[undefined | null | []]>([[[]], [undefined], [null]])
('should not call onValueChange on edit search if emptyValue = %s does not equal to the initial value', async (emptyValue) => {
const { dom, mocks } = await setupPickerInputForTest<TestItemType, number>({
emptyValue: emptyValue,
Expand All @@ -1379,5 +1405,24 @@ describe('PickerInput', () => {

expect(mocks.onValueChange).toHaveBeenCalledTimes(0);
});

it('should not call onValueChange on edit search if emptyValue on clear button', async () => {
const { dom, mocks } = await setupPickerInputForTest<TestItemType, number>({
emptyValue: [],
value: undefined,
selectionMode: 'multi',
searchPosition: 'body',
});

fireEvent.click(dom.input);

await PickerInputTestObject.clickOptionCheckbox('A1'); // check

await PickerInputTestObject.clickClearAllOptions();

await waitFor(async () => {
expect(mocks.onValueChange).toHaveBeenLastCalledWith([]);
});
});
});
});

0 comments on commit 6ce8a1f

Please sign in to comment.