Skip to content

Commit

Permalink
feat(kit): prevent disabled days selection for calendar-range (#8328)
Browse files Browse the repository at this point in the history
  • Loading branch information
p-ivannikov authored Aug 13, 2024
1 parent f191f9a commit 13d1f4c
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,35 @@ test.describe('InputDateRange', () => {
'07-item-and-calendar-interactions.png',
);
});

test('Prevent selection of range with disabled days', async ({page}) => {
const calendar = new TuiCalendarPO(
inputDateRange.calendarRange.locator('tui-calendar'),
);

const getCellState = async (cell: Locator): Promise<string | null> =>
cell.getAttribute('data-state');

const getDaysState = async (): Promise<Array<string | null>> =>
Promise.all((await calendar.getDays()).map(getCellState));

await tuiGoto(page, 'components/input-date-range/API?disabledItemHandler$=1');

await inputDateRange.textfield.click();

// check disabled items length before day selection
expect(
(await getDaysState()).filter(state => state === 'disabled'),
).toHaveLength(20);

await calendar.clickOnCalendarDay(7);

// check range which includes disabled days
// range should have only 2 enabled items
expect(
(await getDaysState()).filter(state => state !== 'disabled'),
).toHaveLength(2);
});
});

test.describe('Examples', () => {
Expand Down
59 changes: 57 additions & 2 deletions projects/kit/components/calendar-range/calendar-range.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export class TuiCalendarRangeComponent implements TuiWithOptionalMinMax<TuiDay>
@Output()
readonly valueChange = new EventEmitter<TuiDayRange | null>();

availableRange: TuiDayRange | null = null;
previousValue: TuiDayRange | null = null;

selectedActivePeriod: TuiDayRangePeriod | null = null;
Expand Down Expand Up @@ -175,6 +176,7 @@ export class TuiCalendarRangeComponent implements TuiWithOptionalMinMax<TuiDay>

if (value === null || !value.isSingleDay) {
this.value = new TuiDayRange(day, day);
this.availableRange = this.findAvailableRange();

return;
}
Expand Down Expand Up @@ -225,7 +227,7 @@ export class TuiCalendarRangeComponent implements TuiWithOptionalMinMax<TuiDay>
): TuiBooleanHandler<TuiDay> {
return item => {
if (!value?.isSingleDay || !minLength) {
return disabledItemHandler(item);
return this.isDisabledItem(disabledItemHandler, value, item);
}

const negativeMinLength = tuiObjectFromEntries(
Expand All @@ -236,7 +238,60 @@ export class TuiCalendarRangeComponent implements TuiWithOptionalMinMax<TuiDay>
const inDisabledRange =
disabledBefore.dayBefore(item) && disabledAfter.dayAfter(item);

return inDisabledRange || disabledItemHandler(item);
return (
inDisabledRange || this.isDisabledItem(disabledItemHandler, value, item)
);
};
}

private isDisabledItem(
disabledItemHandler: TuiBooleanHandler<TuiDay>,
value: TuiDayRange | null,
item: TuiDay,
): boolean {
return (
disabledItemHandler(item) ||
(!!value?.isSingleDay && !this.availableRangeContainsItem(item))
);
}

private availableRangeContainsItem(item: TuiDay): boolean {
if (this.availableRange === null) {
return true;
}

const {from, to} = this.availableRange;

return from.daySameOrBefore(item) && to.daySameOrAfter(item);
}

private findAvailableRange(): TuiDayRange | null {
const {disabledItemHandler, value} = this;

if (!value?.isSingleDay || disabledItemHandler === ALWAYS_FALSE_HANDLER) {
return null;
}

let from = value.from;
let to = value.from;

let leftShift = true;
let rightShift = true;

while (leftShift || rightShift) {
leftShift = !disabledItemHandler(from.append({day: -1}));

if (leftShift) {
from = from.append({day: -1});
}

rightShift = !disabledItemHandler(to.append({day: 1}));

if (rightShift) {
to = to.append({day: 1});
}
}

return new TuiDayRange(from, to);
}
}

0 comments on commit 13d1f4c

Please sign in to comment.