@lemonadejs/calendar 5.2.0 → 5.2.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 CHANGED
@@ -1,88 +1,90 @@
1
- # JavaScript Calendar
2
-
3
- [Official JavaScript Calendar Documenation](https://lemonadejs.com/docs/plugins/calendar)
4
-
5
- Compatible with Vanilla JavaScript, LemonadeJS, React, VueJS or Angular.
6
-
7
- # JavaScript Calendar
8
-
9
- Leverage the power of the LemonadeJS Calendar, a lightweight and versatile JavaScript component compatible with React, VueJS, and Angular. Designed to enhance web applications, it offers an embeddable calendar for easy date, time, and range selections. Key features include:
10
-
11
- - Intuitive keyboard navigation.
12
- - A reactive and responsive design for seamless device adaptation.
13
- - Flexible range selection for various applications.
14
- - Customizable options to match your project needs.
15
-
16
- ## Getting Started
17
-
18
- You can install using NPM or using directly from a CDN.
19
-
20
- ### npm Installation
21
-
22
- To install it in your project using npm, run the following command:
23
-
24
- ```bash
25
- $ npm install @lemonadejs/calendar
26
- ```
27
-
28
- ### CDN
29
-
30
- For immediate use without NPM, include these script tags in your HTML for access to the calendar and its dependencies:
31
-
32
- ```html
33
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lemonadejs/modal/dist/style.min.css" />
34
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lemonadejs/calendar/dist/style.min.css" />
35
- <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Material+Icons" />
36
- <script src="https://cdn.jsdelivr.net/npm/lemonadejs/dist/lemonade.min.js"></script>
37
- <script src="https://cdn.jsdelivr.net/npm/@lemonadejs/modal/dist/index.min.js"></script>
38
- <script src="https://cdn.jsdelivr.net/npm/@lemonadejs/calendar/dist/index.min.js"></script>
39
- ```
40
-
41
- ### Usage
42
-
43
- Quick example with ReactJS.
44
-
45
- ```javascript
46
- import React, { useRef } from 'react';
47
- import Calendar from '@lemonadejs/calendar/dist/react';
48
-
49
- import "@lemonadejs/calendar/dist/style.css";
50
- import "@lemonadejs/modal/dist/style.css";
51
-
52
- export default function App() {
53
- const calendarRef = useRef();
54
-
55
- return (<>
56
- <Calendar type={'inline'} ref={calendarRef} value={new Date()} />
57
- </>);
58
- }
59
- ```
60
-
61
- ### Configuration
62
-
63
- You can configure things such as calendar starting date, calendar events, and customize functions.
64
-
65
- #### Calendar Properties
66
-
67
- | Attribute | Type | Description |
68
- | --------- |------------------|-------------------------------------------------------------------------------------------------------------------|
69
- | type? | string | Determines the rendering type for the calendar. Options: 'inline', 'default'. |
70
- | range? | boolean | Enables the range mode for date selection. |
71
- | value? | number or string | Represents the currently selected date. |
72
- | numeric? | boolean | Enables the use of numeric dates, treating them as serial numbers. |
73
- | input? | HTML element | An optional reference to control the calendar opening. The value is automatically bound when using this property. |
74
-
75
- ### Calendar Events
76
-
77
- | Event | Description |
78
- |----------------------------------|-------------------------------------|
79
- | onchange?: (self, value) => void | Called when a new date is selected. |
80
-
81
- ## License
82
-
83
- The LemonadeJS [Reactive JavaScript Calendar](https://lemonadejs.com/docs/plugins/calendar) is released under the MIT.
84
-
85
- ## Other Tools
86
-
87
- - [jSuites Plugins - JavaScript Calendar](https://jsuites.net/docs/javascript-calendar)
88
- - [Jspreadsheet - JavaScript Spreadsheet](https://jspreadsheet.com/)
1
+ # JavaScript Calendar
2
+
3
+ [Official JavaScript Calendar Documenation](https://lemonadejs.com/docs/plugins/calendar)
4
+
5
+ Compatible with Vanilla JavaScript, LemonadeJS, React, VueJS or Angular.
6
+
7
+ # JavaScript Calendar
8
+
9
+ Leverage the power of the LemonadeJS Calendar, a lightweight and versatile JavaScript component compatible with React, VueJS, and Angular. Designed to enhance web applications, it offers an embeddable calendar for easy date, time, and range selections. Key features include:
10
+
11
+ - Intuitive keyboard navigation.
12
+ - A reactive and responsive design for seamless device adaptation.
13
+ - Flexible range selection for various applications.
14
+ - Customizable options to match your project needs.
15
+
16
+ ## Getting Started
17
+
18
+ You can install using NPM or using directly from a CDN.
19
+
20
+ ### npm Installation
21
+
22
+ To install it in your project using npm, run the following command:
23
+
24
+ ```bash
25
+ $ npm install @lemonadejs/calendar
26
+ ```
27
+
28
+ ### CDN
29
+
30
+ For immediate use without NPM, include these script tags in your HTML for access to the calendar and its dependencies:
31
+
32
+ ```html
33
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lemonadejs/modal/dist/style.min.css" />
34
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lemonadejs/calendar/dist/style.min.css" />
35
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Material+Icons" />
36
+ <script src="https://cdn.jsdelivr.net/npm/lemonadejs/dist/lemonade.min.js"></script>
37
+ <script src="https://cdn.jsdelivr.net/npm/@lemonadejs/modal/dist/index.min.js"></script>
38
+ <script src="https://cdn.jsdelivr.net/npm/@lemonadejs/calendar/dist/index.min.js"></script>
39
+ ```
40
+
41
+ ### Usage
42
+
43
+ Quick example with ReactJS.
44
+
45
+ ```javascript
46
+ import React, { useRef } from 'react';
47
+ import Calendar from '@lemonadejs/calendar/dist/react';
48
+
49
+ import '@lemonadejs/calendar/dist/style.css';
50
+ import '@lemonadejs/modal/dist/style.css';
51
+
52
+ export default function App() {
53
+ const calendarRef = useRef();
54
+
55
+ return (
56
+ <>
57
+ <Calendar type={'inline'} ref={calendarRef} value={new Date()} />
58
+ </>
59
+ );
60
+ }
61
+ ```
62
+
63
+ ### Configuration
64
+
65
+ You can configure things such as calendar starting date, calendar events, and customize functions.
66
+
67
+ #### Calendar Properties
68
+
69
+ | Attribute | Type | Description |
70
+ | --------- | ---------------- | ----------------------------------------------------------------------------------------------------------------- |
71
+ | type? | string | Determines the rendering type for the calendar. Options: 'inline', 'default'. |
72
+ | range? | boolean | Enables the range mode for date selection. |
73
+ | value? | number or string | Represents the currently selected date. |
74
+ | numeric? | boolean | Enables the use of numeric dates, treating them as serial numbers. |
75
+ | input? | HTML element | An optional reference to control the calendar opening. The value is automatically bound when using this property. |
76
+
77
+ ### Calendar Events
78
+
79
+ | Event | Description |
80
+ | -------------------------------- | ----------------------------------- |
81
+ | onchange?: (self, value) => void | Called when a new date is selected. |
82
+
83
+ ## License
84
+
85
+ The LemonadeJS [Reactive JavaScript Calendar](https://lemonadejs.com/docs/plugins/calendar) is released under the MIT.
86
+
87
+ ## Other Tools
88
+
89
+ - [jSuites Plugins - JavaScript Calendar](https://jsuites.net/docs/javascript-calendar)
90
+ - [Jspreadsheet - JavaScript Spreadsheet](https://jspreadsheet.com/)
package/dist/index.js CHANGED
@@ -304,7 +304,7 @@ if (! Modal && typeof (require) === 'function') {
304
304
  return component;
305
305
  })();
306
306
 
307
- const Mask = (function() {
307
+ const Mask = (function Mask() {
308
308
  // Currency
309
309
  const tokens = {
310
310
  // Text
@@ -325,6 +325,33 @@ if (! Modal && typeof (require) === 'function') {
325
325
  general: [ 'A', '0', '\\?', '\\*', ',,M', ',,,B', '[0-9a-zA-Z\\$]+', '_\\(', '_\\)', '\\(', '\\)', '_-', '.']
326
326
  }
327
327
 
328
+ // All expressions
329
+ const allExpressions = [].concat(tokens.fraction, tokens.currency, tokens.datetime, tokens.percentage, tokens.scientific, tokens.numeric, tokens.text, tokens.general).join('|');
330
+
331
+ // Pre-compile all regexes once at initialization for better performance
332
+ const compiledTokens = {};
333
+ const tokenPriority = ['fraction', 'currency', 'scientific', 'percentage', 'numeric', 'datetime', 'text', 'general'];
334
+
335
+ // Initialize compiled regexes
336
+ for (const type of tokenPriority) {
337
+ compiledTokens[type] = tokens[type].map(pattern => ({
338
+ regex: new RegExp('^' + pattern + '$', 'gi'),
339
+ method: pattern
340
+ }));
341
+ }
342
+
343
+ // Pre-compile regex for getTokens function
344
+ const allExpressionsRegex = new RegExp(allExpressions, 'gi');
345
+
346
+ // Pre-compile currency symbol regexes for autoCastingCurrency
347
+ const knownSymbols = ['$', '€', '£', '¥', '₹', '₽', '₩', '₫', 'R$', 'CHF', 'AED'];
348
+ const currencyRegexes = knownSymbols.map(s => ({
349
+ symbol: s,
350
+ regex: new RegExp(`^${s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')}(\\s?)`)
351
+ }));
352
+
353
+ const hiddenCaret = "\u200B";
354
+
328
355
  // Labels
329
356
  const weekDaysFull = Helpers.weekdays;
330
357
  const weekDays = Helpers.weekdaysShort;
@@ -333,6 +360,29 @@ if (! Modal && typeof (require) === 'function') {
333
360
 
334
361
  // Helpers
335
362
 
363
+ const focus = function(el) {
364
+ if (el.textContent.length) {
365
+ // Handle contenteditable elements
366
+ const range = document.createRange();
367
+ const sel = window.getSelection();
368
+
369
+ let node = el;
370
+ // Go as deep as possible to the last text node
371
+ while (node.lastChild) node = node.lastChild;
372
+ // Ensure it's a text node
373
+ if (node.nodeType === Node.TEXT_NODE) {
374
+ range.setStart(node, node.length);
375
+ } else {
376
+ range.setStart(node, node.childNodes.length);
377
+ }
378
+ range.collapse(true);
379
+ sel.removeAllRanges();
380
+ sel.addRange(range);
381
+
382
+ el.scrollLeft = el.scrollWidth;
383
+ }
384
+ }
385
+
336
386
  /**
337
387
  * Returns if the given value is considered blank
338
388
  */
@@ -461,7 +511,6 @@ if (! Modal && typeof (require) === 'function') {
461
511
  const setCaret = function(index) {
462
512
  if (typeof index !== 'number') index = Number(index) || 0;
463
513
 
464
- // Inputs/Textareas
465
514
  if (this.tagName !== 'DIV' || this.isContentEditable !== true) {
466
515
  const n = this.value ?? '';
467
516
  if (index < 0) index = 0;
@@ -648,14 +697,18 @@ if (! Modal && typeof (require) === 'function') {
648
697
  }
649
698
  } else {
650
699
  if (this.values[this.index] == 1 && parseInt(v) < 3) {
651
- this.date[1] = this.values[this.index] += v;
700
+ this.values[this.index] += v;
652
701
  commit();
653
702
  } else if (this.values[this.index] == 0 && parseInt(v) > 0 && parseInt(v) < 10) {
654
- this.date[1] = this.values[this.index] += v;
703
+ this.values[this.index] += v;
655
704
  commit();
656
705
  } else {
657
706
  let test = parseInt(this.values[this.index]);
658
707
  if (test > 0 && test <= 12) {
708
+ if (! single) {
709
+ test = '0' + test;
710
+ }
711
+ this.values[this.index] = test;
659
712
  commit();
660
713
  return false;
661
714
  }
@@ -706,6 +759,10 @@ if (! Modal && typeof (require) === 'function') {
706
759
  } else {
707
760
  let test = parseInt(this.values[this.index]);
708
761
  if (test > 0 && test <= 31) {
762
+ if (! single) {
763
+ test = '0' + test;
764
+ }
765
+ this.values[this.index] = test;
709
766
  commit();
710
767
  return false;
711
768
  }
@@ -935,10 +992,7 @@ if (! Modal && typeof (require) === 'function') {
935
992
  }
936
993
  this.values[this.index] += this.decimal;
937
994
  }
938
- } else if (v === "\u200B") {
939
- this.values[this.index] += v;
940
995
  }
941
-
942
996
  },
943
997
  '[0#]+([.,]{1}0*#*)?%': function(v) {
944
998
  parseMethods['[0#]+([.,]{1}0*#*)?'].call(this, v);
@@ -1094,7 +1148,7 @@ if (! Modal && typeof (require) === 'function') {
1094
1148
  // Add the value
1095
1149
  this.values[this.index] += v;
1096
1150
  // Only if caret is before the change
1097
- let current = this.values[this.index].replace('\u200B','');
1151
+ let current = this.values[this.index];
1098
1152
  // Add token to the values
1099
1153
  if (current !== word.substring(0,current.length)) {
1100
1154
  this.values[this.index] = word;
@@ -1121,7 +1175,7 @@ if (! Modal && typeof (require) === 'function') {
1121
1175
  this.index++;
1122
1176
  }
1123
1177
  },
1124
- '\\*': function(v) {
1178
+ '\\*': function() {
1125
1179
  this.values[this.index] = '';
1126
1180
  this.index++;
1127
1181
  return false;
@@ -1160,17 +1214,17 @@ if (! Modal && typeof (require) === 'function') {
1160
1214
  }
1161
1215
  this.values[this.index] += v;
1162
1216
  },
1163
- '_\\(': function(v) {
1217
+ '_\\(': function() {
1164
1218
  this.values[this.index] = ' ';
1165
1219
  this.index++;
1166
1220
  return false;
1167
1221
  },
1168
- '_\\)': function(v) {
1222
+ '_\\)': function() {
1169
1223
  this.values[this.index] = ' ';
1170
1224
  this.index++;
1171
1225
  return false;
1172
1226
  },
1173
- '\\(': function(v) {
1227
+ '\\(': function() {
1174
1228
  if (this.type === 'currency' && this.parenthesisForNegativeNumbers) {
1175
1229
  this.values[this.index] = '';
1176
1230
  } else {
@@ -1179,7 +1233,7 @@ if (! Modal && typeof (require) === 'function') {
1179
1233
  this.index++;
1180
1234
  return false;
1181
1235
  },
1182
- '\\)': function(v) {
1236
+ '\\)': function() {
1183
1237
  if (this.type === 'currency' && this.parenthesisForNegativeNumbers) {
1184
1238
  this.values[this.index] = '';
1185
1239
  } else {
@@ -1188,17 +1242,17 @@ if (! Modal && typeof (require) === 'function') {
1188
1242
  this.index++;
1189
1243
  return false;
1190
1244
  },
1191
- '_-': function(v) {
1245
+ '_-': function() {
1192
1246
  this.values[this.index] = ' ';
1193
1247
  this.index++;
1194
1248
  return false;
1195
1249
  },
1196
- ',,M': function(v) {
1250
+ ',,M': function() {
1197
1251
  this.values[this.index] = 'M';
1198
1252
  this.index++;
1199
1253
  return false;
1200
1254
  },
1201
- ',,,B': function(v) {
1255
+ ',,,B': function() {
1202
1256
  this.values[this.index] = 'B';
1203
1257
  this.index++;
1204
1258
  return false;
@@ -1243,9 +1297,8 @@ if (! Modal && typeof (require) === 'function') {
1243
1297
  // Types TODO: Generate types so we can garantee that text,scientific, numeric,percentage, current are not duplicates. If they are, it will be general or broken.
1244
1298
 
1245
1299
  const getTokens = function(str) {
1246
- const expressions = [].concat(tokens.fraction, tokens.currency, tokens.datetime, tokens.percentage, tokens.scientific, tokens.numeric, tokens.text, tokens.general);
1247
- // Expression to extract all tokens from the string
1248
- return str.match(new RegExp(expressions.join('|'), 'gi'));
1300
+ allExpressionsRegex.lastIndex = 0; // Reset for global regex
1301
+ return str.match(allExpressionsRegex);
1249
1302
  }
1250
1303
 
1251
1304
  /**
@@ -1253,35 +1306,23 @@ if (! Modal && typeof (require) === 'function') {
1253
1306
  */
1254
1307
  const getMethod = function(str, temporary) {
1255
1308
  str = str.toString().toUpperCase();
1256
- const types = Object.keys(tokens);
1257
1309
 
1258
1310
  // Check for datetime mask
1259
- let datetime = true;
1260
- for (let i = 0; i < temporary.length; i++) {
1261
- let type = temporary[i].type;
1262
- if (! (type === 'datetime' || type === 'general')) {
1263
- datetime = false;
1264
- }
1265
- }
1266
-
1267
- // Remove date time from the possible types
1268
- if (datetime !== true) {
1269
- let index = types.indexOf('datetime');
1270
- types.splice(index, 1);
1271
- }
1311
+ const datetime = temporary.every(t => t.type === 'datetime' || t.type === 'general');
1272
1312
 
1273
- // Get the method based on the token
1274
- for (let i = 0; i < types.length; i++) {
1275
- let type = types[i];
1313
+ // Use priority order for faster matching with pre-compiled regexes
1314
+ for (const type of tokenPriority) {
1315
+ if (!datetime && type === 'datetime') continue;
1276
1316
 
1277
- for (let j = 0; j < tokens[type].length; j++) {
1278
- let e = new RegExp('^' + tokens[type][j] + '$', 'gi'); // Anchor regex
1279
- let r = str.match(e);
1280
- if (r) {
1281
- return { type: type, method: tokens[type][j] }
1317
+ for (const compiled of compiledTokens[type]) {
1318
+ let regex = compiled.regex;
1319
+ regex.lastIndex = 0; // Reset regex state
1320
+ if (regex.test(str)) {
1321
+ return { type: type, method: compiled.method };
1282
1322
  }
1283
1323
  }
1284
1324
  }
1325
+ return null;
1285
1326
  }
1286
1327
 
1287
1328
  const fixMinuteToken = function(t) {
@@ -1417,7 +1458,7 @@ if (! Modal && typeof (require) === 'function') {
1417
1458
 
1418
1459
  const isNumber = function(num) {
1419
1460
  if (typeof(num) === 'string') {
1420
- num = num.replace("\u200B", "").trim();
1461
+ num = num.trim();
1421
1462
  }
1422
1463
  return !isNaN(num) && num !== null && num !== '';
1423
1464
  }
@@ -1711,7 +1752,7 @@ if (! Modal && typeof (require) === 'function') {
1711
1752
  }
1712
1753
 
1713
1754
  const extractDateAndTime = function(value) {
1714
- value = '' + value.substring(0,19);
1755
+ value = value.toString().substring(0,19);
1715
1756
  let splitStr = (value.indexOf('T') !== -1) ? 'T' : ' ';
1716
1757
  value = value.split(splitStr);
1717
1758
 
@@ -1759,11 +1800,20 @@ if (! Modal && typeof (require) === 'function') {
1759
1800
  // Walk every character on the value
1760
1801
  let method;
1761
1802
  while (method = getMethodByPosition(control)) {
1762
- // Get the method name to handle the current token
1763
- let ret = method.call(control, control.value[control.position]);
1764
- // Next position
1765
- if (ret !== false) {
1803
+ let char = control.value[control.position];
1804
+ if (char === hiddenCaret) {
1805
+ control.caret = {
1806
+ index: control.index,
1807
+ position: control.values[control.index]?.length ?? 0,
1808
+ }
1766
1809
  control.position++;
1810
+ } else {
1811
+ // Get the method name to handle the current token
1812
+ let ret = method.call(control, char);
1813
+ // Next position
1814
+ if (ret !== false) {
1815
+ control.position++;
1816
+ }
1767
1817
  }
1768
1818
  }
1769
1819
 
@@ -1785,6 +1835,13 @@ if (! Modal && typeof (require) === 'function') {
1785
1835
  }
1786
1836
  }
1787
1837
  }
1838
+ if (control.caret) {
1839
+ let index = control.caret.index;
1840
+ let position = control.caret.position;
1841
+ let value = control.values[index] ?? '';
1842
+ // Re-apply the caret to the original position
1843
+ control.values[index] = value.substring(0, position) + hiddenCaret + value.substring(position);
1844
+ }
1788
1845
 
1789
1846
  control.value = getValue(control);
1790
1847
 
@@ -1897,7 +1954,6 @@ if (! Modal && typeof (require) === 'function') {
1897
1954
  const parts = str.split('-');
1898
1955
  const p1 = parseInt(parts[0]);
1899
1956
  const p2 = parseInt(parts[1]);
1900
- const p3 = parseInt(parts[2]);
1901
1957
 
1902
1958
  if (p1 <= 12 && p2 <= 31 && p2 > 12) {
1903
1959
  patterns.push('mm-dd-yyyy', 'mm-dd-yy', 'm-d-yyyy', 'm-d-yy');
@@ -2085,13 +2141,10 @@ if (! Modal && typeof (require) === 'function') {
2085
2141
  const hasParens = /^\s*\(.+\)\s*$/.test(original);
2086
2142
  let value = original.replace(/[()\-]/g, '').trim();
2087
2143
 
2088
- // Known symbols
2089
- const knownSymbols = ['$', '€', '£', '¥', '₹', '₽', '₩', '₫', 'R$', 'CHF', 'AED'];
2144
+ // Use pre-compiled currency regexes
2090
2145
  let symbol = '';
2091
2146
 
2092
- for (let s of knownSymbols) {
2093
- const escaped = s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
2094
- const regex = new RegExp(`^${escaped}(\\s?)`);
2147
+ for (let {symbol: s, regex} of currencyRegexes) {
2095
2148
  const match = value.match(regex);
2096
2149
  if (match) {
2097
2150
  symbol = s + (match[1] || '');
@@ -2441,8 +2494,6 @@ if (! Modal && typeof (require) === 'function') {
2441
2494
  return returnObject ? o : result;
2442
2495
  };
2443
2496
 
2444
- // TODO: We have a large number like 1000000 and I want format it to 1,00 or 1M or… (display million/thousands/full numbers). In the excel we can do that with custom format cell “0,00..” However, when I tried applying similar formatting with the mask cell of Jspreadsheet, it didn't work. Could you advise how we can achieve this?
2445
-
2446
2497
  Component.render = function(value, options, fullMask) {
2447
2498
  // Nothing to render
2448
2499
  if (value === '' || value === undefined || value === null) {
@@ -2531,7 +2582,7 @@ if (! Modal && typeof (require) === 'function') {
2531
2582
  } else {
2532
2583
  options.input.value = value;
2533
2584
  }
2534
- jSuites.focus(options.input);
2585
+ focus(options.input);
2535
2586
  }
2536
2587
 
2537
2588
  return value;
@@ -2564,6 +2615,11 @@ if (! Modal && typeof (require) === 'function') {
2564
2615
  return '';
2565
2616
  }
2566
2617
 
2618
+ // Tokens
2619
+ const dateTokens = ['DAY', 'WD', 'DDDD', 'DDD', 'DD', 'D', 'Q', 'HH24', 'HH12', 'HH', '\\[H\\]', 'H', 'AM/PM', 'MI', 'SS', 'MS', 'YYYY', 'YYY', 'YY', 'Y', 'MONTH', 'MON', 'MMMMM', 'MMMM', 'MMM', 'MM', 'M', '.'];
2620
+ // All date tokens
2621
+ const allDateTokens = dateTokens.join('|')
2622
+
2567
2623
  Component.getDateString = function(value, options) {
2568
2624
  if (! options) {
2569
2625
  options = {};
@@ -2595,11 +2651,9 @@ if (! Modal && typeof (require) === 'function') {
2595
2651
  value = Helpers.numToDate(value);
2596
2652
  }
2597
2653
 
2598
- // Tokens
2599
- let tokens = ['DAY', 'WD', 'DDDD', 'DDD', 'DD', 'D', 'Q', 'HH24', 'HH12', 'HH', '\\[H\\]', 'H', 'AM/PM', 'MI', 'SS', 'MS', 'YYYY', 'YYY', 'YY', 'Y', 'MONTH', 'MON', 'MMMMM', 'MMMM', 'MMM', 'MM', 'M', '.'];
2600
2654
 
2601
2655
  // Expression to extract all tokens from the string
2602
- let e = new RegExp(tokens.join('|'), 'gi');
2656
+ let e = new RegExp(allDateTokens, 'gi');
2603
2657
  // Extract
2604
2658
  let t = format.match(e);
2605
2659
 
@@ -2793,7 +2847,7 @@ if (! Modal && typeof (require) === 'function') {
2793
2847
  // Keep the current caret position
2794
2848
  let caret = getCaret(element);
2795
2849
  if (caret) {
2796
- value = value.substring(0, caret) + "\u200B" + value.substring(caret);
2850
+ value = value.substring(0, caret) + hiddenCaret + value.substring(caret);
2797
2851
  }
2798
2852
 
2799
2853
  // Run mask
@@ -2804,15 +2858,17 @@ if (! Modal && typeof (require) === 'function') {
2804
2858
  // Apply the result back to the element
2805
2859
  if (newValue !== value && ! e.inputType.includes('delete')) {
2806
2860
  // Set the caret to the position before transformation
2807
- let caret = newValue.indexOf("\u200B");
2861
+ let caret = newValue.indexOf(hiddenCaret);
2808
2862
  if (caret !== -1) {
2809
2863
  // Apply value
2810
- element[property] = newValue.replace("\u200B", "");
2864
+ element[property] = newValue.replace(hiddenCaret, "");
2811
2865
  // Set caret
2812
2866
  setCaret.call(element, caret);
2813
2867
  } else {
2814
2868
  // Apply value
2815
2869
  element[property] = newValue;
2870
+ // Make sure the caret is positioned in the end
2871
+ focus(element);
2816
2872
  }
2817
2873
  }
2818
2874
  }
@@ -2822,7 +2878,7 @@ if (! Modal && typeof (require) === 'function') {
2822
2878
  Component.adjustPrecision = adjustPrecision;
2823
2879
 
2824
2880
  return Component;
2825
- })();
2881
+ }());
2826
2882
 
2827
2883
  const isNumber = function (num) {
2828
2884
  if (typeof(num) === 'string') {
@@ -3385,12 +3441,18 @@ if (! Modal && typeof (require) === 'function') {
3385
3441
  let input = getInput();
3386
3442
  let value = self.value;
3387
3443
  if (input) {
3444
+ let v;
3388
3445
  if (input.tagName === 'INPUT' || input.tagName === 'TEXTAREA') {
3389
3446
  isEditable = !input.hasAttribute('readonly') && !input.hasAttribute('disabled');
3390
- value = input.value;
3447
+ v = input.value;
3391
3448
  } else if (input.isContentEditable) {
3392
3449
  isEditable = true;
3393
- value = input.textContent;
3450
+ v = input.textContent;
3451
+ }
3452
+
3453
+ let tmp = Mask.extractDateFromString(v, self.format);
3454
+ if (tmp) {
3455
+ value = tmp;
3394
3456
  }
3395
3457
  }
3396
3458
 
@@ -3641,8 +3703,20 @@ if (! Modal && typeof (require) === 'function') {
3641
3703
  // Update input
3642
3704
  let input = getInput();
3643
3705
  if (input) {
3706
+ if (self.format && v) {
3707
+ if (self.range) {
3708
+ if (v[0]) {
3709
+ v[0] = Mask.render(v[0], self.format);
3710
+ }
3711
+ if (v[1]) {
3712
+ v[1] = Mask.render(v[1], self.format);
3713
+ }
3714
+ } else {
3715
+ v = Mask.render(v, self.format);
3716
+ }
3717
+ }
3644
3718
  // Update input value
3645
- input.value = Mask.render(v, self.format);
3719
+ input.value = v;
3646
3720
  // Dispatch event
3647
3721
  Dispatch.call(input, null, 'change', {
3648
3722
  instance: self,
package/dist/style.css CHANGED
@@ -126,6 +126,7 @@
126
126
  cursor: pointer;
127
127
  border-radius: 100px;
128
128
  background-origin: padding-box;
129
+ min-width: 38px;
129
130
  }
130
131
 
131
132
  .lm-calendar-content > div[data-disabled="true"] {
package/package.json CHANGED
@@ -1,23 +1,23 @@
1
- {
2
- "name": "@lemonadejs/calendar",
3
- "title": "LemonadeJS calendar",
4
- "description": "LemonadeJS reactive JavaScript calendar plugin",
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
- "dependencies": {
17
- "lemonadejs": "^5.2.0",
18
- "@lemonadejs/modal": "^5.2.0"
19
- },
20
- "main": "dist/index.js",
21
- "types": "dist/index.d.ts",
22
- "version": "5.2.0"
23
- }
1
+ {
2
+ "name": "@lemonadejs/calendar",
3
+ "title": "LemonadeJS calendar",
4
+ "description": "LemonadeJS reactive JavaScript calendar plugin",
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
+ "dependencies": {
17
+ "lemonadejs": "^5.2.0",
18
+ "@lemonadejs/modal": "^5.2.0"
19
+ },
20
+ "main": "dist/index.js",
21
+ "types": "dist/index.d.ts",
22
+ "version": "5.2.1"
23
+ }