Skip to content

Commit

Permalink
Merge pull request #118 from uvarov-frontend/feature/add_selection_to…
Browse files Browse the repository at this point in the history
…_multiple

Feature/add selection to multiple
  • Loading branch information
uvarov-frontend authored Sep 30, 2023
2 parents 44a07a8 + 8736e67 commit b51c50e
Show file tree
Hide file tree
Showing 18 changed files with 128 additions and 64 deletions.
4 changes: 4 additions & 0 deletions demo/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,7 @@
color: white !important;
}
}

.wrapper-calendar {
@apply w-[550px]
}
2 changes: 1 addition & 1 deletion demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<meta name="viewport" content="initial-scale=1,width=device-width">
<meta name="format-detection" content="telephone=no">
<title>Vanilla Calendar - A pure JavaScript date and time picker using TypeScript so it supports any JS framework and library.</title>
<link rel="icon" type="image/svg+xml" href="@/demo/favicon.svg">
<link rel="icon" type="image/svg+xml" href="./favicon.svg">
<link rel="stylesheet" href="./index.css">
<script defer src="./main.ts" type="module"></script>
</head>
Expand Down
4 changes: 3 additions & 1 deletion demo/pages/multiple/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
<body class="font-sans bg-white bg-light-mode text-slate-900 min-h-screen container mx-auto text-center flex flex-col items-center py-12 dark:bg-slate-900 dark:bg-dark-mode dark:text-white">
<h1 class="block mb-7 text-6xl font-extrabold">Vanilla Calendar</h1>
<p class="text-lg mb-12 dark:text-slate-400">A pure JavaScript date and time picker using TypeScript so it supports any JS framework and library.</p>
<div id="calendar"></div>
<div class="wrapper-calendar">
<div id="calendar"></div>
</div>
</body>
</html>
3 changes: 3 additions & 0 deletions package/src/classes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ const classes = {
calendarInputWrapper: 'vanilla-calendar-input-wrapper',
controls: 'vanilla-calendar-controls',
grid: 'vanilla-calendar-grid',
gridDisabled: 'vanilla-calendar-grid_disabled',
column: 'vanilla-calendar-column',
columnMonth: 'vanilla-calendar-column_month',
columnYear: 'vanilla-calendar-column_year',
header: 'vanilla-calendar-header',
headerContent: 'vanilla-calendar-header__content',
month: 'vanilla-calendar-month',
Expand Down
3 changes: 2 additions & 1 deletion package/src/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
TypesCalendar,
IActions,
ICSSClasses,
IDate,
Expand All @@ -22,7 +23,7 @@ type Settings = {

export type Options = {
input?: boolean;
type?: 'default' | 'multiple' | 'month' | 'year';
type?: TypesCalendar;
months?: number;
jumpMonths?: number;
date?: Partial<IDate>;
Expand Down
20 changes: 20 additions & 0 deletions package/src/scripts/helpers/getColumnID.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { IVanillaCalendar } from '../../types';

const getColumnID = (self: IVanillaCalendar, columnClass: string, personalClass: string, id: number, dataAttr: string) => {
const columnEls = (self.HTMLElement as HTMLElement).querySelectorAll(`.${self.CSSClasses.column}`) as NodeListOf<HTMLElement>;
const firstColumnID = Number((columnEls[0].querySelector(`.${personalClass}`) as HTMLElement).getAttribute(dataAttr));
const lastColumnID = Number((columnEls[columnEls.length - 1].querySelector(`.${personalClass}`) as HTMLElement).getAttribute(dataAttr));
const indexColumn = [...columnEls].findIndex((column) => column.classList.contains(columnClass));

if (firstColumnID === lastColumnID || indexColumn < 0) {
return id;
}

if (firstColumnID < lastColumnID || (self.currentType !== 'year' && firstColumnID > lastColumnID)) {
return id - indexColumn;
}

return id;
};

export default getColumnID;
32 changes: 25 additions & 7 deletions package/src/scripts/methods/clickCalendar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import createYears from './createYears';
import generateDate from '../helpers/generateDate';
import mainMethod from './mainMethod';
import handlerMultipleRanged from './handlerMultipleRanged';
import getColumnID from '../helpers/getColumnID';

const clickCalendar = (self: IVanillaCalendar) => {
(self.HTMLElement as HTMLElement).addEventListener('click', (e) => {
Expand All @@ -22,6 +23,8 @@ const clickCalendar = (self: IVanillaCalendar) => {
const yearItemEl: HTMLElement | null = element.closest(`.${self.CSSClasses.yearsYear}`);
const monthHeaderEl: HTMLElement | null = element.closest(`.${self.CSSClasses.month}`);
const monthItemEl: HTMLElement | null = element.closest(`.${self.CSSClasses.monthsMonth}`);
const gridEl: HTMLElement | null = element.closest(`.${self.CSSClasses.grid}`);
const columnEl: HTMLElement | null = element.closest(`.${self.CSSClasses.column}`);

const clickArrowMonth = () => {
if (arrowEl && self.currentType !== 'year' && self.currentType !== 'month') {
Expand Down Expand Up @@ -141,23 +144,25 @@ const clickCalendar = (self: IVanillaCalendar) => {
};

const clickYear = () => {
if (!self.settings.selection.year || self.currentType === 'multiple') return;
if (!self.settings.selection.year) return;
if (arrowEl && self.currentType === 'year') {
if (self.viewYear === undefined) return;
if (arrowNextEl) {
self.viewYear += 15;
} else if (arrowPrevEl) {
self.viewYear -= 15;
}
createYears(self);
createYears(self, e.target as HTMLElement);
} else if (self.currentType !== 'year' && yearHeaderEl) {
createYears(self);
createYears(self, e.target as HTMLElement);
} else if (self.currentType === 'year' && yearHeaderEl) {
self.currentType = self.type;
mainMethod(self);
} else if (yearItemEl) {
if (self.selectedMonth === undefined || !self.dateMin || !self.dateMax) return;
self.selectedYear = Number(yearItemEl.dataset.calendarYear);
self.selectedYear = self.type === 'multiple'
? getColumnID(self, self.CSSClasses.columnYear, self.CSSClasses.year, Number(yearItemEl.dataset.calendarYear), 'data-calendar-selected-year')
: Number(yearItemEl.dataset.calendarYear);
self.currentType = self.type;
if (self.selectedMonth < self.dateMin.getMonth() && self.selectedYear === self.dateMin.getFullYear()) {
self.selectedMonth = self.dateMin.getMonth();
Expand All @@ -167,21 +172,34 @@ const clickCalendar = (self: IVanillaCalendar) => {
}
if (self.actions.clickYear) self.actions.clickYear(e, self.selectedYear);
mainMethod(self);
} else if (self.type === 'multiple' && self.currentType === 'year' && gridEl && !columnEl) {
self.currentType = self.type;
mainMethod(self);
}
};

const clickMonth = () => {
if (!self.settings.selection.month || self.currentType === 'multiple') return;
if (!self.settings.selection.month) return;
if (self.currentType !== 'month' && monthHeaderEl) {
createMonths(self);
createMonths(self, e.target as HTMLElement);
} else if (self.currentType === 'month' && monthHeaderEl) {
self.currentType = self.type;
mainMethod(self);
} else if (monthItemEl) {
self.selectedMonth = Number(monthItemEl.dataset.calendarMonth);
self.selectedMonth = self.type === 'multiple'
? getColumnID(self, self.CSSClasses.columnMonth, self.CSSClasses.month, Number(monthItemEl.dataset.calendarMonth), 'data-calendar-selected-month')
: Number(monthItemEl.dataset.calendarMonth);
if (self.type === 'multiple') {
const column = monthItemEl.closest(`.${self.CSSClasses.columnMonth}`) as HTMLElement;
const year = column.querySelector(`.${self.CSSClasses.year}`) as HTMLElement;
self.selectedYear = Number(year.dataset.calendarSelectedYear);
}
self.currentType = self.type;
if (self.actions.clickMonth) self.actions.clickMonth(e, self.selectedMonth);
mainMethod(self);
} else if (self.type === 'multiple' && self.currentType === 'month' && gridEl && !columnEl) {
self.currentType = self.type;
mainMethod(self);
}
};

Expand Down
21 changes: 20 additions & 1 deletion package/src/scripts/methods/createDOM.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
import { IVanillaCalendar } from '../../types';
import { DOMParser, MultipleParser } from '../helpers/parserComponent';

const createDOM = (self: IVanillaCalendar) => {
const createDOM = (self: IVanillaCalendar, target?: HTMLElement) => {
const calendarElement = (self.HTMLElement as HTMLElement);
calendarElement.classList.add(self.CSSClasses.calendar);

const switcherTypeMultiple = (columnClass: string, DOMTemplates: string) => {
if (!target) return;
const controls = (self.HTMLElement as HTMLElement).querySelector(`.${self.CSSClasses.controls}`);
if (controls) (self.HTMLElement as HTMLElement).removeChild(controls);
const grid = (self.HTMLElement as HTMLElement).querySelector(`.${self.CSSClasses.grid}`) as HTMLElement;
grid.classList.add(self.CSSClasses.gridDisabled);
const columnElement = target.closest(`.${self.CSSClasses.column}`) as HTMLElement;
columnElement.classList.add(columnClass);
columnElement.innerHTML = DOMParser(self, DOMTemplates);
};

switch (self.currentType) {
case 'default':
calendarElement.classList.add(self.CSSClasses.calendarDefault);
Expand All @@ -20,12 +31,20 @@ const createDOM = (self: IVanillaCalendar) => {
calendarElement.innerHTML = MultipleParser(self, DOMParser(self, self.DOMTemplates.multiple));
break;
case 'month':
if (self.type === 'multiple') {
switcherTypeMultiple(self.CSSClasses.columnMonth, self.DOMTemplates.month);
break;
}
calendarElement.classList.remove(self.CSSClasses.calendarDefault);
calendarElement.classList.add(self.CSSClasses.calendarMonth);
calendarElement.classList.remove(self.CSSClasses.calendarYear);
calendarElement.innerHTML = DOMParser(self, self.DOMTemplates.month);
break;
case 'year':
if (self.type === 'multiple') {
switcherTypeMultiple(self.CSSClasses.columnYear, self.DOMTemplates.year);
break;
}
calendarElement.classList.remove(self.CSSClasses.calendarDefault);
calendarElement.classList.remove(self.CSSClasses.calendarMonth);
calendarElement.classList.add(self.CSSClasses.calendarYear);
Expand Down
9 changes: 5 additions & 4 deletions package/src/scripts/methods/createMonths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ import createDOM from './createDOM';
import showMonth from './showMonth';
import showYear from './showYear';

const createMonths = (self: IVanillaCalendar) => {
const createMonths = (self: IVanillaCalendar, target?: HTMLElement) => {
const selectedMonth = target?.dataset.calendarSelectedMonth ? Number(target?.dataset.calendarSelectedMonth) : self.selectedMonth;
self.currentType = 'month';
createDOM(self);
createDOM(self, target);
showMonth(self);
showYear(self);

const monthsEl = (self.HTMLElement as HTMLElement).querySelector(`.${self.CSSClasses.months}`);
if (self.selectedMonth === undefined || self.selectedYear === undefined || !self.dateMin || !self.dateMax || !monthsEl) return;
if (self.selectedYear === undefined || !self.dateMin || !self.dateMax || !monthsEl) return;

if (self.settings.selection.month) monthsEl.classList.add(self.CSSClasses.monthsSelecting);

Expand All @@ -22,7 +23,7 @@ const createMonths = (self: IVanillaCalendar) => {
const month = self.locale.months[i];
const monthEl = templateMonthEl.cloneNode(true) as HTMLButtonElement;

if (i === self.selectedMonth) {
if (i === selectedMonth) {
monthEl.classList.add(self.CSSClasses.monthsMonthSelected);
}
if (i < self.dateMin.getMonth() && self.selectedYear === self.dateMin.getFullYear()) {
Expand Down
7 changes: 4 additions & 3 deletions package/src/scripts/methods/createYears.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import createDOM from './createDOM';
import showMonth from './showMonth';
import showYear from './showYear';

const createYears = (self: IVanillaCalendar) => {
const createYears = (self: IVanillaCalendar, target?: HTMLElement) => {
if (self.viewYear === undefined || !self.dateMin || !self.dateMax) return;
const selectedYear = target?.dataset.calendarSelectedYear ? Number(target?.dataset.calendarSelectedYear) : self.selectedYear;
self.currentType = 'year';
createDOM(self);
createDOM(self, target);
showMonth(self);
showYear(self);
controlArrows(self);
Expand All @@ -23,7 +24,7 @@ const createYears = (self: IVanillaCalendar) => {
const year = i;
const yearEl = templateYearEl.cloneNode(true) as HTMLButtonElement;

if (year === self.selectedYear) {
if (year === selectedYear) {
yearEl.classList.add(self.CSSClasses.yearsYearSelected);
}
if (year < self.dateMin.getFullYear()) {
Expand Down
26 changes: 18 additions & 8 deletions package/src/scripts/methods/mainMethod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,23 @@ import getLocale from './getLocale';
import setTheme from './setTheme';

const mainMethod = (self: IVanillaCalendar) => {
const typeMapper = {
default() {
createWeek(self);
createDays(self);
},
multiple() {
createWeek(self);
createDays(self);
},
month() {
createMonths(self);
},
year() {
createYears(self);
},
};

setTheme(self);
getLocale(self);
createDOM(self);
Expand All @@ -20,14 +37,7 @@ const mainMethod = (self: IVanillaCalendar) => {
controlArrows(self);
createTime(self);

if (self.currentType === 'default' || self.currentType === 'multiple') {
createWeek(self);
createDays(self);
} else if (self.currentType === 'month') {
createMonths(self);
} else if (self.currentType === 'year') {
createYears(self);
}
typeMapper[self.currentType]();
};

export default mainMethod;
2 changes: 1 addition & 1 deletion package/src/scripts/methods/showMonth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const showMonth = (self: IVanillaCalendar) => {
months[index].dataset.calendarSelectedMonth = String(selectedMonth);
months[index].innerText = self.locale.months[selectedMonth];

if (!self.settings.selection.month || self.currentType === 'multiple') {
if (!self.settings.selection.month) {
months[index].tabIndex = -1;
months[index].classList.add(self.CSSClasses.monthDisabled);
} else {
Expand Down
2 changes: 1 addition & 1 deletion package/src/scripts/methods/showYear.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const showYear = (self: IVanillaCalendar) => {
years[index].dataset.calendarSelectedYear = String(selectedYear);
years[index].innerText = String(selectedYear);

if (!self.settings.selection.year || self.currentType === 'multiple') {
if (!self.settings.selection.year) {
years[index].tabIndex = -1;
years[index].classList.add(self.CSSClasses.yearDisabled);
} else {
Expand Down
5 changes: 3 additions & 2 deletions package/src/scripts/vanilla-calendar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
IPopups,
ICSSClasses,
IDOMTemplates,
TypesCalendar,
} from '../types';
import resetCalendar from './methods/resetCalendar';
import updateCalendar from './methods/updateCalendar';
Expand All @@ -22,7 +23,7 @@ export default class VanillaCalendar<T extends (HTMLElement | string), R extends

input!: boolean;

type!: 'default' | 'multiple' | 'month' | 'year';
type!: TypesCalendar;

months!: number;

Expand All @@ -42,7 +43,7 @@ export default class VanillaCalendar<T extends (HTMLElement | string), R extends

DOMTemplates!: IDOMTemplates;

currentType!: string;
currentType!: TypesCalendar;

constructor(selector: T, option?: R) {
this.HTMLElement = typeof selector === 'string' ? document.querySelector(selector) : selector;
Expand Down
10 changes: 0 additions & 10 deletions package/src/styles/themes/dark.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,6 @@
@apply outline-orange-300
}

[data-calendar-theme="dark"].vanilla-calendar.vanilla-calendar_multiple .vanilla-calendar-month,
[data-calendar-theme="dark"].vanilla-calendar.vanilla-calendar_multiple .vanilla-calendar-year {
@apply text-white hover:text-white
}

[data-calendar-theme="dark"].vanilla-calendar.vanilla-calendar_multiple .vanilla-calendar-month.vanilla-calendar-month_disabled,
[data-calendar-theme="dark"].vanilla-calendar.vanilla-calendar_multiple .vanilla-calendar-year.vanilla-calendar-year_disabled {
@apply text-white
}

[data-calendar-theme="dark"] .vanilla-calendar-arrow::before {
@apply bg-white;
}
Expand Down
10 changes: 0 additions & 10 deletions package/src/styles/themes/light.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,6 @@
@apply outline-orange-300
}

[data-calendar-theme="light"].vanilla-calendar.vanilla-calendar_multiple .vanilla-calendar-month,
[data-calendar-theme="light"].vanilla-calendar.vanilla-calendar_multiple .vanilla-calendar-year {
@apply text-slate-900 hover:text-slate-900
}

[data-calendar-theme="light"].vanilla-calendar.vanilla-calendar_multiple .vanilla-calendar-month.vanilla-calendar-month_disabled,
[data-calendar-theme="light"].vanilla-calendar.vanilla-calendar_multiple .vanilla-calendar-year.vanilla-calendar-year_disabled {
@apply text-slate-900
}

[data-calendar-theme="light"] .vanilla-calendar-arrow::before {
@apply bg-slate-900;
}
Expand Down
Loading

0 comments on commit b51c50e

Please sign in to comment.