svelte-range-calendar 0.2.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -1
- package/dist/Calendar.svelte +142 -111
- package/dist/Calendar.svelte.d.ts +49 -28
- package/dist/shared/dates.d.ts +13 -17
- package/dist/shared/dates.js +70 -66
- package/dist/shared/formatters.d.ts +1 -1
- package/dist/shared/types.d.ts +12 -12
- package/package.json +2 -3
- package/src/Calendar.svelte +142 -111
- package/src/shared/dates.ts +100 -105
- package/src/shared/formatters.ts +1 -1
- package/src/shared/types.ts +12 -12
package/src/shared/dates.ts
CHANGED
|
@@ -1,21 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
getCenturyStart,
|
|
4
|
-
getDayEnd,
|
|
5
|
-
getDayStart,
|
|
6
|
-
getDecadeEnd,
|
|
7
|
-
getDecadeStart,
|
|
8
|
-
getMonthEnd,
|
|
9
|
-
getMonthStart,
|
|
10
|
-
getYearEnd,
|
|
11
|
-
getYearStart,
|
|
12
|
-
} from 'svelte-date-utils';
|
|
1
|
+
import { createDateUtils } from 'svelte-date-utils';
|
|
2
|
+
import type { DateAdapter } from 'svelte-date-utils';
|
|
13
3
|
|
|
14
4
|
import type { CalendarType, DateType, LooseValue, LooseValuePiece, Range, View } from './types.js';
|
|
15
5
|
|
|
16
6
|
export const views = ['century', 'decade', 'year', 'month'] as const satisfies readonly View[];
|
|
17
7
|
|
|
18
|
-
/** Type of date represented by a single tile in a given view. */
|
|
19
8
|
export const tileTypes: Record<View, DateType> = {
|
|
20
9
|
century: 'decade',
|
|
21
10
|
decade: 'year',
|
|
@@ -23,36 +12,25 @@ export const tileTypes: Record<View, DateType> = {
|
|
|
23
12
|
month: 'day',
|
|
24
13
|
};
|
|
25
14
|
|
|
26
|
-
const dayInMs = 24 * 60 * 60 * 1000;
|
|
27
|
-
|
|
28
|
-
const gregoryRegions = new Set(
|
|
29
|
-
'AG AS AU BD BR BS BT BW BZ CA CO DM DO ET GT GU HK HN ID IN JM JP KE KH KR LA MH MM MO MT MX MZ NI NP PA PE PH PK PR PT PY SA SG SV TH TT TW UM US VE VI WS YE ZA ZW'.split(
|
|
30
|
-
' ',
|
|
31
|
-
),
|
|
32
|
-
);
|
|
33
|
-
const islamicRegions = new Set('AE AF BH DJ DZ EG IQ IR JO KW LY OM QA SD SY'.split(' '));
|
|
34
|
-
|
|
35
15
|
export function getCalendarType(locale: string): CalendarType {
|
|
36
16
|
let region: string | undefined;
|
|
37
|
-
|
|
38
17
|
try {
|
|
39
18
|
region = new Intl.Locale(locale).maximize().region;
|
|
40
19
|
} catch {
|
|
41
20
|
region = locale.split('-')[1]?.toUpperCase();
|
|
42
21
|
}
|
|
43
|
-
|
|
44
|
-
if (region
|
|
45
|
-
return 'hebrew';
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (region && islamicRegions.has(region)) {
|
|
22
|
+
if (region === 'IL') return 'hebrew';
|
|
23
|
+
if (region && 'AE AF BH DJ DZ EG IQ IR JO KW LY OM QA SD SY'.split(' ').includes(region)) {
|
|
49
24
|
return 'islamic';
|
|
50
25
|
}
|
|
51
|
-
|
|
52
|
-
|
|
26
|
+
if (
|
|
27
|
+
region &&
|
|
28
|
+
'AG AS AU BD BR BS BT BW BZ CA CO DM DO ET GT GU HK HN ID IN JM JP KE KH KR LA MH MM MO MT MX MZ NI NP PA PE PH PK PR PT PY SA SG SV TH TT TW UM US VE VI WS YE ZA ZW'
|
|
29
|
+
.split(' ')
|
|
30
|
+
.includes(region)
|
|
31
|
+
) {
|
|
53
32
|
return 'gregory';
|
|
54
33
|
}
|
|
55
|
-
|
|
56
34
|
return 'iso8601';
|
|
57
35
|
}
|
|
58
36
|
|
|
@@ -63,128 +41,145 @@ const weekStartDays: Record<CalendarType, number> = {
|
|
|
63
41
|
islamic: 6,
|
|
64
42
|
};
|
|
65
43
|
|
|
66
|
-
export function isWeekend(
|
|
67
|
-
|
|
68
|
-
|
|
44
|
+
export function isWeekend<T>(
|
|
45
|
+
adapter: DateAdapter<T>,
|
|
46
|
+
date: T,
|
|
47
|
+
calendarType: CalendarType,
|
|
48
|
+
): boolean {
|
|
49
|
+
const day = adapter.toJsDate(date).getDay();
|
|
69
50
|
return calendarType === 'islamic' || calendarType === 'hebrew'
|
|
70
51
|
? day === 5 || day === 6
|
|
71
52
|
: day === 0 || day === 6;
|
|
72
53
|
}
|
|
73
54
|
|
|
74
|
-
export function addDays(date:
|
|
75
|
-
return
|
|
55
|
+
export function addDays<T>(adapter: DateAdapter<T>, date: T, days: number): T {
|
|
56
|
+
return adapter.startOfDay(adapter.addDays(date, days));
|
|
76
57
|
}
|
|
77
58
|
|
|
78
|
-
export function getBeginOfWeek(date:
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
return addDays(date, -offset);
|
|
59
|
+
export function getBeginOfWeek<T>(adapter: DateAdapter<T>, date: T, calendarType: CalendarType): T {
|
|
60
|
+
const day = adapter.toJsDate(date).getDay();
|
|
61
|
+
const offset = (day - weekStartDays[calendarType] + 7) % 7;
|
|
62
|
+
return addDays(adapter, date, -offset);
|
|
82
63
|
}
|
|
83
64
|
|
|
84
|
-
export function getDaysBetween(from:
|
|
85
|
-
const
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
65
|
+
export function getDaysBetween<T>(adapter: DateAdapter<T>, from: T, to: T): number {
|
|
66
|
+
const a = adapter.toJsDate(from);
|
|
67
|
+
const b = adapter.toJsDate(to);
|
|
68
|
+
const fromDay = Date.UTC(a.getFullYear(), a.getMonth(), a.getDate());
|
|
69
|
+
const toDay = Date.UTC(b.getFullYear(), b.getMonth(), b.getDate());
|
|
70
|
+
return Math.round((toDay - fromDay) / 86_400_000);
|
|
89
71
|
}
|
|
90
72
|
|
|
91
|
-
export function getWeekNumber(
|
|
73
|
+
export function getWeekNumber<T>(
|
|
74
|
+
adapter: DateAdapter<T>,
|
|
75
|
+
date: T,
|
|
76
|
+
calendarType: CalendarType,
|
|
77
|
+
): number {
|
|
78
|
+
const jsDate = adapter.toJsDate(date);
|
|
92
79
|
if (calendarType === 'iso8601') {
|
|
93
|
-
const
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
80
|
+
const day = jsDate.getDay() || 7;
|
|
81
|
+
const thursday = addDays(adapter, date, 4 - day);
|
|
82
|
+
const year = adapter.getYear(thursday);
|
|
83
|
+
const yearStart = adapter.setDate(
|
|
84
|
+
adapter.setMonth(adapter.setYear(adapter.date(), year), 0),
|
|
85
|
+
1,
|
|
86
|
+
);
|
|
87
|
+
return Math.ceil((getDaysBetween(adapter, yearStart, thursday) + 1) / 7);
|
|
97
88
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
const firstWeekStart = getBeginOfWeek(new Date(weekStart.getFullYear(), 0, 1), calendarType);
|
|
107
|
-
|
|
108
|
-
return Math.round(getDaysBetween(firstWeekStart, weekStart) / 7) + 1;
|
|
89
|
+
const weekStart = getBeginOfWeek(adapter, date, calendarType);
|
|
90
|
+
if (adapter.getYear(addDays(adapter, weekStart, 6)) > adapter.getYear(weekStart)) return 1;
|
|
91
|
+
const year = adapter.getYear(weekStart);
|
|
92
|
+
const firstDate = adapter.setDate(adapter.setMonth(adapter.setYear(adapter.date(), year), 0), 1);
|
|
93
|
+
const firstWeekStart = getBeginOfWeek(adapter, firstDate, calendarType);
|
|
94
|
+
return Math.round(getDaysBetween(adapter, firstWeekStart, weekStart) / 7) + 1;
|
|
109
95
|
}
|
|
110
96
|
|
|
111
|
-
export function getBegin(type: DateType, date:
|
|
97
|
+
export function getBegin<T>(adapter: DateAdapter<T>, type: DateType, date: T): T {
|
|
98
|
+
const utils = createDateUtils(adapter);
|
|
112
99
|
switch (type) {
|
|
113
100
|
case 'century':
|
|
114
|
-
return getCenturyStart(date);
|
|
101
|
+
return utils.getCenturyStart(date);
|
|
115
102
|
case 'decade':
|
|
116
|
-
return getDecadeStart(date);
|
|
103
|
+
return utils.getDecadeStart(date);
|
|
117
104
|
case 'year':
|
|
118
|
-
return getYearStart(date);
|
|
105
|
+
return utils.getYearStart(date);
|
|
119
106
|
case 'month':
|
|
120
|
-
return getMonthStart(date);
|
|
107
|
+
return utils.getMonthStart(date);
|
|
121
108
|
case 'day':
|
|
122
|
-
return getDayStart(date);
|
|
109
|
+
return utils.getDayStart(date);
|
|
123
110
|
}
|
|
124
111
|
}
|
|
125
112
|
|
|
126
|
-
export function getEnd(type: DateType, date:
|
|
113
|
+
export function getEnd<T>(adapter: DateAdapter<T>, type: DateType, date: T): T {
|
|
114
|
+
const utils = createDateUtils(adapter);
|
|
127
115
|
switch (type) {
|
|
128
116
|
case 'century':
|
|
129
|
-
return getCenturyEnd(date);
|
|
117
|
+
return utils.getCenturyEnd(date);
|
|
130
118
|
case 'decade':
|
|
131
|
-
return getDecadeEnd(date);
|
|
119
|
+
return utils.getDecadeEnd(date);
|
|
132
120
|
case 'year':
|
|
133
|
-
return getYearEnd(date);
|
|
121
|
+
return utils.getYearEnd(date);
|
|
134
122
|
case 'month':
|
|
135
|
-
return getMonthEnd(date);
|
|
123
|
+
return utils.getMonthEnd(date);
|
|
136
124
|
case 'day':
|
|
137
|
-
return getDayEnd(date);
|
|
125
|
+
return utils.getDayEnd(date);
|
|
138
126
|
}
|
|
139
127
|
}
|
|
140
128
|
|
|
141
|
-
export function getRange(type: DateType, date:
|
|
142
|
-
return [getBegin(type, date), getEnd(type, date)];
|
|
129
|
+
export function getRange<T>(adapter: DateAdapter<T>, type: DateType, date: T): Range<T> {
|
|
130
|
+
return [getBegin(adapter, type, date), getEnd(adapter, type, date)];
|
|
143
131
|
}
|
|
144
132
|
|
|
145
133
|
const stepInYears: Record<View, number> = { century: 100, decade: 10, month: 0, year: 1 };
|
|
146
134
|
const bigStepInYears: Record<View, number> = { century: 0, decade: 100, month: 1, year: 10 };
|
|
147
135
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
export function shiftDate(view: View, date: Date, amount: number, double = false): Date {
|
|
153
|
-
const year = date.getFullYear();
|
|
154
|
-
const month = date.getMonth();
|
|
136
|
+
function makeDate<T>(adapter: DateAdapter<T>, year: number, month: number, day = 1): T {
|
|
137
|
+
const date = adapter.setYear(adapter.date(), year);
|
|
138
|
+
return adapter.setDate(adapter.setMonth(date, month), day);
|
|
139
|
+
}
|
|
155
140
|
|
|
141
|
+
export function shiftDate<T>(
|
|
142
|
+
adapter: DateAdapter<T>,
|
|
143
|
+
view: View,
|
|
144
|
+
date: T,
|
|
145
|
+
amount: number,
|
|
146
|
+
double = false,
|
|
147
|
+
): T {
|
|
148
|
+
const year = adapter.getYear(date);
|
|
149
|
+
const month = adapter.getMonth(date);
|
|
156
150
|
if (!double) {
|
|
157
151
|
return view === 'month'
|
|
158
|
-
?
|
|
159
|
-
: getBegin(view,
|
|
152
|
+
? makeDate(adapter, year, month + amount)
|
|
153
|
+
: getBegin(adapter, view, makeDate(adapter, year + amount * stepInYears[view], 0));
|
|
160
154
|
}
|
|
161
|
-
|
|
162
155
|
return getBegin(
|
|
156
|
+
adapter,
|
|
163
157
|
view,
|
|
164
|
-
|
|
158
|
+
makeDate(adapter, year + amount * bigStepInYears[view], view === 'month' ? month : 0),
|
|
165
159
|
);
|
|
166
160
|
}
|
|
167
161
|
|
|
168
|
-
export function isRangeWithinRange
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
162
|
+
export function isRangeWithinRange<T>(
|
|
163
|
+
adapter: DateAdapter<T>,
|
|
164
|
+
greater: Range<T>,
|
|
165
|
+
smaller: Range<T>,
|
|
166
|
+
): boolean {
|
|
167
|
+
return !adapter.isAfter(smaller[0], greater[0]) && !adapter.isBefore(smaller[1], greater[1]);
|
|
172
168
|
}
|
|
173
169
|
|
|
174
|
-
export function toDate(
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
const date = value
|
|
180
|
-
|
|
181
|
-
return Number.isNaN(date.getTime()) ? null : date;
|
|
170
|
+
export function toDate<T>(
|
|
171
|
+
adapter: DateAdapter<T>,
|
|
172
|
+
value: LooseValuePiece<T> | undefined,
|
|
173
|
+
): T | null {
|
|
174
|
+
if (value === null || value === undefined) return null;
|
|
175
|
+
const date = typeof value === 'string' ? adapter.date(value) : value;
|
|
176
|
+
return adapter.isValid(date) ? date : null;
|
|
182
177
|
}
|
|
183
178
|
|
|
184
|
-
export function normalizeValue
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
return [toDate(value), null];
|
|
179
|
+
export function normalizeValue<T>(
|
|
180
|
+
adapter: DateAdapter<T>,
|
|
181
|
+
value: LooseValue<T> | undefined,
|
|
182
|
+
): Range<T | null> {
|
|
183
|
+
if (Array.isArray(value)) return [toDate(adapter, value[0]), toDate(adapter, value[1])];
|
|
184
|
+
return [toDate(adapter, value), null];
|
|
190
185
|
}
|
package/src/shared/formatters.ts
CHANGED
|
@@ -12,7 +12,7 @@ function getFormatter(locale: string | undefined, options: Intl.DateTimeFormatOp
|
|
|
12
12
|
return formatter;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
export type Formatter = (locale: string | undefined, date:
|
|
15
|
+
export type Formatter<T = Date> = (locale: string | undefined, date: T) => string;
|
|
16
16
|
|
|
17
17
|
export const formatDay: Formatter = (locale, date) =>
|
|
18
18
|
getFormatter(locale, { day: 'numeric' }).format(date);
|
package/src/shared/types.ts
CHANGED
|
@@ -8,13 +8,13 @@ export type Detail = View;
|
|
|
8
8
|
|
|
9
9
|
export type DateType = View | 'day';
|
|
10
10
|
|
|
11
|
-
export type LooseValuePiece = string |
|
|
11
|
+
export type LooseValuePiece<T = Date> = string | T | null;
|
|
12
12
|
|
|
13
|
-
export type LooseValue = LooseValuePiece | Range<LooseValuePiece
|
|
13
|
+
export type LooseValue<T = Date> = LooseValuePiece<T> | Range<LooseValuePiece<T>>;
|
|
14
14
|
|
|
15
|
-
export type ValuePiece = Date | null;
|
|
15
|
+
export type ValuePiece<T = Date> = T | null;
|
|
16
16
|
|
|
17
|
-
export type Value = ValuePiece | Range<ValuePiece
|
|
17
|
+
export type Value<T = Date> = ValuePiece<T> | Range<ValuePiece<T>>;
|
|
18
18
|
|
|
19
19
|
export type ReturnValue = 'start' | 'end' | 'range';
|
|
20
20
|
|
|
@@ -27,21 +27,21 @@ export type NavigationAction =
|
|
|
27
27
|
| 'drillUp'
|
|
28
28
|
| 'drillDown';
|
|
29
29
|
|
|
30
|
-
export type ViewCallbackProperties = {
|
|
30
|
+
export type ViewCallbackProperties<T = Date> = {
|
|
31
31
|
action: NavigationAction;
|
|
32
|
-
activeStartDate:
|
|
33
|
-
value: LooseValue | undefined;
|
|
32
|
+
activeStartDate: T | null;
|
|
33
|
+
value: LooseValue<T> | undefined;
|
|
34
34
|
view: View;
|
|
35
35
|
};
|
|
36
36
|
|
|
37
|
-
export type TileArgs = {
|
|
38
|
-
activeStartDate:
|
|
39
|
-
date:
|
|
37
|
+
export type TileArgs<T = Date> = {
|
|
38
|
+
activeStartDate: T;
|
|
39
|
+
date: T;
|
|
40
40
|
view: View;
|
|
41
41
|
};
|
|
42
42
|
|
|
43
|
-
export type NavigationLabelArgs = {
|
|
44
|
-
date:
|
|
43
|
+
export type NavigationLabelArgs<T = Date> = {
|
|
44
|
+
date: T;
|
|
45
45
|
label: string;
|
|
46
46
|
locale: string | undefined;
|
|
47
47
|
view: View;
|