diff --git a/src/components/multi_select_state.js b/src/components/multi_select_state.js
index d8206b3..afe6013 100644
--- a/src/components/multi_select_state.js
+++ b/src/components/multi_select_state.js
@@ -1,6 +1,7 @@
import React, { PureComponent } from "react";
import {
getSelectedByAllItems,
+ getSelectedItemsOutsideInterval,
filterUnselectedByIds,
findItem,
getMinMaxIndexes,
@@ -69,16 +70,33 @@ const withMultiSelectState = WrappedComponent =>
}
handleMultiSelection(index) {
- const { items, isLocked } = this.props;
- const { filteredItems, firstItemShiftSelected } = this.state;
+ const { items, isLocked, maxSelectedItems } = this.props;
+ const {
+ filteredItems,
+ firstItemShiftSelected,
+ selectedItems
+ } = this.state;
+
+ const interval = getMinMaxIndexes(
+ index,
+ firstItemShiftSelected,
+ items,
+ selectedItems,
+ maxSelectedItems
+ );
+ const outsideSelectedItems = getSelectedItemsOutsideInterval(
+ index,
+ firstItemShiftSelected,
+ items,
+ selectedItems
+ );
- const interval = getMinMaxIndexes(index, firstItemShiftSelected);
const newSelectedItems = items.filter(
(item, index) =>
(isWithin(index, interval) &&
!isLocked(item) &&
findItem(item, filteredItems)) ||
- findItem(item, this.state.selectedItems)
+ findItem(item, outsideSelectedItems)
);
const newFilteredSelectedItems = this.getNewFilteredSelectedItems(
newSelectedItems
diff --git a/src/components/multi_select_state_utils.js b/src/components/multi_select_state_utils.js
index 56f9f2d..34b4dc7 100644
--- a/src/components/multi_select_state_utils.js
+++ b/src/components/multi_select_state_utils.js
@@ -32,11 +32,71 @@ export const getSelectedByAllItems = (itemsToSelect, selectedItems, items) => {
return [...destinationItems, ...sourceItems];
};
-export const getMinMaxIndexes = (currentIndex, firstItemShiftSelected) =>
+export const getMinMaxIndexes = (
+ currentIndex,
+ firstItemShiftSelected,
+ items,
+ selectedItems,
+ maxSelected
+) => {
+ const numberOfItemsOutsideSelected = getSelectedItemsOutsideInterval(
+ currentIndex,
+ firstItemShiftSelected,
+ items,
+ selectedItems
+ ).length;
+ const sumItemsShouldBeSelect =
+ numberOfItemsOutsideSelected +
+ Math.abs(firstItemShiftSelected - currentIndex) +
+ 1;
+
+ if (maxSelected && maxSelected <= sumItemsShouldBeSelect) {
+ return getIndexesWhenShiftSelected(
+ currentIndex,
+ firstItemShiftSelected,
+ maxSelected,
+ numberOfItemsOutsideSelected
+ );
+ }
+ return getInputInterval(currentIndex, firstItemShiftSelected);
+};
+
+const getIndexesWhenShiftSelected = (
+ currentIndex,
+ firstItemShiftSelected,
+ maxSelected,
+ numberOfItemsOutsideSelected
+) => {
+ const sumItemsAllowToSelect = maxSelected - numberOfItemsOutsideSelected - 1;
+ return firstItemShiftSelected > currentIndex
+ ? {
+ minIndex: firstItemShiftSelected - sumItemsAllowToSelect,
+ maxIndex: firstItemShiftSelected
+ }
+ : {
+ minIndex: firstItemShiftSelected,
+ maxIndex: firstItemShiftSelected + sumItemsAllowToSelect
+ };
+};
+
+const getInputInterval = (currentIndex, firstItemShiftSelected) =>
firstItemShiftSelected > currentIndex
? { minIndex: currentIndex, maxIndex: firstItemShiftSelected }
: { minIndex: firstItemShiftSelected, maxIndex: currentIndex };
+export const getSelectedItemsOutsideInterval = (
+ currentIndex,
+ firstItemShiftSelected,
+ sourceItems,
+ selectedItems
+) => {
+ const interval = getInputInterval(currentIndex, firstItemShiftSelected);
+ return selectedItems.filter(selectedItem => {
+ const index = sourceItems.findIndex(item => item.id === selectedItem.id);
+ return !isWithin(index, interval) || selectedItem.disabled;
+ });
+};
+
export const isWithin = (index, { minIndex, maxIndex }) =>
index >= minIndex && index <= maxIndex;
diff --git a/tests/components/multi_select_state.spec.js b/tests/components/multi_select_state.spec.js
index a9a18fc..b2a5188 100644
--- a/tests/components/multi_select_state.spec.js
+++ b/tests/components/multi_select_state.spec.js
@@ -715,4 +715,40 @@ describe("withMultiSelectState", () => {
items[4]
]);
});
+
+ test("case select with shift items where shouldBeSelect > maxSelectedItems", () => {
+ const ConditionalComponent = withMultiSelectState(CustomComponent);
+ const items = [ITEM_1, ITEM_2, ITEM_3, ITEM_4, ITEM_12];
+
+ const wrapper = shallow(
+
+ );
+ wrapper.props().selectItem(EVENT_WITH_SHIFT, ITEM_12.id);
+ wrapper.update();
+ wrapper.props().selectItem(EVENT_WITH_SHIFT, ITEM_3.id);
+ wrapper.update();
+ expect(wrapper.prop("selectedItems")).toEqual([ITEM_1, ITEM_4, ITEM_12]);
+ });
+
+ test("case select with shift items where shouldBeSelect < maxSelectedItems", () => {
+ const ConditionalComponent = withMultiSelectState(CustomComponent);
+ const items = [ITEM_1, ITEM_2, ITEM_3, ITEM_4];
+
+ const wrapper = shallow(
+
+ );
+ wrapper.props().selectItem(EVENT_WITH_SHIFT, ITEM_1.id);
+ wrapper.update();
+ wrapper.props().selectItem(EVENT_WITH_SHIFT, ITEM_3.id);
+ wrapper.update();
+ expect(wrapper.prop("selectedItems")).toEqual([ITEM_1, ITEM_2, ITEM_3]);
+ });
});
diff --git a/tests/components/multi_select_state_utils.spec.js b/tests/components/multi_select_state_utils.spec.js
index 66f6905..e1f2a83 100644
--- a/tests/components/multi_select_state_utils.spec.js
+++ b/tests/components/multi_select_state_utils.spec.js
@@ -1,6 +1,8 @@
import {
filterUnselectedByIds,
- getSelectedByAllItems
+ getSelectedByAllItems,
+ getSelectedItemsOutsideInterval,
+ getAvailableIntervalForSelection
} from "../../src/components/multi_select_state_utils";
const items = [
@@ -76,4 +78,52 @@ describe("testing utils for multi select state", () => {
);
expect(allSelectedItems).toEqual([]);
});
+
+ test("filter selectedItems that not in interval", () => {
+ const selectedItemsOutsideInterval = getSelectedItemsOutsideInterval(
+ items,
+ selectedItems,
+ { minIndex: 1, maxIndex: 3 }
+ );
+ expect(selectedItemsOutsideInterval.length).toEqual(1);
+ expect(selectedItemsOutsideInterval[0]).toEqual(selectedItems[0]);
+ });
+
+ test("filter itemsToSelect that not in interval", () => {
+ const selectedItemsOutsideInterval = getSelectedItemsOutsideInterval(
+ items,
+ itemsToSelect,
+ { minIndex: 0, maxIndex: 3 }
+ );
+ expect(selectedItemsOutsideInterval.length).toEqual(0);
+ });
+
+ test("available interval when minIndex == firstItemShiftSelected", () => {
+ const initialInterval = { minIndex: 0, maxIndex: 3 };
+ const maxSelectedItems = 3;
+ const selectedItemsOutsideInterval = 0;
+ const firstItemShiftSelected = 0;
+ const availableInterval = getAvailableIntervalForSelection(
+ initialInterval,
+ selectedItemsOutsideInterval,
+ maxSelectedItems,
+ firstItemShiftSelected
+ );
+ expect(availableInterval).toEqual({ minIndex: 0, maxIndex: 2 });
+ });
+
+ test("available interval when maxIndex == firstItemShiftSelected", () => {
+ const initialInterval = { minIndex: 1, maxIndex: 3 };
+ const maxSelectedItems = 3;
+ const selectedItemsOutsideInterval = 1;
+ const firstItemShiftSelected = 3;
+
+ const availableInterval = getAvailableIntervalForSelection(
+ initialInterval,
+ selectedItemsOutsideInterval,
+ maxSelectedItems,
+ firstItemShiftSelected
+ );
+ expect(availableInterval).toEqual({ minIndex: 2, maxIndex: 3 });
+ });
});