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.
@@ -386,23 +386,28 @@ var PickerController = class {
386
386
  this.draft = this.draft.year(day.year()).month(day.month()).date(day.date());
387
387
  this.focusedDay = day;
388
388
  this.emit();
389
+ this.maybeCommitInline();
389
390
  }
390
391
  setHour(hourValue) {
391
392
  this.draft = this.draft.hour(hourValue);
392
393
  this.emit();
394
+ this.maybeCommitInline();
393
395
  }
394
396
  setMinute(minute) {
395
397
  this.draft = this.draft.minute(minute);
396
398
  this.emit();
399
+ this.maybeCommitInline();
397
400
  }
398
401
  setSecond(second) {
399
402
  this.draft = this.draft.second(second);
400
403
  this.emit();
404
+ this.maybeCommitInline();
401
405
  }
402
406
  setAmPm(isAm) {
403
407
  const { hour } = to12Hour(this.draft.hour());
404
408
  this.draft = this.draft.hour(to24Hour(hour, isAm));
405
409
  this.emit();
410
+ this.maybeCommitInline();
406
411
  }
407
412
  toggleHours() {
408
413
  this.showHours = !this.showHours;
@@ -448,22 +453,26 @@ var PickerController = class {
448
453
  }
449
454
  this.showHours = false;
450
455
  this.emit();
456
+ this.maybeCommitInline();
451
457
  }
452
458
  selectMinuteOption(opt) {
453
459
  this.draft = this.draft.minute(Number(opt));
454
460
  this.showMinutes = false;
455
461
  this.emit();
462
+ this.maybeCommitInline();
456
463
  }
457
464
  selectSecondOption(opt) {
458
465
  this.draft = this.draft.second(Number(opt));
459
466
  this.showSecondsOpen = false;
460
467
  this.emit();
468
+ this.maybeCommitInline();
461
469
  }
462
470
  selectAmPmOption(opt) {
463
471
  const { hour } = to12Hour(this.draft.hour());
464
472
  this.draft = this.draft.hour(to24Hour(hour, opt === "AM"));
465
473
  this.showAmPm = false;
466
474
  this.emit();
475
+ this.maybeCommitInline();
467
476
  }
468
477
  handleGridKeyDown(key) {
469
478
  const snap = this.snapshot;
@@ -513,23 +522,30 @@ var PickerController = class {
513
522
  this.emit();
514
523
  return true;
515
524
  }
516
- confirm() {
525
+ buildPayload() {
517
526
  const snap = this.snapshot;
518
- let payload;
519
527
  if (snap.asString === false) {
520
528
  if (snap.mode === "time") {
521
- payload = buildTimeValue(this.draft, snap.resolvedFormat);
522
- } else if (snap.mode === "date") {
523
- payload = this.draft.startOf("day").toDate();
524
- } else {
525
- payload = this.draft.toDate();
529
+ return buildTimeValue(this.draft, snap.resolvedFormat);
526
530
  }
527
- } else {
528
- if (snap.asString === void 0) {
529
- warnAsStringDeprecation();
531
+ if (snap.mode === "date") {
532
+ return this.draft.startOf("day").toDate();
530
533
  }
531
- payload = formatValue(this.draft, snap.resolvedFormat);
534
+ return this.draft.toDate();
532
535
  }
536
+ if (snap.asString === void 0) {
537
+ warnAsStringDeprecation();
538
+ }
539
+ return formatValue(this.draft, snap.resolvedFormat);
540
+ }
541
+ maybeCommitInline() {
542
+ if (!this.options.inline) {
543
+ return;
544
+ }
545
+ this.options.onChange?.(this.buildPayload());
546
+ }
547
+ confirm() {
548
+ const payload = this.buildPayload();
533
549
  this.options.onChange?.(payload);
534
550
  this.close();
535
551
  return payload;
@@ -1133,13 +1149,15 @@ function renderPicker(controller, snap, titleId, position, options) {
1133
1149
  })
1134
1150
  );
1135
1151
  }
1136
- footerChildren.push(
1137
- el("button", {
1138
- type: "button",
1139
- onClick: () => controller.confirm(),
1140
- textContent: snap.labels.ok
1141
- })
1142
- );
1152
+ if (!snap.inline) {
1153
+ footerChildren.push(
1154
+ el("button", {
1155
+ type: "button",
1156
+ onClick: () => controller.confirm(),
1157
+ textContent: snap.labels.ok
1158
+ })
1159
+ );
1160
+ }
1143
1161
  picker.append(el("div", { className: "ctp-footer" }, footerChildren));
1144
1162
  return picker;
1145
1163
  }
@@ -1273,6 +1291,15 @@ var RangeController = class {
1273
1291
  end: parseValue(range?.end ?? null, format)
1274
1292
  };
1275
1293
  }
1294
+ sameDay(a, b) {
1295
+ if (a === null && b === null) {
1296
+ return true;
1297
+ }
1298
+ if (a === null || b === null) {
1299
+ return false;
1300
+ }
1301
+ return a.isSame(b, "day");
1302
+ }
1276
1303
  setOptions(partial) {
1277
1304
  this.options = { ...this.options, ...partial };
1278
1305
  if (partial.open !== void 0) {
@@ -1286,11 +1313,14 @@ var RangeController = class {
1286
1313
  } else if (partial.value !== void 0) {
1287
1314
  const format = this.options.format ?? DATE_FORMAT;
1288
1315
  const parsed = this.parseRange(partial.value, format);
1289
- this.start = parsed.start;
1290
- this.end = parsed.end;
1291
- if (parsed.start) {
1292
- this.viewMonth = parsed.start.startOf("month");
1293
- this.focusedDay = parsed.start;
1316
+ const unchanged = this.sameDay(parsed.start, this.start) && this.sameDay(parsed.end, this.end);
1317
+ if (!unchanged) {
1318
+ this.start = parsed.start;
1319
+ this.end = parsed.end;
1320
+ if (parsed.start) {
1321
+ this.viewMonth = parsed.start.startOf("month");
1322
+ this.focusedDay = parsed.start;
1323
+ }
1294
1324
  }
1295
1325
  }
1296
1326
  }
@@ -1422,6 +1452,11 @@ var RangeController = class {
1422
1452
  this.focusedDay = day;
1423
1453
  }
1424
1454
  this.emit();
1455
+ if (this.options.asString === false) {
1456
+ this.emitRange(this.start, this.end);
1457
+ } else if (this.options.inline && this.start && this.end) {
1458
+ this.emitRange(this.start, this.end);
1459
+ }
1425
1460
  }
1426
1461
  setHoverEnd(day) {
1427
1462
  if (this.start && !this.end) {
@@ -1541,12 +1576,51 @@ function applyStyle2(node, style) {
1541
1576
  }
1542
1577
  Object.assign(node.style, style);
1543
1578
  }
1579
+ function sameDay(a, b) {
1580
+ if (a === null && b === null) {
1581
+ return true;
1582
+ }
1583
+ if (a === null || b === null) {
1584
+ return false;
1585
+ }
1586
+ return a.isSame(b, "day");
1587
+ }
1588
+ function dayDateClassName(dayData) {
1589
+ return cx(
1590
+ "ctp-box",
1591
+ "ctp-box-date",
1592
+ !dayData.isCurrentMonth && "not-current-month",
1593
+ dayData.isDisabled && "disabled-date",
1594
+ dayData.isWeekend && "weekend-day",
1595
+ dayData.isCurrentDate && "ctp-today",
1596
+ dayData.isInRange && "ctp-in-range",
1597
+ dayData.isRangeStart && "ctp-range-start",
1598
+ dayData.isRangeEnd && "ctp-range-end"
1599
+ );
1600
+ }
1601
+ function syncDayButton(btn, dayData, snap) {
1602
+ const focused = dayData.date.isSame(snap.focusedDay, "day");
1603
+ const disabled = !dayData.isCurrentMonth || dayData.isDisabled;
1604
+ btn.className = dayDateClassName(dayData);
1605
+ btn.tabIndex = focused ? 0 : -1;
1606
+ btn.disabled = disabled;
1607
+ btn.setAttribute(
1608
+ "aria-selected",
1609
+ String(Boolean(dayData.isRangeStart || dayData.isRangeEnd))
1610
+ );
1611
+ btn.setAttribute("aria-disabled", String(disabled));
1612
+ }
1613
+ function canPatchHoverOnly(prev, next) {
1614
+ 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;
1615
+ }
1544
1616
  function createDateTimeRangePicker(target, options = {}) {
1545
1617
  const controller = new RangeController(options);
1546
1618
  const titleId = `ctp-range-${Math.random().toString(36).slice(2, 9)}`;
1547
1619
  let cleanups = [];
1548
1620
  let host = null;
1549
1621
  let portalRoot = null;
1622
+ let lastSnap = null;
1623
+ let dayButtons = null;
1550
1624
  const teardown = () => {
1551
1625
  cleanups.forEach((c) => c());
1552
1626
  cleanups = [];
@@ -1554,13 +1628,29 @@ function createDateTimeRangePicker(target, options = {}) {
1554
1628
  portalRoot = null;
1555
1629
  host?.remove();
1556
1630
  host = null;
1631
+ lastSnap = null;
1632
+ dayButtons = null;
1557
1633
  };
1558
1634
  const paint = () => {
1559
- teardown();
1560
1635
  const snap = controller.getSnapshot();
1561
1636
  if (!snap.open && !snap.inline) {
1637
+ teardown();
1562
1638
  return;
1563
1639
  }
1640
+ if (lastSnap && dayButtons && host && canPatchHoverOnly(lastSnap, snap)) {
1641
+ for (const week of snap.weeks) {
1642
+ for (const dayData of week) {
1643
+ const key = dayData.date.format("YYYY-MM-DD");
1644
+ const btn = dayButtons.get(key);
1645
+ if (btn) {
1646
+ syncDayButton(btn, dayData, snap);
1647
+ }
1648
+ }
1649
+ }
1650
+ lastSnap = snap;
1651
+ return;
1652
+ }
1653
+ teardown();
1564
1654
  const now = dayjs();
1565
1655
  const year = snap.viewMonth.year();
1566
1656
  const windowStart = Math.floor(year / 12) * 12;
@@ -1609,6 +1699,7 @@ function createDateTimeRangePicker(target, options = {}) {
1609
1699
  ])
1610
1700
  ]);
1611
1701
  if (snap.calPanel === "day") {
1702
+ const buttons = /* @__PURE__ */ new Map();
1612
1703
  const grid = el2("div", {
1613
1704
  className: "ctp-main-calendar",
1614
1705
  role: "grid",
@@ -1619,7 +1710,8 @@ function createDateTimeRangePicker(target, options = {}) {
1619
1710
  if (controller.handleGridKeyDown(ke.key)) {
1620
1711
  ke.preventDefault();
1621
1712
  }
1622
- }
1713
+ },
1714
+ onMouseleave: () => controller.setHoverEnd(null)
1623
1715
  });
1624
1716
  for (const label of snap.weekdayLabels) {
1625
1717
  grid.append(
@@ -1634,47 +1726,38 @@ function createDateTimeRangePicker(target, options = {}) {
1634
1726
  for (const dayData of week) {
1635
1727
  const focused = dayData.date.isSame(snap.focusedDay, "day");
1636
1728
  const disabled = !dayData.isCurrentMonth || dayData.isDisabled;
1637
- grid.append(
1638
- el2("button", {
1639
- type: "button",
1640
- role: "gridcell",
1641
- tabIndex: focused ? 0 : -1,
1642
- ariaSelected: Boolean(
1643
- dayData.isRangeStart || dayData.isRangeEnd
1644
- ),
1645
- ariaDisabled: disabled,
1646
- disabled,
1647
- ariaLabel: formatLocalized(
1648
- dayData.date,
1649
- "dddd, MMMM D, YYYY",
1650
- snap.locale
1651
- ),
1652
- className: cx(
1653
- "ctp-box",
1654
- "ctp-box-date",
1655
- !dayData.isCurrentMonth && "not-current-month",
1656
- dayData.isDisabled && "disabled-date",
1657
- dayData.isWeekend && "weekend-day",
1658
- dayData.isCurrentDate && "ctp-today",
1659
- dayData.isInRange && "ctp-in-range",
1660
- dayData.isRangeStart && "ctp-range-start",
1661
- dayData.isRangeEnd && "ctp-range-end"
1662
- ),
1663
- onClick: () => {
1664
- if (!disabled) {
1665
- controller.pickDay(dayData.date);
1666
- }
1667
- },
1668
- onMouseenter: () => {
1669
- if (!disabled && snap.start && !snap.end) {
1670
- controller.setHoverEnd(dayData.date);
1671
- }
1672
- },
1673
- textContent: dayData.date.format("D")
1674
- })
1675
- );
1729
+ const btn = el2("button", {
1730
+ type: "button",
1731
+ role: "gridcell",
1732
+ tabIndex: focused ? 0 : -1,
1733
+ ariaSelected: Boolean(
1734
+ dayData.isRangeStart || dayData.isRangeEnd
1735
+ ),
1736
+ ariaDisabled: disabled,
1737
+ disabled,
1738
+ ariaLabel: formatLocalized(
1739
+ dayData.date,
1740
+ "dddd, MMMM D, YYYY",
1741
+ snap.locale
1742
+ ),
1743
+ className: dayDateClassName(dayData),
1744
+ onClick: () => {
1745
+ if (!disabled) {
1746
+ controller.pickDay(dayData.date);
1747
+ }
1748
+ },
1749
+ onMouseenter: () => {
1750
+ if (!disabled && snap.start && !snap.end) {
1751
+ controller.setHoverEnd(dayData.date);
1752
+ }
1753
+ },
1754
+ textContent: dayData.date.format("D")
1755
+ });
1756
+ buttons.set(dayData.date.format("YYYY-MM-DD"), btn);
1757
+ grid.append(btn);
1676
1758
  }
1677
1759
  }
1760
+ dayButtons = buttons;
1678
1761
  body.append(grid);
1679
1762
  } else if (snap.calPanel === "month") {
1680
1763
  const grid = el2("div", {
@@ -1744,14 +1827,16 @@ function createDateTimeRangePicker(target, options = {}) {
1744
1827
  })
1745
1828
  );
1746
1829
  }
1747
- footerChildren.push(
1748
- el2("button", {
1749
- type: "button",
1750
- disabled: !snap.start || !snap.end,
1751
- onClick: () => controller.confirm(),
1752
- textContent: snap.labels.ok
1753
- })
1754
- );
1830
+ if (!snap.inline) {
1831
+ footerChildren.push(
1832
+ el2("button", {
1833
+ type: "button",
1834
+ disabled: !snap.start || !snap.end,
1835
+ onClick: () => controller.confirm(),
1836
+ textContent: snap.labels.ok
1837
+ })
1838
+ );
1839
+ }
1755
1840
  const picker = el2(
1756
1841
  "div",
1757
1842
  {
@@ -1776,6 +1861,7 @@ function createDateTimeRangePicker(target, options = {}) {
1776
1861
  if (snap.inline) {
1777
1862
  host = picker;
1778
1863
  target.append(picker);
1864
+ lastSnap = snap;
1779
1865
  return;
1780
1866
  }
1781
1867
  const backdrop = el2("div", {
@@ -1793,6 +1879,7 @@ function createDateTimeRangePicker(target, options = {}) {
1793
1879
  attachFocusTrap(picker, true),
1794
1880
  attachEscape(() => controller.close(), true)
1795
1881
  );
1882
+ lastSnap = snap;
1796
1883
  };
1797
1884
  const unsub = controller.subscribe(paint);
1798
1885
  paint();
@@ -1,6 +1,6 @@
1
1
  export { defineCustomElements } from '../wc/index.mjs';
2
- import '../rangeRenderer-AVv6PJbW.mjs';
3
- import '../rangeController-Bq35aBwe.mjs';
2
+ import '../rangeRenderer-CE99Ji3Q.mjs';
3
+ import '../rangeController-BBZcdM0Z.mjs';
4
4
  import 'dayjs';
5
5
 
6
6
  /** Ensure custom elements are registered (idempotent). */
@@ -1,6 +1,6 @@
1
1
  export { defineCustomElements } from '../wc/index.js';
2
- import '../rangeRenderer-a3hFk-kK.js';
3
- import '../rangeController-Bq35aBwe.js';
2
+ import '../rangeRenderer-CeLuwT6V.js';
3
+ import '../rangeController-BBZcdM0Z.js';
4
4
  import 'dayjs';
5
5
 
6
6
  /** Ensure custom elements are registered (idempotent). */