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;
@@ -1121,13 +1137,15 @@ function renderPicker(controller, snap, titleId, position, options) {
1121
1137
  })
1122
1138
  );
1123
1139
  }
1124
- footerChildren.push(
1125
- el("button", {
1126
- type: "button",
1127
- onClick: () => controller.confirm(),
1128
- textContent: snap.labels.ok
1129
- })
1130
- );
1140
+ if (!snap.inline) {
1141
+ footerChildren.push(
1142
+ el("button", {
1143
+ type: "button",
1144
+ onClick: () => controller.confirm(),
1145
+ textContent: snap.labels.ok
1146
+ })
1147
+ );
1148
+ }
1131
1149
  picker.append(el("div", { className: "ctp-footer" }, footerChildren));
1132
1150
  return picker;
1133
1151
  }
@@ -1261,6 +1279,15 @@ var RangeController = class {
1261
1279
  end: parseValue(range?.end ?? null, format)
1262
1280
  };
1263
1281
  }
1282
+ sameDay(a, b) {
1283
+ if (a === null && b === null) {
1284
+ return true;
1285
+ }
1286
+ if (a === null || b === null) {
1287
+ return false;
1288
+ }
1289
+ return a.isSame(b, "day");
1290
+ }
1264
1291
  setOptions(partial) {
1265
1292
  this.options = { ...this.options, ...partial };
1266
1293
  if (partial.open !== void 0) {
@@ -1274,11 +1301,14 @@ var RangeController = class {
1274
1301
  } else if (partial.value !== void 0) {
1275
1302
  const format = this.options.format ?? DATE_FORMAT;
1276
1303
  const parsed = this.parseRange(partial.value, format);
1277
- this.start = parsed.start;
1278
- this.end = parsed.end;
1279
- if (parsed.start) {
1280
- this.viewMonth = parsed.start.startOf("month");
1281
- this.focusedDay = parsed.start;
1304
+ const unchanged = this.sameDay(parsed.start, this.start) && this.sameDay(parsed.end, this.end);
1305
+ if (!unchanged) {
1306
+ this.start = parsed.start;
1307
+ this.end = parsed.end;
1308
+ if (parsed.start) {
1309
+ this.viewMonth = parsed.start.startOf("month");
1310
+ this.focusedDay = parsed.start;
1311
+ }
1282
1312
  }
1283
1313
  }
1284
1314
  }
@@ -1410,6 +1440,11 @@ var RangeController = class {
1410
1440
  this.focusedDay = day;
1411
1441
  }
1412
1442
  this.emit();
1443
+ if (this.options.asString === false) {
1444
+ this.emitRange(this.start, this.end);
1445
+ } else if (this.options.inline && this.start && this.end) {
1446
+ this.emitRange(this.start, this.end);
1447
+ }
1413
1448
  }
1414
1449
  setHoverEnd(day) {
1415
1450
  if (this.start && !this.end) {
@@ -1529,12 +1564,51 @@ function applyStyle2(node, style) {
1529
1564
  }
1530
1565
  Object.assign(node.style, style);
1531
1566
  }
1567
+ function sameDay(a, b) {
1568
+ if (a === null && b === null) {
1569
+ return true;
1570
+ }
1571
+ if (a === null || b === null) {
1572
+ return false;
1573
+ }
1574
+ return a.isSame(b, "day");
1575
+ }
1576
+ function dayDateClassName(dayData) {
1577
+ return cx(
1578
+ "ctp-box",
1579
+ "ctp-box-date",
1580
+ !dayData.isCurrentMonth && "not-current-month",
1581
+ dayData.isDisabled && "disabled-date",
1582
+ dayData.isWeekend && "weekend-day",
1583
+ dayData.isCurrentDate && "ctp-today",
1584
+ dayData.isInRange && "ctp-in-range",
1585
+ dayData.isRangeStart && "ctp-range-start",
1586
+ dayData.isRangeEnd && "ctp-range-end"
1587
+ );
1588
+ }
1589
+ function syncDayButton(btn, dayData, snap) {
1590
+ const focused = dayData.date.isSame(snap.focusedDay, "day");
1591
+ const disabled = !dayData.isCurrentMonth || dayData.isDisabled;
1592
+ btn.className = dayDateClassName(dayData);
1593
+ btn.tabIndex = focused ? 0 : -1;
1594
+ btn.disabled = disabled;
1595
+ btn.setAttribute(
1596
+ "aria-selected",
1597
+ String(Boolean(dayData.isRangeStart || dayData.isRangeEnd))
1598
+ );
1599
+ btn.setAttribute("aria-disabled", String(disabled));
1600
+ }
1601
+ function canPatchHoverOnly(prev, next) {
1602
+ 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;
1603
+ }
1532
1604
  function createDateTimeRangePicker(target, options = {}) {
1533
1605
  const controller = new RangeController(options);
1534
1606
  const titleId = `ctp-range-${Math.random().toString(36).slice(2, 9)}`;
1535
1607
  let cleanups = [];
1536
1608
  let host = null;
1537
1609
  let portalRoot = null;
1610
+ let lastSnap = null;
1611
+ let dayButtons = null;
1538
1612
  const teardown = () => {
1539
1613
  cleanups.forEach((c) => c());
1540
1614
  cleanups = [];
@@ -1542,13 +1616,29 @@ function createDateTimeRangePicker(target, options = {}) {
1542
1616
  portalRoot = null;
1543
1617
  host?.remove();
1544
1618
  host = null;
1619
+ lastSnap = null;
1620
+ dayButtons = null;
1545
1621
  };
1546
1622
  const paint = () => {
1547
- teardown();
1548
1623
  const snap = controller.getSnapshot();
1549
1624
  if (!snap.open && !snap.inline) {
1625
+ teardown();
1626
+ return;
1627
+ }
1628
+ if (lastSnap && dayButtons && host && canPatchHoverOnly(lastSnap, snap)) {
1629
+ for (const week of snap.weeks) {
1630
+ for (const dayData of week) {
1631
+ const key = dayData.date.format("YYYY-MM-DD");
1632
+ const btn = dayButtons.get(key);
1633
+ if (btn) {
1634
+ syncDayButton(btn, dayData, snap);
1635
+ }
1636
+ }
1637
+ }
1638
+ lastSnap = snap;
1550
1639
  return;
1551
1640
  }
1641
+ teardown();
1552
1642
  const now = dayjs();
1553
1643
  const year = snap.viewMonth.year();
1554
1644
  const windowStart = Math.floor(year / 12) * 12;
@@ -1597,6 +1687,7 @@ function createDateTimeRangePicker(target, options = {}) {
1597
1687
  ])
1598
1688
  ]);
1599
1689
  if (snap.calPanel === "day") {
1690
+ const buttons = /* @__PURE__ */ new Map();
1600
1691
  const grid = el2("div", {
1601
1692
  className: "ctp-main-calendar",
1602
1693
  role: "grid",
@@ -1607,7 +1698,8 @@ function createDateTimeRangePicker(target, options = {}) {
1607
1698
  if (controller.handleGridKeyDown(ke.key)) {
1608
1699
  ke.preventDefault();
1609
1700
  }
1610
- }
1701
+ },
1702
+ onMouseleave: () => controller.setHoverEnd(null)
1611
1703
  });
1612
1704
  for (const label of snap.weekdayLabels) {
1613
1705
  grid.append(
@@ -1622,47 +1714,38 @@ function createDateTimeRangePicker(target, options = {}) {
1622
1714
  for (const dayData of week) {
1623
1715
  const focused = dayData.date.isSame(snap.focusedDay, "day");
1624
1716
  const disabled = !dayData.isCurrentMonth || dayData.isDisabled;
1625
- grid.append(
1626
- el2("button", {
1627
- type: "button",
1628
- role: "gridcell",
1629
- tabIndex: focused ? 0 : -1,
1630
- ariaSelected: Boolean(
1631
- dayData.isRangeStart || dayData.isRangeEnd
1632
- ),
1633
- ariaDisabled: disabled,
1634
- disabled,
1635
- ariaLabel: formatLocalized(
1636
- dayData.date,
1637
- "dddd, MMMM D, YYYY",
1638
- snap.locale
1639
- ),
1640
- className: cx(
1641
- "ctp-box",
1642
- "ctp-box-date",
1643
- !dayData.isCurrentMonth && "not-current-month",
1644
- dayData.isDisabled && "disabled-date",
1645
- dayData.isWeekend && "weekend-day",
1646
- dayData.isCurrentDate && "ctp-today",
1647
- dayData.isInRange && "ctp-in-range",
1648
- dayData.isRangeStart && "ctp-range-start",
1649
- dayData.isRangeEnd && "ctp-range-end"
1650
- ),
1651
- onClick: () => {
1652
- if (!disabled) {
1653
- controller.pickDay(dayData.date);
1654
- }
1655
- },
1656
- onMouseenter: () => {
1657
- if (!disabled && snap.start && !snap.end) {
1658
- controller.setHoverEnd(dayData.date);
1659
- }
1660
- },
1661
- textContent: dayData.date.format("D")
1662
- })
1663
- );
1717
+ const btn = el2("button", {
1718
+ type: "button",
1719
+ role: "gridcell",
1720
+ tabIndex: focused ? 0 : -1,
1721
+ ariaSelected: Boolean(
1722
+ dayData.isRangeStart || dayData.isRangeEnd
1723
+ ),
1724
+ ariaDisabled: disabled,
1725
+ disabled,
1726
+ ariaLabel: formatLocalized(
1727
+ dayData.date,
1728
+ "dddd, MMMM D, YYYY",
1729
+ snap.locale
1730
+ ),
1731
+ className: dayDateClassName(dayData),
1732
+ onClick: () => {
1733
+ if (!disabled) {
1734
+ controller.pickDay(dayData.date);
1735
+ }
1736
+ },
1737
+ onMouseenter: () => {
1738
+ if (!disabled && snap.start && !snap.end) {
1739
+ controller.setHoverEnd(dayData.date);
1740
+ }
1741
+ },
1742
+ textContent: dayData.date.format("D")
1743
+ });
1744
+ buttons.set(dayData.date.format("YYYY-MM-DD"), btn);
1745
+ grid.append(btn);
1664
1746
  }
1665
1747
  }
1748
+ dayButtons = buttons;
1666
1749
  body.append(grid);
1667
1750
  } else if (snap.calPanel === "month") {
1668
1751
  const grid = el2("div", {
@@ -1732,14 +1815,16 @@ function createDateTimeRangePicker(target, options = {}) {
1732
1815
  })
1733
1816
  );
1734
1817
  }
1735
- footerChildren.push(
1736
- el2("button", {
1737
- type: "button",
1738
- disabled: !snap.start || !snap.end,
1739
- onClick: () => controller.confirm(),
1740
- textContent: snap.labels.ok
1741
- })
1742
- );
1818
+ if (!snap.inline) {
1819
+ footerChildren.push(
1820
+ el2("button", {
1821
+ type: "button",
1822
+ disabled: !snap.start || !snap.end,
1823
+ onClick: () => controller.confirm(),
1824
+ textContent: snap.labels.ok
1825
+ })
1826
+ );
1827
+ }
1743
1828
  const picker = el2(
1744
1829
  "div",
1745
1830
  {
@@ -1764,6 +1849,7 @@ function createDateTimeRangePicker(target, options = {}) {
1764
1849
  if (snap.inline) {
1765
1850
  host = picker;
1766
1851
  target.append(picker);
1852
+ lastSnap = snap;
1767
1853
  return;
1768
1854
  }
1769
1855
  const backdrop = el2("div", {
@@ -1781,6 +1867,7 @@ function createDateTimeRangePicker(target, options = {}) {
1781
1867
  attachFocusTrap(picker),
1782
1868
  attachEscape(() => controller.close())
1783
1869
  );
1870
+ lastSnap = snap;
1784
1871
  };
1785
1872
  const unsub = controller.subscribe(paint);
1786
1873
  paint();
@@ -1,5 +1,5 @@
1
- import { D as DateTimePickerHandle, a as DateTimeRangePickerHandle } from '../rangeRenderer-AVv6PJbW.mjs';
2
- import { f as DateTimeChangeValue } from '../rangeController-Bq35aBwe.mjs';
1
+ import { D as DateTimePickerHandle, a as DateTimeRangePickerHandle } from '../rangeRenderer-CE99Ji3Q.mjs';
2
+ import { f as DateTimeChangeValue } from '../rangeController-BBZcdM0Z.mjs';
3
3
  import 'dayjs';
4
4
 
5
5
  /** Ensure the shared stylesheet is in the document (light DOM). */
@@ -1,5 +1,5 @@
1
- import { D as DateTimePickerHandle, a as DateTimeRangePickerHandle } from '../rangeRenderer-a3hFk-kK.js';
2
- import { f as DateTimeChangeValue } from '../rangeController-Bq35aBwe.js';
1
+ import { D as DateTimePickerHandle, a as DateTimeRangePickerHandle } from '../rangeRenderer-CeLuwT6V.js';
2
+ import { f as DateTimeChangeValue } from '../rangeController-BBZcdM0Z.js';
3
3
  import 'dayjs';
4
4
 
5
5
  /** Ensure the shared stylesheet is in the document (light DOM). */