@idds/js 1.0.36 → 1.0.38

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 +513 -238
  2. package/dist/index.js +411 -333
  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,10 +121,19 @@ var InaUI = (() => {
120
121
  // src/js/components/stateful/datepicker.js
121
122
  function initDatepicker() {
122
123
  document.querySelectorAll(".ina-date-picker").forEach((datepicker) => {
124
+ const trigger = datepicker.querySelector(".ina-date-picker__trigger");
125
+ const triggerText = trigger.querySelector(".ina-date-picker__trigger-text");
126
+ const panel = datepicker.querySelector(".ina-date-picker__panel");
127
+ let panelContent = panel.querySelector(".ina-date-picker__panel-content");
128
+ if (!panelContent) {
129
+ panelContent = document.createElement("div");
130
+ panelContent.className = "ina-date-picker__panel-content";
131
+ panel.appendChild(panelContent);
132
+ }
123
133
  let currentDate = /* @__PURE__ */ new Date();
124
- let selectedDateTarget = null;
125
134
  let selectedDate = null;
126
- const MONTHS = [
135
+ let isOpen = false;
136
+ const MONTHS_ID = [
127
137
  "Januari",
128
138
  "Februari",
129
139
  "Maret",
@@ -137,267 +147,325 @@ var InaUI = (() => {
137
147
  "November",
138
148
  "Desember"
139
149
  ];
140
- const DAYS = ["Min", "Sen", "Sel", "Rab", "Kam", "Jum", "Sab"];
141
- const datepickerTrigger = datepicker.querySelector(
142
- ".ina-date-picker__trigger"
143
- );
144
- const datepickerPopover = datepicker.querySelector(
145
- ".ina-date-picker__popover"
146
- );
147
- const datepickerMonthTrigger = datepicker.querySelector(
148
- ".ina-date-picker__month-trigger"
149
- );
150
- const datepickerMonthPopover = datepicker.querySelector(
151
- ".ina-date-picker__month-popover"
152
- );
153
- const datepickerMonthItem = datepicker.querySelectorAll(
154
- ".ina-date-picker__month-item"
155
- );
156
- const datepickerYearTrigger = datepicker.querySelector(
157
- ".ina-date-picker__year-trigger"
158
- );
159
- const datepickerYearPopover = datepicker.querySelector(
160
- ".ina-date-picker__year-popover"
161
- );
162
- const datepickerYearPrevButton = datepicker.querySelector(
163
- ".ina-date-picker__year-nav-prev"
164
- );
165
- const datepickerYearCurrent = datepicker.querySelector(
166
- ".ina-date-picker__year-current"
167
- );
168
- const datepickerYearNextButton = datepicker.querySelector(
169
- ".ina-date-picker__year-nav-next"
170
- );
171
- const datepickerYearContent = datepicker.querySelector(
172
- ".ina-date-picker__year-content"
173
- );
174
- const datepickerYearItem = datepicker.querySelectorAll(
175
- ".ina-date-picker__year-item"
176
- );
177
- const datepickerContent = datepicker.querySelector(
178
- ".ina-date-picker__content"
179
- );
180
- const prevMonthButton = datepicker.querySelector(
181
- ".ina-date-picker__nav-prev"
182
- );
183
- const nextMonthButton = datepicker.querySelector(
184
- ".ina-date-picker__nav-next"
185
- );
186
- const datepickerSubmitButton = datepicker.querySelector(
187
- ".ina-date-picker__submit"
188
- );
189
- function renderYear(startYear, endYear) {
190
- datepickerYearContent.innerHTML = "";
191
- datepickerYearCurrent.textContent = `${startYear} - ${endYear}`;
192
- for (let y = startYear; y <= endYear; y++) {
193
- const yearEl = document.createElement("button");
194
- yearEl.className = "ina-date-picker__year-item";
195
- yearEl.textContent = y;
196
- yearEl.dataset.year = y;
197
- if (y === currentDate.getFullYear()) {
198
- yearEl.classList.add("selected");
150
+ const MONTHS_SHORT_ID = [
151
+ "Jan",
152
+ "Feb",
153
+ "Mar",
154
+ "Apr",
155
+ "Mei",
156
+ "Jun",
157
+ "Jul",
158
+ "Agu",
159
+ "Sep",
160
+ "Okt",
161
+ "Nov",
162
+ "Des"
163
+ ];
164
+ const DAYS_SHORT = ["Min", "Sen", "Sel", "Rab", "Kam", "Jum", "Sab"];
165
+ function formatDate(date) {
166
+ const day = date.getDate().toString().padStart(2, "0");
167
+ const monthIndex = date.getMonth();
168
+ const year = date.getFullYear();
169
+ return `${day} ${MONTHS_SHORT_ID[monthIndex]} ${year}`;
170
+ }
171
+ function createIcon(name, size = 16) {
172
+ if (name === "chevron-left") {
173
+ 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>`;
174
+ }
175
+ if (name === "chevron-right") {
176
+ 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>`;
177
+ }
178
+ return "";
179
+ }
180
+ function createMonthPicker(initialMonth, onChange) {
181
+ const container = document.createElement("div");
182
+ container.className = "ina-month-picker";
183
+ let currentMonthIdx = initialMonth;
184
+ let isPickerOpen = false;
185
+ const pickerTrigger = document.createElement("button");
186
+ pickerTrigger.type = "button";
187
+ pickerTrigger.className = "ina-month-picker__trigger ina-month-picker__trigger--size-sm";
188
+ const updateTriggerText = () => {
189
+ pickerTrigger.innerHTML = `
190
+ <span class="ina-month-picker__trigger-text">${MONTHS_SHORT_ID[currentMonthIdx]}</span>
191
+ `;
192
+ };
193
+ updateTriggerText();
194
+ pickerTrigger.addEventListener("click", (e) => {
195
+ e.stopPropagation();
196
+ togglePicker(!isPickerOpen);
197
+ });
198
+ const pickerPanel = document.createElement("div");
199
+ pickerPanel.className = "ina-month-picker__panel";
200
+ const grid = document.createElement("div");
201
+ grid.className = "ina-month-picker__grid";
202
+ MONTHS_SHORT_ID.forEach((m, idx) => {
203
+ const btn = document.createElement("button");
204
+ btn.type = "button";
205
+ btn.className = "ina-month-picker__month-option";
206
+ if (idx === currentMonthIdx)
207
+ btn.classList.add("ina-month-picker__month-option--selected");
208
+ btn.textContent = m;
209
+ btn.addEventListener("click", (e) => {
210
+ e.stopPropagation();
211
+ currentMonthIdx = idx;
212
+ updateTriggerText();
213
+ grid.querySelectorAll(".ina-month-picker__month-option").forEach((b, i) => {
214
+ if (i === idx)
215
+ b.classList.add("ina-month-picker__month-option--selected");
216
+ else
217
+ b.classList.remove("ina-month-picker__month-option--selected");
218
+ });
219
+ togglePicker(false);
220
+ onChange(idx);
221
+ });
222
+ grid.appendChild(btn);
223
+ });
224
+ pickerPanel.appendChild(grid);
225
+ container.appendChild(pickerTrigger);
226
+ container.appendChild(pickerPanel);
227
+ function togglePicker(show) {
228
+ isPickerOpen = show;
229
+ if (show) {
230
+ pickerPanel.classList.add("ina-month-picker__panel--open");
231
+ pickerTrigger.setAttribute("aria-expanded", "true");
232
+ } else {
233
+ pickerPanel.classList.remove("ina-month-picker__panel--open");
234
+ pickerTrigger.setAttribute("aria-expanded", "false");
199
235
  }
200
- datepickerYearContent.appendChild(yearEl);
201
236
  }
237
+ document.addEventListener("click", (e) => {
238
+ if (!container.contains(e.target)) togglePicker(false);
239
+ });
240
+ return {
241
+ element: container,
242
+ setMonth: (m) => {
243
+ currentMonthIdx = m;
244
+ updateTriggerText();
245
+ grid.querySelectorAll(".ina-month-picker__month-option").forEach((b, i) => {
246
+ if (i === m)
247
+ b.classList.add("ina-month-picker__month-option--selected");
248
+ else
249
+ b.classList.remove("ina-month-picker__month-option--selected");
250
+ });
251
+ }
252
+ };
202
253
  }
203
- function renderCalendar(year, month) {
204
- datepickerContent.innerHTML = "";
205
- datepickerMonthTrigger.textContent = MONTHS[month].substring(0, 3);
206
- datepickerYearTrigger.textContent = year;
207
- DAYS.forEach((day) => {
208
- const dayNameWrapper = document.createElement("div");
209
- dayNameWrapper.className = "ina-date-picker__dayname-wrapper";
210
- const dayNameEl = document.createElement("span");
211
- dayNameEl.className = "ina-date-picker__dayname";
212
- dayNameEl.textContent = day.substring(0, 3);
213
- dayNameWrapper.appendChild(dayNameEl);
214
- datepickerContent.appendChild(dayNameWrapper);
254
+ function createYearPicker(initialYear, onChange) {
255
+ const container = document.createElement("div");
256
+ container.className = "ina-year-picker";
257
+ let currentYearVal = initialYear;
258
+ let isPickerOpen = false;
259
+ let decadeStart = Math.floor(initialYear / 20) * 20;
260
+ const pickerTrigger = document.createElement("button");
261
+ pickerTrigger.type = "button";
262
+ pickerTrigger.className = "ina-year-picker__trigger ina-year-picker__trigger--size-sm";
263
+ const updateTriggerText = () => {
264
+ pickerTrigger.innerHTML = `
265
+ <span class="ina-year-picker__trigger-text">${currentYearVal}</span>
266
+ `;
267
+ };
268
+ updateTriggerText();
269
+ pickerTrigger.addEventListener("click", (e) => {
270
+ e.stopPropagation();
271
+ togglePicker(!isPickerOpen);
272
+ });
273
+ const pickerPanel = document.createElement("div");
274
+ pickerPanel.className = "ina-year-picker__panel";
275
+ const header = document.createElement("div");
276
+ header.className = "ina-year-picker__header";
277
+ const prevBtn = document.createElement("button");
278
+ prevBtn.type = "button";
279
+ prevBtn.className = "ina-year-picker__nav-button";
280
+ prevBtn.innerHTML = createIcon("chevron-left");
281
+ prevBtn.onclick = (e) => {
282
+ e.stopPropagation();
283
+ decadeStart -= 20;
284
+ renderGrid();
285
+ };
286
+ const nextBtn = document.createElement("button");
287
+ nextBtn.type = "button";
288
+ nextBtn.className = "ina-year-picker__nav-button";
289
+ nextBtn.innerHTML = createIcon("chevron-right");
290
+ nextBtn.onclick = (e) => {
291
+ e.stopPropagation();
292
+ decadeStart += 20;
293
+ renderGrid();
294
+ };
295
+ const rangeText = document.createElement("span");
296
+ rangeText.className = "ina-year-picker__decade-range";
297
+ header.append(prevBtn, rangeText, nextBtn);
298
+ const grid = document.createElement("div");
299
+ grid.className = "ina-year-picker__grid";
300
+ function renderGrid() {
301
+ grid.innerHTML = "";
302
+ rangeText.textContent = `${decadeStart} - ${decadeStart + 19}`;
303
+ for (let y = decadeStart; y < decadeStart + 20; y++) {
304
+ const btn = document.createElement("button");
305
+ btn.type = "button";
306
+ btn.className = "ina-year-picker__year-option";
307
+ if (y === currentYearVal)
308
+ btn.classList.add("ina-year-picker__year-option--selected");
309
+ btn.textContent = y;
310
+ btn.addEventListener("click", (e) => {
311
+ e.stopPropagation();
312
+ currentYearVal = y;
313
+ updateTriggerText();
314
+ togglePicker(false);
315
+ onChange(y);
316
+ });
317
+ grid.appendChild(btn);
318
+ }
319
+ }
320
+ pickerPanel.append(header, grid);
321
+ container.append(pickerTrigger, pickerPanel);
322
+ function togglePicker(show) {
323
+ isPickerOpen = show;
324
+ if (show) {
325
+ decadeStart = Math.floor(currentYearVal / 20) * 20;
326
+ renderGrid();
327
+ pickerPanel.classList.add("ina-year-picker__panel--open");
328
+ pickerTrigger.setAttribute("aria-expanded", "true");
329
+ } else {
330
+ pickerPanel.classList.remove("ina-year-picker__panel--open");
331
+ pickerTrigger.setAttribute("aria-expanded", "false");
332
+ }
333
+ }
334
+ document.addEventListener("click", (e) => {
335
+ if (!container.contains(e.target)) togglePicker(false);
336
+ });
337
+ return {
338
+ element: container,
339
+ setYear: (y) => {
340
+ currentYearVal = y;
341
+ updateTriggerText();
342
+ }
343
+ };
344
+ }
345
+ function renderCalendar() {
346
+ panelContent.innerHTML = "";
347
+ const year = currentDate.getFullYear();
348
+ const month = currentDate.getMonth();
349
+ const calendarContainer = document.createElement("div");
350
+ calendarContainer.className = "ina-date-picker__calendar-container";
351
+ const header = document.createElement("div");
352
+ header.className = "ina-date-picker__calendar-header";
353
+ const prevBtn = document.createElement("button");
354
+ prevBtn.className = "ina-date-picker__nav-button";
355
+ prevBtn.type = "button";
356
+ prevBtn.innerHTML = createIcon("chevron-left", 20);
357
+ prevBtn.addEventListener("click", (e) => {
358
+ e.stopPropagation();
359
+ currentDate.setMonth(month - 1);
360
+ renderCalendar();
361
+ });
362
+ const nextBtn = document.createElement("button");
363
+ nextBtn.className = "ina-date-picker__nav-button";
364
+ nextBtn.type = "button";
365
+ nextBtn.innerHTML = createIcon("chevron-right", 20);
366
+ nextBtn.addEventListener("click", (e) => {
367
+ e.stopPropagation();
368
+ currentDate.setMonth(month + 1);
369
+ renderCalendar();
370
+ });
371
+ const controls = document.createElement("div");
372
+ controls.className = "ina-date-picker__header-controls";
373
+ const monthContainer = document.createElement("div");
374
+ monthContainer.className = "ina-date-picker__dropdown-container";
375
+ const monthPicker = createMonthPicker(month, (newMonth) => {
376
+ currentDate.setMonth(newMonth);
377
+ renderCalendar();
378
+ });
379
+ monthContainer.appendChild(monthPicker.element);
380
+ const yearContainer = document.createElement("div");
381
+ yearContainer.className = "ina-date-picker__dropdown-container";
382
+ const yearPicker = createYearPicker(year, (newYear) => {
383
+ currentDate.setFullYear(newYear);
384
+ renderCalendar();
385
+ });
386
+ yearContainer.appendChild(yearPicker.element);
387
+ controls.append(monthContainer, yearContainer);
388
+ header.append(prevBtn, controls, nextBtn);
389
+ const grid = document.createElement("div");
390
+ grid.className = "ina-date-picker__calendar-grid";
391
+ DAYS_SHORT.forEach((day) => {
392
+ const dh = document.createElement("div");
393
+ dh.className = "ina-date-picker__day-header";
394
+ dh.textContent = day;
395
+ grid.appendChild(dh);
215
396
  });
216
397
  const firstDayOfMonth = new Date(year, month, 1).getDay();
217
398
  const daysInMonth = new Date(year, month + 1, 0).getDate();
218
399
  const daysInPrevMonth = new Date(year, month, 0).getDate();
219
- for (let i = 0; i < firstDayOfMonth; i++) {
220
- const dayEl = document.createElement("button");
221
- dayEl.className = "ina-date-picker__calendar-day outside-month";
222
- dayEl.textContent = daysInPrevMonth - firstDayOfMonth + 1 + i;
223
- dayEl.disabled = true;
224
- datepickerContent.appendChild(dayEl);
400
+ for (let i = firstDayOfMonth - 1; i >= 0; i--) {
401
+ const dayBtn = document.createElement("button");
402
+ dayBtn.type = "button";
403
+ dayBtn.className = "ina-date-picker__day ina-date-picker__day--other-month ina-date-picker__day--disabled";
404
+ dayBtn.textContent = daysInPrevMonth - i;
405
+ grid.appendChild(dayBtn);
225
406
  }
226
407
  const today = /* @__PURE__ */ new Date();
227
408
  for (let i = 1; i <= daysInMonth; i++) {
228
- const dayEl = document.createElement("button");
229
- dayEl.className = "ina-date-picker__calendar-day";
230
- dayEl.textContent = i;
231
- dayEl.dataset.date = new Date(year, month, i).toISOString();
232
- if (year === today.getFullYear() && month === today.getMonth() && i === today.getDate()) {
233
- const marker = document.createElement("span");
234
- marker.className = "ina-date-picker__today-marker";
235
- marker.textContent = "Hari ini";
236
- dayEl.appendChild(marker);
237
- dayEl.classList.add("today");
409
+ const dayBtn = document.createElement("button");
410
+ dayBtn.type = "button";
411
+ dayBtn.className = "ina-date-picker__day";
412
+ dayBtn.textContent = i;
413
+ let isSelected = false;
414
+ if (selectedDate && selectedDate.getDate() === i && selectedDate.getMonth() === month && selectedDate.getFullYear() === year) {
415
+ dayBtn.classList.add("ina-date-picker__day--selected");
416
+ isSelected = true;
238
417
  }
239
- if (selectedDate && year === selectedDate.getFullYear() && month === selectedDate.getMonth() && i === selectedDate.getDate()) {
240
- dayEl.classList.add("selected");
418
+ if (today.getDate() === i && today.getMonth() === month && today.getFullYear() === year) {
419
+ dayBtn.classList.add("ina-date-picker__day--today");
241
420
  }
242
- datepickerContent.appendChild(dayEl);
243
- }
244
- const totalCells = 42;
245
- const cellsRendered = firstDayOfMonth + daysInMonth;
246
- const remainingCells = totalCells - cellsRendered;
247
- for (let i = 1; i <= remainingCells; i++) {
248
- const dayEl = document.createElement("button");
249
- dayEl.className = "ina-date-picker__calendar-day outside-month";
250
- dayEl.textContent = i;
251
- dayEl.disabled = true;
252
- datepickerContent.appendChild(dayEl);
253
- }
254
- datepickerMonthPopover.innerHTML = "";
255
- MONTHS.forEach((monthName, index) => {
256
- const monthEl = document.createElement("button");
257
- monthEl.className = "ina-date-picker__month-item";
258
- monthEl.textContent = monthName.substring(0, 3);
259
- monthEl.dataset.month = index;
260
- if (index === month) {
261
- monthEl.classList.add("selected");
421
+ if (!isSelected) {
422
+ dayBtn.classList.add("ina-date-picker__day--hover");
262
423
  }
263
- datepickerMonthPopover.appendChild(monthEl);
264
- });
265
- datepickerYearContent.innerHTML = "";
266
- const startYear = Math.floor(year / 10) * 10;
267
- const endYear = startYear + 19;
268
- datepickerYearCurrent.textContent = `${startYear} - ${endYear}`;
269
- for (let y = startYear; y <= endYear; y++) {
270
- const yearEl = document.createElement("button");
271
- yearEl.className = "ina-date-picker__year-item";
272
- yearEl.textContent = y;
273
- yearEl.dataset.year = y;
274
- if (y === year) {
275
- yearEl.classList.add("selected");
276
- }
277
- datepickerYearContent.appendChild(yearEl);
278
- }
279
- }
280
- function togglePopover() {
281
- if (datepickerPopover.style.display === "none" || datepickerPopover.style.display === "") {
282
- datepickerPopover.style.display = "block";
283
- renderCalendar(currentDate.getFullYear(), currentDate.getMonth());
284
- } else {
285
- datepickerPopover.style.display = "none";
424
+ dayBtn.addEventListener("click", (e) => {
425
+ e.stopPropagation();
426
+ selectedDate = new Date(year, month, i);
427
+ triggerText.textContent = formatDate(selectedDate);
428
+ triggerText.classList.add("ina-date-picker__trigger-text--value");
429
+ triggerText.classList.remove(
430
+ "ina-date-picker__trigger-text--placeholder"
431
+ );
432
+ datepicker.dispatchEvent(
433
+ new CustomEvent("date:changed", { detail: { selectedDate } })
434
+ );
435
+ toggle(false);
436
+ });
437
+ grid.appendChild(dayBtn);
286
438
  }
287
- }
288
- function toggleMonthPopover() {
289
- if (datepickerMonthPopover.style.display === "none" || datepickerMonthPopover.style.display === "") {
290
- datepickerMonthPopover.style.display = "grid";
291
- } else {
292
- datepickerMonthPopover.style.display = "none";
439
+ const currentCells = grid.children.length - 7;
440
+ const remaining = 42 - currentCells;
441
+ for (let i = 1; i <= remaining; i++) {
442
+ const dayBtn = document.createElement("button");
443
+ dayBtn.type = "button";
444
+ dayBtn.className = "ina-date-picker__day ina-date-picker__day--other-month ina-date-picker__day--disabled";
445
+ dayBtn.textContent = i;
446
+ grid.appendChild(dayBtn);
293
447
  }
448
+ calendarContainer.append(header, grid);
449
+ panelContent.appendChild(calendarContainer);
294
450
  }
295
- function toggleYearPopover() {
296
- if (datepickerYearPopover.style.display === "none" || datepickerYearPopover.style.display === "") {
297
- datepickerYearPopover.style.display = "block";
451
+ function toggle(show) {
452
+ isOpen = show;
453
+ if (show) {
454
+ panel.classList.add("ina-date-picker__panel--open");
455
+ renderCalendar();
298
456
  } else {
299
- datepickerYearPopover.style.display = "none";
457
+ panel.classList.remove("ina-date-picker__panel--open");
300
458
  }
301
459
  }
302
- datepickerTrigger.addEventListener("click", (e) => {
303
- e.stopPropagation();
304
- togglePopover();
305
- });
306
- prevMonthButton.addEventListener("click", () => {
307
- currentDate.setMonth(currentDate.getMonth() - 1);
308
- renderCalendar(currentDate.getFullYear(), currentDate.getMonth());
309
- });
310
- nextMonthButton.addEventListener("click", () => {
311
- currentDate.setMonth(currentDate.getMonth() + 1);
312
- renderCalendar(currentDate.getFullYear(), currentDate.getMonth());
313
- });
314
- datepickerMonthTrigger.addEventListener("click", (e) => {
460
+ trigger.addEventListener("click", (e) => {
315
461
  e.stopPropagation();
316
- toggleMonthPopover();
317
- });
318
- datepickerYearTrigger.addEventListener("click", (e) => {
319
- e.stopPropagation();
320
- toggleYearPopover();
321
- });
322
- document.addEventListener("click", (e) => {
323
- if (!datepickerPopover.contains(e.target) && e.target !== datepickerTrigger && !datepickerTrigger.contains(e.target)) {
324
- datepickerPopover.style.display = "none";
325
- }
326
- });
327
- document.addEventListener("click", (e) => {
328
- if (!datepickerMonthPopover.contains(e.target) && e.target !== datepickerMonthTrigger && !datepickerMonthTrigger.contains(e.target)) {
329
- datepickerMonthPopover.style.display = "none";
330
- }
462
+ toggle(!isOpen);
331
463
  });
332
464
  document.addEventListener("click", (e) => {
333
- if (!datepickerYearPopover.contains(e.target) && e.target !== datepickerYearTrigger && !datepickerYearTrigger.contains(e.target)) {
334
- datepickerYearPopover.style.display = "none";
335
- }
336
- });
337
- datepickerMonthPopover.addEventListener("click", (e) => {
338
- e.stopPropagation();
339
- const target = e.target;
340
- if (target.classList.contains("ina-date-picker__month-item")) {
341
- const monthIndex = parseInt(target.dataset.month);
342
- currentDate.setMonth(monthIndex);
343
- renderCalendar(currentDate.getFullYear(), currentDate.getMonth());
344
- datepickerMonthPopover.style.display = "none";
345
- }
346
- });
347
- datepickerYearPopover.addEventListener("click", (e) => {
348
- e.stopPropagation();
349
- const target = e.target;
350
- if (target.classList.contains("ina-date-picker__year-nav-prev")) {
351
- const currentYearRange = datepickerYearCurrent.textContent.split(" - ").map((y) => parseInt(y));
352
- const newStartYear = currentYearRange[0] - 20;
353
- const newEndYear = currentYearRange[1] - 20;
354
- renderYear(newStartYear, newEndYear);
355
- } else if (target.classList.contains("ina-date-picker__year-nav-next")) {
356
- const currentYearRange = datepickerYearCurrent.textContent.split(" - ").map((y) => parseInt(y));
357
- const newStartYear = currentYearRange[0] + 20;
358
- const newEndYear = currentYearRange[1] + 20;
359
- renderYear(newStartYear, newEndYear);
360
- }
361
- });
362
- datepickerYearContent.addEventListener("click", (e) => {
363
- e.stopPropagation();
364
- const target = e.target;
365
- if (target.classList.contains("ina-date-picker__year-item")) {
366
- const yearValue = parseInt(target.dataset.year);
367
- currentDate.setFullYear(yearValue);
368
- renderCalendar(currentDate.getFullYear(), currentDate.getMonth());
369
- datepickerYearPopover.style.display = "none";
370
- }
371
- });
372
- datepickerContent.addEventListener("click", (e) => {
373
- const target = e.target;
374
- if (target.classList.contains("ina-date-picker__calendar-day") && !target.classList.contains("outside-month")) {
375
- if (target.classList.contains("selected")) {
376
- target.classList.remove("selected");
377
- selectedDateTarget = null;
378
- } else {
379
- const selectedDateEl = datepickerContent.querySelector(
380
- ".ina-date-picker__calendar-day.selected"
381
- );
382
- selectedDateEl?.classList.remove("selected");
383
- target.classList.add("selected");
384
- selectedDateTarget = target;
385
- }
386
- }
465
+ if (!datepicker.contains(e.target)) toggle(false);
387
466
  });
388
- datepickerSubmitButton.addEventListener("click", () => {
389
- selectedDate = selectedDateTarget ? new Date(selectedDateTarget.dataset.date) : null;
390
- currentDate = selectedDate ? new Date(selectedDate) : /* @__PURE__ */ new Date();
391
- datepicker.dispatchEvent(
392
- new CustomEvent("date:changed", { detail: { selectedDate } })
393
- );
394
- datepickerPopover.style.display = "none";
395
- });
396
- renderCalendar(currentDate.getFullYear(), currentDate.getMonth());
397
467
  });
398
468
  }
399
- document.addEventListener("DOMContentLoaded", () => {
400
- });
401
469
 
402
470
  // src/js/components/stateless/modal.js
403
471
  function initModal(rootSelector = `.${PREFIX}-modal`) {
@@ -819,6 +887,212 @@ var InaUI = (() => {
819
887
  });
820
888
  }
821
889
 
890
+ // src/js/components/stateful/timepicker.js
891
+ function initTimepicker() {
892
+ document.querySelectorAll(".ina-time-picker").forEach((picker) => {
893
+ if (picker.dataset.initialized === "true") return;
894
+ picker.dataset.initialized = "true";
895
+ const input = picker.querySelector(".ina-time-picker__input");
896
+ const wrapper = picker.querySelector(".ina-time-picker__wrapper");
897
+ if (!input || !wrapper) return;
898
+ const format = picker.dataset.format || "HH:mm";
899
+ const use12Hours = picker.dataset.use12Hours === "true";
900
+ const showSecond = picker.dataset.showSecond === "true";
901
+ const disabled = picker.classList.contains("ina-time-picker--disabled");
902
+ const allowClear = picker.dataset.allowClear !== "false";
903
+ let isOpen = false;
904
+ let internalValue = input.value || "";
905
+ let panel = picker.querySelector(".ina-time-picker__panel");
906
+ if (!panel) {
907
+ panel = document.createElement("div");
908
+ panel.className = "ina-time-picker__panel";
909
+ panel.style.display = "none";
910
+ picker.appendChild(panel);
911
+ }
912
+ let content = panel.querySelector(".ina-time-picker__content");
913
+ if (!content) {
914
+ content = document.createElement("div");
915
+ content.className = "ina-time-picker__content";
916
+ panel.appendChild(content);
917
+ } else {
918
+ content.innerHTML = "";
919
+ }
920
+ let actions = panel.querySelector(".ina-time-picker__actions");
921
+ if (!actions) {
922
+ actions = document.createElement("div");
923
+ actions.className = "ina-time-picker__actions";
924
+ const confirmBtn = document.createElement("button");
925
+ confirmBtn.type = "button";
926
+ confirmBtn.className = "ina-time-picker__confirm-button";
927
+ confirmBtn.textContent = "Pilih";
928
+ confirmBtn.onclick = (e) => {
929
+ e.stopPropagation();
930
+ close();
931
+ };
932
+ actions.appendChild(confirmBtn);
933
+ panel.appendChild(actions);
934
+ }
935
+ const parseTime = (timeStr) => {
936
+ if (!timeStr) return { hours: 0, minutes: 0, seconds: 0, period: "AM" };
937
+ let hours = 0, minutes = 0, seconds = 0, period = "AM";
938
+ try {
939
+ if (use12Hours) {
940
+ const [time, p] = timeStr.split(" ");
941
+ const [h, m, s] = time.split(":");
942
+ hours = parseInt(h || "0", 10);
943
+ minutes = parseInt(m || "0", 10);
944
+ seconds = parseInt(s || "0", 10);
945
+ period = p || "AM";
946
+ } else {
947
+ const [h, m, s] = timeStr.split(":");
948
+ hours = parseInt(h || "0", 10);
949
+ minutes = parseInt(m || "0", 10);
950
+ seconds = parseInt(s || "0", 10);
951
+ }
952
+ } catch (e) {
953
+ console.warn("Invalid time format", timeStr);
954
+ }
955
+ return { hours, minutes, seconds, period };
956
+ };
957
+ const formatTime = (h, m, s, p) => {
958
+ const pad = (n) => n.toString().padStart(2, "0");
959
+ if (use12Hours) {
960
+ let displayHours = h;
961
+ if (displayHours === 0) displayHours = 12;
962
+ const main = `${pad(displayHours)}:${pad(m)}`;
963
+ const sec = showSecond ? `:${pad(s)}` : "";
964
+ return `${main}${sec} ${p}`;
965
+ } else {
966
+ const main = `${pad(h)}:${pad(m)}`;
967
+ const sec = showSecond ? `:${pad(s)}` : "";
968
+ return `${main}${sec}`;
969
+ }
970
+ };
971
+ let currentTime = parseTime(internalValue);
972
+ const renderColumn = (type, max) => {
973
+ const column = document.createElement("div");
974
+ column.className = `ina-time-picker__column ina-time-picker__column--${type}`;
975
+ const colContent = document.createElement("div");
976
+ colContent.className = "ina-time-picker__column-content";
977
+ column.appendChild(colContent);
978
+ const start = type === "hour" && use12Hours ? 1 : 0;
979
+ const end = type === "hour" && use12Hours ? 12 : max - 1;
980
+ for (let i = start; i <= end; i++) {
981
+ const option = document.createElement("div");
982
+ option.className = "ina-time-picker__option";
983
+ option.textContent = i.toString().padStart(2, "0");
984
+ option.dataset.value = i;
985
+ let isSelected = false;
986
+ if (type === "hour") {
987
+ isSelected = currentTime.hours === i || use12Hours && currentTime.hours === 0 && i === 12;
988
+ } else if (type === "minute") isSelected = currentTime.minutes === i;
989
+ else if (type === "second") isSelected = currentTime.seconds === i;
990
+ if (isSelected)
991
+ option.classList.add("ina-time-picker__option--selected");
992
+ option.addEventListener("click", (e) => {
993
+ e.stopPropagation();
994
+ const val = parseInt(option.dataset.value, 10);
995
+ if (type === "hour")
996
+ currentTime.hours = use12Hours && val === 12 ? 0 : val;
997
+ if (type === "hour") currentTime.hours = val;
998
+ if (type === "minute") currentTime.minutes = val;
999
+ if (type === "second") currentTime.seconds = val;
1000
+ updateInput();
1001
+ colContent.querySelectorAll(".ina-time-picker__option").forEach(
1002
+ (el) => el.classList.remove("ina-time-picker__option--selected")
1003
+ );
1004
+ option.classList.add("ina-time-picker__option--selected");
1005
+ });
1006
+ colContent.appendChild(option);
1007
+ }
1008
+ return column;
1009
+ };
1010
+ const renderPeriodColumn = () => {
1011
+ const column = document.createElement("div");
1012
+ column.className = `ina-time-picker__column ina-time-picker__column--period`;
1013
+ const colContent = document.createElement("div");
1014
+ colContent.className = "ina-time-picker__column-content";
1015
+ column.appendChild(colContent);
1016
+ ["AM", "PM"].forEach((p) => {
1017
+ const option = document.createElement("div");
1018
+ option.className = "ina-time-picker__option";
1019
+ option.textContent = p;
1020
+ if (currentTime.period === p)
1021
+ option.classList.add("ina-time-picker__option--selected");
1022
+ option.addEventListener("click", (e) => {
1023
+ e.stopPropagation();
1024
+ currentTime.period = p;
1025
+ updateInput();
1026
+ colContent.querySelectorAll(".ina-time-picker__option").forEach(
1027
+ (el) => el.classList.remove("ina-time-picker__option--selected")
1028
+ );
1029
+ option.classList.add("ina-time-picker__option--selected");
1030
+ });
1031
+ colContent.appendChild(option);
1032
+ });
1033
+ return column;
1034
+ };
1035
+ const updateInput = () => {
1036
+ const val = formatTime(
1037
+ currentTime.hours,
1038
+ currentTime.minutes,
1039
+ currentTime.seconds,
1040
+ currentTime.period
1041
+ );
1042
+ input.value = val;
1043
+ picker.dataset.value = val;
1044
+ input.dispatchEvent(new Event("change", { bubbles: true }));
1045
+ };
1046
+ const buildPanel = () => {
1047
+ content.innerHTML = "";
1048
+ content.appendChild(renderColumn("hour", use12Hours ? 13 : 24));
1049
+ content.appendChild(renderColumn("minute", 60));
1050
+ if (showSecond) content.appendChild(renderColumn("second", 60));
1051
+ if (use12Hours) content.appendChild(renderPeriodColumn());
1052
+ };
1053
+ const open = () => {
1054
+ if (disabled) return;
1055
+ isOpen = true;
1056
+ picker.classList.add("ina-time-picker--open");
1057
+ panel.style.display = "block";
1058
+ currentTime = parseTime(input.value);
1059
+ buildPanel();
1060
+ document.dispatchEvent(
1061
+ new CustomEvent("closeTimePicker", { detail: { exclude: picker } })
1062
+ );
1063
+ };
1064
+ const close = () => {
1065
+ isOpen = false;
1066
+ picker.classList.remove("ina-time-picker--open");
1067
+ panel.style.display = "none";
1068
+ };
1069
+ const toggle = (e) => {
1070
+ e.stopPropagation();
1071
+ if (isOpen) close();
1072
+ else open();
1073
+ };
1074
+ wrapper.addEventListener("click", toggle);
1075
+ input.addEventListener("click", (e) => {
1076
+ });
1077
+ document.addEventListener("click", (e) => {
1078
+ if (!picker.contains(e.target)) close();
1079
+ });
1080
+ document.addEventListener("closeTimePicker", (e) => {
1081
+ if (e.detail && e.detail.exclude !== picker) close();
1082
+ });
1083
+ const clearBtn = picker.querySelector(".ina-time-picker__clear-button");
1084
+ if (clearBtn && allowClear) {
1085
+ clearBtn.addEventListener("click", (e) => {
1086
+ e.stopPropagation();
1087
+ input.value = "";
1088
+ currentTime = { hours: 0, minutes: 0, seconds: 0, period: "AM" };
1089
+ picker.dataset.value = "";
1090
+ input.dispatchEvent(new Event("change", { bubbles: true }));
1091
+ });
1092
+ }
1093
+ });
1094
+ }
1095
+
822
1096
  // src/js/index.js
823
1097
  var PREFIX = "ina-ss";
824
1098
 
@@ -1296,6 +1570,7 @@ var InaUI = (() => {
1296
1570
  initModal();
1297
1571
  initRangeDatepicker();
1298
1572
  initTab();
1573
+ initTimepicker();
1299
1574
  initToggle();
1300
1575
  });
1301
1576
  }