@idds/js 1.0.37 → 1.0.39

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/dist/index.iife.js +464 -138
  2. package/dist/index.js +304 -185
  3. package/package.json +1 -1
@@ -31,6 +31,7 @@ var InaUI = (() => {
31
31
  initModal: () => initModal,
32
32
  initRangeDatepicker: () => initRangeDatepicker,
33
33
  initTab: () => initTab,
34
+ initTimepicker: () => initTimepicker,
34
35
  initToggle: () => initToggle,
35
36
  showToast: () => showToast
36
37
  });
@@ -120,17 +121,24 @@ var InaUI = (() => {
120
121
  // src/js/components/stateful/datepicker.js
121
122
  function initDatepicker() {
122
123
  document.querySelectorAll(".ina-date-picker").forEach((datepicker) => {
124
+ if (datepicker.dataset.initialized === "true") return;
125
+ datepicker.dataset.initialized = "true";
126
+ const mode = datepicker.dataset.mode || "single";
127
+ const format = datepicker.dataset.format || "d MMMM yyyy";
123
128
  const trigger = datepicker.querySelector(".ina-date-picker__trigger");
124
129
  const triggerText = trigger.querySelector(".ina-date-picker__trigger-text");
125
130
  const panel = datepicker.querySelector(".ina-date-picker__panel");
131
+ panel.style.display = "none";
126
132
  let panelContent = panel.querySelector(".ina-date-picker__panel-content");
127
133
  if (!panelContent) {
128
134
  panelContent = document.createElement("div");
129
135
  panelContent.className = "ina-date-picker__panel-content";
130
136
  panel.appendChild(panelContent);
131
137
  }
132
- let currentDate = /* @__PURE__ */ new Date();
138
+ let viewDate = /* @__PURE__ */ new Date();
133
139
  let selectedDate = null;
140
+ let selectedDates = [];
141
+ let rangeDate = [null, null];
134
142
  let isOpen = false;
135
143
  const MONTHS_ID = [
136
144
  "Januari",
@@ -162,18 +170,67 @@ var InaUI = (() => {
162
170
  ];
163
171
  const DAYS_SHORT = ["Min", "Sen", "Sel", "Rab", "Kam", "Jum", "Sab"];
164
172
  function formatDate(date) {
173
+ if (!date) return "";
165
174
  const day = date.getDate().toString().padStart(2, "0");
166
175
  const monthIndex = date.getMonth();
167
176
  const year = date.getFullYear();
168
177
  return `${day} ${MONTHS_SHORT_ID[monthIndex]} ${year}`;
169
178
  }
170
- function createIcon(name, size = 16) {
171
- if (name === "chevron-left") {
172
- return `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-chevron-left"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M15 6l-6 6l6 6" /></svg>`;
173
- }
174
- if (name === "chevron-right") {
175
- return `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-chevron-right"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M9 6l6 6l-6 6" /></svg>`;
179
+ function updateTrigger() {
180
+ if (mode === "single") {
181
+ if (selectedDate) {
182
+ triggerText.textContent = formatDate(selectedDate);
183
+ triggerText.classList.add("ina-date-picker__trigger-text--value");
184
+ triggerText.classList.remove(
185
+ "ina-date-picker__trigger-text--placeholder"
186
+ );
187
+ } else {
188
+ triggerText.textContent = "Pilih Tanggal";
189
+ triggerText.classList.remove("ina-date-picker__trigger-text--value");
190
+ triggerText.classList.add(
191
+ "ina-date-picker__trigger-text--placeholder"
192
+ );
193
+ }
194
+ } else if (mode === "range") {
195
+ if (rangeDate[0] && rangeDate[1]) {
196
+ const start = formatDate(rangeDate[0]);
197
+ const end = formatDate(rangeDate[1]);
198
+ triggerText.textContent = `${start} - ${end}`;
199
+ triggerText.classList.add("ina-date-picker__trigger-text--value");
200
+ triggerText.classList.remove(
201
+ "ina-date-picker__trigger-text--placeholder"
202
+ );
203
+ } else if (rangeDate[0]) {
204
+ triggerText.textContent = `${formatDate(rangeDate[0])} - ...`;
205
+ triggerText.classList.add("ina-date-picker__trigger-text--value");
206
+ } else {
207
+ triggerText.textContent = "Pilih Rentang Tanggal";
208
+ triggerText.classList.remove("ina-date-picker__trigger-text--value");
209
+ triggerText.classList.add(
210
+ "ina-date-picker__trigger-text--placeholder"
211
+ );
212
+ }
213
+ } else if (mode === "multiple") {
214
+ if (selectedDates.length > 0) {
215
+ triggerText.textContent = `${selectedDates.length} Tanggal Terpilih`;
216
+ triggerText.classList.add("ina-date-picker__trigger-text--value");
217
+ triggerText.classList.remove(
218
+ "ina-date-picker__trigger-text--placeholder"
219
+ );
220
+ } else {
221
+ triggerText.textContent = "Pilih Beberapa Tanggal";
222
+ triggerText.classList.remove("ina-date-picker__trigger-text--value");
223
+ triggerText.classList.add(
224
+ "ina-date-picker__trigger-text--placeholder"
225
+ );
226
+ }
176
227
  }
228
+ }
229
+ function createIcon(name, size = 16) {
230
+ if (name === "chevron-left")
231
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 6l-6 6l6 6" /></svg>`;
232
+ if (name === "chevron-right")
233
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 6l6 6l-6 6" /></svg>`;
177
234
  return "";
178
235
  }
179
236
  function createMonthPicker(initialMonth, onChange) {
@@ -184,16 +241,10 @@ var InaUI = (() => {
184
241
  const pickerTrigger = document.createElement("button");
185
242
  pickerTrigger.type = "button";
186
243
  pickerTrigger.className = "ina-month-picker__trigger ina-month-picker__trigger--size-sm";
187
- const updateTriggerText = () => {
188
- pickerTrigger.innerHTML = `
189
- <span class="ina-month-picker__trigger-text">${MONTHS_SHORT_ID[currentMonthIdx]}</span>
190
- `;
244
+ const updateText = () => {
245
+ pickerTrigger.innerHTML = `<span class="ina-month-picker__trigger-text">${MONTHS_SHORT_ID[currentMonthIdx]}</span>`;
191
246
  };
192
- updateTriggerText();
193
- pickerTrigger.addEventListener("click", (e) => {
194
- e.stopPropagation();
195
- togglePicker(!isPickerOpen);
196
- });
247
+ updateText();
197
248
  const pickerPanel = document.createElement("div");
198
249
  pickerPanel.className = "ina-month-picker__panel";
199
250
  const grid = document.createElement("div");
@@ -208,21 +259,18 @@ var InaUI = (() => {
208
259
  btn.addEventListener("click", (e) => {
209
260
  e.stopPropagation();
210
261
  currentMonthIdx = idx;
211
- updateTriggerText();
212
- grid.querySelectorAll(".ina-month-picker__month-option").forEach((b, i) => {
213
- if (i === idx)
214
- b.classList.add("ina-month-picker__month-option--selected");
215
- else
216
- b.classList.remove("ina-month-picker__month-option--selected");
217
- });
262
+ updateText();
218
263
  togglePicker(false);
219
264
  onChange(idx);
220
265
  });
221
266
  grid.appendChild(btn);
222
267
  });
223
268
  pickerPanel.appendChild(grid);
224
- container.appendChild(pickerTrigger);
225
- container.appendChild(pickerPanel);
269
+ container.append(pickerTrigger, pickerPanel);
270
+ pickerTrigger.addEventListener("click", (e) => {
271
+ e.stopPropagation();
272
+ togglePicker(!isPickerOpen);
273
+ });
226
274
  function togglePicker(show) {
227
275
  isPickerOpen = show;
228
276
  if (show) {
@@ -240,13 +288,7 @@ var InaUI = (() => {
240
288
  element: container,
241
289
  setMonth: (m) => {
242
290
  currentMonthIdx = m;
243
- updateTriggerText();
244
- grid.querySelectorAll(".ina-month-picker__month-option").forEach((b, i) => {
245
- if (i === m)
246
- b.classList.add("ina-month-picker__month-option--selected");
247
- else
248
- b.classList.remove("ina-month-picker__month-option--selected");
249
- });
291
+ updateText();
250
292
  }
251
293
  };
252
294
  }
@@ -259,16 +301,10 @@ var InaUI = (() => {
259
301
  const pickerTrigger = document.createElement("button");
260
302
  pickerTrigger.type = "button";
261
303
  pickerTrigger.className = "ina-year-picker__trigger ina-year-picker__trigger--size-sm";
262
- const updateTriggerText = () => {
263
- pickerTrigger.innerHTML = `
264
- <span class="ina-year-picker__trigger-text">${currentYearVal}</span>
265
- `;
304
+ const updateText = () => {
305
+ pickerTrigger.innerHTML = `<span class="ina-year-picker__trigger-text">${currentYearVal}</span>`;
266
306
  };
267
- updateTriggerText();
268
- pickerTrigger.addEventListener("click", (e) => {
269
- e.stopPropagation();
270
- togglePicker(!isPickerOpen);
271
- });
307
+ updateText();
272
308
  const pickerPanel = document.createElement("div");
273
309
  pickerPanel.className = "ina-year-picker__panel";
274
310
  const header = document.createElement("div");
@@ -309,7 +345,7 @@ var InaUI = (() => {
309
345
  btn.addEventListener("click", (e) => {
310
346
  e.stopPropagation();
311
347
  currentYearVal = y;
312
- updateTriggerText();
348
+ updateText();
313
349
  togglePicker(false);
314
350
  onChange(y);
315
351
  });
@@ -318,16 +354,18 @@ var InaUI = (() => {
318
354
  }
319
355
  pickerPanel.append(header, grid);
320
356
  container.append(pickerTrigger, pickerPanel);
357
+ pickerTrigger.addEventListener("click", (e) => {
358
+ e.stopPropagation();
359
+ togglePicker(!isPickerOpen);
360
+ });
321
361
  function togglePicker(show) {
322
362
  isPickerOpen = show;
323
363
  if (show) {
324
364
  decadeStart = Math.floor(currentYearVal / 20) * 20;
325
365
  renderGrid();
326
366
  pickerPanel.classList.add("ina-year-picker__panel--open");
327
- pickerTrigger.setAttribute("aria-expanded", "true");
328
367
  } else {
329
368
  pickerPanel.classList.remove("ina-year-picker__panel--open");
330
- pickerTrigger.setAttribute("aria-expanded", "false");
331
369
  }
332
370
  }
333
371
  document.addEventListener("click", (e) => {
@@ -337,131 +375,212 @@ var InaUI = (() => {
337
375
  element: container,
338
376
  setYear: (y) => {
339
377
  currentYearVal = y;
340
- updateTriggerText();
378
+ updateText();
341
379
  }
342
380
  };
343
381
  }
344
- function renderCalendar() {
345
- panelContent.innerHTML = "";
346
- const year = currentDate.getFullYear();
347
- const month = currentDate.getMonth();
348
- const calendarContainer = document.createElement("div");
349
- calendarContainer.className = "ina-date-picker__calendar-container";
382
+ function renderCalendarGrid(baseDate, isNextMonth = false) {
383
+ const year = baseDate.getFullYear();
384
+ const month = baseDate.getMonth();
385
+ const container = document.createElement("div");
386
+ if (!isNextMonth) {
387
+ container.className = "ina-date-picker__calendar-container";
388
+ } else {
389
+ container.className = "ina-date-picker__calendar";
390
+ }
350
391
  const header = document.createElement("div");
351
- header.className = "ina-date-picker__calendar-header";
352
- const prevBtn = document.createElement("button");
353
- prevBtn.className = "ina-date-picker__nav-button";
354
- prevBtn.type = "button";
355
- prevBtn.innerHTML = createIcon("chevron-left", 20);
356
- prevBtn.addEventListener("click", (e) => {
357
- e.stopPropagation();
358
- currentDate.setMonth(month - 1);
359
- renderCalendar();
360
- });
361
- const nextBtn = document.createElement("button");
362
- nextBtn.className = "ina-date-picker__nav-button";
363
- nextBtn.type = "button";
364
- nextBtn.innerHTML = createIcon("chevron-right", 20);
365
- nextBtn.addEventListener("click", (e) => {
366
- e.stopPropagation();
367
- currentDate.setMonth(month + 1);
368
- renderCalendar();
369
- });
370
- const controls = document.createElement("div");
371
- controls.className = "ina-date-picker__header-controls";
372
- const monthContainer = document.createElement("div");
373
- monthContainer.className = "ina-date-picker__dropdown-container";
374
- const monthPicker = createMonthPicker(month, (newMonth) => {
375
- currentDate.setMonth(newMonth);
376
- renderCalendar();
377
- });
378
- monthContainer.appendChild(monthPicker.element);
379
- const yearContainer = document.createElement("div");
380
- yearContainer.className = "ina-date-picker__dropdown-container";
381
- const yearPicker = createYearPicker(year, (newYear) => {
382
- currentDate.setFullYear(newYear);
383
- renderCalendar();
384
- });
385
- yearContainer.appendChild(yearPicker.element);
386
- controls.append(monthContainer, yearContainer);
387
- header.append(prevBtn, controls, nextBtn);
392
+ header.className = isNextMonth ? "ina-date-picker__next-month-header" : "ina-date-picker__calendar-header";
393
+ if (!isNextMonth) {
394
+ const prevBtn = document.createElement("button");
395
+ prevBtn.type = "button";
396
+ prevBtn.className = "ina-date-picker__nav-button";
397
+ prevBtn.innerHTML = createIcon("chevron-left");
398
+ prevBtn.onclick = (e) => {
399
+ e.stopPropagation();
400
+ viewDate.setMonth(viewDate.getMonth() - 1);
401
+ render();
402
+ };
403
+ header.appendChild(prevBtn);
404
+ } else {
405
+ const spacer = document.createElement("div");
406
+ spacer.style.width = "32px";
407
+ header.appendChild(spacer);
408
+ }
409
+ if (!isNextMonth) {
410
+ const controls = document.createElement("div");
411
+ controls.className = "ina-date-picker__header-controls";
412
+ const monthCont = document.createElement("div");
413
+ monthCont.className = "ina-date-picker__dropdown-container";
414
+ const monthPicker = createMonthPicker(month, (m) => {
415
+ viewDate.setMonth(m);
416
+ render();
417
+ });
418
+ monthCont.appendChild(monthPicker.element);
419
+ const yearCont = document.createElement("div");
420
+ yearCont.className = "ina-date-picker__dropdown-container";
421
+ const yearPicker = createYearPicker(year, (y) => {
422
+ viewDate.setFullYear(y);
423
+ render();
424
+ });
425
+ yearCont.appendChild(yearPicker.element);
426
+ controls.append(monthCont, yearCont);
427
+ header.appendChild(controls);
428
+ } else {
429
+ const title = document.createElement("div");
430
+ title.className = "ina-date-picker__calendar-title";
431
+ title.textContent = `${MONTHS_ID[month]} ${year}`;
432
+ header.appendChild(title);
433
+ }
434
+ const showNextBtn = mode === "single" && !isNextMonth || isNextMonth;
435
+ if (showNextBtn) {
436
+ const nextBtn = document.createElement("button");
437
+ nextBtn.type = "button";
438
+ nextBtn.className = "ina-date-picker__nav-button";
439
+ nextBtn.innerHTML = createIcon("chevron-right");
440
+ nextBtn.onclick = (e) => {
441
+ e.stopPropagation();
442
+ viewDate.setMonth(viewDate.getMonth() + 1);
443
+ render();
444
+ };
445
+ header.appendChild(nextBtn);
446
+ } else if (!isNextMonth) {
447
+ const spacer = document.createElement("div");
448
+ spacer.style.width = "32px";
449
+ header.appendChild(spacer);
450
+ }
388
451
  const grid = document.createElement("div");
389
452
  grid.className = "ina-date-picker__calendar-grid";
390
- DAYS_SHORT.forEach((day) => {
453
+ DAYS_SHORT.forEach((d) => {
391
454
  const dh = document.createElement("div");
392
455
  dh.className = "ina-date-picker__day-header";
393
- dh.textContent = day;
456
+ dh.textContent = d;
394
457
  grid.appendChild(dh);
395
458
  });
396
459
  const firstDayOfMonth = new Date(year, month, 1).getDay();
397
460
  const daysInMonth = new Date(year, month + 1, 0).getDate();
398
461
  const daysInPrevMonth = new Date(year, month, 0).getDate();
462
+ const today = /* @__PURE__ */ new Date();
399
463
  for (let i = firstDayOfMonth - 1; i >= 0; i--) {
400
- const dayBtn = document.createElement("button");
401
- dayBtn.type = "button";
402
- dayBtn.className = "ina-date-picker__day ina-date-picker__day--other-month ina-date-picker__day--disabled";
403
- dayBtn.textContent = daysInPrevMonth - i;
404
- grid.appendChild(dayBtn);
464
+ const btn = document.createElement("button");
465
+ btn.type = "button";
466
+ btn.className = "ina-date-picker__day ina-date-picker__day--other-month ina-date-picker__day--disabled";
467
+ btn.textContent = daysInPrevMonth - i;
468
+ grid.appendChild(btn);
405
469
  }
406
- const today = /* @__PURE__ */ new Date();
407
470
  for (let i = 1; i <= daysInMonth; i++) {
408
- const dayBtn = document.createElement("button");
409
- dayBtn.type = "button";
410
- dayBtn.className = "ina-date-picker__day";
411
- dayBtn.textContent = i;
471
+ const date = new Date(year, month, i);
472
+ const btn = document.createElement("button");
473
+ btn.type = "button";
474
+ btn.className = "ina-date-picker__day";
475
+ btn.textContent = i;
412
476
  let isSelected = false;
413
- if (selectedDate && selectedDate.getDate() === i && selectedDate.getMonth() === month && selectedDate.getFullYear() === year) {
414
- dayBtn.classList.add("ina-date-picker__day--selected");
415
- isSelected = true;
416
- }
417
- if (today.getDate() === i && today.getMonth() === month && today.getFullYear() === year) {
418
- dayBtn.classList.add("ina-date-picker__day--today");
477
+ let isInRange = false;
478
+ if (mode === "single" && selectedDate) {
479
+ if (date.toDateString() === selectedDate.toDateString())
480
+ isSelected = true;
481
+ } else if (mode === "multiple") {
482
+ if (selectedDates.some((d) => d.toDateString() === date.toDateString()))
483
+ isSelected = true;
484
+ } else if (mode === "range") {
485
+ const [start, end] = rangeDate;
486
+ if (start && date.toDateString() === start.toDateString())
487
+ isSelected = true;
488
+ if (end && date.toDateString() === end.toDateString())
489
+ isSelected = true;
490
+ if (start && end && date > start && date < end) isInRange = true;
419
491
  }
420
- if (!isSelected) {
421
- dayBtn.classList.add("ina-date-picker__day--hover");
422
- }
423
- dayBtn.addEventListener("click", (e) => {
492
+ if (isSelected) btn.classList.add("ina-date-picker__day--selected");
493
+ if (isInRange) btn.classList.add("ina-date-picker__day--in-range");
494
+ if (date.toDateString() === today.toDateString())
495
+ btn.classList.add("ina-date-picker__day--today");
496
+ if (!isSelected && !isInRange)
497
+ btn.classList.add("ina-date-picker__day--hover");
498
+ btn.onclick = (e) => {
424
499
  e.stopPropagation();
425
- selectedDate = new Date(year, month, i);
426
- triggerText.textContent = formatDate(selectedDate);
427
- triggerText.classList.add("ina-date-picker__trigger-text--value");
428
- triggerText.classList.remove(
429
- "ina-date-picker__trigger-text--placeholder"
430
- );
500
+ if (mode === "single") {
501
+ selectedDate = date;
502
+ close();
503
+ } else if (mode === "multiple") {
504
+ const existsIdx = selectedDates.findIndex(
505
+ (d) => d.toDateString() === date.toDateString()
506
+ );
507
+ if (existsIdx >= 0) selectedDates.splice(existsIdx, 1);
508
+ else selectedDates.push(date);
509
+ render();
510
+ } else if (mode === "range") {
511
+ const [start, end] = rangeDate;
512
+ if (!start || start && end) {
513
+ rangeDate = [date, null];
514
+ } else {
515
+ if (date < start) {
516
+ rangeDate = [date, start];
517
+ } else {
518
+ rangeDate = [start, date];
519
+ }
520
+ close();
521
+ }
522
+ render();
523
+ }
524
+ updateTrigger();
431
525
  datepicker.dispatchEvent(
432
- new CustomEvent("date:changed", { detail: { selectedDate } })
526
+ new CustomEvent("date:changed", {
527
+ detail: {
528
+ selectedDate: mode === "single" ? selectedDate : mode === "multiple" ? selectedDates : rangeDate
529
+ }
530
+ })
433
531
  );
434
- toggle(false);
435
- });
436
- grid.appendChild(dayBtn);
532
+ };
533
+ grid.appendChild(btn);
437
534
  }
438
- const currentCells = grid.children.length - 7;
439
- const remaining = 42 - currentCells;
535
+ const usedCells = grid.children.length - 7;
536
+ const remaining = 42 - usedCells;
440
537
  for (let i = 1; i <= remaining; i++) {
441
- const dayBtn = document.createElement("button");
442
- dayBtn.type = "button";
443
- dayBtn.className = "ina-date-picker__day ina-date-picker__day--other-month ina-date-picker__day--disabled";
444
- dayBtn.textContent = i;
445
- grid.appendChild(dayBtn);
538
+ const btn = document.createElement("button");
539
+ btn.type = "button";
540
+ btn.className = "ina-date-picker__day ina-date-picker__day--other-month ina-date-picker__day--disabled";
541
+ btn.textContent = i;
542
+ grid.appendChild(btn);
446
543
  }
447
- calendarContainer.append(header, grid);
448
- panelContent.appendChild(calendarContainer);
544
+ container.append(header, grid);
545
+ return container;
449
546
  }
450
- function toggle(show) {
451
- isOpen = show;
452
- if (show) {
453
- panel.classList.add("ina-date-picker__panel--open");
454
- renderCalendar();
455
- } else {
456
- panel.classList.remove("ina-date-picker__panel--open");
547
+ function render() {
548
+ panelContent.innerHTML = "";
549
+ const cal1 = renderCalendarGrid(viewDate);
550
+ panelContent.appendChild(cal1);
551
+ if (mode === "range" || mode === "multiple") {
552
+ const nextMonthDate = new Date(
553
+ viewDate.getFullYear(),
554
+ viewDate.getMonth() + 1,
555
+ 1
556
+ );
557
+ const cal2 = renderCalendarGrid(nextMonthDate, true);
558
+ panelContent.appendChild(cal2);
457
559
  }
458
560
  }
561
+ function open() {
562
+ isOpen = true;
563
+ panel.classList.add("ina-date-picker__panel--open");
564
+ panel.style.display = "block";
565
+ render();
566
+ }
567
+ function close() {
568
+ isOpen = false;
569
+ panel.classList.remove("ina-date-picker__panel--open");
570
+ panel.style.display = "none";
571
+ }
572
+ function toggle() {
573
+ if (isOpen) close();
574
+ else open();
575
+ }
459
576
  trigger.addEventListener("click", (e) => {
460
577
  e.stopPropagation();
461
- toggle(!isOpen);
578
+ toggle();
462
579
  });
463
580
  document.addEventListener("click", (e) => {
464
- if (!datepicker.contains(e.target)) toggle(false);
581
+ if (!datepicker.contains(e.target)) {
582
+ close();
583
+ }
465
584
  });
466
585
  });
467
586
  }
@@ -886,6 +1005,212 @@ var InaUI = (() => {
886
1005
  });
887
1006
  }
888
1007
 
1008
+ // src/js/components/stateful/timepicker.js
1009
+ function initTimepicker() {
1010
+ document.querySelectorAll(".ina-time-picker").forEach((picker) => {
1011
+ if (picker.dataset.initialized === "true") return;
1012
+ picker.dataset.initialized = "true";
1013
+ const input = picker.querySelector(".ina-time-picker__input");
1014
+ const wrapper = picker.querySelector(".ina-time-picker__wrapper");
1015
+ if (!input || !wrapper) return;
1016
+ const format = picker.dataset.format || "HH:mm";
1017
+ const use12Hours = picker.dataset.use12Hours === "true";
1018
+ const showSecond = picker.dataset.showSecond === "true";
1019
+ const disabled = picker.classList.contains("ina-time-picker--disabled");
1020
+ const allowClear = picker.dataset.allowClear !== "false";
1021
+ let isOpen = false;
1022
+ let internalValue = input.value || "";
1023
+ let panel = picker.querySelector(".ina-time-picker__panel");
1024
+ if (!panel) {
1025
+ panel = document.createElement("div");
1026
+ panel.className = "ina-time-picker__panel";
1027
+ panel.style.display = "none";
1028
+ picker.appendChild(panel);
1029
+ }
1030
+ let content = panel.querySelector(".ina-time-picker__content");
1031
+ if (!content) {
1032
+ content = document.createElement("div");
1033
+ content.className = "ina-time-picker__content";
1034
+ panel.appendChild(content);
1035
+ } else {
1036
+ content.innerHTML = "";
1037
+ }
1038
+ let actions = panel.querySelector(".ina-time-picker__actions");
1039
+ if (!actions) {
1040
+ actions = document.createElement("div");
1041
+ actions.className = "ina-time-picker__actions";
1042
+ const confirmBtn = document.createElement("button");
1043
+ confirmBtn.type = "button";
1044
+ confirmBtn.className = "ina-time-picker__confirm-button";
1045
+ confirmBtn.textContent = "Pilih";
1046
+ confirmBtn.onclick = (e) => {
1047
+ e.stopPropagation();
1048
+ close();
1049
+ };
1050
+ actions.appendChild(confirmBtn);
1051
+ panel.appendChild(actions);
1052
+ }
1053
+ const parseTime = (timeStr) => {
1054
+ if (!timeStr) return { hours: 0, minutes: 0, seconds: 0, period: "AM" };
1055
+ let hours = 0, minutes = 0, seconds = 0, period = "AM";
1056
+ try {
1057
+ if (use12Hours) {
1058
+ const [time, p] = timeStr.split(" ");
1059
+ const [h, m, s] = time.split(":");
1060
+ hours = parseInt(h || "0", 10);
1061
+ minutes = parseInt(m || "0", 10);
1062
+ seconds = parseInt(s || "0", 10);
1063
+ period = p || "AM";
1064
+ } else {
1065
+ const [h, m, s] = timeStr.split(":");
1066
+ hours = parseInt(h || "0", 10);
1067
+ minutes = parseInt(m || "0", 10);
1068
+ seconds = parseInt(s || "0", 10);
1069
+ }
1070
+ } catch (e) {
1071
+ console.warn("Invalid time format", timeStr);
1072
+ }
1073
+ return { hours, minutes, seconds, period };
1074
+ };
1075
+ const formatTime = (h, m, s, p) => {
1076
+ const pad = (n) => n.toString().padStart(2, "0");
1077
+ if (use12Hours) {
1078
+ let displayHours = h;
1079
+ if (displayHours === 0) displayHours = 12;
1080
+ const main = `${pad(displayHours)}:${pad(m)}`;
1081
+ const sec = showSecond ? `:${pad(s)}` : "";
1082
+ return `${main}${sec} ${p}`;
1083
+ } else {
1084
+ const main = `${pad(h)}:${pad(m)}`;
1085
+ const sec = showSecond ? `:${pad(s)}` : "";
1086
+ return `${main}${sec}`;
1087
+ }
1088
+ };
1089
+ let currentTime = parseTime(internalValue);
1090
+ const renderColumn = (type, max) => {
1091
+ const column = document.createElement("div");
1092
+ column.className = `ina-time-picker__column ina-time-picker__column--${type}`;
1093
+ const colContent = document.createElement("div");
1094
+ colContent.className = "ina-time-picker__column-content";
1095
+ column.appendChild(colContent);
1096
+ const start = type === "hour" && use12Hours ? 1 : 0;
1097
+ const end = type === "hour" && use12Hours ? 12 : max - 1;
1098
+ for (let i = start; i <= end; i++) {
1099
+ const option = document.createElement("div");
1100
+ option.className = "ina-time-picker__option";
1101
+ option.textContent = i.toString().padStart(2, "0");
1102
+ option.dataset.value = i;
1103
+ let isSelected = false;
1104
+ if (type === "hour") {
1105
+ isSelected = currentTime.hours === i || use12Hours && currentTime.hours === 0 && i === 12;
1106
+ } else if (type === "minute") isSelected = currentTime.minutes === i;
1107
+ else if (type === "second") isSelected = currentTime.seconds === i;
1108
+ if (isSelected)
1109
+ option.classList.add("ina-time-picker__option--selected");
1110
+ option.addEventListener("click", (e) => {
1111
+ e.stopPropagation();
1112
+ const val = parseInt(option.dataset.value, 10);
1113
+ if (type === "hour")
1114
+ currentTime.hours = use12Hours && val === 12 ? 0 : val;
1115
+ if (type === "hour") currentTime.hours = val;
1116
+ if (type === "minute") currentTime.minutes = val;
1117
+ if (type === "second") currentTime.seconds = val;
1118
+ updateInput();
1119
+ colContent.querySelectorAll(".ina-time-picker__option").forEach(
1120
+ (el) => el.classList.remove("ina-time-picker__option--selected")
1121
+ );
1122
+ option.classList.add("ina-time-picker__option--selected");
1123
+ });
1124
+ colContent.appendChild(option);
1125
+ }
1126
+ return column;
1127
+ };
1128
+ const renderPeriodColumn = () => {
1129
+ const column = document.createElement("div");
1130
+ column.className = `ina-time-picker__column ina-time-picker__column--period`;
1131
+ const colContent = document.createElement("div");
1132
+ colContent.className = "ina-time-picker__column-content";
1133
+ column.appendChild(colContent);
1134
+ ["AM", "PM"].forEach((p) => {
1135
+ const option = document.createElement("div");
1136
+ option.className = "ina-time-picker__option";
1137
+ option.textContent = p;
1138
+ if (currentTime.period === p)
1139
+ option.classList.add("ina-time-picker__option--selected");
1140
+ option.addEventListener("click", (e) => {
1141
+ e.stopPropagation();
1142
+ currentTime.period = p;
1143
+ updateInput();
1144
+ colContent.querySelectorAll(".ina-time-picker__option").forEach(
1145
+ (el) => el.classList.remove("ina-time-picker__option--selected")
1146
+ );
1147
+ option.classList.add("ina-time-picker__option--selected");
1148
+ });
1149
+ colContent.appendChild(option);
1150
+ });
1151
+ return column;
1152
+ };
1153
+ const updateInput = () => {
1154
+ const val = formatTime(
1155
+ currentTime.hours,
1156
+ currentTime.minutes,
1157
+ currentTime.seconds,
1158
+ currentTime.period
1159
+ );
1160
+ input.value = val;
1161
+ picker.dataset.value = val;
1162
+ input.dispatchEvent(new Event("change", { bubbles: true }));
1163
+ };
1164
+ const buildPanel = () => {
1165
+ content.innerHTML = "";
1166
+ content.appendChild(renderColumn("hour", use12Hours ? 13 : 24));
1167
+ content.appendChild(renderColumn("minute", 60));
1168
+ if (showSecond) content.appendChild(renderColumn("second", 60));
1169
+ if (use12Hours) content.appendChild(renderPeriodColumn());
1170
+ };
1171
+ const open = () => {
1172
+ if (disabled) return;
1173
+ isOpen = true;
1174
+ picker.classList.add("ina-time-picker--open");
1175
+ panel.style.display = "block";
1176
+ currentTime = parseTime(input.value);
1177
+ buildPanel();
1178
+ document.dispatchEvent(
1179
+ new CustomEvent("closeTimePicker", { detail: { exclude: picker } })
1180
+ );
1181
+ };
1182
+ const close = () => {
1183
+ isOpen = false;
1184
+ picker.classList.remove("ina-time-picker--open");
1185
+ panel.style.display = "none";
1186
+ };
1187
+ const toggle = (e) => {
1188
+ e.stopPropagation();
1189
+ if (isOpen) close();
1190
+ else open();
1191
+ };
1192
+ wrapper.addEventListener("click", toggle);
1193
+ input.addEventListener("click", (e) => {
1194
+ });
1195
+ document.addEventListener("click", (e) => {
1196
+ if (!picker.contains(e.target)) close();
1197
+ });
1198
+ document.addEventListener("closeTimePicker", (e) => {
1199
+ if (e.detail && e.detail.exclude !== picker) close();
1200
+ });
1201
+ const clearBtn = picker.querySelector(".ina-time-picker__clear-button");
1202
+ if (clearBtn && allowClear) {
1203
+ clearBtn.addEventListener("click", (e) => {
1204
+ e.stopPropagation();
1205
+ input.value = "";
1206
+ currentTime = { hours: 0, minutes: 0, seconds: 0, period: "AM" };
1207
+ picker.dataset.value = "";
1208
+ input.dispatchEvent(new Event("change", { bubbles: true }));
1209
+ });
1210
+ }
1211
+ });
1212
+ }
1213
+
889
1214
  // src/js/index.js
890
1215
  var PREFIX = "ina-ss";
891
1216
 
@@ -1363,6 +1688,7 @@ var InaUI = (() => {
1363
1688
  initModal();
1364
1689
  initRangeDatepicker();
1365
1690
  initTab();
1691
+ initTimepicker();
1366
1692
  initToggle();
1367
1693
  });
1368
1694
  }