universal-datetime-picker 2.0.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -397,23 +397,28 @@ var PickerController = class {
397
397
  this.draft = this.draft.year(day.year()).month(day.month()).date(day.date());
398
398
  this.focusedDay = day;
399
399
  this.emit();
400
+ this.maybeCommitInline();
400
401
  }
401
402
  setHour(hourValue) {
402
403
  this.draft = this.draft.hour(hourValue);
403
404
  this.emit();
405
+ this.maybeCommitInline();
404
406
  }
405
407
  setMinute(minute) {
406
408
  this.draft = this.draft.minute(minute);
407
409
  this.emit();
410
+ this.maybeCommitInline();
408
411
  }
409
412
  setSecond(second) {
410
413
  this.draft = this.draft.second(second);
411
414
  this.emit();
415
+ this.maybeCommitInline();
412
416
  }
413
417
  setAmPm(isAm) {
414
418
  const { hour } = to12Hour(this.draft.hour());
415
419
  this.draft = this.draft.hour(to24Hour(hour, isAm));
416
420
  this.emit();
421
+ this.maybeCommitInline();
417
422
  }
418
423
  toggleHours() {
419
424
  this.showHours = !this.showHours;
@@ -459,22 +464,26 @@ var PickerController = class {
459
464
  }
460
465
  this.showHours = false;
461
466
  this.emit();
467
+ this.maybeCommitInline();
462
468
  }
463
469
  selectMinuteOption(opt) {
464
470
  this.draft = this.draft.minute(Number(opt));
465
471
  this.showMinutes = false;
466
472
  this.emit();
473
+ this.maybeCommitInline();
467
474
  }
468
475
  selectSecondOption(opt) {
469
476
  this.draft = this.draft.second(Number(opt));
470
477
  this.showSecondsOpen = false;
471
478
  this.emit();
479
+ this.maybeCommitInline();
472
480
  }
473
481
  selectAmPmOption(opt) {
474
482
  const { hour } = to12Hour(this.draft.hour());
475
483
  this.draft = this.draft.hour(to24Hour(hour, opt === "AM"));
476
484
  this.showAmPm = false;
477
485
  this.emit();
486
+ this.maybeCommitInline();
478
487
  }
479
488
  handleGridKeyDown(key) {
480
489
  const snap = this.snapshot;
@@ -524,23 +533,30 @@ var PickerController = class {
524
533
  this.emit();
525
534
  return true;
526
535
  }
527
- confirm() {
536
+ buildPayload() {
528
537
  const snap = this.snapshot;
529
- let payload;
530
538
  if (snap.asString === false) {
531
539
  if (snap.mode === "time") {
532
- payload = buildTimeValue(this.draft, snap.resolvedFormat);
533
- } else if (snap.mode === "date") {
534
- payload = this.draft.startOf("day").toDate();
535
- } else {
536
- payload = this.draft.toDate();
540
+ return buildTimeValue(this.draft, snap.resolvedFormat);
537
541
  }
538
- } else {
539
- if (snap.asString === void 0) {
540
- warnAsStringDeprecation();
542
+ if (snap.mode === "date") {
543
+ return this.draft.startOf("day").toDate();
541
544
  }
542
- payload = formatValue(this.draft, snap.resolvedFormat);
545
+ return this.draft.toDate();
543
546
  }
547
+ if (snap.asString === void 0) {
548
+ warnAsStringDeprecation();
549
+ }
550
+ return formatValue(this.draft, snap.resolvedFormat);
551
+ }
552
+ maybeCommitInline() {
553
+ if (!this.options.inline) {
554
+ return;
555
+ }
556
+ this.options.onChange?.(this.buildPayload());
557
+ }
558
+ confirm() {
559
+ const payload = this.buildPayload();
544
560
  this.options.onChange?.(payload);
545
561
  this.close();
546
562
  return payload;
@@ -1144,13 +1160,15 @@ function renderPicker(controller, snap, titleId, position, options) {
1144
1160
  })
1145
1161
  );
1146
1162
  }
1147
- footerChildren.push(
1148
- el("button", {
1149
- type: "button",
1150
- onClick: () => controller.confirm(),
1151
- textContent: snap.labels.ok
1152
- })
1153
- );
1163
+ if (!snap.inline) {
1164
+ footerChildren.push(
1165
+ el("button", {
1166
+ type: "button",
1167
+ onClick: () => controller.confirm(),
1168
+ textContent: snap.labels.ok
1169
+ })
1170
+ );
1171
+ }
1154
1172
  picker.append(el("div", { className: "ctp-footer" }, footerChildren));
1155
1173
  return picker;
1156
1174
  }
@@ -1284,6 +1302,15 @@ var RangeController = class {
1284
1302
  end: parseValue(range?.end ?? null, format)
1285
1303
  };
1286
1304
  }
1305
+ sameDay(a, b) {
1306
+ if (a === null && b === null) {
1307
+ return true;
1308
+ }
1309
+ if (a === null || b === null) {
1310
+ return false;
1311
+ }
1312
+ return a.isSame(b, "day");
1313
+ }
1287
1314
  setOptions(partial) {
1288
1315
  this.options = { ...this.options, ...partial };
1289
1316
  if (partial.open !== void 0) {
@@ -1297,11 +1324,14 @@ var RangeController = class {
1297
1324
  } else if (partial.value !== void 0) {
1298
1325
  const format = this.options.format ?? DATE_FORMAT;
1299
1326
  const parsed = this.parseRange(partial.value, format);
1300
- this.start = parsed.start;
1301
- this.end = parsed.end;
1302
- if (parsed.start) {
1303
- this.viewMonth = parsed.start.startOf("month");
1304
- this.focusedDay = parsed.start;
1327
+ const unchanged = this.sameDay(parsed.start, this.start) && this.sameDay(parsed.end, this.end);
1328
+ if (!unchanged) {
1329
+ this.start = parsed.start;
1330
+ this.end = parsed.end;
1331
+ if (parsed.start) {
1332
+ this.viewMonth = parsed.start.startOf("month");
1333
+ this.focusedDay = parsed.start;
1334
+ }
1305
1335
  }
1306
1336
  }
1307
1337
  }
@@ -1433,6 +1463,11 @@ var RangeController = class {
1433
1463
  this.focusedDay = day;
1434
1464
  }
1435
1465
  this.emit();
1466
+ if (this.options.asString === false) {
1467
+ this.emitRange(this.start, this.end);
1468
+ } else if (this.options.inline && this.start && this.end) {
1469
+ this.emitRange(this.start, this.end);
1470
+ }
1436
1471
  }
1437
1472
  setHoverEnd(day) {
1438
1473
  if (this.start && !this.end) {
@@ -1552,12 +1587,51 @@ function applyStyle2(node, style) {
1552
1587
  }
1553
1588
  Object.assign(node.style, style);
1554
1589
  }
1590
+ function sameDay(a, b) {
1591
+ if (a === null && b === null) {
1592
+ return true;
1593
+ }
1594
+ if (a === null || b === null) {
1595
+ return false;
1596
+ }
1597
+ return a.isSame(b, "day");
1598
+ }
1599
+ function dayDateClassName(dayData) {
1600
+ return cx(
1601
+ "ctp-box",
1602
+ "ctp-box-date",
1603
+ !dayData.isCurrentMonth && "not-current-month",
1604
+ dayData.isDisabled && "disabled-date",
1605
+ dayData.isWeekend && "weekend-day",
1606
+ dayData.isCurrentDate && "ctp-today",
1607
+ dayData.isInRange && "ctp-in-range",
1608
+ dayData.isRangeStart && "ctp-range-start",
1609
+ dayData.isRangeEnd && "ctp-range-end"
1610
+ );
1611
+ }
1612
+ function syncDayButton(btn, dayData, snap) {
1613
+ const focused = dayData.date.isSame(snap.focusedDay, "day");
1614
+ const disabled = !dayData.isCurrentMonth || dayData.isDisabled;
1615
+ btn.className = dayDateClassName(dayData);
1616
+ btn.tabIndex = focused ? 0 : -1;
1617
+ btn.disabled = disabled;
1618
+ btn.setAttribute(
1619
+ "aria-selected",
1620
+ String(Boolean(dayData.isRangeStart || dayData.isRangeEnd))
1621
+ );
1622
+ btn.setAttribute("aria-disabled", String(disabled));
1623
+ }
1624
+ function canPatchHoverOnly(prev, next) {
1625
+ return prev.calPanel === "day" && next.calPanel === "day" && prev.viewMonth.isSame(next.viewMonth, "month") && sameDay(prev.start, next.start) && sameDay(prev.end, next.end) && prev.focusedDay.isSame(next.focusedDay, "day") && prev.open === next.open && prev.inline === next.inline;
1626
+ }
1555
1627
  function createDateTimeRangePicker(target, options = {}) {
1556
1628
  const controller = new RangeController(options);
1557
1629
  const titleId = `ctp-range-${Math.random().toString(36).slice(2, 9)}`;
1558
1630
  let cleanups = [];
1559
1631
  let host = null;
1560
1632
  let portalRoot = null;
1633
+ let lastSnap = null;
1634
+ let dayButtons = null;
1561
1635
  const teardown = () => {
1562
1636
  cleanups.forEach((c) => c());
1563
1637
  cleanups = [];
@@ -1565,13 +1639,29 @@ function createDateTimeRangePicker(target, options = {}) {
1565
1639
  portalRoot = null;
1566
1640
  host?.remove();
1567
1641
  host = null;
1642
+ lastSnap = null;
1643
+ dayButtons = null;
1568
1644
  };
1569
1645
  const paint = () => {
1570
- teardown();
1571
1646
  const snap = controller.getSnapshot();
1572
1647
  if (!snap.open && !snap.inline) {
1648
+ teardown();
1573
1649
  return;
1574
1650
  }
1651
+ if (lastSnap && dayButtons && host && canPatchHoverOnly(lastSnap, snap)) {
1652
+ for (const week of snap.weeks) {
1653
+ for (const dayData of week) {
1654
+ const key = dayData.date.format("YYYY-MM-DD");
1655
+ const btn = dayButtons.get(key);
1656
+ if (btn) {
1657
+ syncDayButton(btn, dayData, snap);
1658
+ }
1659
+ }
1660
+ }
1661
+ lastSnap = snap;
1662
+ return;
1663
+ }
1664
+ teardown();
1575
1665
  const now = dayjs__default.default();
1576
1666
  const year = snap.viewMonth.year();
1577
1667
  const windowStart = Math.floor(year / 12) * 12;
@@ -1620,6 +1710,7 @@ function createDateTimeRangePicker(target, options = {}) {
1620
1710
  ])
1621
1711
  ]);
1622
1712
  if (snap.calPanel === "day") {
1713
+ const buttons = /* @__PURE__ */ new Map();
1623
1714
  const grid = el2("div", {
1624
1715
  className: "ctp-main-calendar",
1625
1716
  role: "grid",
@@ -1630,7 +1721,8 @@ function createDateTimeRangePicker(target, options = {}) {
1630
1721
  if (controller.handleGridKeyDown(ke.key)) {
1631
1722
  ke.preventDefault();
1632
1723
  }
1633
- }
1724
+ },
1725
+ onMouseleave: () => controller.setHoverEnd(null)
1634
1726
  });
1635
1727
  for (const label of snap.weekdayLabels) {
1636
1728
  grid.append(
@@ -1645,47 +1737,38 @@ function createDateTimeRangePicker(target, options = {}) {
1645
1737
  for (const dayData of week) {
1646
1738
  const focused = dayData.date.isSame(snap.focusedDay, "day");
1647
1739
  const disabled = !dayData.isCurrentMonth || dayData.isDisabled;
1648
- grid.append(
1649
- el2("button", {
1650
- type: "button",
1651
- role: "gridcell",
1652
- tabIndex: focused ? 0 : -1,
1653
- ariaSelected: Boolean(
1654
- dayData.isRangeStart || dayData.isRangeEnd
1655
- ),
1656
- ariaDisabled: disabled,
1657
- disabled,
1658
- ariaLabel: formatLocalized(
1659
- dayData.date,
1660
- "dddd, MMMM D, YYYY",
1661
- snap.locale
1662
- ),
1663
- className: cx(
1664
- "ctp-box",
1665
- "ctp-box-date",
1666
- !dayData.isCurrentMonth && "not-current-month",
1667
- dayData.isDisabled && "disabled-date",
1668
- dayData.isWeekend && "weekend-day",
1669
- dayData.isCurrentDate && "ctp-today",
1670
- dayData.isInRange && "ctp-in-range",
1671
- dayData.isRangeStart && "ctp-range-start",
1672
- dayData.isRangeEnd && "ctp-range-end"
1673
- ),
1674
- onClick: () => {
1675
- if (!disabled) {
1676
- controller.pickDay(dayData.date);
1677
- }
1678
- },
1679
- onMouseenter: () => {
1680
- if (!disabled && snap.start && !snap.end) {
1681
- controller.setHoverEnd(dayData.date);
1682
- }
1683
- },
1684
- textContent: dayData.date.format("D")
1685
- })
1686
- );
1740
+ const btn = el2("button", {
1741
+ type: "button",
1742
+ role: "gridcell",
1743
+ tabIndex: focused ? 0 : -1,
1744
+ ariaSelected: Boolean(
1745
+ dayData.isRangeStart || dayData.isRangeEnd
1746
+ ),
1747
+ ariaDisabled: disabled,
1748
+ disabled,
1749
+ ariaLabel: formatLocalized(
1750
+ dayData.date,
1751
+ "dddd, MMMM D, YYYY",
1752
+ snap.locale
1753
+ ),
1754
+ className: dayDateClassName(dayData),
1755
+ onClick: () => {
1756
+ if (!disabled) {
1757
+ controller.pickDay(dayData.date);
1758
+ }
1759
+ },
1760
+ onMouseenter: () => {
1761
+ if (!disabled && snap.start && !snap.end) {
1762
+ controller.setHoverEnd(dayData.date);
1763
+ }
1764
+ },
1765
+ textContent: dayData.date.format("D")
1766
+ });
1767
+ buttons.set(dayData.date.format("YYYY-MM-DD"), btn);
1768
+ grid.append(btn);
1687
1769
  }
1688
1770
  }
1771
+ dayButtons = buttons;
1689
1772
  body.append(grid);
1690
1773
  } else if (snap.calPanel === "month") {
1691
1774
  const grid = el2("div", {
@@ -1755,14 +1838,16 @@ function createDateTimeRangePicker(target, options = {}) {
1755
1838
  })
1756
1839
  );
1757
1840
  }
1758
- footerChildren.push(
1759
- el2("button", {
1760
- type: "button",
1761
- disabled: !snap.start || !snap.end,
1762
- onClick: () => controller.confirm(),
1763
- textContent: snap.labels.ok
1764
- })
1765
- );
1841
+ if (!snap.inline) {
1842
+ footerChildren.push(
1843
+ el2("button", {
1844
+ type: "button",
1845
+ disabled: !snap.start || !snap.end,
1846
+ onClick: () => controller.confirm(),
1847
+ textContent: snap.labels.ok
1848
+ })
1849
+ );
1850
+ }
1766
1851
  const picker = el2(
1767
1852
  "div",
1768
1853
  {
@@ -1787,6 +1872,7 @@ function createDateTimeRangePicker(target, options = {}) {
1787
1872
  if (snap.inline) {
1788
1873
  host = picker;
1789
1874
  target.append(picker);
1875
+ lastSnap = snap;
1790
1876
  return;
1791
1877
  }
1792
1878
  const backdrop = el2("div", {
@@ -1804,6 +1890,7 @@ function createDateTimeRangePicker(target, options = {}) {
1804
1890
  attachFocusTrap(picker, true),
1805
1891
  attachEscape(() => controller.close(), true)
1806
1892
  );
1893
+ lastSnap = snap;
1807
1894
  };
1808
1895
  const unsub = controller.subscribe(paint);
1809
1896
  paint();