@rushdi94/hijri-datepicker 1.0.1 → 2.0.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 +106 -39
- package/dist/hijri-datepicker.cjs.js +401 -237
- package/dist/hijri-datepicker.cjs.js.map +1 -1
- package/dist/hijri-datepicker.esm.js +396 -238
- package/dist/hijri-datepicker.esm.js.map +1 -1
- package/dist/hijri-datepicker.umd.js +401 -237
- package/dist/hijri-datepicker.umd.js.map +1 -1
- package/dist/types/HijriDatePicker.d.ts +56 -28
- package/dist/types/hijri-calendar.d.ts +11 -0
- package/dist/types/index.d.ts +3 -3
- package/dist/types/styles.d.ts +1 -1
- package/package.json +1 -1
|
@@ -7,8 +7,13 @@ const HIJRI_MONTHS_AR = [
|
|
|
7
7
|
'جمادى الأولى', 'جمادى الآخرة', 'رجب', 'شعبان',
|
|
8
8
|
'رمضان', 'شوال', 'ذو القعدة', 'ذو الحجة',
|
|
9
9
|
];
|
|
10
|
-
|
|
10
|
+
const GREGORIAN_MONTHS_EN = [
|
|
11
|
+
'January', 'February', 'March', 'April', 'May', 'June',
|
|
12
|
+
'July', 'August', 'September', 'October', 'November', 'December',
|
|
13
|
+
];
|
|
14
|
+
// Sunday → Saturday
|
|
11
15
|
const WEEKDAY_AR = ['الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت'];
|
|
16
|
+
const WEEKDAY_EN = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
|
12
17
|
// ── calendar arithmetic ──────────────────────────────────────────────────────
|
|
13
18
|
function gToJDN(y, m, d) {
|
|
14
19
|
const a = Math.floor((14 - m) / 12);
|
|
@@ -59,7 +64,7 @@ function jdnToH(jdn) {
|
|
|
59
64
|
const year = 30 * n + j - 30;
|
|
60
65
|
return [year, month, day];
|
|
61
66
|
}
|
|
62
|
-
// ──
|
|
67
|
+
// ── Hijri helpers ─────────────────────────────────────────────────────────────
|
|
63
68
|
function toHijri(date) {
|
|
64
69
|
const [year, month, day] = jdnToH(gToJDN(date.getFullYear(), date.getMonth() + 1, date.getDate()));
|
|
65
70
|
return { year, month, day };
|
|
@@ -74,7 +79,7 @@ function daysInMonth(year, month) {
|
|
|
74
79
|
return hToJDN(ny, nm, 1) - hToJDN(year, month, 1);
|
|
75
80
|
}
|
|
76
81
|
function firstWeekday(year, month) {
|
|
77
|
-
return toGregorian(year, month, 1).getDay();
|
|
82
|
+
return toGregorian(year, month, 1).getDay();
|
|
78
83
|
}
|
|
79
84
|
function todayHijri() {
|
|
80
85
|
return toHijri(new Date());
|
|
@@ -104,79 +109,80 @@ function parseHijri(value, fmt = 'DD/MM/YYYY') {
|
|
|
104
109
|
return null;
|
|
105
110
|
}
|
|
106
111
|
}
|
|
112
|
+
// ── Gregorian helpers ─────────────────────────────────────────────────────────
|
|
113
|
+
function daysInMonthGregorian(year, month) {
|
|
114
|
+
return new Date(year, month, 0).getDate();
|
|
115
|
+
}
|
|
116
|
+
function firstWeekdayGregorian(year, month) {
|
|
117
|
+
return new Date(year, month - 1, 1).getDay();
|
|
118
|
+
}
|
|
119
|
+
function todayGregorian() {
|
|
120
|
+
const d = new Date();
|
|
121
|
+
return { year: d.getFullYear(), month: d.getMonth() + 1, day: d.getDate() };
|
|
122
|
+
}
|
|
123
|
+
function formatGregorian(g, fmt = 'DD/MM/YYYY') {
|
|
124
|
+
return fmt
|
|
125
|
+
.replace('YYYY', String(g.year))
|
|
126
|
+
.replace('MM', String(g.month).padStart(2, '0'))
|
|
127
|
+
.replace('DD', String(g.day).padStart(2, '0'))
|
|
128
|
+
.replace('M', String(g.month))
|
|
129
|
+
.replace('D', String(g.day));
|
|
130
|
+
}
|
|
107
131
|
|
|
108
132
|
const CSS = /* css */ `
|
|
109
133
|
/* ── HijriDatePicker ─────────────────────────────────────────────────────── */
|
|
110
|
-
.hdp,
|
|
111
|
-
.hdp *,
|
|
112
|
-
.hdp *::before,
|
|
113
|
-
.hdp *::after {
|
|
134
|
+
.hdp, .hdp *, .hdp *::before, .hdp *::after {
|
|
114
135
|
box-sizing: border-box;
|
|
115
136
|
font-family: system-ui, -apple-system, 'Segoe UI', Tahoma, Arial, sans-serif;
|
|
116
137
|
}
|
|
117
138
|
|
|
118
|
-
/* wrapper */
|
|
119
139
|
.hdp-wrapper { position: relative; display: inline-block; }
|
|
120
140
|
|
|
121
|
-
/* input */
|
|
141
|
+
/* ── input ───────────────────────────────────────────────────────────────── */
|
|
122
142
|
.hdp-input-wrap { position: relative; display: block; }
|
|
123
143
|
.hdp-input {
|
|
124
|
-
width: 100%;
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
font-size: 14px;
|
|
129
|
-
cursor: pointer;
|
|
130
|
-
background: #fff;
|
|
131
|
-
outline: none;
|
|
132
|
-
color: #333;
|
|
133
|
-
min-width: 210px;
|
|
144
|
+
width: 100%; padding: 9px 14px 9px 38px;
|
|
145
|
+
border: 1.5px solid #d1d5db; border-radius: 8px;
|
|
146
|
+
font-size: 14px; cursor: pointer; background: #fff;
|
|
147
|
+
outline: none; color: #333; min-width: 210px;
|
|
134
148
|
transition: border-color .2s, box-shadow .2s;
|
|
135
|
-
caret-color: transparent;
|
|
136
|
-
text-align: inherit;
|
|
149
|
+
caret-color: transparent; text-align: inherit;
|
|
137
150
|
}
|
|
138
151
|
[dir="rtl"] .hdp-input { padding: 9px 14px 9px 38px; text-align: right; }
|
|
139
152
|
[dir="ltr"] .hdp-input { padding: 9px 38px 9px 14px; text-align: left; }
|
|
140
153
|
.hdp-input::placeholder { color: #aaa; }
|
|
141
|
-
.hdp-input:focus,
|
|
142
|
-
.hdp-input.open {
|
|
154
|
+
.hdp-input:focus, .hdp-input.open {
|
|
143
155
|
border-color: var(--hdp-primary, #8b1a2e);
|
|
144
156
|
box-shadow: 0 0 0 3px rgba(139,26,46,.14);
|
|
145
157
|
}
|
|
146
158
|
.hdp-input-icon {
|
|
147
|
-
position: absolute;
|
|
148
|
-
|
|
149
|
-
transform: translateY(-50%);
|
|
150
|
-
pointer-events: none;
|
|
151
|
-
color: #9ca3af;
|
|
152
|
-
width: 18px;
|
|
153
|
-
height: 18px;
|
|
159
|
+
position: absolute; top: 50%; transform: translateY(-50%);
|
|
160
|
+
pointer-events: none; color: #9ca3af; width: 18px; height: 18px;
|
|
154
161
|
}
|
|
155
162
|
[dir="rtl"] .hdp-input-icon { left: 10px; right: auto; }
|
|
156
163
|
[dir="ltr"] .hdp-input-icon { right: 10px; left: auto; }
|
|
157
164
|
|
|
158
165
|
/* ── popup ───────────────────────────────────────────────────────────────── */
|
|
159
166
|
.hdp-popup {
|
|
160
|
-
position: absolute;
|
|
161
|
-
|
|
162
|
-
z-index: 99999;
|
|
163
|
-
}
|
|
164
|
-
[dir="rtl"] .hdp-popup { right: 0; left: auto; }
|
|
165
|
-
[dir="ltr"] .hdp-popup { left: 0; right: auto; }
|
|
166
|
-
.hdp-popup {
|
|
167
|
-
width: 312px;
|
|
168
|
-
border-radius: 12px;
|
|
169
|
-
overflow: visible;
|
|
167
|
+
position: absolute; top: calc(100% + 8px); z-index: 99999;
|
|
168
|
+
width: 312px; border-radius: 12px; overflow: visible;
|
|
170
169
|
box-shadow: 0 8px 32px rgba(0,0,0,.18), 0 2px 8px rgba(0,0,0,.08);
|
|
171
170
|
background: var(--hdp-body-bg, #fff);
|
|
172
171
|
animation: _hdpIn .15s cubic-bezier(.2,.8,.4,1);
|
|
173
172
|
}
|
|
173
|
+
[dir="rtl"] .hdp-popup { right: 0; left: auto; }
|
|
174
|
+
[dir="ltr"] .hdp-popup { left: 0; right: auto; }
|
|
175
|
+
@keyframes _hdpIn {
|
|
176
|
+
from { opacity: 0; transform: translateY(-8px) scale(.97); }
|
|
177
|
+
to { opacity: 1; transform: translateY(0) scale(1); }
|
|
178
|
+
}
|
|
179
|
+
.hdp-popup.hdp-inline {
|
|
180
|
+
position: static; box-shadow: 0 2px 16px rgba(0,0,0,.1); animation: none;
|
|
181
|
+
}
|
|
174
182
|
|
|
175
|
-
/*
|
|
183
|
+
/* caret pointing up to input */
|
|
176
184
|
.hdp-popup:not(.hdp-inline)::before {
|
|
177
|
-
content: '';
|
|
178
|
-
position: absolute;
|
|
179
|
-
top: -8px;
|
|
185
|
+
content: ''; position: absolute; top: -8px;
|
|
180
186
|
width: 0; height: 0;
|
|
181
187
|
border-left: 9px solid transparent;
|
|
182
188
|
border-right: 9px solid transparent;
|
|
@@ -185,192 +191,158 @@ const CSS = /* css */ `
|
|
|
185
191
|
}
|
|
186
192
|
[dir="rtl"] .hdp-popup:not(.hdp-inline)::before { right: 18px; left: auto; }
|
|
187
193
|
[dir="ltr"] .hdp-popup:not(.hdp-inline)::before { left: 18px; right: auto; }
|
|
188
|
-
@keyframes _hdpIn {
|
|
189
|
-
from { opacity: 0; transform: translateY(-8px) scale(.97); }
|
|
190
|
-
to { opacity: 1; transform: translateY(0) scale(1); }
|
|
191
|
-
}
|
|
192
|
-
.hdp-popup.hdp-inline {
|
|
193
|
-
position: static;
|
|
194
|
-
box-shadow: 0 2px 16px rgba(0,0,0,.1);
|
|
195
|
-
animation: none;
|
|
196
|
-
}
|
|
197
194
|
|
|
198
195
|
/* ── header ──────────────────────────────────────────────────────────────── */
|
|
199
196
|
.hdp-header {
|
|
200
197
|
background: var(--hdp-primary, #8b1a2e);
|
|
201
198
|
color: var(--hdp-on-primary, #fff);
|
|
202
|
-
|
|
203
|
-
flex-direction: row;
|
|
204
|
-
align-items: stretch;
|
|
205
|
-
height: 44px;
|
|
199
|
+
border-radius: 12px 12px 0 0;
|
|
200
|
+
display: flex; flex-direction: row;
|
|
201
|
+
align-items: stretch; height: 44px;
|
|
206
202
|
user-select: none;
|
|
207
203
|
}
|
|
208
204
|
|
|
209
|
-
/* prev / next month arrows */
|
|
210
205
|
.hdp-nav {
|
|
211
|
-
flex-shrink: 0;
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
background:
|
|
215
|
-
color: var(--hdp-on-primary, #fff);
|
|
216
|
-
cursor: pointer;
|
|
217
|
-
display: flex; align-items: center; justify-content: center;
|
|
218
|
-
font-size: 18px;
|
|
219
|
-
transition: background .15s;
|
|
220
|
-
line-height: 1;
|
|
206
|
+
flex-shrink: 0; width: 32px; border: none;
|
|
207
|
+
background: transparent; color: var(--hdp-on-primary, #fff);
|
|
208
|
+
cursor: pointer; display: flex; align-items: center; justify-content: center;
|
|
209
|
+
font-size: 18px; transition: background .15s; line-height: 1;
|
|
221
210
|
}
|
|
222
211
|
.hdp-nav:hover { background: rgba(255,255,255,.18); }
|
|
223
212
|
|
|
224
|
-
/*
|
|
213
|
+
/* month half */
|
|
225
214
|
.hdp-month-half {
|
|
226
|
-
flex: 1;
|
|
227
|
-
|
|
228
|
-
align-items: center;
|
|
229
|
-
justify-content: center;
|
|
230
|
-
border-right: 1px solid rgba(255,255,255,.2);
|
|
231
|
-
padding: 0 4px;
|
|
232
|
-
min-width: 0;
|
|
215
|
+
flex: 1; display: flex; align-items: center; justify-content: center;
|
|
216
|
+
border-right: 1px solid rgba(255,255,255,.2); padding: 0 4px; min-width: 0;
|
|
233
217
|
}
|
|
234
|
-
|
|
235
218
|
.hdp-month-select {
|
|
236
|
-
width: 100%;
|
|
237
|
-
appearance: none;
|
|
238
|
-
-webkit-appearance: none;
|
|
219
|
+
width: 100%; appearance: none; -webkit-appearance: none;
|
|
239
220
|
background: transparent url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%23ffffff' stroke-width='1.8' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") no-repeat right 8px center;
|
|
240
|
-
border: none;
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
color: var(--hdp-on-primary, #fff);
|
|
244
|
-
cursor: pointer;
|
|
245
|
-
outline: none;
|
|
246
|
-
text-align: center;
|
|
247
|
-
text-align-last: center;
|
|
248
|
-
letter-spacing: .2px;
|
|
249
|
-
}
|
|
250
|
-
[dir="rtl"] .hdp-month-select {
|
|
251
|
-
background-position: left 8px center;
|
|
252
|
-
padding: 6px 10px 6px 26px;
|
|
221
|
+
border: none; padding: 6px 26px 6px 10px;
|
|
222
|
+
font-size: 13px; font-weight: 700; color: var(--hdp-on-primary, #fff);
|
|
223
|
+
cursor: pointer; outline: none; text-align: center; text-align-last: center;
|
|
253
224
|
}
|
|
225
|
+
[dir="rtl"] .hdp-month-select { background-position: left 8px center; padding: 6px 10px 6px 26px; }
|
|
254
226
|
.hdp-month-select:hover { background-color: rgba(255,255,255,.12); border-radius: 6px; }
|
|
255
227
|
.hdp-month-select option { background: #fff; color: #111; font-weight: 600; }
|
|
256
228
|
|
|
257
|
-
/*
|
|
229
|
+
/* year half */
|
|
258
230
|
.hdp-year-half {
|
|
259
|
-
flex: 1;
|
|
260
|
-
|
|
261
|
-
align-items: center;
|
|
262
|
-
justify-content: center;
|
|
263
|
-
padding: 0 6px;
|
|
264
|
-
min-width: 0;
|
|
231
|
+
flex: 1; display: flex; align-items: center; justify-content: center;
|
|
232
|
+
padding: 0 6px; min-width: 0;
|
|
265
233
|
}
|
|
266
|
-
|
|
267
|
-
/* inner wrapper: year number + arrows in a row */
|
|
268
|
-
.hdp-year-inner {
|
|
269
|
-
display: flex;
|
|
270
|
-
align-items: center;
|
|
271
|
-
gap: 3px;
|
|
272
|
-
}
|
|
273
|
-
|
|
234
|
+
.hdp-year-inner { display: flex; align-items: center; gap: 3px; }
|
|
274
235
|
.hdp-year-display {
|
|
275
|
-
font-size: 15px; font-weight: 800;
|
|
276
|
-
|
|
277
|
-
letter-spacing: .4px;
|
|
278
|
-
line-height: 1;
|
|
279
|
-
white-space: nowrap;
|
|
236
|
+
font-size: 15px; font-weight: 800; color: var(--hdp-on-primary, #fff);
|
|
237
|
+
letter-spacing: .4px; line-height: 1; white-space: nowrap;
|
|
280
238
|
}
|
|
281
|
-
|
|
282
|
-
/* arrows: collapsed (width 0) when not hovered, slide in on hover */
|
|
283
239
|
.hdp-year-arrows {
|
|
284
|
-
display: flex;
|
|
285
|
-
|
|
286
|
-
gap: 2px;
|
|
287
|
-
max-width: 0;
|
|
288
|
-
overflow: hidden;
|
|
289
|
-
opacity: 0;
|
|
290
|
-
pointer-events: none;
|
|
240
|
+
display: flex; flex-direction: column; gap: 2px;
|
|
241
|
+
max-width: 0; overflow: hidden; opacity: 0; pointer-events: none;
|
|
291
242
|
transition: max-width .18s ease, opacity .18s ease;
|
|
292
243
|
}
|
|
293
|
-
.hdp-year-half:hover .hdp-year-arrows {
|
|
294
|
-
max-width: 22px;
|
|
295
|
-
opacity: 1;
|
|
296
|
-
pointer-events: auto;
|
|
297
|
-
}
|
|
298
|
-
|
|
244
|
+
.hdp-year-half:hover .hdp-year-arrows { max-width: 22px; opacity: 1; pointer-events: auto; }
|
|
299
245
|
.hdp-year-arrow {
|
|
300
|
-
background: none;
|
|
301
|
-
|
|
302
|
-
color: var(--hdp-on-primary, #fff);
|
|
303
|
-
cursor: pointer;
|
|
304
|
-
width: 18px; height: 13px;
|
|
246
|
+
background: none; border: none; color: var(--hdp-on-primary, #fff);
|
|
247
|
+
cursor: pointer; width: 18px; height: 13px;
|
|
305
248
|
display: flex; align-items: center; justify-content: center;
|
|
306
|
-
font-size: 7px;
|
|
307
|
-
|
|
308
|
-
padding: 0;
|
|
309
|
-
line-height: 1;
|
|
310
|
-
flex-shrink: 0;
|
|
311
|
-
transition: background .12s;
|
|
249
|
+
font-size: 7px; border-radius: 3px; padding: 0; flex-shrink: 0;
|
|
250
|
+
line-height: 1; transition: background .12s;
|
|
312
251
|
}
|
|
313
252
|
.hdp-year-arrow:hover { background: rgba(255,255,255,.25); }
|
|
314
253
|
|
|
254
|
+
/* calendar mode toggle */
|
|
255
|
+
.hdp-mode-btn {
|
|
256
|
+
flex-shrink: 0; background: rgba(255,255,255,.15);
|
|
257
|
+
border: 1px solid rgba(255,255,255,.3); border-radius: 5px;
|
|
258
|
+
color: var(--hdp-on-primary, #fff); cursor: pointer;
|
|
259
|
+
font-size: 11px; font-weight: 800;
|
|
260
|
+
padding: 0 7px; margin: 8px 6px; height: 28px;
|
|
261
|
+
transition: background .15s; line-height: 1; white-space: nowrap;
|
|
262
|
+
}
|
|
263
|
+
.hdp-mode-btn:hover { background: rgba(255,255,255,.3); }
|
|
264
|
+
|
|
315
265
|
/* ── weekday row ─────────────────────────────────────────────────────────── */
|
|
316
266
|
.hdp-weekdays {
|
|
317
|
-
display: grid;
|
|
318
|
-
|
|
319
|
-
background: var(--hdp-primary, #8b1a2e);
|
|
320
|
-
padding: 0 10px 10px;
|
|
267
|
+
display: grid; grid-template-columns: repeat(7, 1fr);
|
|
268
|
+
background: var(--hdp-primary, #8b1a2e); padding: 0 10px 10px;
|
|
321
269
|
}
|
|
322
270
|
.hdp-wday {
|
|
323
|
-
text-align: center;
|
|
324
|
-
font-
|
|
325
|
-
color: var(--hdp-on-primary, #fff);
|
|
326
|
-
opacity: .82;
|
|
327
|
-
font-weight: 500;
|
|
328
|
-
padding: 3px 0;
|
|
271
|
+
text-align: center; font-size: 11.5px; color: var(--hdp-on-primary, #fff);
|
|
272
|
+
opacity: .82; font-weight: 500; padding: 3px 0;
|
|
329
273
|
}
|
|
330
274
|
|
|
331
275
|
/* ── days ────────────────────────────────────────────────────────────────── */
|
|
332
276
|
.hdp-days {
|
|
333
|
-
display: grid;
|
|
334
|
-
|
|
335
|
-
padding: 8px 8px 12px;
|
|
336
|
-
gap: 2px;
|
|
337
|
-
border-radius: 0 0 12px 12px;
|
|
277
|
+
display: grid; grid-template-columns: repeat(7, 1fr);
|
|
278
|
+
padding: 8px 8px 12px; gap: 2px;
|
|
338
279
|
background: var(--hdp-body-bg, #fff);
|
|
339
280
|
}
|
|
340
281
|
.hdp-day {
|
|
341
|
-
aspect-ratio: 1;
|
|
342
|
-
|
|
343
|
-
border-radius: 50%;
|
|
344
|
-
font-size: 13.5px;
|
|
345
|
-
cursor: pointer;
|
|
282
|
+
aspect-ratio: 1; display: flex; align-items: center; justify-content: center;
|
|
283
|
+
border-radius: 50%; font-size: 13.5px; cursor: pointer;
|
|
346
284
|
color: var(--hdp-day-color, #1f2937);
|
|
347
285
|
transition: background .12s, color .12s, transform .08s;
|
|
348
|
-
font-weight: 400;
|
|
349
|
-
border: 2px solid transparent;
|
|
350
|
-
}
|
|
351
|
-
.hdp-day:not(.hdp-empty):hover {
|
|
352
|
-
background: var(--hdp-hover-bg, rgba(139,26,46,.1));
|
|
353
|
-
transform: scale(1.08);
|
|
286
|
+
font-weight: 400; border: 2px solid transparent;
|
|
354
287
|
}
|
|
288
|
+
.hdp-day:not(.hdp-empty):hover { background: var(--hdp-hover-bg); transform: scale(1.08); }
|
|
355
289
|
.hdp-day.hdp-today:not(.hdp-selected) {
|
|
356
|
-
border-color: var(--hdp-primary, #8b1a2e);
|
|
357
|
-
color: var(--hdp-primary, #8b1a2e);
|
|
358
|
-
font-weight: 700;
|
|
290
|
+
border-color: var(--hdp-primary, #8b1a2e); color: var(--hdp-primary, #8b1a2e); font-weight: 700;
|
|
359
291
|
}
|
|
360
292
|
.hdp-day.hdp-selected {
|
|
361
293
|
background: var(--hdp-primary, #8b1a2e) !important;
|
|
362
294
|
color: var(--hdp-on-primary, #fff) !important;
|
|
363
|
-
font-weight: 700;
|
|
364
|
-
border-color: transparent !important;
|
|
365
|
-
transform: scale(1.1);
|
|
295
|
+
font-weight: 700; border-color: transparent !important; transform: scale(1.1);
|
|
366
296
|
}
|
|
367
|
-
.hdp-day.hdp-empty {
|
|
368
|
-
|
|
369
|
-
|
|
297
|
+
.hdp-day.hdp-empty { cursor: default; pointer-events: none; }
|
|
298
|
+
|
|
299
|
+
/* ── time section ────────────────────────────────────────────────────────── */
|
|
300
|
+
.hdp-time-section {
|
|
301
|
+
display: flex; align-items: center; justify-content: center; gap: 6px;
|
|
302
|
+
padding: 10px 16px 14px;
|
|
303
|
+
border-top: 1px solid #f0f0f0;
|
|
304
|
+
background: #f9fafb;
|
|
305
|
+
border-radius: 0 0 12px 12px;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.hdp-spinner {
|
|
309
|
+
display: flex; flex-direction: column; align-items: center; gap: 2px;
|
|
310
|
+
}
|
|
311
|
+
.hdp-spinner-btn {
|
|
312
|
+
background: none; border: none; color: #999; cursor: pointer;
|
|
313
|
+
width: 38px; height: 18px;
|
|
314
|
+
display: flex; align-items: center; justify-content: center;
|
|
315
|
+
font-size: 8px; border-radius: 4px; padding: 0; line-height: 1;
|
|
316
|
+
transition: background .12s, color .12s;
|
|
317
|
+
}
|
|
318
|
+
.hdp-spinner-btn:hover { background: var(--hdp-hover-bg); color: var(--hdp-primary, #8b1a2e); }
|
|
319
|
+
.hdp-spinner-val {
|
|
320
|
+
font-size: 26px; font-weight: 700;
|
|
321
|
+
color: var(--hdp-day-color, #1f2937);
|
|
322
|
+
min-width: 38px; text-align: center; line-height: 1;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
.hdp-time-colon {
|
|
326
|
+
font-size: 24px; font-weight: 700;
|
|
327
|
+
color: var(--hdp-day-color, #1f2937);
|
|
328
|
+
margin-top: 18px; line-height: 1;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
.hdp-ampm {
|
|
332
|
+
display: flex; flex-direction: column; gap: 4px; margin-top: 18px;
|
|
333
|
+
}
|
|
334
|
+
.hdp-ampm-btn {
|
|
335
|
+
background: #e5e7eb; border: none; border-radius: 6px;
|
|
336
|
+
padding: 5px 10px; font-size: 11px; font-weight: 700;
|
|
337
|
+
color: #555; cursor: pointer; transition: background .12s, color .12s;
|
|
370
338
|
}
|
|
339
|
+
.hdp-ampm-btn.hdp-ampm-active {
|
|
340
|
+
background: var(--hdp-primary, #8b1a2e); color: var(--hdp-on-primary, #fff);
|
|
341
|
+
}
|
|
342
|
+
.hdp-ampm-btn:not(.hdp-ampm-active):hover { background: #d1d5db; }
|
|
371
343
|
`;
|
|
372
344
|
|
|
373
|
-
// ── style injection
|
|
345
|
+
// ── style injection ───────────────────────────────────────────────────────────
|
|
374
346
|
let _stylesInjected = false;
|
|
375
347
|
function ensureStyles() {
|
|
376
348
|
if (_stylesInjected || typeof document === 'undefined')
|
|
@@ -381,14 +353,16 @@ function ensureStyles() {
|
|
|
381
353
|
el.textContent = CSS;
|
|
382
354
|
document.head.appendChild(el);
|
|
383
355
|
}
|
|
384
|
-
// ──
|
|
356
|
+
// ── defaults ──────────────────────────────────────────────────────────────────
|
|
385
357
|
const DEFAULT_WEEKDAYS_AR = [...WEEKDAY_AR];
|
|
386
358
|
const DEFAULT_WEEKDAYS_EN = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
|
359
|
+
// ── component ─────────────────────────────────────────────────────────────────
|
|
387
360
|
class HijriDatePicker {
|
|
388
361
|
// ── constructor ────────────────────────────────────────────────────────────
|
|
389
362
|
constructor(options) {
|
|
390
363
|
var _a;
|
|
391
|
-
this.
|
|
364
|
+
this.selectedHijri = null;
|
|
365
|
+
this.selectedGregorian = null;
|
|
392
366
|
// ── event handlers ─────────────────────────────────────────────────────────
|
|
393
367
|
this._onDocClick = (e) => {
|
|
394
368
|
if (!this.root.contains(e.target))
|
|
@@ -405,15 +379,19 @@ class HijriDatePicker {
|
|
|
405
379
|
const defaults = {
|
|
406
380
|
inline: false,
|
|
407
381
|
dir,
|
|
408
|
-
placeholder: dir === 'rtl' ? 'اختر تاريخاً هجرياً' : 'Select
|
|
382
|
+
placeholder: dir === 'rtl' ? 'اختر تاريخاً هجرياً' : 'Select date',
|
|
409
383
|
weekdayLabels: dir === 'rtl' ? DEFAULT_WEEKDAYS_AR : DEFAULT_WEEKDAYS_EN,
|
|
410
384
|
monthLabels: [...HIJRI_MONTHS_AR],
|
|
385
|
+
gregorianMonthLabels: [...GREGORIAN_MONTHS_EN],
|
|
411
386
|
primaryColor: '#8b1a2e',
|
|
412
387
|
onPrimaryColor: '#ffffff',
|
|
413
388
|
bodyBg: '#ffffff',
|
|
414
389
|
dayColor: '#1f2937',
|
|
415
390
|
format: 'DD/MM/YYYY',
|
|
416
391
|
initialDate: today,
|
|
392
|
+
initialMode: 'hijri',
|
|
393
|
+
showTime: false,
|
|
394
|
+
use24h: false,
|
|
417
395
|
editable: false,
|
|
418
396
|
container: options.container,
|
|
419
397
|
onSelect: () => undefined,
|
|
@@ -422,8 +400,19 @@ class HijriDatePicker {
|
|
|
422
400
|
};
|
|
423
401
|
this.opts = { ...defaults, ...options, dir };
|
|
424
402
|
this.isRTL = this.opts.dir === 'rtl';
|
|
425
|
-
this.
|
|
426
|
-
this.
|
|
403
|
+
this.calMode = this.opts.initialMode;
|
|
404
|
+
if (this.calMode === 'hijri') {
|
|
405
|
+
this.viewYear = this.opts.initialDate.year;
|
|
406
|
+
this.viewMonth = this.opts.initialDate.month;
|
|
407
|
+
}
|
|
408
|
+
else {
|
|
409
|
+
const g = todayGregorian();
|
|
410
|
+
this.viewYear = g.year;
|
|
411
|
+
this.viewMonth = g.month;
|
|
412
|
+
}
|
|
413
|
+
this.hour = this.opts.use24h ? 0 : 12;
|
|
414
|
+
this.minute = 0;
|
|
415
|
+
this.ampm = 'AM';
|
|
427
416
|
ensureStyles();
|
|
428
417
|
this._mount();
|
|
429
418
|
}
|
|
@@ -473,8 +462,13 @@ class HijriDatePicker {
|
|
|
473
462
|
if (this.opts.editable) {
|
|
474
463
|
this.inputEl.addEventListener('input', () => {
|
|
475
464
|
const parsed = parseHijri(this.inputEl.value, this.opts.format);
|
|
476
|
-
if (parsed)
|
|
477
|
-
|
|
465
|
+
if (parsed) {
|
|
466
|
+
const gDate = toGregorian(parsed.year, parsed.month, parsed.day);
|
|
467
|
+
const gregorian = {
|
|
468
|
+
year: gDate.getFullYear(), month: gDate.getMonth() + 1, day: gDate.getDate(),
|
|
469
|
+
};
|
|
470
|
+
this._applySelection(parsed, gregorian, false);
|
|
471
|
+
}
|
|
478
472
|
});
|
|
479
473
|
}
|
|
480
474
|
const icon = document.createElement('span');
|
|
@@ -500,38 +494,34 @@ class HijriDatePicker {
|
|
|
500
494
|
popup.style.left = '0';
|
|
501
495
|
}
|
|
502
496
|
popup.setAttribute('role', 'dialog');
|
|
503
|
-
popup.setAttribute('aria-label', this.isRTL ? 'منتقي التاريخ
|
|
497
|
+
popup.setAttribute('aria-label', this.isRTL ? 'منتقي التاريخ' : 'Date Picker');
|
|
504
498
|
popup.appendChild(this._buildHeader());
|
|
505
499
|
popup.appendChild(this._buildWeekdays());
|
|
506
500
|
this.daysGrid = this._buildDaysGrid();
|
|
507
501
|
popup.appendChild(this.daysGrid);
|
|
502
|
+
if (this.opts.showTime) {
|
|
503
|
+
popup.appendChild(this._buildTimeSection());
|
|
504
|
+
}
|
|
508
505
|
return popup;
|
|
509
506
|
}
|
|
510
507
|
// ── header ─────────────────────────────────────────────────────────────────
|
|
511
508
|
_buildHeader() {
|
|
512
509
|
const hdr = document.createElement('div');
|
|
513
510
|
hdr.className = 'hdp-header';
|
|
514
|
-
//
|
|
511
|
+
// Month half (left)
|
|
515
512
|
const monthHalf = document.createElement('div');
|
|
516
513
|
monthHalf.className = 'hdp-month-half';
|
|
517
514
|
this.monthSelectEl = document.createElement('select');
|
|
518
515
|
this.monthSelectEl.className = 'hdp-month-select';
|
|
519
|
-
this.
|
|
520
|
-
this.opts.monthLabels.forEach((name, i) => {
|
|
521
|
-
const opt = document.createElement('option');
|
|
522
|
-
opt.value = String(i + 1);
|
|
523
|
-
opt.textContent = name;
|
|
524
|
-
this.monthSelectEl.appendChild(opt);
|
|
525
|
-
});
|
|
516
|
+
this._rebuildMonthOptions();
|
|
526
517
|
this.monthSelectEl.addEventListener('change', () => {
|
|
527
518
|
this.viewMonth = Number(this.monthSelectEl.value);
|
|
528
519
|
this._renderDays();
|
|
529
520
|
});
|
|
530
521
|
monthHalf.appendChild(this.monthSelectEl);
|
|
531
|
-
//
|
|
522
|
+
// Year half (right)
|
|
532
523
|
const yearHalf = document.createElement('div');
|
|
533
524
|
yearHalf.className = 'hdp-year-half';
|
|
534
|
-
// Inner group: year number + arrows side by side
|
|
535
525
|
const yearInner = document.createElement('div');
|
|
536
526
|
yearInner.className = 'hdp-year-inner';
|
|
537
527
|
this.yearDisplayEl = document.createElement('span');
|
|
@@ -541,31 +531,25 @@ class HijriDatePicker {
|
|
|
541
531
|
const yearUp = document.createElement('button');
|
|
542
532
|
yearUp.className = 'hdp-year-arrow';
|
|
543
533
|
yearUp.innerHTML = '▲';
|
|
544
|
-
yearUp.
|
|
545
|
-
yearUp.addEventListener('click', () => {
|
|
546
|
-
this.viewYear++;
|
|
547
|
-
this._syncHeader();
|
|
548
|
-
this._renderDays();
|
|
549
|
-
});
|
|
534
|
+
yearUp.addEventListener('click', () => { this.viewYear++; this._syncHeader(); this._renderDays(); });
|
|
550
535
|
const yearDown = document.createElement('button');
|
|
551
536
|
yearDown.className = 'hdp-year-arrow';
|
|
552
537
|
yearDown.innerHTML = '▼';
|
|
553
|
-
yearDown.
|
|
554
|
-
yearDown.addEventListener('click', () => {
|
|
555
|
-
this.viewYear--;
|
|
556
|
-
this._syncHeader();
|
|
557
|
-
this._renderDays();
|
|
558
|
-
});
|
|
538
|
+
yearDown.addEventListener('click', () => { this.viewYear--; this._syncHeader(); this._renderDays(); });
|
|
559
539
|
yearArrows.appendChild(yearUp);
|
|
560
540
|
yearArrows.appendChild(yearDown);
|
|
561
541
|
yearInner.appendChild(this.yearDisplayEl);
|
|
562
542
|
yearInner.appendChild(yearArrows);
|
|
563
543
|
yearHalf.appendChild(yearInner);
|
|
564
|
-
//
|
|
544
|
+
// Calendar mode toggle button
|
|
545
|
+
this.modeBtnEl = document.createElement('button');
|
|
546
|
+
this.modeBtnEl.className = 'hdp-mode-btn';
|
|
547
|
+
this.modeBtnEl.addEventListener('click', () => this._switchMode());
|
|
565
548
|
hdr.appendChild(this._navBtn('‹', -1));
|
|
566
549
|
hdr.appendChild(monthHalf);
|
|
567
550
|
hdr.appendChild(yearHalf);
|
|
568
551
|
hdr.appendChild(this._navBtn('›', 1));
|
|
552
|
+
hdr.appendChild(this.modeBtnEl);
|
|
569
553
|
this._syncHeader();
|
|
570
554
|
return hdr;
|
|
571
555
|
}
|
|
@@ -573,13 +557,45 @@ class HijriDatePicker {
|
|
|
573
557
|
const btn = document.createElement('button');
|
|
574
558
|
btn.className = 'hdp-nav';
|
|
575
559
|
btn.innerHTML = symbol;
|
|
576
|
-
btn.setAttribute('aria-label', delta > 0 ? '
|
|
560
|
+
btn.setAttribute('aria-label', delta > 0 ? 'Next month' : 'Previous month');
|
|
577
561
|
btn.addEventListener('click', () => this._navigate(delta));
|
|
578
562
|
return btn;
|
|
579
563
|
}
|
|
580
564
|
_syncHeader() {
|
|
581
565
|
this.monthSelectEl.value = String(this.viewMonth);
|
|
582
566
|
this.yearDisplayEl.textContent = String(this.viewYear);
|
|
567
|
+
this.modeBtnEl.textContent = this.calMode === 'hijri' ? 'G' : 'ه';
|
|
568
|
+
this.modeBtnEl.title = this.calMode === 'hijri' ? 'Switch to Gregorian' : 'Switch to Hijri';
|
|
569
|
+
}
|
|
570
|
+
_rebuildMonthOptions() {
|
|
571
|
+
const labels = this.calMode === 'hijri'
|
|
572
|
+
? this.opts.monthLabels
|
|
573
|
+
: this.opts.gregorianMonthLabels;
|
|
574
|
+
this.monthSelectEl.innerHTML = '';
|
|
575
|
+
labels.forEach((name, i) => {
|
|
576
|
+
const opt = document.createElement('option');
|
|
577
|
+
opt.value = String(i + 1);
|
|
578
|
+
opt.textContent = name;
|
|
579
|
+
this.monthSelectEl.appendChild(opt);
|
|
580
|
+
});
|
|
581
|
+
this.monthSelectEl.value = String(this.viewMonth);
|
|
582
|
+
}
|
|
583
|
+
_switchMode() {
|
|
584
|
+
if (this.calMode === 'hijri') {
|
|
585
|
+
const gDate = toGregorian(this.viewYear, this.viewMonth, 1);
|
|
586
|
+
this.viewYear = gDate.getFullYear();
|
|
587
|
+
this.viewMonth = gDate.getMonth() + 1;
|
|
588
|
+
this.calMode = 'gregorian';
|
|
589
|
+
}
|
|
590
|
+
else {
|
|
591
|
+
const h = toHijri(new Date(this.viewYear, this.viewMonth - 1, 1));
|
|
592
|
+
this.viewYear = h.year;
|
|
593
|
+
this.viewMonth = h.month;
|
|
594
|
+
this.calMode = 'hijri';
|
|
595
|
+
}
|
|
596
|
+
this._rebuildMonthOptions();
|
|
597
|
+
this._syncHeader();
|
|
598
|
+
this._renderDays();
|
|
583
599
|
}
|
|
584
600
|
// ── weekdays ───────────────────────────────────────────────────────────────
|
|
585
601
|
_buildWeekdays() {
|
|
@@ -603,9 +619,15 @@ class HijriDatePicker {
|
|
|
603
619
|
_renderDays(grid) {
|
|
604
620
|
const g = grid !== null && grid !== void 0 ? grid : this.daysGrid;
|
|
605
621
|
g.innerHTML = '';
|
|
606
|
-
const
|
|
607
|
-
const
|
|
608
|
-
const
|
|
622
|
+
const isHijri = this.calMode === 'hijri';
|
|
623
|
+
const todayH = todayHijri();
|
|
624
|
+
const todayG = todayGregorian();
|
|
625
|
+
const total = isHijri
|
|
626
|
+
? daysInMonth(this.viewYear, this.viewMonth)
|
|
627
|
+
: daysInMonthGregorian(this.viewYear, this.viewMonth);
|
|
628
|
+
const start = isHijri
|
|
629
|
+
? firstWeekday(this.viewYear, this.viewMonth)
|
|
630
|
+
: firstWeekdayGregorian(this.viewYear, this.viewMonth);
|
|
609
631
|
for (let i = 0; i < start; i++) {
|
|
610
632
|
const blank = document.createElement('div');
|
|
611
633
|
blank.className = 'hdp-day hdp-empty';
|
|
@@ -617,12 +639,14 @@ class HijriDatePicker {
|
|
|
617
639
|
cell.textContent = String(d);
|
|
618
640
|
cell.setAttribute('role', 'button');
|
|
619
641
|
cell.setAttribute('tabindex', '0');
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
this.
|
|
625
|
-
|
|
642
|
+
const isToday = isHijri
|
|
643
|
+
? (d === todayH.day && this.viewMonth === todayH.month && this.viewYear === todayH.year)
|
|
644
|
+
: (d === todayG.day && this.viewMonth === todayG.month && this.viewYear === todayG.year);
|
|
645
|
+
const isSel = isHijri
|
|
646
|
+
? (this.selectedHijri !== null && d === this.selectedHijri.day &&
|
|
647
|
+
this.viewMonth === this.selectedHijri.month && this.viewYear === this.selectedHijri.year)
|
|
648
|
+
: (this.selectedGregorian !== null && d === this.selectedGregorian.day &&
|
|
649
|
+
this.viewMonth === this.selectedGregorian.month && this.viewYear === this.selectedGregorian.year);
|
|
626
650
|
if (isToday)
|
|
627
651
|
cell.classList.add('hdp-today');
|
|
628
652
|
if (isSel)
|
|
@@ -637,6 +661,78 @@ class HijriDatePicker {
|
|
|
637
661
|
g.appendChild(cell);
|
|
638
662
|
}
|
|
639
663
|
}
|
|
664
|
+
// ── time section ───────────────────────────────────────────────────────────
|
|
665
|
+
_buildTimeSection() {
|
|
666
|
+
const section = document.createElement('div');
|
|
667
|
+
section.className = 'hdp-time-section';
|
|
668
|
+
const { el: hourEl, display: hourDisp } = this._buildSpinner(() => {
|
|
669
|
+
this.hour = this.opts.use24h ? (this.hour + 1) % 24 : (this.hour === 12 ? 1 : this.hour + 1);
|
|
670
|
+
this._syncTime();
|
|
671
|
+
}, () => {
|
|
672
|
+
this.hour = this.opts.use24h ? (this.hour - 1 + 24) % 24 : (this.hour === 1 ? 12 : this.hour - 1);
|
|
673
|
+
this._syncTime();
|
|
674
|
+
});
|
|
675
|
+
this.hourDisplayEl = hourDisp;
|
|
676
|
+
const colon = document.createElement('span');
|
|
677
|
+
colon.className = 'hdp-time-colon';
|
|
678
|
+
colon.textContent = ':';
|
|
679
|
+
const { el: minEl, display: minDisp } = this._buildSpinner(() => { this.minute = (this.minute + 1) % 60; this._syncTime(); }, () => { this.minute = (this.minute - 1 + 60) % 60; this._syncTime(); });
|
|
680
|
+
this.minuteDisplayEl = minDisp;
|
|
681
|
+
section.appendChild(hourEl);
|
|
682
|
+
section.appendChild(colon);
|
|
683
|
+
section.appendChild(minEl);
|
|
684
|
+
if (!this.opts.use24h) {
|
|
685
|
+
const ampm = document.createElement('div');
|
|
686
|
+
ampm.className = 'hdp-ampm';
|
|
687
|
+
const amBtn = document.createElement('button');
|
|
688
|
+
amBtn.className = 'hdp-ampm-btn';
|
|
689
|
+
amBtn.textContent = 'AM';
|
|
690
|
+
amBtn.addEventListener('click', () => { this.ampm = 'AM'; this._syncTime(); });
|
|
691
|
+
const pmBtn = document.createElement('button');
|
|
692
|
+
pmBtn.className = 'hdp-ampm-btn';
|
|
693
|
+
pmBtn.textContent = 'PM';
|
|
694
|
+
pmBtn.addEventListener('click', () => { this.ampm = 'PM'; this._syncTime(); });
|
|
695
|
+
ampm.appendChild(amBtn);
|
|
696
|
+
ampm.appendChild(pmBtn);
|
|
697
|
+
this.ampmContainerEl = ampm;
|
|
698
|
+
section.appendChild(ampm);
|
|
699
|
+
}
|
|
700
|
+
this._syncTime();
|
|
701
|
+
return section;
|
|
702
|
+
}
|
|
703
|
+
_buildSpinner(onUp, onDown) {
|
|
704
|
+
const el = document.createElement('div');
|
|
705
|
+
el.className = 'hdp-spinner';
|
|
706
|
+
const upBtn = document.createElement('button');
|
|
707
|
+
upBtn.className = 'hdp-spinner-btn';
|
|
708
|
+
upBtn.innerHTML = '▲';
|
|
709
|
+
upBtn.addEventListener('click', onUp);
|
|
710
|
+
const display = document.createElement('span');
|
|
711
|
+
display.className = 'hdp-spinner-val';
|
|
712
|
+
const downBtn = document.createElement('button');
|
|
713
|
+
downBtn.className = 'hdp-spinner-btn';
|
|
714
|
+
downBtn.innerHTML = '▼';
|
|
715
|
+
downBtn.addEventListener('click', onDown);
|
|
716
|
+
el.appendChild(upBtn);
|
|
717
|
+
el.appendChild(display);
|
|
718
|
+
el.appendChild(downBtn);
|
|
719
|
+
return { el, display };
|
|
720
|
+
}
|
|
721
|
+
_syncTime() {
|
|
722
|
+
this.hourDisplayEl.textContent = String(this.hour).padStart(2, '0');
|
|
723
|
+
this.minuteDisplayEl.textContent = String(this.minute).padStart(2, '0');
|
|
724
|
+
if (!this.opts.use24h && this.ampmContainerEl) {
|
|
725
|
+
const btns = this.ampmContainerEl.querySelectorAll('.hdp-ampm-btn');
|
|
726
|
+
btns[0].classList.toggle('hdp-ampm-active', this.ampm === 'AM');
|
|
727
|
+
btns[1].classList.toggle('hdp-ampm-active', this.ampm === 'PM');
|
|
728
|
+
}
|
|
729
|
+
if (this.selectedHijri && this.selectedGregorian) {
|
|
730
|
+
const fmt = this._buildFormatted(this.selectedHijri, this.selectedGregorian);
|
|
731
|
+
if (this.inputEl)
|
|
732
|
+
this.inputEl.value = fmt;
|
|
733
|
+
this.opts.onSelect({ hijri: this.selectedHijri, gregorian: this.selectedGregorian, time: { hour: this.hour, minute: this.minute, ampm: this.ampm } }, fmt);
|
|
734
|
+
}
|
|
735
|
+
}
|
|
640
736
|
// ── navigation ─────────────────────────────────────────────────────────────
|
|
641
737
|
_navigate(delta) {
|
|
642
738
|
this.viewMonth += delta;
|
|
@@ -653,21 +749,44 @@ class HijriDatePicker {
|
|
|
653
749
|
}
|
|
654
750
|
// ── selection ──────────────────────────────────────────────────────────────
|
|
655
751
|
_pickDay(day) {
|
|
656
|
-
|
|
752
|
+
let hijri;
|
|
753
|
+
let gregorian;
|
|
754
|
+
if (this.calMode === 'hijri') {
|
|
755
|
+
hijri = { year: this.viewYear, month: this.viewMonth, day };
|
|
756
|
+
const gDate = toGregorian(hijri.year, hijri.month, hijri.day);
|
|
757
|
+
gregorian = { year: gDate.getFullYear(), month: gDate.getMonth() + 1, day: gDate.getDate() };
|
|
758
|
+
}
|
|
759
|
+
else {
|
|
760
|
+
gregorian = { year: this.viewYear, month: this.viewMonth, day };
|
|
761
|
+
hijri = toHijri(new Date(gregorian.year, gregorian.month - 1, gregorian.day));
|
|
762
|
+
}
|
|
763
|
+
this._applySelection(hijri, gregorian, true);
|
|
657
764
|
}
|
|
658
|
-
_applySelection(
|
|
659
|
-
this.
|
|
660
|
-
this.
|
|
661
|
-
this.
|
|
662
|
-
|
|
765
|
+
_applySelection(hijri, gregorian, closeAfter) {
|
|
766
|
+
this.selectedHijri = { ...hijri };
|
|
767
|
+
this.selectedGregorian = { ...gregorian };
|
|
768
|
+
this.viewYear = this.calMode === 'hijri' ? hijri.year : gregorian.year;
|
|
769
|
+
this.viewMonth = this.calMode === 'hijri' ? hijri.month : gregorian.month;
|
|
770
|
+
const fmt = this._buildFormatted(hijri, gregorian);
|
|
663
771
|
if (this.inputEl)
|
|
664
772
|
this.inputEl.value = fmt;
|
|
665
773
|
this._syncHeader();
|
|
666
774
|
this._renderDays();
|
|
667
|
-
this.opts.onSelect(
|
|
668
|
-
if (closeAfter && !this.opts.inline)
|
|
775
|
+
this.opts.onSelect({ hijri, gregorian, time: this.opts.showTime ? { hour: this.hour, minute: this.minute, ampm: this.ampm } : null }, fmt);
|
|
776
|
+
if (closeAfter && !this.opts.inline && !this.opts.showTime)
|
|
669
777
|
this._close();
|
|
670
778
|
}
|
|
779
|
+
_buildFormatted(hijri, gregorian) {
|
|
780
|
+
const dateStr = this.calMode === 'hijri'
|
|
781
|
+
? formatHijri(hijri, this.opts.format)
|
|
782
|
+
: formatGregorian(gregorian, this.opts.format);
|
|
783
|
+
if (!this.opts.showTime)
|
|
784
|
+
return dateStr;
|
|
785
|
+
const hh = String(this.hour).padStart(2, '0');
|
|
786
|
+
const mm = String(this.minute).padStart(2, '0');
|
|
787
|
+
const timeStr = this.opts.use24h ? ` ${hh}:${mm}` : ` ${hh}:${mm} ${this.ampm}`;
|
|
788
|
+
return dateStr + timeStr;
|
|
789
|
+
}
|
|
671
790
|
// ── open / close ───────────────────────────────────────────────────────────
|
|
672
791
|
_open() {
|
|
673
792
|
var _a;
|
|
@@ -686,17 +805,62 @@ class HijriDatePicker {
|
|
|
686
805
|
this.opts.onClose();
|
|
687
806
|
}
|
|
688
807
|
// ── public API ─────────────────────────────────────────────────────────────
|
|
689
|
-
/** Get the currently selected
|
|
808
|
+
/** Get the currently selected date/time value */
|
|
690
809
|
getValue() {
|
|
691
|
-
|
|
810
|
+
if (!this.selectedHijri || !this.selectedGregorian)
|
|
811
|
+
return null;
|
|
812
|
+
return {
|
|
813
|
+
hijri: { ...this.selectedHijri },
|
|
814
|
+
gregorian: { ...this.selectedGregorian },
|
|
815
|
+
time: this.opts.showTime ? { hour: this.hour, minute: this.minute, ampm: this.ampm } : null,
|
|
816
|
+
};
|
|
692
817
|
}
|
|
693
|
-
/**
|
|
818
|
+
/** Set a Hijri date programmatically */
|
|
694
819
|
setValue(date) {
|
|
695
|
-
|
|
820
|
+
const gDate = toGregorian(date.year, date.month, date.day);
|
|
821
|
+
const gregorian = {
|
|
822
|
+
year: gDate.getFullYear(), month: gDate.getMonth() + 1, day: gDate.getDate(),
|
|
823
|
+
};
|
|
824
|
+
if (this.calMode === 'hijri') {
|
|
825
|
+
this.viewYear = date.year;
|
|
826
|
+
this.viewMonth = date.month;
|
|
827
|
+
}
|
|
828
|
+
else {
|
|
829
|
+
this.viewYear = gregorian.year;
|
|
830
|
+
this.viewMonth = gregorian.month;
|
|
831
|
+
}
|
|
832
|
+
this._applySelection(date, gregorian, false);
|
|
833
|
+
}
|
|
834
|
+
/** Set a Gregorian date programmatically */
|
|
835
|
+
setValueGregorian(date) {
|
|
836
|
+
const hijri = toHijri(new Date(date.year, date.month - 1, date.day));
|
|
837
|
+
if (this.calMode === 'gregorian') {
|
|
838
|
+
this.viewYear = date.year;
|
|
839
|
+
this.viewMonth = date.month;
|
|
840
|
+
}
|
|
841
|
+
else {
|
|
842
|
+
this.viewYear = hijri.year;
|
|
843
|
+
this.viewMonth = hijri.month;
|
|
844
|
+
}
|
|
845
|
+
this._applySelection(hijri, date, false);
|
|
846
|
+
}
|
|
847
|
+
/** Set the time programmatically */
|
|
848
|
+
setTime(hour, minute, ampm = 'AM') {
|
|
849
|
+
this.hour = hour;
|
|
850
|
+
this.minute = minute;
|
|
851
|
+
this.ampm = ampm;
|
|
852
|
+
if (this.opts.showTime)
|
|
853
|
+
this._syncTime();
|
|
854
|
+
}
|
|
855
|
+
/** Switch calendar display mode */
|
|
856
|
+
setMode(mode) {
|
|
857
|
+
if (this.calMode !== mode)
|
|
858
|
+
this._switchMode();
|
|
696
859
|
}
|
|
697
860
|
/** Clear the selected date */
|
|
698
861
|
clear() {
|
|
699
|
-
this.
|
|
862
|
+
this.selectedHijri = null;
|
|
863
|
+
this.selectedGregorian = null;
|
|
700
864
|
if (this.inputEl)
|
|
701
865
|
this.inputEl.value = '';
|
|
702
866
|
this._renderDays();
|
|
@@ -714,14 +878,8 @@ class HijriDatePicker {
|
|
|
714
878
|
this._applyVars(this.root);
|
|
715
879
|
this._renderDays();
|
|
716
880
|
}
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
this._open();
|
|
720
|
-
}
|
|
721
|
-
/** Close the picker programmatically */
|
|
722
|
-
close() {
|
|
723
|
-
this._close();
|
|
724
|
-
}
|
|
881
|
+
open() { this._open(); }
|
|
882
|
+
close() { this._close(); }
|
|
725
883
|
/** Remove the picker from the DOM and clean up listeners */
|
|
726
884
|
destroy() {
|
|
727
885
|
document.removeEventListener('click', this._onDocClick, true);
|
|
@@ -730,14 +888,20 @@ class HijriDatePicker {
|
|
|
730
888
|
}
|
|
731
889
|
}
|
|
732
890
|
|
|
891
|
+
exports.GREGORIAN_MONTHS_EN = GREGORIAN_MONTHS_EN;
|
|
733
892
|
exports.HIJRI_MONTHS_AR = HIJRI_MONTHS_AR;
|
|
734
893
|
exports.HijriDatePicker = HijriDatePicker;
|
|
735
894
|
exports.WEEKDAY_AR = WEEKDAY_AR;
|
|
895
|
+
exports.WEEKDAY_EN = WEEKDAY_EN;
|
|
736
896
|
exports.daysInMonth = daysInMonth;
|
|
897
|
+
exports.daysInMonthGregorian = daysInMonthGregorian;
|
|
737
898
|
exports.firstWeekday = firstWeekday;
|
|
899
|
+
exports.firstWeekdayGregorian = firstWeekdayGregorian;
|
|
900
|
+
exports.formatGregorian = formatGregorian;
|
|
738
901
|
exports.formatHijri = formatHijri;
|
|
739
902
|
exports.parseHijri = parseHijri;
|
|
740
903
|
exports.toGregorian = toGregorian;
|
|
741
904
|
exports.toHijri = toHijri;
|
|
905
|
+
exports.todayGregorian = todayGregorian;
|
|
742
906
|
exports.todayHijri = todayHijri;
|
|
743
907
|
//# sourceMappingURL=hijri-datepicker.cjs.js.map
|