@lemonadejs/calendar 5.8.4 → 5.9.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 +71 -41
- package/dist/index.d.ts +131 -103
- package/dist/index.js +26 -2
- package/dist/react.d.ts +55 -18
- package/dist/react.js +112 -42
- package/dist/vue.d.ts +22 -15
- package/dist/vue.js +39 -47
- package/package.json +17 -1
package/README.md
CHANGED
|
@@ -1,34 +1,28 @@
|
|
|
1
1
|
# JavaScript Calendar
|
|
2
2
|
|
|
3
|
-
[Official JavaScript Calendar
|
|
3
|
+
[Official JavaScript Calendar Documentation](https://lemonadejs.com/docs/plugins/calendar)
|
|
4
4
|
|
|
5
5
|
Compatible with Vanilla JavaScript, LemonadeJS, React, VueJS or Angular.
|
|
6
6
|
|
|
7
|
-
# JavaScript Calendar
|
|
8
|
-
|
|
9
7
|
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
8
|
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
9
|
+
- Intuitive keyboard navigation.
|
|
10
|
+
- A reactive and responsive design for seamless device adaptation.
|
|
11
|
+
- Flexible range selection for various applications.
|
|
12
|
+
- Customizable options to match your project needs.
|
|
15
13
|
|
|
16
14
|
## Getting Started
|
|
17
15
|
|
|
18
|
-
You can install using NPM or
|
|
16
|
+
You can install using NPM or directly from a CDN.
|
|
19
17
|
|
|
20
18
|
### npm Installation
|
|
21
19
|
|
|
22
|
-
To install it in your project using npm, run the following command:
|
|
23
|
-
|
|
24
20
|
```bash
|
|
25
|
-
|
|
21
|
+
npm install @lemonadejs/calendar
|
|
26
22
|
```
|
|
27
23
|
|
|
28
24
|
### CDN
|
|
29
25
|
|
|
30
|
-
For immediate use without NPM, include these script tags in your HTML for access to the calendar and its dependencies:
|
|
31
|
-
|
|
32
26
|
```html
|
|
33
27
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lemonadejs/modal/dist/style.min.css" />
|
|
34
28
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lemonadejs/calendar/dist/style.min.css" />
|
|
@@ -40,7 +34,7 @@ For immediate use without NPM, include these script tags in your HTML for access
|
|
|
40
34
|
|
|
41
35
|
### Usage
|
|
42
36
|
|
|
43
|
-
Quick example with
|
|
37
|
+
Quick example with React:
|
|
44
38
|
|
|
45
39
|
```javascript
|
|
46
40
|
import React, { useRef } from 'react';
|
|
@@ -52,39 +46,75 @@ import '@lemonadejs/modal/dist/style.css';
|
|
|
52
46
|
export default function App() {
|
|
53
47
|
const calendarRef = useRef();
|
|
54
48
|
|
|
55
|
-
return (
|
|
56
|
-
<>
|
|
57
|
-
<Calendar type={'inline'} ref={calendarRef} value={new Date()} />
|
|
58
|
-
</>
|
|
59
|
-
);
|
|
49
|
+
return <Calendar type="inline" ref={calendarRef} value={new Date()} />;
|
|
60
50
|
}
|
|
61
51
|
```
|
|
62
52
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
|
70
|
-
|
|
|
71
|
-
|
|
|
72
|
-
|
|
|
73
|
-
|
|
|
74
|
-
|
|
|
75
|
-
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
|
80
|
-
|
|
|
81
|
-
|
|
|
53
|
+
## API Reference
|
|
54
|
+
|
|
55
|
+
### Options
|
|
56
|
+
|
|
57
|
+
| Attribute | Type | Description |
|
|
58
|
+
|----------------|---------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------|
|
|
59
|
+
| `type?` | `'default' \| 'auto' \| 'picker' \| 'inline'` | Render mode. `'auto'` resolves to `'default'` (≥ 800px wide) or `'picker'` (smaller). `Default: 'default'`. |
|
|
60
|
+
| `format?` | `string` | Date format using Excel-like tokens (e.g. `'dd/mm/yyyy'`). |
|
|
61
|
+
| `value?` | `number \| string \| Date \| Array` | Initial value. ISO string (`'2025-06-15'`), Excel-style serial number, native `Date`, or `[start, end]` tuple in range mode. |
|
|
62
|
+
| `numeric?` | `boolean` | Return values as Excel-style numbers via `getValue()`. `Default: false`. |
|
|
63
|
+
| `range?` | `boolean` | Enable range selection. `Default: false`. |
|
|
64
|
+
| `footer?` | `boolean` | Show the footer (Reset / Done buttons + Today + time picker). `Default: true`. |
|
|
65
|
+
| `time?` | `boolean` | Show hour and minute selectors in the footer. `Default: false`. |
|
|
66
|
+
| `grid?` | `boolean` | Apply grid display mode (sets `data-grid="true"` on root). `Default: false`. |
|
|
67
|
+
| `placeholder?` | `string` | Placeholder applied to a bound input. |
|
|
68
|
+
| `disabled?` | `boolean` | Disable interaction. `Default: false`. |
|
|
69
|
+
| `startingDay?` | `number` | First day of the week (`0=Sun … 6=Sat`). `Default: 0`. |
|
|
70
|
+
| `validRange?` | `string[] \| number[] \| Function` | Bounds tuple `[from, to]` (ISO or Excel serial), or a predicate `(day, month, year, item) => boolean` to disable a cell. |
|
|
71
|
+
| `data?` | `Array<{ date: string, [key: string]: any }>` | Event entries; cells with a matching `date` get a `data-event` marker. |
|
|
72
|
+
| `wheel?` | `boolean` | Allow mouse-wheel month navigation. `Default: true`. |
|
|
73
|
+
| `input?` | `HTMLInputElement \| 'auto'` | Existing input to bind, or `'auto'` to create one. |
|
|
74
|
+
| `initInput?` | `boolean` | Wire up input listeners (open-on-focus, type-to-update). `Default: true`. |
|
|
75
|
+
|
|
76
|
+
### Events
|
|
77
|
+
|
|
78
|
+
| Event | Signature | Description |
|
|
79
|
+
|-------------|------------------------------------------|-----------------------------------------------------------------------------------|
|
|
80
|
+
| `onchange?` | `(self, value) => void` | Fired when the value changes (date selection or `setValue`). |
|
|
81
|
+
| `onupdate?` | `(self, value) => void` | Fired when the cursor moves between cells (e.g. via arrow keys). |
|
|
82
|
+
| `onopen?` | `(self) => void` | Fired when the modal opens (`'picker'` / `'default'` types only). |
|
|
83
|
+
| `onclose?` | `(self, origin) => void` | Fired when the modal closes. `origin` is `'button'`, `'escape'`, `'focusout'`, or any custom string passed to `close({ origin })`. |
|
|
84
|
+
| `onChange?` | `(event) => void` | **React-only.** Forwarded to the bound input's native `change` DOM event. Distinct from `onchange`. |
|
|
85
|
+
|
|
86
|
+
### Instance
|
|
87
|
+
|
|
88
|
+
Calling `Calendar(root, options)` returns an instance exposing:
|
|
89
|
+
|
|
90
|
+
| Property / Method | Description |
|
|
91
|
+
|--------------------|----------------------------------------------------------------------------------------------|
|
|
92
|
+
| `el` | Root DOM element. |
|
|
93
|
+
| `value` | Current value (assignable; mutation triggers a re-render). |
|
|
94
|
+
| `format` | Active date format mask. |
|
|
95
|
+
| `type` | Resolved type (post-`'auto'` resolution). |
|
|
96
|
+
| `view` | Current view: `'days' \| 'months' \| 'years'`. |
|
|
97
|
+
| `range` | Range mode flag. |
|
|
98
|
+
| `rangeValues` | `[start, end]` numeric tuple while a range is active, `null` otherwise. |
|
|
99
|
+
| `modal` | Modal instance (only for `'picker'` / `'default'` types). |
|
|
100
|
+
| `content` | Inner content element (focus target for keyboard navigation). |
|
|
101
|
+
| `input` | Bound input element (auto-created or user-provided). |
|
|
102
|
+
| `open()` | Open the modal. |
|
|
103
|
+
| `close(options?)` | Close the modal. Pass `{ origin: '...' }` to label the close source. |
|
|
104
|
+
| `isClosed()` | `true` / `false` for modal types; `undefined` for `'inline'`. |
|
|
105
|
+
| `setView(view)` | Switch view. Accepts `'days'`, `'months'`, `'years'`. |
|
|
106
|
+
| `next()` | Navigate forward (month / year / year-block depending on the current view). |
|
|
107
|
+
| `prev()` | Navigate backward. |
|
|
108
|
+
| `reset()` | Clear the value and close the modal when applicable. |
|
|
109
|
+
| `getValue()` | Return the current value as a string (or number when `numeric: true`). |
|
|
110
|
+
| `setValue(v)` | Set the value programmatically. Accepts ISO strings, Excel serial numbers, or `[start, end]` tuples in range mode. |
|
|
111
|
+
| `update()` | Commit the current cursor selection (used by Done button). |
|
|
82
112
|
|
|
83
113
|
## License
|
|
84
114
|
|
|
85
|
-
|
|
115
|
+
Released under the MIT license.
|
|
86
116
|
|
|
87
117
|
## Other Tools
|
|
88
118
|
|
|
89
|
-
-
|
|
90
|
-
-
|
|
119
|
+
- [jSuites Plugins - JavaScript Calendar](https://jsuites.net/docs/javascript-calendar)
|
|
120
|
+
- [Jspreadsheet - JavaScript Spreadsheet](https://jspreadsheet.com/)
|
package/dist/index.d.ts
CHANGED
|
@@ -1,103 +1,131 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Official Type definitions for LemonadeJS plugins
|
|
3
|
-
* https://lemonadejs.com
|
|
4
|
-
* Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
declare function Calendar(el: HTMLElement, options?: Calendar.Options): Calendar.Instance;
|
|
8
|
-
|
|
9
|
-
declare namespace Calendar {
|
|
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
|
-
/**
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
|
|
84
|
-
/** Calendar
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Official Type definitions for LemonadeJS plugins
|
|
3
|
+
* https://lemonadejs.com
|
|
4
|
+
* Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
declare function Calendar(el: HTMLElement, options?: Calendar.Options): Calendar.Instance;
|
|
8
|
+
|
|
9
|
+
declare namespace Calendar {
|
|
10
|
+
/** Item passed to a `validRange` function — describes the cell being evaluated. */
|
|
11
|
+
interface ValidRangeItem {
|
|
12
|
+
date: string;
|
|
13
|
+
[key: string]: any;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** `validRange` may be a tuple of bounds (numeric or ISO strings) or a predicate
|
|
17
|
+
* returning truthy to disable a cell. */
|
|
18
|
+
type ValidRange =
|
|
19
|
+
| number[]
|
|
20
|
+
| string[]
|
|
21
|
+
| ((day: number, month: number, year: number, item: ValidRangeItem) => boolean | void);
|
|
22
|
+
|
|
23
|
+
interface CloseOptions {
|
|
24
|
+
/** Where the close was triggered from: 'button', 'escape', 'focusout', or any custom string. */
|
|
25
|
+
origin?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface Options {
|
|
29
|
+
/** Calendar type. Use picker for a responsive modal, auto to automatic detect screen size and open between default or picker. */
|
|
30
|
+
type?: 'default' | 'auto' | 'picker' | 'inline';
|
|
31
|
+
/** Date format. Excel like format dd/mm/yyyy */
|
|
32
|
+
format?: string;
|
|
33
|
+
/** Range picker */
|
|
34
|
+
range?: boolean;
|
|
35
|
+
/** Initial value. Accepts an ISO string, an Excel serial number, a `Date`, or `[start, end]` for range mode. */
|
|
36
|
+
value?: number | string | Date | Array<number | string | Date>;
|
|
37
|
+
/** Calendar value will be a excel-like number or a ISO string. Default false */
|
|
38
|
+
numeric?: boolean;
|
|
39
|
+
/** Show Footer. Default: true **/
|
|
40
|
+
footer?: boolean;
|
|
41
|
+
/** Show hour and minute picker **/
|
|
42
|
+
time?: boolean;
|
|
43
|
+
/** Show grid mode. Default: false */
|
|
44
|
+
grid?: boolean;
|
|
45
|
+
/** Placeholder */
|
|
46
|
+
placeholder?: string;
|
|
47
|
+
/** Disabled. Default false **/
|
|
48
|
+
disabled?: boolean;
|
|
49
|
+
/** Starting day of the week. From 0-6 where zero is Sunday and six is Saturday */
|
|
50
|
+
startingDay?: number;
|
|
51
|
+
/** Bounds tuple, or predicate returning truthy to disable a cell. */
|
|
52
|
+
validRange?: ValidRange;
|
|
53
|
+
/** Calendar events data */
|
|
54
|
+
data?: Array<{ date: string; [key: string]: any }>;
|
|
55
|
+
/** Update view on mouse wheel. Default: true */
|
|
56
|
+
wheel?: boolean;
|
|
57
|
+
/** Bind the calendar to an HTML input element, or `'auto'` to create one. */
|
|
58
|
+
input?: HTMLInputElement | 'auto';
|
|
59
|
+
/** Create events and assign the calendar classes for the input. Default: true */
|
|
60
|
+
initInput?: boolean;
|
|
61
|
+
/** Fired when the calendar value changes (date selection). */
|
|
62
|
+
onchange?: (self: Instance, value: string | number) => void;
|
|
63
|
+
/** Fired when the cursor moves between cells (e.g. arrow-key navigation). */
|
|
64
|
+
onupdate?: (self: Instance, value: string) => void;
|
|
65
|
+
/** Fired when the modal closes. `origin` identifies the source ('button', 'escape', 'focusout', or custom). */
|
|
66
|
+
onclose?: (self: Instance, origin: string) => void;
|
|
67
|
+
/** Fired when the modal opens. */
|
|
68
|
+
onopen?: (self: Instance) => void;
|
|
69
|
+
/** React-only: forwarded to the bound input's native `change` DOM event. Distinct from `onchange`. */
|
|
70
|
+
onChange?: (e: Event) => void;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
interface Instance {
|
|
74
|
+
/** The root DOM element. */
|
|
75
|
+
el: HTMLElement;
|
|
76
|
+
/** Calendar type — may be re-assigned at runtime when initial type is 'auto'. */
|
|
77
|
+
type?: 'default' | 'auto' | 'picker' | 'inline';
|
|
78
|
+
/** Date format */
|
|
79
|
+
format: string;
|
|
80
|
+
/** Range picker */
|
|
81
|
+
range: boolean;
|
|
82
|
+
/** Value */
|
|
83
|
+
value: number | string;
|
|
84
|
+
/** Calendar value will be a excel-like number or a ISO string. Default false */
|
|
85
|
+
numeric: boolean;
|
|
86
|
+
/** Footer. Default: true **/
|
|
87
|
+
footer: boolean;
|
|
88
|
+
/** Show hour and minute picker **/
|
|
89
|
+
time: boolean;
|
|
90
|
+
/** Show grid mode. Default: false */
|
|
91
|
+
grid: boolean;
|
|
92
|
+
/** Placeholder */
|
|
93
|
+
placeholder: string;
|
|
94
|
+
/** Disabled. Default false **/
|
|
95
|
+
disabled: boolean;
|
|
96
|
+
/** Update view on mouse wheel. Default: true */
|
|
97
|
+
wheel: boolean;
|
|
98
|
+
/** Bound input element (created when `input: 'auto'`). */
|
|
99
|
+
input: HTMLInputElement;
|
|
100
|
+
/** Modal instance — present only when `type` resolves to 'picker' or 'default'. */
|
|
101
|
+
modal?: any;
|
|
102
|
+
/** Inner content element used as the focusable target for keyboard navigation. */
|
|
103
|
+
content?: HTMLElement;
|
|
104
|
+
/** Current view. */
|
|
105
|
+
view?: 'days' | 'months' | 'years';
|
|
106
|
+
/** Active range tuple as numeric (Excel-like) values when `range: true`; null otherwise. */
|
|
107
|
+
rangeValues: [number, number] | null;
|
|
108
|
+
/** Open the calendar modal */
|
|
109
|
+
open: () => void;
|
|
110
|
+
/** Close the calendar modal */
|
|
111
|
+
close: (options?: CloseOptions) => void;
|
|
112
|
+
/** Whether the calendar modal is currently closed. Returns undefined for inline calendars. */
|
|
113
|
+
isClosed?: () => boolean | undefined;
|
|
114
|
+
/** Change the view */
|
|
115
|
+
setView: (view: 'days' | 'months' | 'years') => void;
|
|
116
|
+
/** Go to the next month or year depending on the view */
|
|
117
|
+
next?: () => void;
|
|
118
|
+
/** Go to the previous month or year depending on the view */
|
|
119
|
+
prev?: () => void;
|
|
120
|
+
/** Reset the calendar value and close the modal when applicable */
|
|
121
|
+
reset?: () => void;
|
|
122
|
+
/** Get the current calendar value */
|
|
123
|
+
getValue?: () => string | number;
|
|
124
|
+
/** Set the current calendar value. Accepts ISO strings, Excel serial numbers, `Date` objects, or `[start, end]` tuples in range mode. */
|
|
125
|
+
setValue?: (value: string | number | Date | Array<number | string | Date>) => void;
|
|
126
|
+
/** Accept the selected value on the calendar */
|
|
127
|
+
update?: () => void;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export default Calendar;
|
package/dist/index.js
CHANGED
|
@@ -63,6 +63,9 @@ const Mask = utils.Mask;
|
|
|
63
63
|
let data = {};
|
|
64
64
|
if (Array.isArray(this.data)) {
|
|
65
65
|
this.data.map(function (v) {
|
|
66
|
+
if (!v || typeof v !== 'object' || typeof v.date !== 'string') {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
66
69
|
let d = year + '-' + Helpers.two(month + 1);
|
|
67
70
|
if (v.date.substring(0, 7) === d) {
|
|
68
71
|
if (!data[v.date]) {
|
|
@@ -291,8 +294,13 @@ const Mask = utils.Mask;
|
|
|
291
294
|
let change = self.onchange;
|
|
292
295
|
self.onchange = null;
|
|
293
296
|
|
|
297
|
+
// Coerce startingDay to a number so string inputs ('1') don't trigger string concat in modulo math
|
|
298
|
+
if (typeof self.startingDay !== 'number') {
|
|
299
|
+
self.startingDay = Number(self.startingDay) || 0;
|
|
300
|
+
}
|
|
301
|
+
|
|
294
302
|
// Weekdays
|
|
295
|
-
self.weekdays = getWeekdays(self.startingDay
|
|
303
|
+
self.weekdays = getWeekdays(self.startingDay);
|
|
296
304
|
|
|
297
305
|
// Cursor
|
|
298
306
|
self.cursor = {};
|
|
@@ -380,6 +388,10 @@ const Mask = utils.Mask;
|
|
|
380
388
|
const setValue = function(v) {
|
|
381
389
|
let d = new Date();
|
|
382
390
|
if (v) {
|
|
391
|
+
// Accept native Date objects by converting to ISO string
|
|
392
|
+
if (v instanceof Date) {
|
|
393
|
+
v = v.toISOString().substring(0, 10);
|
|
394
|
+
}
|
|
383
395
|
if (isTrue(self.range)) {
|
|
384
396
|
if (v) {
|
|
385
397
|
if (! Array.isArray(v)) {
|
|
@@ -508,6 +520,9 @@ const Mask = utils.Mask;
|
|
|
508
520
|
}
|
|
509
521
|
|
|
510
522
|
const select = function(e, s) {
|
|
523
|
+
if (self.disabled === true) {
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
511
526
|
// Get new date content
|
|
512
527
|
let d = updateDate(s.value, getPosition());
|
|
513
528
|
// New date
|
|
@@ -699,11 +714,17 @@ const Mask = utils.Mask;
|
|
|
699
714
|
}
|
|
700
715
|
|
|
701
716
|
const normalize = function(v) {
|
|
717
|
+
if (v instanceof Date) {
|
|
718
|
+
v = Helpers.dateToString ? Helpers.dateToString(v) : v.toISOString().substring(0, 10);
|
|
719
|
+
}
|
|
702
720
|
if (! Array.isArray(v)) {
|
|
703
721
|
v = v.toString().split(',');
|
|
704
722
|
}
|
|
705
723
|
|
|
706
724
|
return v.map(item => {
|
|
725
|
+
if (item instanceof Date) {
|
|
726
|
+
return Helpers.dateToString ? Helpers.dateToString(item) : item.toISOString().substring(0, 10);
|
|
727
|
+
}
|
|
707
728
|
if (Number(item) == item) {
|
|
708
729
|
return Helpers.numToDate(item);
|
|
709
730
|
} else {
|
|
@@ -1012,7 +1033,10 @@ const Mask = utils.Mask;
|
|
|
1012
1033
|
if (prop === 'view') {
|
|
1013
1034
|
reloadView(true);
|
|
1014
1035
|
} else if (prop === 'startingDay') {
|
|
1015
|
-
|
|
1036
|
+
if (typeof self.startingDay !== 'number') {
|
|
1037
|
+
self.startingDay = Number(self.startingDay) || 0;
|
|
1038
|
+
}
|
|
1039
|
+
self.weekdays = getWeekdays(self.startingDay);
|
|
1016
1040
|
} else if (prop === 'value') {
|
|
1017
1041
|
dispatchOnChangeEvent();
|
|
1018
1042
|
}
|
package/dist/react.d.ts
CHANGED
|
@@ -1,18 +1,55 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Official Type definitions for the LemonadeJS plugins
|
|
3
|
-
* https://lemonadejs.net/docs/plugins/calendar
|
|
4
|
-
* Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
|
|
5
|
-
*/
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Official Type definitions for the LemonadeJS plugins
|
|
3
|
+
* https://lemonadejs.net/docs/plugins/calendar
|
|
4
|
+
* Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
|
|
5
|
+
*/
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import Calendar from './index';
|
|
8
|
+
|
|
9
|
+
declare namespace CalendarReact {
|
|
10
|
+
/**
|
|
11
|
+
* React-idiomatic camelCase aliases for the lemonadejs callbacks. The
|
|
12
|
+
* wrapper drops the leading `self` argument before invoking these — the
|
|
13
|
+
* instance is available via the forwarded ref.
|
|
14
|
+
*
|
|
15
|
+
* The lowercase names from `Calendar.Options` (e.g. `onchange`) still
|
|
16
|
+
* work for legacy compatibility, but new code should prefer these.
|
|
17
|
+
*/
|
|
18
|
+
interface ReactCallbacks {
|
|
19
|
+
/** Fired when the value changes (date selection or `setValue`). */
|
|
20
|
+
onChange?: (value: string | number) => void;
|
|
21
|
+
/** Fired when the cursor moves between cells (e.g. via arrow keys). */
|
|
22
|
+
onUpdate?: (value: string) => void;
|
|
23
|
+
/** Fired when the modal opens. */
|
|
24
|
+
onOpen?: () => void;
|
|
25
|
+
/**
|
|
26
|
+
* Fired when the modal closes. `origin` is `'button'`, `'escape'`,
|
|
27
|
+
* `'focusout'`, or any custom string passed to `close({ origin })`.
|
|
28
|
+
*/
|
|
29
|
+
onClose?: (origin: string) => void;
|
|
30
|
+
/**
|
|
31
|
+
* Wired to the bound input element's native DOM `change` event.
|
|
32
|
+
* Renamed from the legacy `onChange` to free that name for
|
|
33
|
+
* `onChange` (the date-selection callback above).
|
|
34
|
+
*/
|
|
35
|
+
onInputChange?: (e: Event) => void;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Wrapper-only props (the wrapping `<div>` accepts these). */
|
|
39
|
+
interface DOMProps {
|
|
40
|
+
className?: string;
|
|
41
|
+
style?: React.CSSProperties;
|
|
42
|
+
children?: React.ReactNode;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
declare const CalendarReact: React.MemoExoticComponent<
|
|
47
|
+
React.ForwardRefExoticComponent<
|
|
48
|
+
Omit<Calendar.Options, 'onchange' | 'onupdate' | 'onclose' | 'onopen' | 'onChange'>
|
|
49
|
+
& CalendarReact.ReactCallbacks
|
|
50
|
+
& CalendarReact.DOMProps
|
|
51
|
+
& React.RefAttributes<Calendar.Instance>
|
|
52
|
+
>
|
|
53
|
+
>;
|
|
54
|
+
|
|
55
|
+
export default CalendarReact;
|
package/dist/react.js
CHANGED
|
@@ -1,42 +1,112 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
|
-
import React, {
|
|
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
|
-
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import React, {
|
|
3
|
+
useRef,
|
|
4
|
+
useEffect,
|
|
5
|
+
useImperativeHandle,
|
|
6
|
+
useState,
|
|
7
|
+
memo,
|
|
8
|
+
} from 'react';
|
|
9
|
+
import Component from './index';
|
|
10
|
+
|
|
11
|
+
// Maps React-style camelCase prop names to the underlying lemonadejs
|
|
12
|
+
// lowercase option names. The wrapper drops the leading `self` argument
|
|
13
|
+
// from camelCase callbacks before invoking the user's handler — `self` is
|
|
14
|
+
// redundant in React because the user already has access to the instance
|
|
15
|
+
// through the forwarded ref.
|
|
16
|
+
//
|
|
17
|
+
// `onInputChange` is calendar-specific: the lemonadejs plugin uses `onChange`
|
|
18
|
+
// (capital C) as a hook for the bound input element's native DOM `change`
|
|
19
|
+
// event. Renaming it to `onInputChange` frees `onChange` to mean "date
|
|
20
|
+
// selection callback" — matching what React users expect.
|
|
21
|
+
const REACT_TO_LEMONADE = {
|
|
22
|
+
onChange: 'onchange',
|
|
23
|
+
onUpdate: 'onupdate',
|
|
24
|
+
onCreate: 'oncreate',
|
|
25
|
+
onBeforeCreate: 'onbeforecreate',
|
|
26
|
+
onChangeEvent: 'onchangeevent',
|
|
27
|
+
onBeforeChangeEvent: 'onbeforechangeevent',
|
|
28
|
+
onBeforeChange: 'onbeforechange',
|
|
29
|
+
onBeforeInsert: 'onbeforeinsert',
|
|
30
|
+
onDelete: 'ondelete',
|
|
31
|
+
onError: 'onerror',
|
|
32
|
+
onClose: 'onclose',
|
|
33
|
+
onOpen: 'onopen',
|
|
34
|
+
onEdition: 'onedition',
|
|
35
|
+
onDblClick: 'ondblclick',
|
|
36
|
+
onInputChange: 'onChange',
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const RESERVED_REACT_PROPS = new Set(['children', 'className', 'style', 'key']);
|
|
40
|
+
|
|
41
|
+
const Calendar = memo(React.forwardRef((props, mainReference) => {
|
|
42
|
+
const containerRef = useRef(null);
|
|
43
|
+
const instanceRef = useRef(null);
|
|
44
|
+
const propsRef = useRef(props);
|
|
45
|
+
const [instance, setInstance] = useState(null);
|
|
46
|
+
|
|
47
|
+
// Keep a ref to the latest props so callback trampolines always invoke
|
|
48
|
+
// the user's most recent function (avoids stale-closure bugs on parent
|
|
49
|
+
// rerenders).
|
|
50
|
+
propsRef.current = props;
|
|
51
|
+
|
|
52
|
+
// Single-mount effect, StrictMode-safe via the `instance` guard.
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
if (!containerRef.current || instance) return;
|
|
55
|
+
|
|
56
|
+
const options = {};
|
|
57
|
+
for (const key in props) {
|
|
58
|
+
if (RESERVED_REACT_PROPS.has(key)) continue;
|
|
59
|
+
const lemonadeKey = REACT_TO_LEMONADE[key] || key;
|
|
60
|
+
const isReactCallback = key in REACT_TO_LEMONADE;
|
|
61
|
+
const value = props[key];
|
|
62
|
+
if (typeof value === 'function') {
|
|
63
|
+
options[lemonadeKey] = isReactCallback
|
|
64
|
+
// React-style: drop the leading `self` argument
|
|
65
|
+
? (...args) => {
|
|
66
|
+
const fn = propsRef.current[key];
|
|
67
|
+
if (typeof fn === 'function') return fn(...args.slice(1));
|
|
68
|
+
}
|
|
69
|
+
// Legacy lowercase callback: pass through unchanged
|
|
70
|
+
: (...args) => {
|
|
71
|
+
const fn = propsRef.current[key];
|
|
72
|
+
if (typeof fn === 'function') return fn(...args);
|
|
73
|
+
};
|
|
74
|
+
} else {
|
|
75
|
+
options[lemonadeKey] = value;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const newInstance = Component(containerRef.current, options);
|
|
80
|
+
instanceRef.current = newInstance;
|
|
81
|
+
setInstance(newInstance);
|
|
82
|
+
}, []);
|
|
83
|
+
|
|
84
|
+
// Prop sync: write non-function prop changes back to the live instance.
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
const inst = instanceRef.current;
|
|
87
|
+
if (!inst) return;
|
|
88
|
+
for (const key in props) {
|
|
89
|
+
if (RESERVED_REACT_PROPS.has(key)) continue;
|
|
90
|
+
if (typeof props[key] === 'function') continue;
|
|
91
|
+
const lemonadeKey = REACT_TO_LEMONADE[key] || key;
|
|
92
|
+
if (Object.prototype.hasOwnProperty.call(inst, lemonadeKey)
|
|
93
|
+
&& props[key] !== inst[lemonadeKey]) {
|
|
94
|
+
inst[lemonadeKey] = props[key];
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}, [props]);
|
|
98
|
+
|
|
99
|
+
// Expose the lemonadejs instance through the forwarded ref.
|
|
100
|
+
useImperativeHandle(mainReference, () => instance, [instance]);
|
|
101
|
+
|
|
102
|
+
return React.createElement(React.Fragment, null,
|
|
103
|
+
React.createElement('div', {
|
|
104
|
+
ref: containerRef,
|
|
105
|
+
className: props.className,
|
|
106
|
+
style: { width: '100%', height: '100%', ...props.style },
|
|
107
|
+
}),
|
|
108
|
+
props.children,
|
|
109
|
+
);
|
|
110
|
+
}));
|
|
111
|
+
|
|
112
|
+
export default Calendar;
|
package/dist/vue.d.ts
CHANGED
|
@@ -1,15 +1,22 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Official Type definitions for the LemonadeJS plugins
|
|
3
|
-
* https://lemonadejs.net
|
|
4
|
-
* Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
|
|
5
|
-
*/
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
declare
|
|
14
|
-
|
|
15
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Official Type definitions for the LemonadeJS plugins
|
|
3
|
+
* https://lemonadejs.net
|
|
4
|
+
* Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
|
|
5
|
+
*/
|
|
6
|
+
import { DefineComponent } from 'vue';
|
|
7
|
+
import Calendar from './index';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Vue 3 wrapper. Use `<Calendar ... ref="calendarRef" />` and access the
|
|
11
|
+
* underlying instance via `calendarRef.value?.current` (e.g. `current.setValue(...)`).
|
|
12
|
+
*/
|
|
13
|
+
declare const CalendarVue: DefineComponent<
|
|
14
|
+
Calendar.Options,
|
|
15
|
+
{},
|
|
16
|
+
{
|
|
17
|
+
el: HTMLElement | null;
|
|
18
|
+
current: Calendar.Instance | null;
|
|
19
|
+
}
|
|
20
|
+
>;
|
|
21
|
+
|
|
22
|
+
export default CalendarVue;
|
package/dist/vue.js
CHANGED
|
@@ -1,47 +1,39 @@
|
|
|
1
|
-
import { h } from 'vue';
|
|
2
|
-
import component from
|
|
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
|
-
this.current[key] = this.$attrs[key];
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
1
|
+
import { h } from 'vue';
|
|
2
|
+
import component from './index';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
inheritAttrs: false,
|
|
6
|
+
mounted() {
|
|
7
|
+
this.$nextTick(() => {
|
|
8
|
+
const options = { ...this.$attrs };
|
|
9
|
+
this.el = this.$refs.container;
|
|
10
|
+
this.current = component(this.$refs.container, options);
|
|
11
|
+
});
|
|
12
|
+
},
|
|
13
|
+
setup() {
|
|
14
|
+
return () => h('div', {
|
|
15
|
+
ref: 'container',
|
|
16
|
+
style: { width: '100%', height: '100%' },
|
|
17
|
+
});
|
|
18
|
+
},
|
|
19
|
+
watch: {
|
|
20
|
+
$attrs: {
|
|
21
|
+
deep: true,
|
|
22
|
+
handler() {
|
|
23
|
+
this.updateState();
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
methods: {
|
|
28
|
+
updateState() {
|
|
29
|
+
if (!this.current) return;
|
|
30
|
+
for (const key in this.$attrs) {
|
|
31
|
+
if (Object.prototype.hasOwnProperty.call(this.$attrs, key)
|
|
32
|
+
&& Object.prototype.hasOwnProperty.call(this.current, key)
|
|
33
|
+
&& this.$attrs[key] !== this.current[key]) {
|
|
34
|
+
this.current[key] = this.$attrs[key];
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
};
|
package/package.json
CHANGED
|
@@ -20,5 +20,21 @@
|
|
|
20
20
|
},
|
|
21
21
|
"main": "dist/index.js",
|
|
22
22
|
"types": "dist/index.d.ts",
|
|
23
|
-
"
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"default": "./dist/index.js"
|
|
27
|
+
},
|
|
28
|
+
"./react": {
|
|
29
|
+
"types": "./dist/react.d.ts",
|
|
30
|
+
"default": "./dist/react.js"
|
|
31
|
+
},
|
|
32
|
+
"./vue": {
|
|
33
|
+
"types": "./dist/vue.d.ts",
|
|
34
|
+
"default": "./dist/vue.js"
|
|
35
|
+
},
|
|
36
|
+
"./style.css": "./dist/style.css",
|
|
37
|
+
"./dist/*": "./dist/*"
|
|
38
|
+
},
|
|
39
|
+
"version": "5.9.0"
|
|
24
40
|
}
|