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