@lemonadejs/calendar 1.1.4 → 3.0.1
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 +80 -0
- package/dist/index.html +11 -0
- package/dist/index.js +701 -49
- package/dist/style.css +229 -0
- package/package.json +24 -22
package/README.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# LemonadeJS Calendar
|
|
2
|
+
|
|
3
|
+
[Official website and documentation is here](https://lemonadejs.net/components/calendar)
|
|
4
|
+
|
|
5
|
+
Compatible with Vanilla JavaScript, LemonadeJS, React, Vue or Angular.
|
|
6
|
+
|
|
7
|
+
The LemonadeJS Calendar Component is a lightweight and agile calendar solution that empowers developers with efficient date management capabilities. With seamless navigation between months and years, intuitive day selection, and the ability to attach values and events, this highly customizable component provides a versatile foundation for scheduling applications, booking systems, and more. Its optimized codebase ensures fast performance, while its responsive design guarantees a consistent user experience across devices. Streamline your date management with the LemonadeJS Calendar Component and unlock enhanced productivity for your users.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- Lightweight: The JavaScript Calendar is only about 2 KBytes;
|
|
12
|
+
- Integration: It can be used as a standalone library or integrated with any modern framework;
|
|
13
|
+
|
|
14
|
+
## Getting Started
|
|
15
|
+
|
|
16
|
+
You can install using NPM or using directly from a CDN.
|
|
17
|
+
|
|
18
|
+
### npm Installation
|
|
19
|
+
|
|
20
|
+
To install it in your project using npm, run the following command:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
$ npm install @lemonadejs/calendar
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### CDN
|
|
27
|
+
|
|
28
|
+
To use calendar via a CDN, include the following script tags in your HTML file:
|
|
29
|
+
|
|
30
|
+
```html
|
|
31
|
+
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/lemonadejs/dist/lemonade.min.js"></script>
|
|
32
|
+
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/@lemonadejs/calendar/dist/index.min.js"></script>
|
|
33
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lemonadejs/calendar/dist/style.min.css" />
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Usage
|
|
37
|
+
|
|
38
|
+
Quick example with Lemonade
|
|
39
|
+
|
|
40
|
+
```javascript
|
|
41
|
+
import Calendar from "@lemonadejs/calendar";
|
|
42
|
+
import "@lemonadejs/calendar/dist/style.css"
|
|
43
|
+
|
|
44
|
+
export default function App() {
|
|
45
|
+
const self = this;
|
|
46
|
+
|
|
47
|
+
return `<Calendar />`;
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Configuration
|
|
52
|
+
|
|
53
|
+
You can configure things such as calendar starting date, calendar events, and customize functions.
|
|
54
|
+
|
|
55
|
+
#### Calendar Properties
|
|
56
|
+
|
|
57
|
+
| Property | Type | Description |
|
|
58
|
+
| -------- | ---- | ----------- |
|
|
59
|
+
| value | date | The value currently attached to the calendar. |
|
|
60
|
+
| range | array | Defines a restricted range of selectable dates within the calendar. Example: ['2023-06-20', '2023-06-25']. |
|
|
61
|
+
| closed | boolean | Control when the calendar modal is open or closed. |
|
|
62
|
+
| time | boolean | Enables time selection into the calendar. |
|
|
63
|
+
|
|
64
|
+
### Calendar Events
|
|
65
|
+
|
|
66
|
+
| Event | Type | Description |
|
|
67
|
+
| -------- | ---- | ----------- |
|
|
68
|
+
| onopen? | () => void | Called when modal opens. |
|
|
69
|
+
| onclose? | () => void | Called when modal closes. |
|
|
70
|
+
| onupdate? | (instance.value) => void | Called when value updates. |
|
|
71
|
+
| onchange? | (instance.value) => void | Called when some state inside the component changes. |
|
|
72
|
+
|
|
73
|
+
## License
|
|
74
|
+
|
|
75
|
+
The [LemonadeJS](https://lemonadejs.net) Calendar is released under the MIT.
|
|
76
|
+
|
|
77
|
+
## Other Tools
|
|
78
|
+
|
|
79
|
+
- [jSuites](https://jsuites.net/v4/)
|
|
80
|
+
- [Jspreadsheet](https://jspreadsheet.com)
|
package/dist/index.html
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<html>
|
|
2
|
+
<script src="https://cdn.jsdelivr.net/npm/lemonadejs/dist/lemonade.min.js"></script>
|
|
3
|
+
<script src="./index.js"></script>
|
|
4
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lemonadejs/calendar/dist/style.min.css" />
|
|
5
|
+
<div id='root'></div>
|
|
6
|
+
|
|
7
|
+
<script>
|
|
8
|
+
console.log(Calendar)
|
|
9
|
+
Calendar(document.getElementById('root'), {});
|
|
10
|
+
</script>
|
|
11
|
+
</html>
|
package/dist/index.js
CHANGED
|
@@ -1,50 +1,702 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
1
|
+
/**
|
|
2
|
+
* render: ()
|
|
3
|
+
* valid-ranges: []
|
|
4
|
+
* disabled
|
|
5
|
+
* dateToNum UTC
|
|
6
|
+
* navigation with icons Enter key
|
|
7
|
+
*/
|
|
8
|
+
if (! lemonade && typeof (require) === 'function') {
|
|
9
|
+
var lemonade = require('lemonadejs');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (! Modal && typeof (require) === 'function') {
|
|
13
|
+
var Modal = require('../../modal/dist/index');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
; (function (global, factory) {
|
|
17
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
|
18
|
+
typeof define === 'function' && define.amd ? define(factory) :
|
|
19
|
+
global.Calendar = factory();
|
|
20
|
+
}(this, (function () {
|
|
21
|
+
|
|
22
|
+
// Weekdays
|
|
23
|
+
const Weekdays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
|
|
24
|
+
|
|
25
|
+
// Months
|
|
26
|
+
const Months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
|
|
27
|
+
|
|
28
|
+
// Excel like dates
|
|
29
|
+
const excelInitialTime = Date.UTC(1900, 0, 0);
|
|
30
|
+
const excelLeapYearBug = Date.UTC(1900, 1, 29);
|
|
31
|
+
const millisecondsPerDay = 86400000;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Date to number
|
|
35
|
+
*/
|
|
36
|
+
const dateToNum = function (jsDate) {
|
|
37
|
+
if (typeof(jsDate) === 'string') {
|
|
38
|
+
jsDate = new Date(jsDate + ' GMT+0');
|
|
39
|
+
}
|
|
40
|
+
let jsDateInMilliseconds = jsDate.getTime();
|
|
41
|
+
if (jsDateInMilliseconds >= excelLeapYearBug) {
|
|
42
|
+
jsDateInMilliseconds += millisecondsPerDay;
|
|
43
|
+
}
|
|
44
|
+
jsDateInMilliseconds -= excelInitialTime;
|
|
45
|
+
|
|
46
|
+
return jsDateInMilliseconds / millisecondsPerDay;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const numToDate = function (excelSerialNumber) {
|
|
50
|
+
let jsDateInMilliseconds = excelInitialTime + excelSerialNumber * millisecondsPerDay;
|
|
51
|
+
if (jsDateInMilliseconds >= excelLeapYearBug) {
|
|
52
|
+
jsDateInMilliseconds -= millisecondsPerDay;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const d = new Date(jsDateInMilliseconds);
|
|
56
|
+
|
|
57
|
+
return [
|
|
58
|
+
d.getUTCFullYear(),
|
|
59
|
+
Two(d.getUTCMonth() + 1),
|
|
60
|
+
Two(d.getUTCDate()),
|
|
61
|
+
Two(d.getUTCHours()),
|
|
62
|
+
Two(d.getUTCMinutes()),
|
|
63
|
+
Two(d.getUTCSeconds()),
|
|
64
|
+
];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Create a data calendar object based on the view
|
|
69
|
+
*/
|
|
70
|
+
const views = {
|
|
71
|
+
years: function(date) {
|
|
72
|
+
let year = date.getFullYear();
|
|
73
|
+
let result = [];
|
|
74
|
+
let start = year % 16;
|
|
75
|
+
let complement = 16 - start;
|
|
76
|
+
|
|
77
|
+
for (let i = year-start; i < year+complement; i++) {
|
|
78
|
+
let item = {
|
|
79
|
+
title: i,
|
|
80
|
+
value: i
|
|
81
|
+
};
|
|
82
|
+
result.push(item);
|
|
83
|
+
// Select cursor
|
|
84
|
+
if (this.cursor.y === i) {
|
|
85
|
+
// Select item
|
|
86
|
+
item.selected = true;
|
|
87
|
+
// Cursor
|
|
88
|
+
this.cursor.index = result.length - 1;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return result;
|
|
92
|
+
},
|
|
93
|
+
months: function(date) {
|
|
94
|
+
let year = date.getFullYear();
|
|
95
|
+
let result = [];
|
|
96
|
+
for (let i = 0; i < 12; i++) {
|
|
97
|
+
let item = {
|
|
98
|
+
title: Months[i].substring(0,3),
|
|
99
|
+
value: i
|
|
100
|
+
}
|
|
101
|
+
// Add the item to the data
|
|
102
|
+
result.push(item);
|
|
103
|
+
// Select cursor
|
|
104
|
+
if (this.cursor.y === year && this.cursor.m === i) {
|
|
105
|
+
// Select item
|
|
106
|
+
item.selected = true;
|
|
107
|
+
// Cursor
|
|
108
|
+
this.cursor.index = result.length - 1;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return result;
|
|
113
|
+
},
|
|
114
|
+
days: function(date) {
|
|
115
|
+
let year = date.getFullYear();
|
|
116
|
+
let month = date.getMonth();
|
|
117
|
+
let data = filterData.call(this, year, month);
|
|
118
|
+
|
|
119
|
+
// First day
|
|
120
|
+
let tmp = new Date(year, month, 1, 0, 0, 0);
|
|
121
|
+
let firstDay = tmp.getDay();
|
|
122
|
+
|
|
123
|
+
let result = [];
|
|
124
|
+
for (let i = 1-firstDay; i <= 42-firstDay; i++) {
|
|
125
|
+
// Get the day
|
|
126
|
+
tmp = new Date(year, month, i, 0, 0, 0);
|
|
127
|
+
// Day
|
|
128
|
+
let day = tmp.getDate();
|
|
129
|
+
// Create the item
|
|
130
|
+
let item = {
|
|
131
|
+
title: day,
|
|
132
|
+
value: i,
|
|
133
|
+
number: dateToNum(tmp.toString())
|
|
134
|
+
}
|
|
135
|
+
// Add the item to the date
|
|
136
|
+
result.push(item);
|
|
137
|
+
// Check selections
|
|
138
|
+
if (tmp.getMonth() !== month) {
|
|
139
|
+
// Days are not in the current month
|
|
140
|
+
item.grey = true;
|
|
141
|
+
} else {
|
|
142
|
+
// Check for data
|
|
143
|
+
let d = [ year, Two(month+1), Two(day)].join('-');
|
|
144
|
+
if (data && data[d]) {
|
|
145
|
+
item.data = data[d];
|
|
146
|
+
}
|
|
147
|
+
// Select cursor
|
|
148
|
+
if (this.cursor.y === year && this.cursor.m === month && this.cursor.d === day) {
|
|
149
|
+
// Select item
|
|
150
|
+
item.selected = true;
|
|
151
|
+
// Cursor
|
|
152
|
+
this.cursor.index = result.length - 1;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Select range
|
|
157
|
+
if (this.type === 'range' && this.range) {
|
|
158
|
+
// Mark the start and end points
|
|
159
|
+
if (this.range[0] === item.number) {
|
|
160
|
+
item.range = true;
|
|
161
|
+
item.start = true;
|
|
162
|
+
}
|
|
163
|
+
if (this.range[1] === item.number) {
|
|
164
|
+
item.range = true;
|
|
165
|
+
item.end = true;
|
|
166
|
+
}
|
|
167
|
+
// Re-recreate teh range
|
|
168
|
+
if (this.range[0] && this.range[1]) {
|
|
169
|
+
if (this.range[0] <= item.number && this.range[1] >= item.number) {
|
|
170
|
+
item.range = true;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return result;
|
|
177
|
+
},
|
|
178
|
+
hours: function() {
|
|
179
|
+
let result = [];
|
|
180
|
+
for (let i = 0; i < 24; i++) {
|
|
181
|
+
let item = {
|
|
182
|
+
title: Two(i),
|
|
183
|
+
value: i
|
|
184
|
+
};
|
|
185
|
+
result.push(item);
|
|
186
|
+
}
|
|
187
|
+
return result;
|
|
188
|
+
},
|
|
189
|
+
minutes: function() {
|
|
190
|
+
let result = [];
|
|
191
|
+
for (let i = 0; i < 60; i=i+5) {
|
|
192
|
+
let item = {
|
|
193
|
+
title: Two(i),
|
|
194
|
+
value: i
|
|
195
|
+
};
|
|
196
|
+
result.push(item);
|
|
197
|
+
}
|
|
198
|
+
return result;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const filterData = function(year, month) {
|
|
203
|
+
// Data for the month
|
|
204
|
+
let data = {};
|
|
205
|
+
if (Array.isArray(this.data)) {
|
|
206
|
+
this.data.map(function (v) {
|
|
207
|
+
let d = year + '-' + Two(month + 1);
|
|
208
|
+
if (v.date.substring(0, 7) === d) {
|
|
209
|
+
if (!data[v.date]) {
|
|
210
|
+
data[v.date] = [];
|
|
211
|
+
}
|
|
212
|
+
data[v.date].push(v);
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
return data;
|
|
217
|
+
}
|
|
218
|
+
// Get the short weekdays name
|
|
219
|
+
const getWeekdays = function() {
|
|
220
|
+
return Weekdays.map(w => {
|
|
221
|
+
return { title: w.substring(0, 1) };
|
|
222
|
+
})
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Define the hump based on the view
|
|
226
|
+
const getJump = function(e) {
|
|
227
|
+
if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
|
|
228
|
+
return this.view === 'days' ? 7 : 4;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return 1;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Get the position of the data based on the view
|
|
235
|
+
const getPosition = function() {
|
|
236
|
+
let position = 2;
|
|
237
|
+
if (this.view === 'years') {
|
|
238
|
+
position = 0;
|
|
239
|
+
} else if (this.view === 'months') {
|
|
240
|
+
position = 1;
|
|
241
|
+
}
|
|
242
|
+
return position;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Transform in two digits
|
|
246
|
+
const Two = function(value) {
|
|
247
|
+
value = '' + value;
|
|
248
|
+
if (value.length == 1) {
|
|
249
|
+
value = '0' + value;
|
|
250
|
+
}
|
|
251
|
+
return value;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
const Calendar = function() {
|
|
255
|
+
let self = this;
|
|
256
|
+
|
|
257
|
+
// Weekdays
|
|
258
|
+
self.weekdays = getWeekdays();
|
|
259
|
+
|
|
260
|
+
// Cursor
|
|
261
|
+
self.cursor = {};
|
|
262
|
+
|
|
263
|
+
// Calendar date
|
|
264
|
+
let date = new Date();
|
|
265
|
+
|
|
266
|
+
// Range
|
|
267
|
+
self.range = null;
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Update the internal date
|
|
271
|
+
* @param {Date|string|number[]} d instance of Date
|
|
272
|
+
*
|
|
273
|
+
*/
|
|
274
|
+
const setDate = function(d) {
|
|
275
|
+
if (Array.isArray(d)) {
|
|
276
|
+
d = new Date(Date.UTC(...d));
|
|
277
|
+
} else if (typeof(d) === 'string') {
|
|
278
|
+
d = new Date(d);
|
|
279
|
+
}
|
|
280
|
+
// Update internal date
|
|
281
|
+
date = d;
|
|
282
|
+
// Update the headers of the calendar
|
|
283
|
+
let value = d.toISOString().substring(0,10).split('-');
|
|
284
|
+
// Update the month label
|
|
285
|
+
self.month = Months[parseInt(value[1])-1];
|
|
286
|
+
// Update the year label
|
|
287
|
+
self.year = parseInt(value[0]);
|
|
288
|
+
// Load data
|
|
289
|
+
if (! self.view) {
|
|
290
|
+
// Start on the days view will start the data
|
|
291
|
+
self.view = 'days';
|
|
292
|
+
} else {
|
|
293
|
+
// Reload the data for the same view
|
|
294
|
+
self.options = views[self.view].call(self, date);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Set the internal cursor
|
|
300
|
+
* @param {object} s
|
|
301
|
+
*/
|
|
302
|
+
const setCursor = function(s) {
|
|
303
|
+
// Remove selection from the current object
|
|
304
|
+
let item = self.options[self.cursor.index];
|
|
305
|
+
if (typeof(item) !== 'undefined') {
|
|
306
|
+
item.selected = false;
|
|
307
|
+
}
|
|
308
|
+
// Update the date based on the click
|
|
309
|
+
let v = updateDate(s.value, getPosition.call(self));
|
|
310
|
+
let d = new Date(Date.UTC(...v));
|
|
311
|
+
// Update cursor controller
|
|
312
|
+
self.cursor = {
|
|
313
|
+
y: d.getFullYear(),
|
|
314
|
+
m: d.getMonth(),
|
|
315
|
+
d: d.getDate(),
|
|
316
|
+
};
|
|
317
|
+
// Update cursor based on the object position
|
|
318
|
+
if (s) {
|
|
319
|
+
// Update selected property
|
|
320
|
+
s.selected = true;
|
|
321
|
+
// New cursor
|
|
322
|
+
self.cursor.index = self.options.indexOf(s);
|
|
323
|
+
}
|
|
324
|
+
return d;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Update the current date
|
|
329
|
+
* @param {number} v new value for year, month or day
|
|
330
|
+
* @param {number} position (0,1,2 - year,month,day)
|
|
331
|
+
* @returns {number[]}
|
|
332
|
+
*/
|
|
333
|
+
const updateDate = function(v, position) {
|
|
334
|
+
// Current internal date
|
|
335
|
+
let value = [date.getFullYear(), date.getMonth(), date.getDate(),0,0,0];
|
|
336
|
+
// Update internal date
|
|
337
|
+
value[position] = v;
|
|
338
|
+
// Return new value
|
|
339
|
+
return value;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* This method move the data from the view up or down
|
|
344
|
+
* @param direction
|
|
345
|
+
*/
|
|
346
|
+
const move = function(direction) {
|
|
347
|
+
let value;
|
|
348
|
+
|
|
349
|
+
// Update the new internal date
|
|
350
|
+
if (self.view === 'days') {
|
|
351
|
+
// Select the new internal date
|
|
352
|
+
value = updateDate(date.getMonth()+direction, 1);
|
|
353
|
+
} else if (self.view === 'months') {
|
|
354
|
+
// Select the new internal date
|
|
355
|
+
value = updateDate(date.getFullYear()+direction, 0);
|
|
356
|
+
} else if (self.view === 'years') {
|
|
357
|
+
// Select the new internal date
|
|
358
|
+
value = updateDate(date.getFullYear()+(direction*16), 0);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Update view
|
|
362
|
+
if (value) {
|
|
363
|
+
setDate(value);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Keyboard handler
|
|
369
|
+
* @param {number} direction of the action
|
|
370
|
+
* @param {object} e keyboard event
|
|
371
|
+
*/
|
|
372
|
+
const moveCursor = function(direction, e) {
|
|
373
|
+
direction = direction * getJump.call(self, e);
|
|
374
|
+
// Remove the selected from the current selection
|
|
375
|
+
let s = self.options[self.cursor.index];
|
|
376
|
+
// If the selection is going outside the viewport
|
|
377
|
+
if (typeof(s) === 'undefined' || ! s.selected) {
|
|
378
|
+
// Go back to the view
|
|
379
|
+
setDate([ self.cursor.y, self.cursor.m, self.cursor.d ]);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// Jump to the index
|
|
383
|
+
let index = self.cursor.index + direction;
|
|
384
|
+
|
|
385
|
+
// See if the new position is in the viewport
|
|
386
|
+
if (typeof(self.options[index]) === 'undefined') {
|
|
387
|
+
// Adjust the index for next collection of data
|
|
388
|
+
if (self.view === 'days') {
|
|
389
|
+
if (index < 0) {
|
|
390
|
+
index = 42 + index;
|
|
391
|
+
} else {
|
|
392
|
+
index = index - 42;
|
|
393
|
+
}
|
|
394
|
+
} else if (self.view === 'years') {
|
|
395
|
+
if (index < 0) {
|
|
396
|
+
index = 4 + index;
|
|
397
|
+
} else {
|
|
398
|
+
index = index - 4;
|
|
399
|
+
}
|
|
400
|
+
} else if (self.view === 'months') {
|
|
401
|
+
if (index < 0) {
|
|
402
|
+
index = 12 + index;
|
|
403
|
+
} else {
|
|
404
|
+
index = index - 12;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// Move the data up or down
|
|
409
|
+
move(direction > 0 ? 1 : -1);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// Update the date based on the click
|
|
413
|
+
setCursor(self.options[index]);
|
|
414
|
+
|
|
415
|
+
// Update ranges
|
|
416
|
+
updateRange(self.options[index])
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* Handler blur
|
|
421
|
+
* @param e
|
|
422
|
+
*/
|
|
423
|
+
const blur = function(e) {
|
|
424
|
+
if (self.modal) {
|
|
425
|
+
if (!(e.relatedTarget && self.modal.el.contains(e.relatedTarget))) {
|
|
426
|
+
if (self.modal.closed === false) {
|
|
427
|
+
// self.modal.closed = true
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Set the limits of a range
|
|
435
|
+
* @param s
|
|
436
|
+
*/
|
|
437
|
+
const setRange = function(s) {
|
|
438
|
+
if (self.view === 'days' && self.type === 'range') {
|
|
439
|
+
let d = self.getValue();
|
|
440
|
+
// Date to number
|
|
441
|
+
let number = dateToNum(d);
|
|
442
|
+
// Start a new range
|
|
443
|
+
if (self.range && (self.range[0] > number || self.range[1])) {
|
|
444
|
+
destroyRange();
|
|
445
|
+
}
|
|
446
|
+
// Range
|
|
447
|
+
s.range = true;
|
|
448
|
+
// Update range
|
|
449
|
+
if (! self.range) {
|
|
450
|
+
s.start = true;
|
|
451
|
+
self.range = [number, null];
|
|
452
|
+
} else {
|
|
453
|
+
s.end = true;
|
|
454
|
+
self.range[1] = number;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Update the visible range
|
|
461
|
+
* @param s
|
|
462
|
+
*/
|
|
463
|
+
const updateRange = function(s) {
|
|
464
|
+
if (self.type === 'range' && self.view === 'days' && self.range) {
|
|
465
|
+
// Creating a range
|
|
466
|
+
if (self.range[0] && ! self.range[1]) {
|
|
467
|
+
let number = s.number;
|
|
468
|
+
if (number) {
|
|
469
|
+
// Update range properties
|
|
470
|
+
for (let i = 0; i < self.options.length; i++) {
|
|
471
|
+
// Item number
|
|
472
|
+
let v = self.options[i].number;
|
|
473
|
+
// Update property condition
|
|
474
|
+
self.options[i].range = v >= self.range[0] && v <= number;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* Destroy the range
|
|
483
|
+
*/
|
|
484
|
+
const destroyRange = function() {
|
|
485
|
+
for (let i = 0; i < self.options.length; i++) {
|
|
486
|
+
self.options[i].range = false;
|
|
487
|
+
self.options[i].start = false;
|
|
488
|
+
self.options[i].end = false;
|
|
489
|
+
}
|
|
490
|
+
self.range = null;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* Select an item with the enter or mouse
|
|
495
|
+
* @param {object} item - selected cell
|
|
496
|
+
*/
|
|
497
|
+
self.select = function(item) {
|
|
498
|
+
// Update cursor generic
|
|
499
|
+
let value = setCursor(item);
|
|
500
|
+
// Update range
|
|
501
|
+
setRange(item);
|
|
502
|
+
// Based where was the click
|
|
503
|
+
if (! (self.view === 'days' && ! item.grey)) {
|
|
504
|
+
// Update the internal date
|
|
505
|
+
setDate(value);
|
|
506
|
+
}
|
|
507
|
+
// Go back to the view of days
|
|
508
|
+
if (self.view !== 'days') {
|
|
509
|
+
self.view = 'days';
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* Next handler
|
|
515
|
+
* @param {object} e mouse event
|
|
516
|
+
*/
|
|
517
|
+
self.next = function(e) {
|
|
518
|
+
if (! e) {
|
|
519
|
+
// Icon click
|
|
520
|
+
move(1);
|
|
521
|
+
} else {
|
|
522
|
+
// Keyboard handler
|
|
523
|
+
moveCursor(1, e);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/**
|
|
528
|
+
* Next handler
|
|
529
|
+
* @param {object} e mouse event
|
|
530
|
+
*/
|
|
531
|
+
self.prev = function(e) {
|
|
532
|
+
if (! e) {
|
|
533
|
+
// Icon click
|
|
534
|
+
move(-1);
|
|
535
|
+
} else {
|
|
536
|
+
// Keyboard handler
|
|
537
|
+
moveCursor(-1, e);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/**
|
|
542
|
+
* Open the modal
|
|
543
|
+
*/
|
|
544
|
+
self.open = function() {
|
|
545
|
+
if (self.modal) {
|
|
546
|
+
self.modal.closed = false;
|
|
547
|
+
// Set the focus
|
|
548
|
+
self.content.focus();
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
/**
|
|
553
|
+
* Close the modal
|
|
554
|
+
*/
|
|
555
|
+
self.close = function() {
|
|
556
|
+
if (self.modal && self.modal.closed === false) {
|
|
557
|
+
self.modal.closed = true;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
/**
|
|
562
|
+
* Get value from cursor
|
|
563
|
+
* @returns {string}
|
|
564
|
+
*/
|
|
565
|
+
self.getValue = function() {
|
|
566
|
+
let v = [ self.cursor.y, self.cursor.m, self.cursor.d ];
|
|
567
|
+
let d = new Date(Date.UTC(...v));
|
|
568
|
+
// Update the headers of the calendar
|
|
569
|
+
return d.toISOString().substring(0,10);
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
self.onchange = function(prop) {
|
|
573
|
+
if (prop === 'view') {
|
|
574
|
+
if (typeof(views[self.view]) === 'function') {
|
|
575
|
+
// When change the view update the data
|
|
576
|
+
self.options = views[self.view].call(self, date);
|
|
577
|
+
}
|
|
578
|
+
} else if (prop === 'value') {
|
|
579
|
+
if (typeof(self.onupdate) === 'function') {
|
|
580
|
+
self.onupdate.call(self, self.value);
|
|
581
|
+
}
|
|
582
|
+
} else if (prop === 'options') {
|
|
583
|
+
self.content.focus();
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
self.onload = function() {
|
|
588
|
+
let d;
|
|
589
|
+
if (self.value) {
|
|
590
|
+
d = new Date(self.value);
|
|
591
|
+
} else {
|
|
592
|
+
d = new Date();
|
|
593
|
+
}
|
|
594
|
+
// Update my index
|
|
595
|
+
self.cursor = {
|
|
596
|
+
y: d.getFullYear(),
|
|
597
|
+
m: d.getMonth(),
|
|
598
|
+
d: d.getDate(),
|
|
599
|
+
};
|
|
600
|
+
// Populate components
|
|
601
|
+
self.hours = views.hours();
|
|
602
|
+
self.minutes = views.minutes();
|
|
603
|
+
|
|
604
|
+
// Update the internal calendar date
|
|
605
|
+
setDate(d);
|
|
606
|
+
|
|
607
|
+
if (self.type !== "inline") {
|
|
608
|
+
// Create modal instance
|
|
609
|
+
self.modal = {
|
|
610
|
+
width: 300,
|
|
611
|
+
closed: true,
|
|
612
|
+
'auto-close': true,
|
|
613
|
+
};
|
|
614
|
+
// Generate modal
|
|
615
|
+
Modal(self.el, self.modal);
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
// Create input controls
|
|
619
|
+
if (self.input) {
|
|
620
|
+
self.input.classList.add('lm-calendar-input');
|
|
621
|
+
self.input.addEventListener('focus', self.open);
|
|
622
|
+
self.input.addEventListener('click', self.open);
|
|
623
|
+
self.input.addEventListener('blur', blur);
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
/**
|
|
627
|
+
* Handler keyboard
|
|
628
|
+
* @param e
|
|
629
|
+
*/
|
|
630
|
+
self.content.addEventListener('keydown', function(e){
|
|
631
|
+
if (e.key === 'ArrowUp' || e.key === 'ArrowLeft') {
|
|
632
|
+
self.prev(e);
|
|
633
|
+
} else if (e.key === 'ArrowDown' || e.key === 'ArrowRight') {
|
|
634
|
+
self.next(e);
|
|
635
|
+
} else if (e.key === 'Enter') {
|
|
636
|
+
// Select
|
|
637
|
+
self.select(self.options[self.cursor.index]);
|
|
638
|
+
// If is range do something different
|
|
639
|
+
if (self.type !== 'range') {
|
|
640
|
+
self.value = self.getValue();
|
|
641
|
+
self.close();
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
});
|
|
645
|
+
|
|
646
|
+
/**
|
|
647
|
+
* Mouse wheel handler
|
|
648
|
+
*/
|
|
649
|
+
self.content.addEventListener('wheel', function(e){
|
|
650
|
+
if (e.deltaY < 0) {
|
|
651
|
+
self.prev();
|
|
652
|
+
} else {
|
|
653
|
+
self.next();
|
|
654
|
+
}
|
|
655
|
+
});
|
|
656
|
+
|
|
657
|
+
/**
|
|
658
|
+
* Range handler
|
|
659
|
+
* @param e
|
|
660
|
+
*/
|
|
661
|
+
self.content.addEventListener('mouseover', function(e){
|
|
662
|
+
if (e.target.lemon) {
|
|
663
|
+
updateRange(e.target.lemon.self);
|
|
664
|
+
}
|
|
665
|
+
});
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
return `<div class="lm-calendar">
|
|
669
|
+
<div class="lm-calendar-options">
|
|
670
|
+
<button onclick="self.value = ''; self.close();">Reset</button>
|
|
671
|
+
<button onclick="self.value = self.getValue(); self.close();">Done</button>
|
|
672
|
+
</div>
|
|
673
|
+
<div class="lm-calendar-container" data-view="{{self.view}}">
|
|
674
|
+
<div class="lm-calendar-header">
|
|
675
|
+
<div>
|
|
676
|
+
<div class="lm-calendar-labels"><div onclick="self.view = 'months'">{{self.month}}</div> <div onclick="self.view = 'years'">{{self.year}}</div></div>
|
|
677
|
+
<div class="lm-calendar-navigation"><i class="material-icons ripple" onclick="self.prev()" tabindex="0">arrow_drop_up</i> <i class="material-icons ripple" onclick="self.next()" tabindex="0">arrow_drop_down</i></div>
|
|
678
|
+
</div>
|
|
679
|
+
<div class="lm-calendar-weekdays" :loop="self.weekdays"><div>{{self.title}}</div></div>
|
|
680
|
+
</div>
|
|
681
|
+
<div class="lm-calendar-content" :loop="self.options" tabindex="0" :ref="self.content">
|
|
682
|
+
<div data-start="{{self.start}}" data-end="{{self.end}}" data-range="{{self.range}}" data-event="{{self.data}}" data-grey="{{self.grey}}" data-bold="{{self.bold}}" data-selected="{{self.selected}}" onclick="self.parent.select(self)">{{self.title}}</div>
|
|
683
|
+
</div>
|
|
684
|
+
<div class="lm-calendar-footer">
|
|
685
|
+
<div><select :loop="self.hours"><option value="{{self.value}}">{{self.title}}</option></select>:<select :loop="self.minutes"><option value="{{self.value}}">{{self.title}}</option></select></div>
|
|
686
|
+
<div><input type="button" value="Update" onclick="self.value = self.getValue(); self.close();" class="ripple"></div>
|
|
687
|
+
</div>
|
|
688
|
+
</div>
|
|
689
|
+
</div>`
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
lemonade.setComponents({ Calendar: Calendar });
|
|
693
|
+
|
|
694
|
+
return function (root, options) {
|
|
695
|
+
if (typeof (root) === 'object') {
|
|
696
|
+
lemonade.render(Calendar, root, options)
|
|
697
|
+
return options;
|
|
698
|
+
} else {
|
|
699
|
+
return Calendar.call(this, root)
|
|
700
|
+
}
|
|
701
|
+
}
|
|
50
702
|
})));
|
package/dist/style.css
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
.lm-calendar .lm-modal {
|
|
2
|
+
min-width: initial;
|
|
3
|
+
min-height: initial;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.lm-calendar-options {
|
|
7
|
+
display: none;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.lm-modal .lm-calendar-options {
|
|
11
|
+
display: flex;
|
|
12
|
+
justify-content: space-between;
|
|
13
|
+
border-bottom: 1px solid #ddd;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.lm-modal .lm-calendar-options button {
|
|
17
|
+
border: 0;
|
|
18
|
+
background-color: transparent;
|
|
19
|
+
text-transform: uppercase;
|
|
20
|
+
cursor: pointer;
|
|
21
|
+
padding: 15px;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.lm-calendar-header {
|
|
25
|
+
display: flex;
|
|
26
|
+
flex-direction: column;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.lm-calendar-header > div:first-child {
|
|
30
|
+
display: flex;
|
|
31
|
+
align-items: center;
|
|
32
|
+
padding: 10px;
|
|
33
|
+
flex: 1;
|
|
34
|
+
user-select: none;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.lm-calendar-header .lm-calendar-labels {
|
|
38
|
+
font-size: 1.4em;
|
|
39
|
+
display: flex;
|
|
40
|
+
flex: 1;
|
|
41
|
+
cursor: pointer;
|
|
42
|
+
padding-left: 5px;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.lm-calendar-header .lm-calendar-labels > div {
|
|
46
|
+
margin: 2px;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.lm-calendar-navigation {
|
|
50
|
+
cursor: pointer;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.lm-calendar-navigation i {
|
|
54
|
+
padding: 5px;
|
|
55
|
+
border-radius: 24px;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.lm-calendar-navigation i:hover {
|
|
59
|
+
background-color: #eee;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.lm-calendar-weekdays {
|
|
63
|
+
display: none;
|
|
64
|
+
grid-template-columns: repeat(7, 1fr);
|
|
65
|
+
grid-gap: 2px;
|
|
66
|
+
padding: 0 10px 0 10px;
|
|
67
|
+
font-size: 0.8em;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.lm-calendar-container[data-view="days"] .lm-calendar-weekdays {
|
|
71
|
+
display: grid;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.lm-calendar-weekdays > div {
|
|
75
|
+
display: inline-block;
|
|
76
|
+
padding: 10px;
|
|
77
|
+
box-sizing: border-box;
|
|
78
|
+
text-align: center;
|
|
79
|
+
font-weight: bold;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.lm-calendar-content {
|
|
83
|
+
display: grid;
|
|
84
|
+
grid-template-columns: repeat(7, 1fr);
|
|
85
|
+
grid-gap: 0;
|
|
86
|
+
padding: 8px;
|
|
87
|
+
font-size: 0.8em;
|
|
88
|
+
outline: none;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.lm-calendar-content > div {
|
|
92
|
+
box-sizing: border-box;
|
|
93
|
+
text-align: center;
|
|
94
|
+
aspect-ratio: 1 / 1;
|
|
95
|
+
display: flex;
|
|
96
|
+
flex-direction: column;
|
|
97
|
+
justify-content: center;
|
|
98
|
+
align-items: center;
|
|
99
|
+
padding: 10px;
|
|
100
|
+
cursor: pointer;
|
|
101
|
+
border-radius: 100px;
|
|
102
|
+
background-origin: padding-box;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.lm-calendar-container[data-view="months"] .lm-calendar-content {
|
|
106
|
+
grid-template-columns: repeat(4, 1fr);
|
|
107
|
+
}
|
|
108
|
+
.lm-calendar-container[data-view="years"] .lm-calendar-content {
|
|
109
|
+
grid-template-columns: repeat(4, 1fr);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.lm-calendar-content > div[data-grey="true"] {
|
|
113
|
+
color: #ccc;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.lm-calendar-content > div[data-bold="true"] {
|
|
117
|
+
font-weight: bold;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.lm-calendar-content > div[data-event="true"]::before {
|
|
121
|
+
content: '';
|
|
122
|
+
position: absolute;
|
|
123
|
+
margin-top: 22px;
|
|
124
|
+
width: 3px;
|
|
125
|
+
height: 3px;
|
|
126
|
+
border-radius: 3px;
|
|
127
|
+
background-color: red;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.lm-calendar-content > div[data-selected="true"] {
|
|
131
|
+
font-weight: bold;
|
|
132
|
+
background-color: #eee;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.lm-calendar-content:focus > div[data-selected="true"] {
|
|
136
|
+
outline: 2px solid black;
|
|
137
|
+
outline-offset: -2px;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.lm-calendar-content > div:hover {
|
|
141
|
+
background-color: #eee;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.lm-calendar-content > div[data-range="true"] {
|
|
145
|
+
position: relative;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.lm-calendar-content > div[data-start="true"],
|
|
149
|
+
.lm-calendar-content > div[data-end="true"] {
|
|
150
|
+
background-color: #78D350;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.lm-calendar-content > div[data-range="true"]::before {
|
|
154
|
+
content: "";
|
|
155
|
+
position: absolute;
|
|
156
|
+
left: 0;
|
|
157
|
+
right: 0;
|
|
158
|
+
top: 8px;
|
|
159
|
+
bottom: 8px;
|
|
160
|
+
background-color: #78D35050;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.lm-calendar-content > div[data-start="true"]::before {
|
|
164
|
+
left: 32px;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.lm-calendar-content > div[data-end="true"]::before {
|
|
168
|
+
right: 32px;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.lm-calendar-footer > div {
|
|
172
|
+
flex: 1;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.lm-calendar-footer {
|
|
176
|
+
display: flex;
|
|
177
|
+
margin: 0 10px 0 10px;
|
|
178
|
+
padding: 8px 0 8px 0;
|
|
179
|
+
line-height: 34px;
|
|
180
|
+
border-top: 1px solid #eee;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.lm-calendar-footer select {
|
|
184
|
+
border: 0;
|
|
185
|
+
background-color: transparent;
|
|
186
|
+
padding: 6px;
|
|
187
|
+
-moz-appearance: none;
|
|
188
|
+
-webkit-appearance: none;
|
|
189
|
+
margin: 2px;
|
|
190
|
+
border-radius: 32px;
|
|
191
|
+
font-size: 1.1em;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.lm-calendar-footer select:focus {
|
|
195
|
+
background-color: #eee;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.lm-calendar-footer select:hover {
|
|
199
|
+
background-color: #eee;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.lm-calendar-footer input {
|
|
203
|
+
border: transparent;
|
|
204
|
+
padding: 8px;
|
|
205
|
+
background-color: #eee;
|
|
206
|
+
width: 100%;
|
|
207
|
+
cursor: pointer;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.lm-calendar-input {
|
|
211
|
+
padding-right: 24px !important;
|
|
212
|
+
box-sizing: border-box;
|
|
213
|
+
background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M200-80q-33 0-56.5-23.5T120-160v-560q0-33 23.5-56.5T200-800h40v-80h80v80h320v-80h80v80h40q33 0 56.5 23.5T840-720v560q0 33-23.5 56.5T760-80H200Zm0-80h560v-400H200v400Zm0-480h560v-80H200v80Zm0 0v-80 80Zm280 240q-17 0-28.5-11.5T440-440q0-17 11.5-28.5T480-480q17 0 28.5 11.5T520-440q0 17-11.5 28.5T480-400Zm-160 0q-17 0-28.5-11.5T280-440q0-17 11.5-28.5T320-480q17 0 28.5 11.5T360-440q0 17-11.5 28.5T320-400Zm320 0q-17 0-28.5-11.5T600-440q0-17 11.5-28.5T640-480q17 0 28.5 11.5T680-440q0 17-11.5 28.5T640-400ZM480-240q-17 0-28.5-11.5T440-280q0-17 11.5-28.5T480-320q17 0 28.5 11.5T520-280q0 17-11.5 28.5T480-240Zm-160 0q-17 0-28.5-11.5T280-280q0-17 11.5-28.5T320-320q17 0 28.5 11.5T360-280q0 17-11.5 28.5T320-240Zm320 0q-17 0-28.5-11.5T600-280q0-17 11.5-28.5T640-320q17 0 28.5 11.5T680-280q0 17-11.5 28.5T640-240Z"/></svg>') top 50% right 0 no-repeat, content-box;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.ripple {
|
|
217
|
+
background-position: center;
|
|
218
|
+
transition: background 0.8s;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.ripple:hover {
|
|
222
|
+
background: #E0E0E0 radial-gradient(circle, transparent 1%, #E0E0E0 1%) center/15000%;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.ripple:active {
|
|
226
|
+
background-color: #E0E0E0;
|
|
227
|
+
background-size: 100%;
|
|
228
|
+
transition: background 0s;
|
|
229
|
+
}
|
package/package.json
CHANGED
|
@@ -1,22 +1,24 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@lemonadejs/calendar",
|
|
3
|
-
"title": "LemonadeJS calendar",
|
|
4
|
-
"description": "LemonadeJS
|
|
5
|
-
"author": {
|
|
6
|
-
"name": "Contact <contact@lemonadejs.net>",
|
|
7
|
-
"url": "https://lemonadejs.net"
|
|
8
|
-
},
|
|
9
|
-
"keywords": [
|
|
10
|
-
"javascript calendar",
|
|
11
|
-
"lemonadejs plugins",
|
|
12
|
-
"js",
|
|
13
|
-
"library",
|
|
14
|
-
"javascript plugins"
|
|
15
|
-
],
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@lemonadejs/calendar",
|
|
3
|
+
"title": "LemonadeJS calendar",
|
|
4
|
+
"description": "LemonadeJS Calendar Component.",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Contact <contact@lemonadejs.net>",
|
|
7
|
+
"url": "https://lemonadejs.net"
|
|
8
|
+
},
|
|
9
|
+
"keywords": [
|
|
10
|
+
"javascript calendar",
|
|
11
|
+
"lemonadejs plugins",
|
|
12
|
+
"js",
|
|
13
|
+
"library",
|
|
14
|
+
"javascript plugins"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "webpack --config webpack.config.js"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"lemonadejs": "^3.3.2"
|
|
21
|
+
},
|
|
22
|
+
"main": "dist/index.js",
|
|
23
|
+
"version": "3.0.1"
|
|
24
|
+
}
|