Skip to content

Commit 9901290

Browse files
committed
Fix issue with move all buttons ignoring filters
1 parent 2e58830 commit 9901290

File tree

3 files changed

+93
-19
lines changed

3 files changed

+93
-19
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## [6.0.3](https://github.com/jakezatecky/react-dual-listbox/compare/v6.0.2...v6.0.3) (2023-02-24)
4+
5+
### Fixed
6+
7+
* Fix issue with move all buttons ignoring filters (#268)
8+
39
## [6.0.2](https://github.com/jakezatecky/react-dual-listbox/compare/v6.0.1...v6.0.2) (2023-02-06)
410

511
### Fixed

src/js/components/DualListBox.jsx

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ function DualListBox(props) {
331331
}
332332

333333
if (direction === 'up') {
334-
// If all of the marked options are already as high as they can get, ignore the
334+
// If all the marked options are already as high as they can get, ignore the
335335
// re-arrangement request because they will end of swapping their order amongst
336336
// themselves.
337337
if (markedOptions[markedOptions.length - 1].order > markedOptions.length - 1) {
@@ -342,8 +342,8 @@ function DualListBox(props) {
342342
});
343343
}
344344
} else if (direction === 'down') {
345-
// Similar to the above, if all of the marked options are already as low as they can
346-
// get, ignore the re-arrangement request.
345+
// Similar to the above, if all the marked options are already as low as they can get,
346+
// ignore the re-arrangement request.
347347
if (markedOptions[0].order < selected.length - markedOptions.length) {
348348
markedOptions.reverse().forEach(({ order }) => {
349349
if (order < selected.length - 1) {
@@ -388,7 +388,7 @@ function DualListBox(props) {
388388
*
389389
* @param {Array} options
390390
*
391-
* @returns {Array}
391+
* @returns {String[]}
392392
*/
393393
function makeOptionsSelectedRecursive(options) {
394394
const { getOptionValue } = props;
@@ -418,7 +418,7 @@ function DualListBox(props) {
418418
*
419419
* @param {Array} options
420420
*
421-
* @returns {Array}
421+
* @returns {String[]}
422422
*/
423423
function makeOptionsSelected(options) {
424424
const availableOptions = filterAvailable(options);
@@ -432,24 +432,24 @@ function DualListBox(props) {
432432
/**
433433
* Recursively unselect the given options, except for those disabled.
434434
*
435-
* @param {Array} selectedOptions
435+
* @param {String[]} previousSelected
436+
* @param {Array} optionsToRemove
436437
*
437-
* @returns {Array}
438+
* @returns {String[]}
438439
*/
439-
function makeOptionsUnselectedRecursive(selectedOptions) {
440+
function makeOptionsUnselectedRecursive(previousSelected, optionsToRemove) {
440441
const { getOptionValue } = props;
441-
let newSelected = [];
442+
let newSelected = [...previousSelected];
442443

443-
selectedOptions.forEach((option) => {
444+
optionsToRemove.forEach((option) => {
444445
if (option.options !== undefined) {
445446
// Traverse any parents for leaf options
446-
newSelected = [
447-
...newSelected,
448-
...makeOptionsUnselectedRecursive(option.options),
449-
];
450-
} else if (option.disabled) {
451-
// Preserve any disabled options
452-
newSelected.push(getOptionValue(option));
447+
newSelected = makeOptionsUnselectedRecursive(newSelected, option.options);
448+
} else if (!option.disabled) {
449+
// Remove non-disabled options
450+
newSelected = newSelected.filter((oldValue) => (
451+
oldValue !== getOptionValue(option)
452+
));
453453
}
454454
});
455455

@@ -464,7 +464,7 @@ function DualListBox(props) {
464464
* @returns {Array}
465465
*/
466466
function makeOptionsUnselected(options) {
467-
return makeOptionsUnselectedRecursive(filterSelected(options, true));
467+
return makeOptionsUnselectedRecursive(selected, filterSelected(options));
468468
}
469469

470470
/**
@@ -560,7 +560,7 @@ function DualListBox(props) {
560560
}
561561

562562
onChange(newSelected, marked, isToSelected ? 'available' : 'selected', isRearrangement);
563-
}, [selected]);
563+
}, [selected, filter]);
564564

565565
/**
566566
* @param {Object} event

test/DualListBox.jsx

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,74 @@ describe('<DualListBox />', async () => {
304304

305305
assert.deepEqual(['luna', 'phobos'], actualSelected);
306306
});
307+
308+
// https://github.com/jakezatecky/react-dual-listbox/issues/268
309+
it('should only move filtered options when moving all to selected', async () => {
310+
let actualSelected = null;
311+
312+
const { user } = setup((
313+
<DualListBox
314+
canFilter
315+
options={[
316+
{ label: 'Moon', value: 'luna' },
317+
{
318+
label: 'Mars',
319+
options: [
320+
{ value: 'phobos', label: 'Phobos' },
321+
{ value: 'deimos', label: 'Deimos' },
322+
],
323+
},
324+
]}
325+
preserveSelectOrder
326+
selected={['deimos']}
327+
onChange={(selected) => {
328+
actualSelected = selected;
329+
}}
330+
/>
331+
));
332+
333+
const filter = screen.getByLabelText('Filter available');
334+
const moveAllRight = screen.getByLabelText('Move all to selected');
335+
336+
await user.type(filter, 'moon');
337+
await user.click(moveAllRight);
338+
339+
assert.deepEqual(['deimos', 'luna'], actualSelected);
340+
});
341+
342+
// https://github.com/jakezatecky/react-dual-listbox/issues/268
343+
it('should only move filtered options when moving all to available', async () => {
344+
let actualSelected = null;
345+
346+
const { user } = setup((
347+
<DualListBox
348+
canFilter
349+
options={[
350+
{ label: 'Moon', value: 'luna' },
351+
{
352+
label: 'Mars',
353+
options: [
354+
{ value: 'phobos', label: 'Phobos' },
355+
{ value: 'deimos', label: 'Deimos' },
356+
],
357+
},
358+
]}
359+
preserveSelectOrder
360+
selected={['phobos', 'deimos']}
361+
onChange={(selected) => {
362+
actualSelected = selected;
363+
}}
364+
/>
365+
));
366+
367+
const filter = screen.getByLabelText('Filter selected');
368+
const moveAllLeft = screen.getByLabelText('Move all to available');
369+
370+
await user.type(filter, 'phob');
371+
await user.click(moveAllLeft);
372+
373+
assert.deepEqual(['deimos'], actualSelected);
374+
});
307375
});
308376

309377
describe('props.className', () => {

0 commit comments

Comments
 (0)