v-datepicker-lite 0.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.
Files changed (3) hide show
  1. package/README.md +223 -0
  2. package/index.js +795 -0
  3. package/package.json +62 -0
package/README.md ADDED
@@ -0,0 +1,223 @@
1
+ # Vue DatePicker
2
+
3
+ A lightweight and customizable Vue 3 date picker component with support for date, time, date-time, week, and month selection modes, featuring accessibility and responsive design.
4
+
5
+ ## Features
6
+
7
+ - **Multiple Selection Modes**: Supports `date`, `time`, `dateTime`, `week`, and `month` modes.
8
+ - **Responsive Design**: Adapts to various screen sizes with a clean, modern UI.
9
+ - **Accessibility**: Includes ARIA attributes and keyboard navigation for enhanced usability.
10
+ - **Customizable**: Flexible props for date format, time format, min/max dates, disabled dates, and more.
11
+ - **Time Selection**: Supports 12h/24h formats with customizable time intervals (15, 30, or 60 minutes).
12
+ - **Performance Optimized**: Uses Vue 3 composition API for efficient rendering and state management.
13
+ - **TypeScript Support**: Fully typed with TypeScript for better developer experience.
14
+
15
+ ## Demo
16
+
17
+ [Live Demo](https://v-datepicker-lite.vercel.app/)
18
+
19
+ ## Installation
20
+
21
+ ```bash
22
+ # npm
23
+ npm install v-datepicker-lite
24
+
25
+ # yarn
26
+ yarn add v-datepicker-lite
27
+
28
+ # pnpm
29
+ pnpm add v-datepicker-lite
30
+ ```
31
+
32
+ ## Usage
33
+
34
+ Below are examples demonstrating different configurations of the Vue DatePicker component.
35
+
36
+ ### 1. Basic Date Picker
37
+
38
+ A simple date picker for selecting a single date.
39
+
40
+ ```vue
41
+ <script setup>
42
+ import { ref } from 'vue'
43
+ import DatePicker from 'v-datepicker-lite'
44
+ import 'v-datepicker-lite/style.css'
45
+
46
+ const selectedDate = (ref < Date) | (null > null)
47
+ </script>
48
+
49
+ <template>
50
+ <div>
51
+ <h3>Date Picker</h3>
52
+ <DatePicker
53
+ v-model:value="selectedDate"
54
+ mode="date" />
55
+ <p>
56
+ Selected:
57
+ {{ selectedDate ? selectedDate.toLocaleDateString() : 'None' }}
58
+ </p>
59
+ </div>
60
+ </template>
61
+ ```
62
+
63
+ ### 2. Week Picker
64
+
65
+ Select an entire week starting from the first day of the selected week.
66
+
67
+ ```vue
68
+ <script setup>
69
+ import { ref } from 'vue'
70
+ import DatePicker from 'v-datepicker-lite'
71
+
72
+ const selectedWeek = (ref < Date) | (null > null)
73
+ </script>
74
+
75
+ <template>
76
+ <div>
77
+ <h3>Week Picker</h3>
78
+ <DatePicker
79
+ v-model:value="selectedWeek"
80
+ mode="week" />
81
+ <p>
82
+ Selected:
83
+ {{ selectedWeek ? selectedWeek.toLocaleDateString() : 'None' }}
84
+ </p>
85
+ </div>
86
+ </template>
87
+ ```
88
+
89
+ ### 3. Month Picker
90
+
91
+ Select a month and year.
92
+
93
+ ```vue
94
+ <script setup>
95
+ import { ref } from 'vue'
96
+ import DatePicker from 'v-datepicker-lite'
97
+
98
+ const selectedMonth = (ref < Date) | (null > null)
99
+ </script>
100
+
101
+ <template>
102
+ <div>
103
+ <h3>Month Picker</h3>
104
+ <DatePicker
105
+ v-model:value="selectedMonth"
106
+ mode="month" />
107
+ <p>
108
+ Selected:
109
+ {{ selectedMonth ? selectedMonth.toLocaleDateString() : 'None' }}
110
+ </p>
111
+ </div>
112
+ </template>
113
+ ```
114
+
115
+ ### 4. DateTime Picker
116
+
117
+ Select both date and time with a 12-hour format.
118
+
119
+ ```vue
120
+ <script setup>
121
+ import { ref } from 'vue'
122
+ import DatePicker from 'v-datepicker-lite'
123
+
124
+ const selectedDateTime = (ref < Date) | (null > null)
125
+ </script>
126
+
127
+ <template>
128
+ <div>
129
+ <h3>DateTime Picker</h3>
130
+ <DatePicker
131
+ v-model:value="selectedDateTime"
132
+ mode="dateTime"
133
+ time-format="12h"
134
+ time-interval="15" />
135
+ <p>
136
+ Selected:
137
+ {{ selectedDateTime ? selectedDateTime.toLocaleString() : 'None' }}
138
+ </p>
139
+ </div>
140
+ </template>
141
+ ```
142
+
143
+ ### 5. Date Picker with Restrictions
144
+
145
+ Restrict date selection with minimum date and disabled date ranges.
146
+
147
+ ```vue
148
+ <script setup>
149
+ import { ref } from 'vue'
150
+ import DatePicker from 'v-datepicker-lite'
151
+
152
+ const selectedDate = (ref < Date) | (null > null)
153
+ </script>
154
+
155
+ <template>
156
+ <div>
157
+ <h3>Restricted Date Picker</h3>
158
+ <DatePicker
159
+ v-model:value="selectedDate"
160
+ mode="date"
161
+ :min-date="new Date().toISOString().split('T')[0]"
162
+ :disabled-dates="[
163
+ { start: '2025-08-15', end: '2025-08-20' },
164
+ { start: '2025-08-25' },
165
+ ]" />
166
+ <p>
167
+ Selected:
168
+ {{ selectedDate ? selectedDate.toLocaleDateString() : 'None' }}
169
+ </p>
170
+ </div>
171
+ </template>
172
+ ```
173
+
174
+ ## Props
175
+
176
+ | Prop | Type | Default | Description |
177
+ | --------------- | ------------------------ | -------------- | ----------------------------------------------------------------- |
178
+ | `value` | `Date \| string \| null` | `null` | v-model binding for the selected date/time. |
179
+ | `mode` | `string` | `'date'` | Selection mode: `date`, `time`, `dateTime`, `week`, or `month`. |
180
+ | `format` | `string` | `'YYYY-MM-DD'` | Date format for string output (e.g., `YYYY-MM-DD HH:mm`). |
181
+ | `timeFormat` | `string` | `'24h'` | Time format: `12h` or `24h`. |
182
+ | `timeInterval` | `number` | `15` | Time selection interval in minutes: `15`, `30`, or `60`. |
183
+ | `minDate` | `string` | `undefined` | Minimum selectable date (ISO format: `YYYY-MM-DD`). |
184
+ | `maxDate` | `string` | `undefined` | Maximum selectable date (ISO format: `YYYY-MM-DD`). |
185
+ | `disabledDates` | `Array` | `[]` | Array of disabled date ranges: `{ start: string, end?: string }`. |
186
+ | `disabled` | `boolean` | `false` | Disables the date picker. |
187
+ | `readonly` | `boolean` | `false` | Makes the date picker read-only. |
188
+
189
+ ## Events
190
+
191
+ | Event | Payload Type | Description |
192
+ | -------------- | ------------------------ | ---------------------------------------- |
193
+ | `update:value` | `Date \| string \| null` | Emitted when the selected value changes. |
194
+ | `change` | `Date \| string \| null` | Emitted when the selected value changes. |
195
+ | `select` | `Date \| string \| null` | Emitted when a date/time is selected. |
196
+
197
+ ## Styling
198
+
199
+ Customize the appearance using the following CSS variables defined in `style.css`:
200
+
201
+ ```css
202
+ :root {
203
+ --date-picker-primary: #4f46e5; /* Primary color for selected items */
204
+ --date-picker-primary-fg: #ffffff; /* Foreground color for selected items */
205
+ --date-picker-text: #374151; /* Text color */
206
+ --date-picker-border: #d1d5db; /* Border color */
207
+ --date-picker-bg: #ffffff; /* Background color */
208
+ --date-picker-secondary: #f7f7f9; /* Secondary background color */
209
+ --date-picker-secondary-dark: #eff0f3; /* Hover background color */
210
+ --date-picker-disabled: #9ca3af; /* Disabled item color */
211
+ --date-picker-today: #fef3c7; /* Today highlight color */
212
+ --date-picker-radius: 0.375em; /* Border radius */
213
+ --date-picker-hover: #f3f4f6; /* Hover background color */
214
+ }
215
+ ```
216
+
217
+ ## Author
218
+
219
+ [safdar-azeem](https://github.com/safdar-azeem)
220
+
221
+ ## License
222
+
223
+ MIT
package/index.js ADDED
@@ -0,0 +1,795 @@
1
+ import { defineComponent as I, computed as S, createElementBlock as p, openBlock as v, createElementVNode as h, Fragment as Y, renderList as T, unref as o, toDisplayString as P, normalizeClass as x, ref as F, watch as L, nextTick as B, onMounted as U, createBlock as V, createCommentVNode as N, normalizeStyle as X, createVNode as Z } from "vue";
2
+ const R = (t, r = "YYYY-MM-DD") => {
3
+ const e = t.getFullYear(), u = String(t.getMonth() + 1).padStart(2, "0"), n = String(t.getDate()).padStart(2, "0"), d = String(t.getHours()).padStart(2, "0"), i = String(t.getMinutes()).padStart(2, "0");
4
+ return r.replace("YYYY", e.toString()).replace("MM", u).replace("DD", n).replace("HH", d).replace("mm", i);
5
+ }, W = (t) => {
6
+ if (!t) return null;
7
+ const r = new Date(t);
8
+ return isNaN(r.getTime()) ? null : r;
9
+ }, G = (t, r) => t.getFullYear() === r.getFullYear() && t.getMonth() === r.getMonth() && t.getDate() === r.getDate(), ee = (t) => {
10
+ const r = new Date(t.getFullYear(), 0, 1), e = (t.getTime() - r.getTime()) / 864e5;
11
+ return Math.ceil((e + r.getDay() + 1) / 7);
12
+ }, E = (t, r) => {
13
+ const e = new Date(t, r, 1), n = new Date(t, r + 1, 0).getDate(), d = e.getDay(), i = [], a = /* @__PURE__ */ new Date(), l = r === 0 ? 11 : r - 1, m = r === 0 ? t - 1 : t, D = new Date(m, l + 1, 0).getDate();
14
+ for (let f = d - 1; f >= 0; f--) {
15
+ const c = new Date(m, l, D - f);
16
+ i.push({
17
+ date: c,
18
+ day: D - f,
19
+ month: l,
20
+ year: m,
21
+ isCurrentMonth: !1,
22
+ isToday: G(c, a),
23
+ isSelected: !1,
24
+ isDisabled: !1
25
+ });
26
+ }
27
+ for (let f = 1; f <= n; f++) {
28
+ const c = new Date(t, r, f);
29
+ i.push({
30
+ date: c,
31
+ day: f,
32
+ month: r,
33
+ year: t,
34
+ isCurrentMonth: !0,
35
+ isToday: G(c, a),
36
+ isSelected: !1,
37
+ isDisabled: !1
38
+ });
39
+ }
40
+ const s = 42 - i.length, M = r === 11 ? 0 : r + 1, k = r === 11 ? t + 1 : t;
41
+ for (let f = 1; f <= s; f++) {
42
+ const c = new Date(k, M, f);
43
+ i.push({
44
+ date: c,
45
+ day: f,
46
+ month: M,
47
+ year: k,
48
+ isCurrentMonth: !1,
49
+ isToday: G(c, a),
50
+ isSelected: !1,
51
+ isDisabled: !1
52
+ });
53
+ }
54
+ return i;
55
+ }, te = (t, r) => {
56
+ const e = E(t, r), u = [];
57
+ for (let n = 0; n < e.length; n += 7) {
58
+ const d = e.slice(n, n + 7), i = ee(d[0].date);
59
+ u.push({
60
+ weekNumber: i,
61
+ days: d,
62
+ isSelected: !1
63
+ });
64
+ }
65
+ return u;
66
+ }, j = (t) => [
67
+ "January",
68
+ "February",
69
+ "March",
70
+ "April",
71
+ "May",
72
+ "June",
73
+ "July",
74
+ "August",
75
+ "September",
76
+ "October",
77
+ "November",
78
+ "December"
79
+ ].map((e, u) => ({
80
+ month: u,
81
+ year: t,
82
+ name: e,
83
+ isSelected: !1,
84
+ isDisabled: !1
85
+ })), ae = (t, r, e, u) => {
86
+ const n = R(t, "YYYY-MM-DD");
87
+ return r && n < r || e && n > e ? !0 : u ? u.some((d) => d.end ? n >= d.start && n <= d.end : n === d.start) : !1;
88
+ }, O = [
89
+ "January",
90
+ "February",
91
+ "March",
92
+ "April",
93
+ "May",
94
+ "June",
95
+ "July",
96
+ "August",
97
+ "September",
98
+ "October",
99
+ "November",
100
+ "December"
101
+ ], K = [
102
+ "Sun",
103
+ "Mon",
104
+ "Tue",
105
+ "Wed",
106
+ "Thu",
107
+ "Fri",
108
+ "Sat"
109
+ ], ne = { class: "date-picker-content" }, le = { class: "date-picker-table" }, se = { class: "date-picker-weekdays-row" }, re = { class: "date-picker-days-body" }, oe = ["onClick", "disabled"], ce = /* @__PURE__ */ I({
110
+ __name: "DateView",
111
+ props: {
112
+ currentDate: {},
113
+ selectedDate: {},
114
+ minDate: {},
115
+ maxDate: {},
116
+ disabledDates: {}
117
+ },
118
+ emits: ["select"],
119
+ setup(t, { emit: r }) {
120
+ const e = t, u = r, n = S(() => E(
121
+ e.currentDate.getFullYear(),
122
+ e.currentDate.getMonth()
123
+ ).map((l) => ({
124
+ ...l,
125
+ isSelected: e.selectedDate ? G(l.date, e.selectedDate) : !1,
126
+ isDisabled: ae(
127
+ l.date,
128
+ e.minDate,
129
+ e.maxDate,
130
+ e.disabledDates
131
+ )
132
+ }))), d = S(() => {
133
+ const a = [];
134
+ for (let l = 0; l < n.value.length; l += 7)
135
+ a.push(n.value.slice(l, l + 7));
136
+ return a;
137
+ }), i = (a) => {
138
+ a.isDisabled || u("select", a.date);
139
+ };
140
+ return (a, l) => (v(), p("div", ne, [
141
+ h("table", le, [
142
+ h("thead", null, [
143
+ h("tr", se, [
144
+ (v(!0), p(Y, null, T(o(K), (m) => (v(), p("th", { key: m }, P(m), 1))), 128))
145
+ ])
146
+ ]),
147
+ h("tbody", re, [
148
+ (v(!0), p(Y, null, T(d.value, (m, D) => (v(), p("tr", {
149
+ key: D,
150
+ class: "date-picker-week-row"
151
+ }, [
152
+ (v(!0), p(Y, null, T(m, (s) => (v(), p("td", {
153
+ key: `${s.year}-${s.month}-${s.day}`,
154
+ class: "date-picker-day-cell"
155
+ }, [
156
+ h("button", {
157
+ class: x([
158
+ "date-picker-day",
159
+ {
160
+ "other-month": !s.isCurrentMonth,
161
+ today: s.isToday,
162
+ selected: s.isSelected,
163
+ disabled: s.isDisabled
164
+ }
165
+ ]),
166
+ onClick: (M) => i(s),
167
+ disabled: s.isDisabled
168
+ }, P(s.day), 11, oe)
169
+ ]))), 128))
170
+ ]))), 128))
171
+ ])
172
+ ])
173
+ ]));
174
+ }
175
+ }), ie = { class: "date-picker-content" }, ue = {
176
+ class: "date-picker-table date-picker-week-table",
177
+ cellpadding: "0",
178
+ cellspacing: "0"
179
+ }, de = { class: "date-picker-weekdays-row" }, me = { class: "date-picker-weeks-body" }, ve = ["onClick"], he = { class: "date-picker-week-number-cell" }, pe = { class: "date-picker-week-number" }, ge = /* @__PURE__ */ I({
180
+ __name: "WeekView",
181
+ props: {
182
+ currentDate: {},
183
+ selectedDate: {}
184
+ },
185
+ emits: ["select"],
186
+ setup(t, { emit: r }) {
187
+ const e = t, u = r, n = S(() => te(
188
+ e.currentDate.getFullYear(),
189
+ e.currentDate.getMonth()
190
+ ).map((a) => {
191
+ const l = e.selectedDate ? a.days.some(
192
+ (m) => G(m.date, e.selectedDate)
193
+ ) : !1;
194
+ return {
195
+ ...a,
196
+ isSelected: l
197
+ };
198
+ })), d = (i) => {
199
+ var l;
200
+ const a = ((l = i.days.find((m) => m.isCurrentMonth)) == null ? void 0 : l.date) || i.days[0].date;
201
+ u("select", a);
202
+ };
203
+ return (i, a) => (v(), p("div", ie, [
204
+ h("table", ue, [
205
+ h("thead", null, [
206
+ h("tr", de, [
207
+ a[0] || (a[0] = h("th", { class: "date-picker-weekday date-picker-week-header" }, " Wk ", -1)),
208
+ (v(!0), p(Y, null, T(o(K), (l) => (v(), p("th", { key: l }, P(l), 1))), 128))
209
+ ])
210
+ ]),
211
+ h("tbody", me, [
212
+ (v(!0), p(Y, null, T(n.value, (l) => (v(), p("tr", {
213
+ key: l.weekNumber,
214
+ class: x([
215
+ "date-picker-week-row",
216
+ {
217
+ selected: l.isSelected
218
+ }
219
+ ]),
220
+ onClick: (m) => d(l)
221
+ }, [
222
+ h("td", he, [
223
+ h("div", pe, P(l.weekNumber), 1)
224
+ ]),
225
+ (v(!0), p(Y, null, T(l.days, (m) => (v(), p("td", {
226
+ key: `${m.year}-${m.month}-${m.day}`,
227
+ class: "date-picker-day-cell"
228
+ }, [
229
+ h("button", {
230
+ class: x([
231
+ "date-picker-day",
232
+ {
233
+ "other-month": !m.isCurrentMonth,
234
+ today: m.isToday
235
+ }
236
+ ])
237
+ }, P(m.day), 3)
238
+ ]))), 128))
239
+ ], 10, ve))), 128))
240
+ ])
241
+ ])
242
+ ]));
243
+ }
244
+ });
245
+ function De(t, r = "24h", e = 15, u) {
246
+ const n = F(0), d = F(0), i = F([]), a = S(() => r === "12h"), l = () => {
247
+ if (t)
248
+ n.value = t.getHours(), d.value = t.getMinutes();
249
+ else {
250
+ const c = /* @__PURE__ */ new Date();
251
+ n.value = c.getHours(), d.value = c.getMinutes();
252
+ }
253
+ D();
254
+ }, m = (c) => {
255
+ c && (n.value = c.getHours(), d.value = c.getMinutes());
256
+ }, D = () => {
257
+ const c = [], b = a.value ? 1 : 0;
258
+ for (let y = 0; y < (a.value ? 2 : 1); y++) {
259
+ const C = a.value ? y === 0 ? " AM" : " PM" : "";
260
+ for (let _ = b; _ <= (a.value ? 12 : 23); _++)
261
+ for (let g = 0; g < 60; g += e) {
262
+ const $ = (a.value, _), H = a.value ? _ === 12 ? y === 0 ? 0 : 12 : _ + y * 12 : _, q = `${String($).padStart(
263
+ 2,
264
+ "0"
265
+ )}:${String(g).padStart(2, "0")}` + C;
266
+ c.push({
267
+ display: q,
268
+ value: `${String(H).padStart(2, "0")}:${String(
269
+ g
270
+ ).padStart(2, "0")}`,
271
+ hour: H,
272
+ minute: g
273
+ });
274
+ }
275
+ }
276
+ a.value ? i.value = c.map((y) => y.display) : i.value = c.map((y) => y.value);
277
+ }, s = () => {
278
+ if (a.value) {
279
+ const c = n.value === 0 ? 12 : n.value > 12 ? n.value - 12 : n.value, b = n.value < 12 ? " AM" : " PM";
280
+ return `${String(c).padStart(2, "0")}:${String(
281
+ d.value
282
+ ).padStart(2, "0")}${b}`;
283
+ }
284
+ return `${String(n.value).padStart(2, "0")}:${String(
285
+ d.value
286
+ ).padStart(2, "0")}`;
287
+ };
288
+ return {
289
+ hours: n,
290
+ minutes: d,
291
+ timeOptions: i,
292
+ is12HourFormat: a,
293
+ initializeTime: l,
294
+ updateTime: m,
295
+ generateTimeOptions: D,
296
+ getCurrentTimeString: s,
297
+ selectTime: (c) => {
298
+ let b, y;
299
+ if (a.value) {
300
+ const [_, g] = c.split(" "), [$, H] = _.split(":");
301
+ b = parseInt($), y = parseInt(H), g === "AM" ? b === 12 && (b = 0) : b !== 12 && (b += 12);
302
+ } else {
303
+ const [_, g] = c.split(":");
304
+ b = parseInt(_), y = parseInt(g);
305
+ }
306
+ n.value = b, d.value = y;
307
+ const C = t ? new Date(t.getTime()) : /* @__PURE__ */ new Date();
308
+ C.setHours(b, y, 0, 0), u("update", C);
309
+ },
310
+ scrollToSelected: (c) => {
311
+ if (!c) return;
312
+ const b = i.value.findIndex(
313
+ (y) => y === s()
314
+ );
315
+ if (b >= 0) {
316
+ const C = c.clientHeight, _ = b * 30 - C / 2 + 30 / 2;
317
+ c.scrollTop = Math.max(0, _);
318
+ }
319
+ },
320
+ onTimeUpdate: (c) => {
321
+ n.value = c.getHours(), d.value = c.getMinutes(), u("update", c);
322
+ }
323
+ };
324
+ }
325
+ const ke = { class: "time-picker-container" }, fe = ["aria-selected", "onClick"], J = /* @__PURE__ */ I({
326
+ __name: "TimeView",
327
+ props: {
328
+ selectedTime: {},
329
+ timeFormat: { default: "24h" },
330
+ timeInterval: { default: 15 }
331
+ },
332
+ emits: ["update"],
333
+ setup(t, { emit: r }) {
334
+ const e = t, u = r, n = F(null), {
335
+ timeOptions: d,
336
+ initializeTime: i,
337
+ updateTime: a,
338
+ getCurrentTimeString: l,
339
+ selectTime: m,
340
+ scrollToSelected: D
341
+ } = De(e.selectedTime, e.timeFormat, e.timeInterval, u);
342
+ return L(
343
+ () => e.selectedTime,
344
+ (s) => {
345
+ a(s), B(() => {
346
+ D(n.value);
347
+ });
348
+ },
349
+ { immediate: !0 }
350
+ ), L(
351
+ () => e.timeFormat,
352
+ () => {
353
+ i(), B(() => {
354
+ D(n.value);
355
+ });
356
+ }
357
+ ), L(
358
+ () => e.timeInterval,
359
+ () => {
360
+ i(), B(() => {
361
+ D(n.value);
362
+ });
363
+ }
364
+ ), U(() => {
365
+ i(), B(() => {
366
+ D(n.value);
367
+ });
368
+ }), (s, M) => (v(), p("div", ke, [
369
+ h("div", {
370
+ ref_key: "timeListRef",
371
+ ref: n,
372
+ class: "time-wheel",
373
+ role: "listbox",
374
+ "aria-label": "Time Selection"
375
+ }, [
376
+ (v(!0), p(Y, null, T(o(d), (k) => (v(), p("div", {
377
+ key: k,
378
+ class: x(["time-option", {
379
+ selected: k === o(l)()
380
+ }]),
381
+ role: "option",
382
+ "aria-selected": k === o(l)(),
383
+ onClick: (f) => o(m)(k)
384
+ }, P(k), 11, fe))), 128))
385
+ ], 512)
386
+ ]));
387
+ }
388
+ }), ye = { class: "year-view-layout" }, be = { class: "years-section" }, _e = { class: "years-list" }, Me = ["onClick"], we = { class: "months-section" }, Se = { class: "date-picker-table date-picker-months-table" }, $e = { class: "date-picker-months-body" }, Ye = ["onClick", "disabled"], Te = /* @__PURE__ */ I({
389
+ __name: "YearView",
390
+ props: {
391
+ currentDate: {},
392
+ selectedDate: {}
393
+ },
394
+ emits: ["select", "month-select"],
395
+ setup(t, { emit: r }) {
396
+ const e = t, u = r, n = S(() => e.currentDate.getFullYear()), d = S(() => {
397
+ var s;
398
+ return (s = e.selectedDate) == null ? void 0 : s.getFullYear();
399
+ }), i = S(() => {
400
+ const s = Math.floor(n.value / 10) * 10;
401
+ return Array.from({ length: 12 }, (M, k) => s + k - 1);
402
+ }), a = S(() => j(n.value).map((s) => ({
403
+ ...s,
404
+ isSelected: e.selectedDate ? s.month === e.selectedDate.getMonth() && s.year === e.selectedDate.getFullYear() : !1
405
+ }))), l = S(() => {
406
+ const s = [];
407
+ for (let M = 0; M < a.value.length; M += 3)
408
+ s.push(a.value.slice(M, M + 3));
409
+ return s;
410
+ }), m = (s) => {
411
+ u("select", s);
412
+ }, D = (s) => {
413
+ u("month-select", s.month);
414
+ };
415
+ return (s, M) => (v(), p("div", ye, [
416
+ h("div", be, [
417
+ h("div", _e, [
418
+ (v(!0), p(Y, null, T(i.value, (k) => (v(), p("button", {
419
+ key: k,
420
+ class: x([
421
+ "year-item",
422
+ {
423
+ selected: k === d.value,
424
+ current: k === n.value
425
+ }
426
+ ]),
427
+ onClick: (f) => m(k)
428
+ }, P(k), 11, Me))), 128))
429
+ ])
430
+ ]),
431
+ h("div", we, [
432
+ h("table", Se, [
433
+ h("tbody", $e, [
434
+ (v(!0), p(Y, null, T(l.value, (k, f) => (v(), p("tr", {
435
+ key: f,
436
+ class: "date-picker-months-row"
437
+ }, [
438
+ (v(!0), p(Y, null, T(k, (c) => (v(), p("td", {
439
+ key: c.month,
440
+ class: "date-picker-month-cell"
441
+ }, [
442
+ h("button", {
443
+ class: x([
444
+ "date-picker-month",
445
+ {
446
+ selected: c.isSelected,
447
+ disabled: c.isDisabled
448
+ }
449
+ ]),
450
+ onClick: (b) => D(c),
451
+ disabled: c.isDisabled
452
+ }, P(c.name.substring(0, 3)), 11, Ye)
453
+ ]))), 128))
454
+ ]))), 128))
455
+ ])
456
+ ])
457
+ ])
458
+ ]));
459
+ }
460
+ }), Ce = { class: "date-picker-content" }, He = { class: "date-picker-table date-picker-months-table" }, Pe = { class: "date-picker-months-body" }, Fe = ["onClick", "disabled"], xe = /* @__PURE__ */ I({
461
+ __name: "MonthView",
462
+ props: {
463
+ currentDate: {},
464
+ selectedDate: {}
465
+ },
466
+ emits: ["select"],
467
+ setup(t, { emit: r }) {
468
+ const e = t, u = r, n = S(() => j(e.currentDate.getFullYear()).map((l) => ({
469
+ ...l,
470
+ isSelected: e.selectedDate ? l.month === e.selectedDate.getMonth() && l.year === e.selectedDate.getFullYear() : !1
471
+ }))), d = S(() => {
472
+ const a = [];
473
+ for (let l = 0; l < n.value.length; l += 3)
474
+ a.push(n.value.slice(l, l + 3));
475
+ return a;
476
+ }), i = (a) => {
477
+ u("select", a.month);
478
+ };
479
+ return (a, l) => (v(), p("div", Ce, [
480
+ h("table", He, [
481
+ h("tbody", Pe, [
482
+ (v(!0), p(Y, null, T(d.value, (m, D) => (v(), p("tr", {
483
+ key: D,
484
+ class: "date-picker-months-row"
485
+ }, [
486
+ (v(!0), p(Y, null, T(m, (s) => (v(), p("td", {
487
+ key: s.month,
488
+ class: "date-picker-month-cell"
489
+ }, [
490
+ h("button", {
491
+ class: x([
492
+ "date-picker-month",
493
+ {
494
+ selected: s.isSelected,
495
+ disabled: s.isDisabled
496
+ }
497
+ ]),
498
+ onClick: (M) => i(s),
499
+ disabled: s.isDisabled
500
+ }, P(s.name), 11, Fe)
501
+ ]))), 128))
502
+ ]))), 128))
503
+ ])
504
+ ])
505
+ ]));
506
+ }
507
+ }), Ne = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><g fill="none" fill-rule="evenodd"><path d="M24 0v24H0V0zM12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.019-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"/><path fill="currentColor" d="M8.293 12.707a1 1 0 0 1 0-1.414l5.657-5.657a1 1 0 1 1 1.414 1.414L10.414 12l4.95 4.95a1 1 0 0 1-1.414 1.414z"/></g></svg>', Ie = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><g fill="none" fill-rule="evenodd"><path d="M24 0v24H0V0zM12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.019-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"/><path fill="currentColor" d="M15.707 11.293a1 1 0 0 1 0 1.414l-5.657 5.657a1 1 0 1 1-1.414-1.414l4.95-4.95l-4.95-4.95a1 1 0 0 1 1.414-1.414z"/></g></svg>', Ve = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="M12 18a6 6 0 1 1 0-12a6 6 0 0 1 0 12m0-1.5a4.5 4.5 0 1 0 0-9a4.5 4.5 0 0 0 0 9"/></svg>', Ge = { class: "date-picker-header" }, qe = ["disabled"], ze = ["innerHTML"], Be = ["innerHTML"], Le = ["disabled"], We = ["innerHTML"], Ae = /* @__PURE__ */ I({
508
+ __name: "DatePickerHeader",
509
+ props: {
510
+ currentDate: {},
511
+ viewMode: {},
512
+ canGoPrev: { type: Boolean },
513
+ canGoNext: { type: Boolean }
514
+ },
515
+ emits: ["prev", "next", "header-click", "current-date"],
516
+ setup(t, { emit: r }) {
517
+ const e = t, u = r, n = S(() => {
518
+ const m = e.currentDate.getFullYear(), D = e.currentDate.getMonth();
519
+ switch (e.viewMode) {
520
+ case "date":
521
+ return `${O[D]} ${m}`;
522
+ case "year":
523
+ const s = Math.floor(m / 10) * 10, M = s + 9;
524
+ return `${s}–${M}`;
525
+ default:
526
+ return `${O[D]} ${m}`;
527
+ }
528
+ }), d = () => {
529
+ u("prev");
530
+ }, i = () => {
531
+ u("next");
532
+ }, a = () => {
533
+ u("header-click");
534
+ }, l = () => {
535
+ u("current-date");
536
+ };
537
+ return (m, D) => (v(), p("div", Ge, [
538
+ h("button", {
539
+ class: "date-picker-title",
540
+ onClick: a,
541
+ type: "button"
542
+ }, P(n.value), 1),
543
+ h("button", {
544
+ class: "date-picker-nav-button ml-auto",
545
+ disabled: !m.canGoPrev,
546
+ onClick: d,
547
+ type: "button",
548
+ "aria-label": "Previous"
549
+ }, [
550
+ h("span", {
551
+ class: "date-picker-nav-icon",
552
+ innerHTML: o(Ne)
553
+ }, null, 8, ze)
554
+ ], 8, qe),
555
+ h("button", {
556
+ class: "date-picker-nav-button",
557
+ onClick: l,
558
+ type: "button",
559
+ "aria-label": "Current Date"
560
+ }, [
561
+ h("span", {
562
+ class: "date-picker-nav-icon",
563
+ innerHTML: o(Ve)
564
+ }, null, 8, Be)
565
+ ]),
566
+ h("button", {
567
+ class: "date-picker-nav-button",
568
+ disabled: !m.canGoNext,
569
+ onClick: i,
570
+ type: "button",
571
+ "aria-label": "Next"
572
+ }, [
573
+ h("span", {
574
+ class: "date-picker-nav-icon",
575
+ innerHTML: o(Ie)
576
+ }, null, 8, We)
577
+ ], 8, Le)
578
+ ]));
579
+ }
580
+ });
581
+ function Oe(t, r) {
582
+ const e = F(/* @__PURE__ */ new Date()), u = F("date"), n = S(() => t.value ? t.value instanceof Date ? t.value : W(t.value) : null), d = S(() => {
583
+ if (!t.minDate) return !0;
584
+ const g = W(t.minDate);
585
+ if (!g) return !0;
586
+ const $ = e.value.getFullYear(), H = e.value.getMonth();
587
+ return new Date($, H, 1) > g;
588
+ }), i = S(() => {
589
+ if (!t.maxDate) return !0;
590
+ const g = W(t.maxDate);
591
+ if (!g) return !0;
592
+ const $ = e.value.getFullYear(), H = e.value.getMonth();
593
+ return new Date($, H + 1, 0) < g;
594
+ }), a = () => {
595
+ d.value && (e.value = new Date(
596
+ e.value.getFullYear(),
597
+ e.value.getMonth() - 1,
598
+ 1
599
+ ));
600
+ }, l = () => {
601
+ i.value && (e.value = new Date(
602
+ e.value.getFullYear(),
603
+ e.value.getMonth() + 1,
604
+ 1
605
+ ));
606
+ }, m = () => {
607
+ e.value = new Date(
608
+ e.value.getFullYear() - 1,
609
+ e.value.getMonth(),
610
+ 1
611
+ );
612
+ }, D = () => {
613
+ e.value = new Date(
614
+ e.value.getFullYear() + 1,
615
+ e.value.getMonth(),
616
+ 1
617
+ );
618
+ }, s = () => {
619
+ e.value = new Date(
620
+ e.value.getFullYear() - 10,
621
+ e.value.getMonth(),
622
+ 1
623
+ );
624
+ }, M = () => {
625
+ e.value = new Date(
626
+ e.value.getFullYear() + 10,
627
+ e.value.getMonth(),
628
+ 1
629
+ );
630
+ }, k = () => {
631
+ e.value = /* @__PURE__ */ new Date(), u.value = "date";
632
+ }, f = () => {
633
+ switch (u.value) {
634
+ case "date":
635
+ u.value = "year";
636
+ break;
637
+ case "year":
638
+ u.value = "date";
639
+ break;
640
+ }
641
+ }, c = (g) => {
642
+ t.mode === "dateTime" && n.value && g.setHours(
643
+ n.value.getHours(),
644
+ n.value.getMinutes()
645
+ ), _(g);
646
+ }, b = (g) => {
647
+ _(g);
648
+ }, y = (g) => {
649
+ e.value = new Date(e.value.getFullYear(), g, 1), u.value = "date", t.mode === "month" && _(new Date(e.value.getFullYear(), g, 1));
650
+ }, C = (g) => {
651
+ e.value = new Date(g, e.value.getMonth(), 1), u.value = "date";
652
+ }, _ = (g) => {
653
+ const $ = typeof t.value == "string" ? R(g, t.format) : g;
654
+ r("update:value", $), r("change", $), r("select", $);
655
+ };
656
+ return {
657
+ currentDate: e,
658
+ viewMode: u,
659
+ selectedDate: n,
660
+ canGoPrev: d,
661
+ canGoNext: i,
662
+ goToPrevMonth: a,
663
+ goToNextMonth: l,
664
+ goToPrevYear: m,
665
+ goToNextYear: D,
666
+ goToPrevDecade: s,
667
+ goToNextDecade: M,
668
+ goToCurrentDate: k,
669
+ onHeaderClick: f,
670
+ onDateSelect: c,
671
+ onWeekSelect: b,
672
+ onMonthSelect: y,
673
+ onYearSelect: C,
674
+ emitValue: _
675
+ };
676
+ }
677
+ const Je = { class: "date-picker" }, Ue = {
678
+ key: 0,
679
+ class: "date-picker-time-section"
680
+ }, Ee = /* @__PURE__ */ I({
681
+ __name: "DatePicker",
682
+ props: {
683
+ value: {},
684
+ mode: { default: "date" },
685
+ minDate: {},
686
+ maxDate: {},
687
+ disabledDates: {},
688
+ format: { default: "YYYY-MM-DD" },
689
+ disabled: { type: Boolean },
690
+ readonly: { type: Boolean },
691
+ timeFormat: { default: "24h" },
692
+ timeInterval: { default: 15 }
693
+ },
694
+ emits: ["update:value", "change", "select"],
695
+ setup(t, { emit: r }) {
696
+ const e = t, u = r, n = F(null), d = F(0), {
697
+ currentDate: i,
698
+ viewMode: a,
699
+ selectedDate: l,
700
+ canGoPrev: m,
701
+ canGoNext: D,
702
+ goToPrevMonth: s,
703
+ goToNextMonth: M,
704
+ goToPrevYear: k,
705
+ goToNextYear: f,
706
+ goToPrevDecade: c,
707
+ goToNextDecade: b,
708
+ goToCurrentDate: y,
709
+ onHeaderClick: C,
710
+ onDateSelect: _,
711
+ onWeekSelect: g,
712
+ onMonthSelect: $,
713
+ onYearSelect: H,
714
+ emitValue: A
715
+ } = Oe(e, u), q = (w) => {
716
+ A(w);
717
+ };
718
+ return U(() => {
719
+ n.value && (d.value = n.value.clientHeight);
720
+ }), (w, z) => (v(), p("div", Je, [
721
+ w.mode !== "time" ? (v(), V(Ae, {
722
+ key: 0,
723
+ "current-date": o(i),
724
+ "view-mode": o(a),
725
+ "can-go-prev": o(m),
726
+ "can-go-next": o(D),
727
+ onPrev: z[0] || (z[0] = (Q) => o(a) === "year" ? o(c)() : o(a) === "month" ? o(k)() : o(s)()),
728
+ onNext: z[1] || (z[1] = (Q) => o(a) === "year" ? o(b)() : o(a) === "month" ? o(f)() : o(M)()),
729
+ onHeaderClick: o(C),
730
+ onCurrentDate: o(y)
731
+ }, null, 8, ["current-date", "view-mode", "can-go-prev", "can-go-next", "onHeaderClick", "onCurrentDate"])) : N("", !0),
732
+ h("div", {
733
+ class: x({
734
+ "date-picker-datetime-layout": w.mode === "dateTime" && o(a) === "date"
735
+ }),
736
+ style: X({
737
+ height: d.value !== 0 ? d.value + "px" : "100%"
738
+ })
739
+ }, [
740
+ h("div", {
741
+ class: "date-picker-date-section",
742
+ ref_key: "datePickerContent",
743
+ ref: n
744
+ }, [
745
+ o(a) === "date" && (w.mode === "date" || w.mode === "dateTime") ? (v(), V(ce, {
746
+ key: 0,
747
+ "current-date": o(i),
748
+ "selected-date": o(l),
749
+ "min-date": w.minDate,
750
+ "max-date": w.maxDate,
751
+ "disabled-dates": w.disabledDates,
752
+ onSelect: o(_)
753
+ }, null, 8, ["current-date", "selected-date", "min-date", "max-date", "disabled-dates", "onSelect"])) : N("", !0),
754
+ w.mode === "week" && o(a) === "date" ? (v(), V(ge, {
755
+ key: 1,
756
+ "current-date": o(i),
757
+ "selected-date": o(l),
758
+ onSelect: o(g)
759
+ }, null, 8, ["current-date", "selected-date", "onSelect"])) : N("", !0),
760
+ o(a) !== "year" && (o(a) === "month" || w.mode === "month") ? (v(), V(xe, {
761
+ key: 2,
762
+ "current-date": o(i),
763
+ "selected-date": o(l),
764
+ onSelect: o($)
765
+ }, null, 8, ["current-date", "selected-date", "onSelect"])) : N("", !0),
766
+ o(a) === "year" ? (v(), V(Te, {
767
+ key: 3,
768
+ "current-date": o(i),
769
+ "selected-date": o(l),
770
+ onSelect: o(H),
771
+ onMonthSelect: o($)
772
+ }, null, 8, ["current-date", "selected-date", "onSelect", "onMonthSelect"])) : N("", !0)
773
+ ], 512),
774
+ w.mode === "dateTime" && o(a) === "date" ? (v(), p("div", Ue, [
775
+ Z(J, {
776
+ "selected-time": o(l),
777
+ "time-format": w.timeFormat,
778
+ "time-interval": w.timeInterval,
779
+ onUpdate: q
780
+ }, null, 8, ["selected-time", "time-format", "time-interval"])
781
+ ])) : N("", !0)
782
+ ], 6),
783
+ w.mode === "time" ? (v(), V(J, {
784
+ key: 1,
785
+ "selected-time": o(l),
786
+ "time-format": w.timeFormat,
787
+ "time-interval": w.timeInterval,
788
+ onUpdate: q
789
+ }, null, 8, ["selected-time", "time-format", "time-interval"])) : N("", !0)
790
+ ]));
791
+ }
792
+ });
793
+ export {
794
+ Ee as default
795
+ };
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "v-datepicker-lite",
3
+ "version": "0.0.1",
4
+ "description": "A lightweight Vue 3 date picker with date, time, date-time, week, and month modes",
5
+ "type": "module",
6
+ "author": "safdar-azeem",
7
+ "license": "MIT",
8
+ "main": "index.js",
9
+ "keywords": [
10
+ "vue",
11
+ "vue3",
12
+ "datepicker",
13
+ "date-picker",
14
+ "calendar",
15
+ "timepicker",
16
+ "time-picker",
17
+ "datetime",
18
+ "date-time-picker",
19
+ "week-picker",
20
+ "month-picker",
21
+ "typescript",
22
+ "composition-api",
23
+ "accessible",
24
+ "responsive",
25
+ "ui-component",
26
+ "frontend"
27
+ ],
28
+ "homepage": "https://github.com/safdar-azeem/v-datepicker-lite#readme",
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "git+https://github.com/safdar-azeem/v-datepicker-lite.git"
32
+ },
33
+ "bugs": {
34
+ "url": "https://github.com/safdar-azeem/v-datepicker-lite/issues"
35
+ },
36
+ "files": [
37
+ "dist",
38
+ "src",
39
+ "README.md",
40
+ "LICENSE"
41
+ ],
42
+ "scripts": {
43
+ "dev": "vite",
44
+ "build": "vue-tsc -b && vite build",
45
+ "preview": "vite preview"
46
+ },
47
+ "peerDependencies": {
48
+ "vue": "^3.4.31"
49
+ },
50
+ "devDependencies": {
51
+ "@types/node": "^20.14.10",
52
+ "@types/vue": "^2.0.0",
53
+ "@vitejs/plugin-vue": "^5.0.5",
54
+ "typescript": "^5.2.2",
55
+ "vite": "^5.3.1",
56
+ "vite-plugin-dts": "^3.9.1",
57
+ "vue-tsc": "^2.0.21"
58
+ },
59
+ "engines": {
60
+ "node": ">=16.0.0"
61
+ }
62
+ }