@vanduo-oss/framework 1.3.4 → 1.3.7
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.
- package/LICENSE +0 -14
- package/README.md +34 -176
- package/css/components/cards.css +11 -1
- package/css/components/datepicker.css +10 -1
- package/css/components/expanding-cards.css +215 -0
- package/css/components/spotlight.css +8 -3
- package/css/components/timeline.css +47 -0
- package/css/components/tooltips.css +8 -8
- package/css/effects/morph.css +247 -0
- package/css/vanduo.css +2 -0
- package/dist/build-info.json +3 -3
- package/dist/vanduo.cjs.js +754 -59
- package/dist/vanduo.cjs.js.map +3 -3
- package/dist/vanduo.cjs.min.js +4 -4
- package/dist/vanduo.cjs.min.js.map +4 -4
- package/dist/vanduo.css +477 -14
- package/dist/vanduo.css.map +1 -1
- package/dist/vanduo.esm.js +754 -59
- package/dist/vanduo.esm.js.map +3 -3
- package/dist/vanduo.esm.min.js +4 -4
- package/dist/vanduo.esm.min.js.map +4 -4
- package/dist/vanduo.js +754 -59
- package/dist/vanduo.js.map +3 -3
- package/dist/vanduo.min.css +2 -2
- package/dist/vanduo.min.css.map +1 -1
- package/dist/vanduo.min.js +4 -4
- package/dist/vanduo.min.js.map +4 -4
- package/js/components/datepicker.js +392 -70
- package/js/components/expanding-cards.js +136 -0
- package/js/components/morph.js +134 -0
- package/js/components/timeline.js +226 -0
- package/js/index.js +4 -1
- package/package.json +1 -1
package/dist/vanduo.cjs.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! Vanduo v1.3.
|
|
1
|
+
/*! Vanduo v1.3.7 | Built: 2026-04-18T12:05:32.603Z | git:20b2d08 | development */
|
|
2
2
|
var __defProp = Object.defineProperty;
|
|
3
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -132,7 +132,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
132
132
|
// js/vanduo.js
|
|
133
133
|
(function() {
|
|
134
134
|
"use strict";
|
|
135
|
-
const VANDUO_VERSION = true ? "1.3.
|
|
135
|
+
const VANDUO_VERSION = true ? "1.3.7" : "0.0.0-dev";
|
|
136
136
|
const Vanduo2 = {
|
|
137
137
|
version: VANDUO_VERSION,
|
|
138
138
|
components: {},
|
|
@@ -6597,6 +6597,410 @@ module.exports = __toCommonJS(index_exports);
|
|
|
6597
6597
|
window.VanduoGlassScroll = GlassScroll;
|
|
6598
6598
|
})();
|
|
6599
6599
|
|
|
6600
|
+
// js/components/morph.js
|
|
6601
|
+
(function() {
|
|
6602
|
+
"use strict";
|
|
6603
|
+
const MORPH_DURATION_MS = 750;
|
|
6604
|
+
const Morph = {
|
|
6605
|
+
instances: /* @__PURE__ */ new Map(),
|
|
6606
|
+
init: function() {
|
|
6607
|
+
const elements = document.querySelectorAll(".vd-morph, [data-vd-morph]");
|
|
6608
|
+
elements.forEach(function(el) {
|
|
6609
|
+
if (Morph.instances.has(el)) return;
|
|
6610
|
+
if (el.getAttribute("data-vd-morph") === "manual") return;
|
|
6611
|
+
Morph.initInstance(el);
|
|
6612
|
+
});
|
|
6613
|
+
},
|
|
6614
|
+
initInstance: function(el) {
|
|
6615
|
+
Morph._ensureLayers(el);
|
|
6616
|
+
const cleanup = [];
|
|
6617
|
+
let morphing = false;
|
|
6618
|
+
const handleClick = function(e) {
|
|
6619
|
+
if (morphing) return;
|
|
6620
|
+
Morph._runMorph(el, e, function() {
|
|
6621
|
+
morphing = false;
|
|
6622
|
+
});
|
|
6623
|
+
morphing = true;
|
|
6624
|
+
};
|
|
6625
|
+
el.addEventListener("click", handleClick);
|
|
6626
|
+
cleanup.push(function() {
|
|
6627
|
+
el.removeEventListener("click", handleClick);
|
|
6628
|
+
});
|
|
6629
|
+
this.instances.set(el, { cleanup });
|
|
6630
|
+
},
|
|
6631
|
+
morph: function(el) {
|
|
6632
|
+
if (!el) return;
|
|
6633
|
+
if (!this.instances.has(el)) this.initInstance(el);
|
|
6634
|
+
this._runMorph(el, null, null);
|
|
6635
|
+
},
|
|
6636
|
+
destroy: function(el) {
|
|
6637
|
+
const instance = this.instances.get(el);
|
|
6638
|
+
if (!instance) return;
|
|
6639
|
+
instance.cleanup.forEach(function(fn) {
|
|
6640
|
+
fn();
|
|
6641
|
+
});
|
|
6642
|
+
this.instances.delete(el);
|
|
6643
|
+
},
|
|
6644
|
+
destroyAll: function() {
|
|
6645
|
+
this.instances.forEach(function(_, el) {
|
|
6646
|
+
Morph.destroy(el);
|
|
6647
|
+
});
|
|
6648
|
+
},
|
|
6649
|
+
/* ── Internal helpers ── */
|
|
6650
|
+
_ensureLayers: function(el) {
|
|
6651
|
+
if (!el.querySelector(".vd-morph-wave")) {
|
|
6652
|
+
const wave = document.createElement("span");
|
|
6653
|
+
wave.className = "vd-morph-wave";
|
|
6654
|
+
wave.setAttribute("aria-hidden", "true");
|
|
6655
|
+
el.insertBefore(wave, el.firstChild);
|
|
6656
|
+
}
|
|
6657
|
+
if (!el.querySelector(".vd-morph-shine")) {
|
|
6658
|
+
const shine = document.createElement("span");
|
|
6659
|
+
shine.className = "vd-morph-shine";
|
|
6660
|
+
shine.setAttribute("aria-hidden", "true");
|
|
6661
|
+
const waveEl = el.querySelector(".vd-morph-wave");
|
|
6662
|
+
if (waveEl && waveEl.nextSibling) {
|
|
6663
|
+
el.insertBefore(shine, waveEl.nextSibling);
|
|
6664
|
+
} else {
|
|
6665
|
+
el.insertBefore(shine, el.firstChild);
|
|
6666
|
+
}
|
|
6667
|
+
}
|
|
6668
|
+
},
|
|
6669
|
+
_runMorph: function(el, pointerEvent, onComplete) {
|
|
6670
|
+
const wave = el.querySelector(".vd-morph-wave");
|
|
6671
|
+
if (wave) {
|
|
6672
|
+
const rect = el.getBoundingClientRect();
|
|
6673
|
+
const cx = rect.left + rect.width / 2;
|
|
6674
|
+
const cy = rect.top + rect.height / 2;
|
|
6675
|
+
const px = pointerEvent ? pointerEvent.clientX || cx : cx;
|
|
6676
|
+
const py = pointerEvent ? pointerEvent.clientY || cy : cy;
|
|
6677
|
+
wave.style.left = px - rect.left + "px";
|
|
6678
|
+
wave.style.top = py - rect.top + "px";
|
|
6679
|
+
}
|
|
6680
|
+
el.classList.add("is-morphing");
|
|
6681
|
+
let duration = MORPH_DURATION_MS;
|
|
6682
|
+
const custom = getComputedStyle(el).getPropertyValue("--morph-duration");
|
|
6683
|
+
if (custom) {
|
|
6684
|
+
const parsed = parseFloat(custom);
|
|
6685
|
+
if (!isNaN(parsed)) duration = parsed * (custom.indexOf("ms") !== -1 ? 1 : 1e3);
|
|
6686
|
+
}
|
|
6687
|
+
setTimeout(function() {
|
|
6688
|
+
el.classList.remove("is-morphing");
|
|
6689
|
+
const current = el.querySelector(".vd-morph-current");
|
|
6690
|
+
const next = el.querySelector(".vd-morph-next");
|
|
6691
|
+
if (current && next) {
|
|
6692
|
+
current.classList.remove("vd-morph-current");
|
|
6693
|
+
current.classList.add("vd-morph-next");
|
|
6694
|
+
next.classList.remove("vd-morph-next");
|
|
6695
|
+
next.classList.add("vd-morph-current");
|
|
6696
|
+
}
|
|
6697
|
+
if (typeof onComplete === "function") onComplete();
|
|
6698
|
+
}, duration);
|
|
6699
|
+
}
|
|
6700
|
+
};
|
|
6701
|
+
if (typeof window.Vanduo !== "undefined") {
|
|
6702
|
+
window.Vanduo.register("morph", Morph);
|
|
6703
|
+
}
|
|
6704
|
+
window.VanduoMorph = Morph;
|
|
6705
|
+
})();
|
|
6706
|
+
|
|
6707
|
+
// js/components/expanding-cards.js
|
|
6708
|
+
(function() {
|
|
6709
|
+
"use strict";
|
|
6710
|
+
const ExpandingCards = {
|
|
6711
|
+
instances: /* @__PURE__ */ new Map(),
|
|
6712
|
+
init: function() {
|
|
6713
|
+
document.querySelectorAll(".vd-expanding-cards").forEach(function(el) {
|
|
6714
|
+
if (el.getAttribute("data-vd-expanding-cards") === "manual") return;
|
|
6715
|
+
if (ExpandingCards.instances.has(el)) return;
|
|
6716
|
+
ExpandingCards.initContainer(el);
|
|
6717
|
+
});
|
|
6718
|
+
},
|
|
6719
|
+
initContainer: function(container) {
|
|
6720
|
+
const cleanup = [];
|
|
6721
|
+
const getCards = function() {
|
|
6722
|
+
return Array.prototype.slice.call(container.querySelectorAll(".vd-expanding-card"));
|
|
6723
|
+
};
|
|
6724
|
+
const setActive = function(card) {
|
|
6725
|
+
const cards = getCards();
|
|
6726
|
+
if (!card || cards.indexOf(card) === -1) return;
|
|
6727
|
+
cards.forEach(function(c) {
|
|
6728
|
+
c.classList.toggle("is-active", c === card);
|
|
6729
|
+
});
|
|
6730
|
+
card.focus({ preventScroll: true });
|
|
6731
|
+
};
|
|
6732
|
+
const onClick = function(e) {
|
|
6733
|
+
const t = e.target;
|
|
6734
|
+
const card = t.closest ? t.closest(".vd-expanding-card") : null;
|
|
6735
|
+
if (!card || !container.contains(card)) return;
|
|
6736
|
+
setActive(card);
|
|
6737
|
+
};
|
|
6738
|
+
const onKeydown = function(e) {
|
|
6739
|
+
if (e.key !== "ArrowLeft" && e.key !== "ArrowRight" && e.key !== "Home" && e.key !== "End") {
|
|
6740
|
+
return;
|
|
6741
|
+
}
|
|
6742
|
+
const cards = getCards().filter(function(c) {
|
|
6743
|
+
return c.offsetParent !== null || c.getClientRects().length > 0;
|
|
6744
|
+
});
|
|
6745
|
+
if (!cards.length) return;
|
|
6746
|
+
const activeEl = document.activeElement;
|
|
6747
|
+
let idx = cards.indexOf(activeEl);
|
|
6748
|
+
if (idx < 0) {
|
|
6749
|
+
idx = cards.findIndex(function(c) {
|
|
6750
|
+
return c.classList.contains("is-active");
|
|
6751
|
+
});
|
|
6752
|
+
}
|
|
6753
|
+
if (idx < 0) idx = 0;
|
|
6754
|
+
if (e.key === "ArrowLeft") {
|
|
6755
|
+
e.preventDefault();
|
|
6756
|
+
setActive(cards[Math.max(0, idx - 1)]);
|
|
6757
|
+
} else if (e.key === "ArrowRight") {
|
|
6758
|
+
e.preventDefault();
|
|
6759
|
+
setActive(cards[Math.min(cards.length - 1, idx + 1)]);
|
|
6760
|
+
} else if (e.key === "Home") {
|
|
6761
|
+
e.preventDefault();
|
|
6762
|
+
setActive(cards[0]);
|
|
6763
|
+
} else if (e.key === "End") {
|
|
6764
|
+
e.preventDefault();
|
|
6765
|
+
setActive(cards[cards.length - 1]);
|
|
6766
|
+
}
|
|
6767
|
+
};
|
|
6768
|
+
container.addEventListener("click", onClick);
|
|
6769
|
+
cleanup.push(function() {
|
|
6770
|
+
container.removeEventListener("click", onClick);
|
|
6771
|
+
});
|
|
6772
|
+
container.addEventListener("keydown", onKeydown);
|
|
6773
|
+
cleanup.push(function() {
|
|
6774
|
+
container.removeEventListener("keydown", onKeydown);
|
|
6775
|
+
});
|
|
6776
|
+
getCards().forEach(function(card) {
|
|
6777
|
+
if (!card.hasAttribute("tabindex")) {
|
|
6778
|
+
card.setAttribute("tabindex", "0");
|
|
6779
|
+
}
|
|
6780
|
+
card.setAttribute("role", "button");
|
|
6781
|
+
if (!card.hasAttribute("aria-pressed")) {
|
|
6782
|
+
card.setAttribute("aria-pressed", card.classList.contains("is-active") ? "true" : "false");
|
|
6783
|
+
}
|
|
6784
|
+
});
|
|
6785
|
+
const syncAria = function() {
|
|
6786
|
+
getCards().forEach(function(card) {
|
|
6787
|
+
card.setAttribute("aria-pressed", card.classList.contains("is-active") ? "true" : "false");
|
|
6788
|
+
});
|
|
6789
|
+
};
|
|
6790
|
+
const mo = new MutationObserver(syncAria);
|
|
6791
|
+
mo.observe(container, { attributes: true, subtree: true, attributeFilter: ["class"] });
|
|
6792
|
+
cleanup.push(function() {
|
|
6793
|
+
mo.disconnect();
|
|
6794
|
+
});
|
|
6795
|
+
syncAria();
|
|
6796
|
+
ExpandingCards.instances.set(container, { cleanup });
|
|
6797
|
+
},
|
|
6798
|
+
destroy: function(container) {
|
|
6799
|
+
const inst = this.instances.get(container);
|
|
6800
|
+
if (!inst) return;
|
|
6801
|
+
inst.cleanup.forEach(function(fn) {
|
|
6802
|
+
fn();
|
|
6803
|
+
});
|
|
6804
|
+
this.instances.delete(container);
|
|
6805
|
+
},
|
|
6806
|
+
destroyAll: function() {
|
|
6807
|
+
this.instances.forEach(function(_, el) {
|
|
6808
|
+
ExpandingCards.destroy(el);
|
|
6809
|
+
});
|
|
6810
|
+
}
|
|
6811
|
+
};
|
|
6812
|
+
if (typeof window.Vanduo !== "undefined") {
|
|
6813
|
+
window.Vanduo.register("expandingCards", ExpandingCards);
|
|
6814
|
+
}
|
|
6815
|
+
window.VanduoExpandingCards = ExpandingCards;
|
|
6816
|
+
})();
|
|
6817
|
+
|
|
6818
|
+
// js/components/timeline.js
|
|
6819
|
+
(function() {
|
|
6820
|
+
"use strict";
|
|
6821
|
+
const STAGGER_MS = 140;
|
|
6822
|
+
const MAX_STAGGER_INDEX = 7;
|
|
6823
|
+
const PLAY_INTERVAL_MS = 800;
|
|
6824
|
+
function countRevealedPrefix(items) {
|
|
6825
|
+
let count = 0;
|
|
6826
|
+
for (let i = 0; i < items.length; i++) {
|
|
6827
|
+
if (!items[i].classList.contains("is-revealed")) break;
|
|
6828
|
+
count++;
|
|
6829
|
+
}
|
|
6830
|
+
return count;
|
|
6831
|
+
}
|
|
6832
|
+
function findPlaybackControls(container) {
|
|
6833
|
+
return container.parentElement || document.body;
|
|
6834
|
+
}
|
|
6835
|
+
function initPlayback(container, items, cleanup) {
|
|
6836
|
+
items.forEach(function(item) {
|
|
6837
|
+
item.classList.remove("is-revealed");
|
|
6838
|
+
});
|
|
6839
|
+
const scope = findPlaybackControls(container);
|
|
6840
|
+
const prevBtn = scope.querySelector("[data-vd-timeline-prev]");
|
|
6841
|
+
const nextBtn = scope.querySelector("[data-vd-timeline-next]");
|
|
6842
|
+
const playBtn = scope.querySelector("[data-vd-timeline-play]");
|
|
6843
|
+
const pauseBtn = scope.querySelector("[data-vd-timeline-pause]");
|
|
6844
|
+
let playTimer = null;
|
|
6845
|
+
function updateNavButtons() {
|
|
6846
|
+
const k = countRevealedPrefix(items);
|
|
6847
|
+
const n = items.length;
|
|
6848
|
+
if (prevBtn) {
|
|
6849
|
+
const atStart = k === 0;
|
|
6850
|
+
prevBtn.disabled = atStart;
|
|
6851
|
+
prevBtn.setAttribute("aria-disabled", atStart ? "true" : "false");
|
|
6852
|
+
}
|
|
6853
|
+
if (nextBtn) {
|
|
6854
|
+
const atEnd = k >= n;
|
|
6855
|
+
nextBtn.disabled = atEnd;
|
|
6856
|
+
nextBtn.setAttribute("aria-disabled", atEnd ? "true" : "false");
|
|
6857
|
+
}
|
|
6858
|
+
if (playBtn) {
|
|
6859
|
+
playBtn.setAttribute("aria-pressed", playTimer ? "true" : "false");
|
|
6860
|
+
}
|
|
6861
|
+
if (pauseBtn) {
|
|
6862
|
+
pauseBtn.disabled = !playTimer;
|
|
6863
|
+
}
|
|
6864
|
+
}
|
|
6865
|
+
function stepNext() {
|
|
6866
|
+
const k = countRevealedPrefix(items);
|
|
6867
|
+
if (k < items.length) {
|
|
6868
|
+
items[k].classList.add("is-revealed");
|
|
6869
|
+
}
|
|
6870
|
+
updateNavButtons();
|
|
6871
|
+
}
|
|
6872
|
+
function stepPrev() {
|
|
6873
|
+
const k = countRevealedPrefix(items);
|
|
6874
|
+
if (k > 0) {
|
|
6875
|
+
items[k - 1].classList.remove("is-revealed");
|
|
6876
|
+
}
|
|
6877
|
+
updateNavButtons();
|
|
6878
|
+
}
|
|
6879
|
+
function play() {
|
|
6880
|
+
if (playTimer) return;
|
|
6881
|
+
playTimer = setInterval(function() {
|
|
6882
|
+
if (countRevealedPrefix(items) >= items.length) {
|
|
6883
|
+
pause();
|
|
6884
|
+
return;
|
|
6885
|
+
}
|
|
6886
|
+
stepNext();
|
|
6887
|
+
}, PLAY_INTERVAL_MS);
|
|
6888
|
+
updateNavButtons();
|
|
6889
|
+
}
|
|
6890
|
+
function pause() {
|
|
6891
|
+
if (playTimer) {
|
|
6892
|
+
clearInterval(playTimer);
|
|
6893
|
+
playTimer = null;
|
|
6894
|
+
}
|
|
6895
|
+
updateNavButtons();
|
|
6896
|
+
}
|
|
6897
|
+
function addClick(el, fn) {
|
|
6898
|
+
if (!el) return;
|
|
6899
|
+
const handler = function(e) {
|
|
6900
|
+
e.preventDefault();
|
|
6901
|
+
fn();
|
|
6902
|
+
};
|
|
6903
|
+
el.addEventListener("click", handler);
|
|
6904
|
+
cleanup.push(function() {
|
|
6905
|
+
el.removeEventListener("click", handler);
|
|
6906
|
+
});
|
|
6907
|
+
}
|
|
6908
|
+
addClick(prevBtn, stepPrev);
|
|
6909
|
+
addClick(nextBtn, stepNext);
|
|
6910
|
+
addClick(playBtn, play);
|
|
6911
|
+
addClick(pauseBtn, pause);
|
|
6912
|
+
cleanup.push(function() {
|
|
6913
|
+
pause();
|
|
6914
|
+
});
|
|
6915
|
+
updateNavButtons();
|
|
6916
|
+
return {
|
|
6917
|
+
stepNext,
|
|
6918
|
+
stepPrev,
|
|
6919
|
+
play,
|
|
6920
|
+
pause
|
|
6921
|
+
};
|
|
6922
|
+
}
|
|
6923
|
+
const Timeline = {
|
|
6924
|
+
instances: /* @__PURE__ */ new Map(),
|
|
6925
|
+
init: function() {
|
|
6926
|
+
document.querySelectorAll(".vd-timeline.vd-timeline-animated").forEach(function(el) {
|
|
6927
|
+
if (Timeline.instances.has(el)) return;
|
|
6928
|
+
Timeline.initInstance(el);
|
|
6929
|
+
});
|
|
6930
|
+
},
|
|
6931
|
+
reinit: function() {
|
|
6932
|
+
Timeline.destroyAll();
|
|
6933
|
+
Timeline.init();
|
|
6934
|
+
},
|
|
6935
|
+
initInstance: function(container) {
|
|
6936
|
+
const cleanup = [];
|
|
6937
|
+
const items = Array.prototype.filter.call(container.children, function(child) {
|
|
6938
|
+
return child.classList && child.classList.contains("vd-timeline-item");
|
|
6939
|
+
});
|
|
6940
|
+
items.forEach(function(item, i) {
|
|
6941
|
+
const idx = Math.min(i, MAX_STAGGER_INDEX);
|
|
6942
|
+
item.style.setProperty("--vd-timeline-reveal-delay", idx * STAGGER_MS + "ms");
|
|
6943
|
+
});
|
|
6944
|
+
const reducedMotion = typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
6945
|
+
if (reducedMotion) {
|
|
6946
|
+
items.forEach(function(item) {
|
|
6947
|
+
item.classList.add("is-revealed");
|
|
6948
|
+
});
|
|
6949
|
+
Timeline.instances.set(container, { cleanup });
|
|
6950
|
+
return;
|
|
6951
|
+
}
|
|
6952
|
+
const playback = container.classList && container.classList.contains("vd-timeline-playback");
|
|
6953
|
+
if (playback) {
|
|
6954
|
+
const playbackApi = initPlayback(container, items, cleanup);
|
|
6955
|
+
Timeline.instances.set(container, { cleanup, playback: playbackApi });
|
|
6956
|
+
return;
|
|
6957
|
+
}
|
|
6958
|
+
if (typeof IntersectionObserver === "undefined") {
|
|
6959
|
+
items.forEach(function(item) {
|
|
6960
|
+
item.classList.add("is-revealed");
|
|
6961
|
+
});
|
|
6962
|
+
Timeline.instances.set(container, { cleanup });
|
|
6963
|
+
return;
|
|
6964
|
+
}
|
|
6965
|
+
const observer = new IntersectionObserver(function(entries) {
|
|
6966
|
+
entries.forEach(function(entry) {
|
|
6967
|
+
if (!entry.isIntersecting) return;
|
|
6968
|
+
entry.target.classList.add("is-revealed");
|
|
6969
|
+
observer.unobserve(entry.target);
|
|
6970
|
+
});
|
|
6971
|
+
}, {
|
|
6972
|
+
root: null,
|
|
6973
|
+
rootMargin: "0px 0px -10% 0px",
|
|
6974
|
+
threshold: 0.15
|
|
6975
|
+
});
|
|
6976
|
+
items.forEach(function(item) {
|
|
6977
|
+
observer.observe(item);
|
|
6978
|
+
});
|
|
6979
|
+
cleanup.push(function() {
|
|
6980
|
+
observer.disconnect();
|
|
6981
|
+
});
|
|
6982
|
+
Timeline.instances.set(container, { cleanup });
|
|
6983
|
+
},
|
|
6984
|
+
destroy: function(container) {
|
|
6985
|
+
const inst = this.instances.get(container);
|
|
6986
|
+
if (!inst) return;
|
|
6987
|
+
inst.cleanup.forEach(function(fn) {
|
|
6988
|
+
fn();
|
|
6989
|
+
});
|
|
6990
|
+
this.instances.delete(container);
|
|
6991
|
+
},
|
|
6992
|
+
destroyAll: function() {
|
|
6993
|
+
this.instances.forEach(function(_, el) {
|
|
6994
|
+
Timeline.destroy(el);
|
|
6995
|
+
});
|
|
6996
|
+
}
|
|
6997
|
+
};
|
|
6998
|
+
if (typeof window.Vanduo !== "undefined") {
|
|
6999
|
+
window.Vanduo.register("timeline", Timeline);
|
|
7000
|
+
}
|
|
7001
|
+
window.VanduoTimeline = Timeline;
|
|
7002
|
+
})();
|
|
7003
|
+
|
|
6600
7004
|
// js/components/flow.js
|
|
6601
7005
|
(function() {
|
|
6602
7006
|
"use strict";
|
|
@@ -7613,6 +8017,115 @@ module.exports = __toCommonJS(index_exports);
|
|
|
7613
8017
|
"use strict";
|
|
7614
8018
|
const DAYS = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
|
|
7615
8019
|
const MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
|
|
8020
|
+
function escapeRegexChar(c) {
|
|
8021
|
+
return c.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
8022
|
+
}
|
|
8023
|
+
function buildParseFormat(format) {
|
|
8024
|
+
let regex = "^";
|
|
8025
|
+
const order = [];
|
|
8026
|
+
let i = 0;
|
|
8027
|
+
while (i < format.length) {
|
|
8028
|
+
const slice = format.slice(i);
|
|
8029
|
+
if (slice.toLowerCase().startsWith("yyyy")) {
|
|
8030
|
+
regex += "(\\d{4})";
|
|
8031
|
+
order.push("y");
|
|
8032
|
+
i += 4;
|
|
8033
|
+
} else if (slice.toLowerCase().startsWith("mm")) {
|
|
8034
|
+
regex += "(\\d{2})";
|
|
8035
|
+
order.push("m");
|
|
8036
|
+
i += 2;
|
|
8037
|
+
} else if (slice.toLowerCase().startsWith("dd")) {
|
|
8038
|
+
regex += "(\\d{2})";
|
|
8039
|
+
order.push("d");
|
|
8040
|
+
i += 2;
|
|
8041
|
+
} else {
|
|
8042
|
+
regex += escapeRegexChar(format[i]);
|
|
8043
|
+
i++;
|
|
8044
|
+
}
|
|
8045
|
+
}
|
|
8046
|
+
regex += "$";
|
|
8047
|
+
return { regex: new RegExp(regex), order };
|
|
8048
|
+
}
|
|
8049
|
+
function parseDateFromFormat(value, format) {
|
|
8050
|
+
if (!value || !format) return null;
|
|
8051
|
+
const { regex, order } = buildParseFormat(format);
|
|
8052
|
+
const m = value.trim().match(regex);
|
|
8053
|
+
if (!m) return null;
|
|
8054
|
+
let y;
|
|
8055
|
+
let mo;
|
|
8056
|
+
let d;
|
|
8057
|
+
let ci = 1;
|
|
8058
|
+
for (let k = 0; k < order.length; k++) {
|
|
8059
|
+
const part = order[k];
|
|
8060
|
+
const v = parseInt(m[ci++], 10);
|
|
8061
|
+
if (Number.isNaN(v)) return null;
|
|
8062
|
+
if (part === "y") y = v;
|
|
8063
|
+
else if (part === "m") mo = v - 1;
|
|
8064
|
+
else if (part === "d") d = v;
|
|
8065
|
+
}
|
|
8066
|
+
if (y === void 0 || mo === void 0 || d === void 0) return null;
|
|
8067
|
+
const dt = new Date(y, mo, d);
|
|
8068
|
+
if (dt.getFullYear() !== y || dt.getMonth() !== mo || dt.getDate() !== d) return null;
|
|
8069
|
+
return dt;
|
|
8070
|
+
}
|
|
8071
|
+
function formatDate(d, format) {
|
|
8072
|
+
const yyyy = String(d.getFullYear());
|
|
8073
|
+
const mm = String(d.getMonth() + 1).padStart(2, "0");
|
|
8074
|
+
const dd = String(d.getDate()).padStart(2, "0");
|
|
8075
|
+
let out = "";
|
|
8076
|
+
let i = 0;
|
|
8077
|
+
while (i < format.length) {
|
|
8078
|
+
const slice = format.slice(i);
|
|
8079
|
+
if (slice.toLowerCase().startsWith("yyyy")) {
|
|
8080
|
+
out += yyyy;
|
|
8081
|
+
i += 4;
|
|
8082
|
+
} else if (slice.toLowerCase().startsWith("mm")) {
|
|
8083
|
+
out += mm;
|
|
8084
|
+
i += 2;
|
|
8085
|
+
} else if (slice.toLowerCase().startsWith("dd")) {
|
|
8086
|
+
out += dd;
|
|
8087
|
+
i += 2;
|
|
8088
|
+
} else {
|
|
8089
|
+
out += format[i];
|
|
8090
|
+
i++;
|
|
8091
|
+
}
|
|
8092
|
+
}
|
|
8093
|
+
return out;
|
|
8094
|
+
}
|
|
8095
|
+
function dateKey(d) {
|
|
8096
|
+
return d.getFullYear() + "-" + String(d.getMonth() + 1).padStart(2, "0") + "-" + String(d.getDate()).padStart(2, "0");
|
|
8097
|
+
}
|
|
8098
|
+
function addDays(d, n) {
|
|
8099
|
+
const x = new Date(d.getFullYear(), d.getMonth(), d.getDate());
|
|
8100
|
+
x.setDate(x.getDate() + n);
|
|
8101
|
+
return x;
|
|
8102
|
+
}
|
|
8103
|
+
function addMonthsClamped(d, n) {
|
|
8104
|
+
return new Date(d.getFullYear(), d.getMonth() + n, d.getDate());
|
|
8105
|
+
}
|
|
8106
|
+
function parseYmdLocal(ymd) {
|
|
8107
|
+
if (!ymd || typeof ymd !== "string") return null;
|
|
8108
|
+
const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(ymd.trim());
|
|
8109
|
+
if (!m) return null;
|
|
8110
|
+
const y = +m[1];
|
|
8111
|
+
const mo = +m[2] - 1;
|
|
8112
|
+
const day = +m[3];
|
|
8113
|
+
const dt = new Date(y, mo, day);
|
|
8114
|
+
if (dt.getFullYear() !== y || dt.getMonth() !== mo || dt.getDate() !== day) return null;
|
|
8115
|
+
return dt;
|
|
8116
|
+
}
|
|
8117
|
+
function startOfWeekSunday(d) {
|
|
8118
|
+
const x = new Date(d.getFullYear(), d.getMonth(), d.getDate());
|
|
8119
|
+
const day = x.getDay();
|
|
8120
|
+
x.setDate(x.getDate() - day);
|
|
8121
|
+
return x;
|
|
8122
|
+
}
|
|
8123
|
+
function endOfWeekSunday(d) {
|
|
8124
|
+
const x = new Date(d.getFullYear(), d.getMonth(), d.getDate());
|
|
8125
|
+
const day = x.getDay();
|
|
8126
|
+
x.setDate(x.getDate() + (6 - day));
|
|
8127
|
+
return x;
|
|
8128
|
+
}
|
|
7616
8129
|
const Datepicker = {
|
|
7617
8130
|
instances: /* @__PURE__ */ new Map(),
|
|
7618
8131
|
init: function() {
|
|
@@ -7624,28 +8137,70 @@ module.exports = __toCommonJS(index_exports);
|
|
|
7624
8137
|
},
|
|
7625
8138
|
initInstance: function(input) {
|
|
7626
8139
|
const cleanup = [];
|
|
7627
|
-
const format = input.getAttribute("data-vd-datepicker-format") || "
|
|
8140
|
+
const format = input.getAttribute("data-vd-datepicker-format") || "YYYY-MM-DD";
|
|
7628
8141
|
const minStr = input.getAttribute("data-vd-datepicker-min");
|
|
7629
8142
|
const maxStr = input.getAttribute("data-vd-datepicker-max");
|
|
7630
|
-
const minDate = minStr ?
|
|
7631
|
-
const maxDate = maxStr ?
|
|
8143
|
+
const minDate = minStr ? parseYmdLocal(minStr) : null;
|
|
8144
|
+
const maxDate = maxStr ? parseYmdLocal(maxStr) : null;
|
|
7632
8145
|
const today = /* @__PURE__ */ new Date();
|
|
7633
8146
|
let viewYear = today.getFullYear();
|
|
7634
8147
|
let viewMonth = today.getMonth();
|
|
7635
8148
|
let selectedDate = null;
|
|
7636
8149
|
let viewMode = "days";
|
|
8150
|
+
let focusedDate = null;
|
|
8151
|
+
let skipNextFocusOpen = false;
|
|
8152
|
+
const isDisabled = (d) => {
|
|
8153
|
+
if (minDate) {
|
|
8154
|
+
const t = new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime();
|
|
8155
|
+
if (t < minDate.getTime()) return true;
|
|
8156
|
+
}
|
|
8157
|
+
if (maxDate) {
|
|
8158
|
+
const t = new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime();
|
|
8159
|
+
if (t > maxDate.getTime()) return true;
|
|
8160
|
+
}
|
|
8161
|
+
return false;
|
|
8162
|
+
};
|
|
8163
|
+
const ensureMonthInRange = (y, m) => {
|
|
8164
|
+
if (!minDate && !maxDate) return { y, m };
|
|
8165
|
+
const first = new Date(y, m, 1);
|
|
8166
|
+
const last = new Date(y, m + 1, 0);
|
|
8167
|
+
if (minDate && last.getTime() < minDate.getTime()) {
|
|
8168
|
+
return { y: minDate.getFullYear(), m: minDate.getMonth() };
|
|
8169
|
+
}
|
|
8170
|
+
if (maxDate && first.getTime() > maxDate.getTime()) {
|
|
8171
|
+
return { y: maxDate.getFullYear(), m: maxDate.getMonth() };
|
|
8172
|
+
}
|
|
8173
|
+
return { y, m };
|
|
8174
|
+
};
|
|
8175
|
+
const firstSelectableInMonth = (y, m) => {
|
|
8176
|
+
const last = new Date(y, m + 1, 0).getDate();
|
|
8177
|
+
for (let day = 1; day <= last; day++) {
|
|
8178
|
+
const dt = new Date(y, m, day);
|
|
8179
|
+
if (!isDisabled(dt)) return dt;
|
|
8180
|
+
}
|
|
8181
|
+
return new Date(y, m, 1);
|
|
8182
|
+
};
|
|
7637
8183
|
if (input.value) {
|
|
7638
|
-
const
|
|
7639
|
-
|
|
8184
|
+
const trimmed = input.value.trim();
|
|
8185
|
+
let parsed = parseDateFromFormat(trimmed, format);
|
|
8186
|
+
if (!parsed) {
|
|
8187
|
+
const fallback = new Date(trimmed);
|
|
8188
|
+
if (!isNaN(fallback.getTime())) parsed = fallback;
|
|
8189
|
+
}
|
|
8190
|
+
if (parsed) {
|
|
7640
8191
|
selectedDate = parsed;
|
|
7641
8192
|
viewYear = parsed.getFullYear();
|
|
7642
8193
|
viewMonth = parsed.getMonth();
|
|
7643
8194
|
}
|
|
7644
8195
|
}
|
|
8196
|
+
const clampedInit = ensureMonthInRange(viewYear, viewMonth);
|
|
8197
|
+
viewYear = clampedInit.y;
|
|
8198
|
+
viewMonth = clampedInit.m;
|
|
7645
8199
|
const popup = document.createElement("div");
|
|
7646
8200
|
popup.className = "vd-datepicker-popup";
|
|
7647
8201
|
popup.setAttribute("role", "dialog");
|
|
7648
8202
|
popup.setAttribute("aria-label", "Choose date");
|
|
8203
|
+
popup.tabIndex = -1;
|
|
7649
8204
|
const wrapper = document.createElement("div");
|
|
7650
8205
|
wrapper.className = "vd-suggest-wrapper";
|
|
7651
8206
|
wrapper.style.position = "relative";
|
|
@@ -7653,18 +8208,80 @@ module.exports = __toCommonJS(index_exports);
|
|
|
7653
8208
|
input.parentNode.insertBefore(wrapper, input);
|
|
7654
8209
|
wrapper.appendChild(input);
|
|
7655
8210
|
wrapper.appendChild(popup);
|
|
7656
|
-
const
|
|
7657
|
-
|
|
7658
|
-
|
|
7659
|
-
|
|
7660
|
-
|
|
8211
|
+
const isSameDay = (a, b) => a && b && a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
|
|
8212
|
+
const selectDate = (date) => {
|
|
8213
|
+
selectedDate = date;
|
|
8214
|
+
viewYear = date.getFullYear();
|
|
8215
|
+
viewMonth = date.getMonth();
|
|
8216
|
+
input.value = formatDate(date, format);
|
|
8217
|
+
skipNextFocusOpen = true;
|
|
8218
|
+
close();
|
|
8219
|
+
input.dispatchEvent(new CustomEvent("datepicker:select", {
|
|
8220
|
+
detail: { date, formatted: input.value },
|
|
8221
|
+
bubbles: true
|
|
8222
|
+
}));
|
|
8223
|
+
input.dispatchEvent(new Event("change", { bubbles: true }));
|
|
8224
|
+
input.focus();
|
|
7661
8225
|
};
|
|
7662
|
-
const
|
|
7663
|
-
if (
|
|
7664
|
-
|
|
7665
|
-
|
|
8226
|
+
const focusFocusedDay = () => {
|
|
8227
|
+
if (viewMode !== "days" || !focusedDate) return;
|
|
8228
|
+
const key = dateKey(focusedDate);
|
|
8229
|
+
const btn = popup.querySelector('[data-vd-date="' + key + '"]');
|
|
8230
|
+
if (btn && !btn.classList.contains("is-outside") && btn.getAttribute("aria-disabled") !== "true") {
|
|
8231
|
+
btn.focus();
|
|
8232
|
+
}
|
|
8233
|
+
};
|
|
8234
|
+
const skipDisabled = (d, stepDir, maxSteps) => {
|
|
8235
|
+
let x = new Date(d.getFullYear(), d.getMonth(), d.getDate());
|
|
8236
|
+
const step = stepDir > 0 ? 1 : -1;
|
|
8237
|
+
for (let i = 0; i < maxSteps; i++) {
|
|
8238
|
+
if (!isDisabled(x)) return x;
|
|
8239
|
+
x = addDays(x, step);
|
|
8240
|
+
}
|
|
8241
|
+
return d;
|
|
8242
|
+
};
|
|
8243
|
+
const createDayBtn = (day, outside, date) => {
|
|
8244
|
+
const btn = document.createElement("button");
|
|
8245
|
+
btn.type = "button";
|
|
8246
|
+
btn.className = "vd-datepicker-day";
|
|
8247
|
+
btn.textContent = day;
|
|
8248
|
+
btn.setAttribute("role", "gridcell");
|
|
8249
|
+
if (outside) {
|
|
8250
|
+
btn.classList.add("is-outside");
|
|
8251
|
+
btn.tabIndex = -1;
|
|
8252
|
+
btn.setAttribute("aria-disabled", "true");
|
|
8253
|
+
return btn;
|
|
8254
|
+
}
|
|
8255
|
+
btn.setAttribute("data-vd-date", dateKey(date));
|
|
8256
|
+
if (date && isSameDay(date, today)) btn.classList.add("is-today");
|
|
8257
|
+
if (date && isSameDay(date, selectedDate)) btn.classList.add("is-selected");
|
|
8258
|
+
if (date && isDisabled(date)) {
|
|
8259
|
+
btn.classList.add("is-disabled");
|
|
8260
|
+
btn.setAttribute("aria-disabled", "true");
|
|
8261
|
+
btn.tabIndex = -1;
|
|
8262
|
+
return btn;
|
|
8263
|
+
}
|
|
8264
|
+
if (date) {
|
|
8265
|
+
const isFocused = focusedDate && isSameDay(date, focusedDate);
|
|
8266
|
+
btn.tabIndex = isFocused ? 0 : -1;
|
|
8267
|
+
btn.addEventListener("click", () => {
|
|
8268
|
+
selectedDate = date;
|
|
8269
|
+
viewYear = date.getFullYear();
|
|
8270
|
+
viewMonth = date.getMonth();
|
|
8271
|
+
focusedDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
|
8272
|
+
input.value = formatDate(date, format);
|
|
8273
|
+
skipNextFocusOpen = true;
|
|
8274
|
+
close();
|
|
8275
|
+
input.dispatchEvent(new CustomEvent("datepicker:select", {
|
|
8276
|
+
detail: { date, formatted: input.value },
|
|
8277
|
+
bubbles: true
|
|
8278
|
+
}));
|
|
8279
|
+
input.dispatchEvent(new Event("change", { bubbles: true }));
|
|
8280
|
+
input.focus();
|
|
8281
|
+
});
|
|
8282
|
+
}
|
|
8283
|
+
return btn;
|
|
7666
8284
|
};
|
|
7667
|
-
const isSameDay = (a, b) => a && b && a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
|
|
7668
8285
|
const render = () => {
|
|
7669
8286
|
popup.innerHTML = "";
|
|
7670
8287
|
const header = document.createElement("div");
|
|
@@ -7734,35 +8351,53 @@ module.exports = __toCommonJS(index_exports);
|
|
|
7734
8351
|
header.appendChild(nextBtn);
|
|
7735
8352
|
popup.appendChild(header);
|
|
7736
8353
|
if (viewMode === "days") {
|
|
8354
|
+
const gridWrap = document.createElement("div");
|
|
8355
|
+
gridWrap.className = "vd-datepicker-grid";
|
|
8356
|
+
gridWrap.setAttribute("role", "grid");
|
|
8357
|
+
gridWrap.setAttribute("aria-label", "Calendar");
|
|
7737
8358
|
const weekdays = document.createElement("div");
|
|
7738
8359
|
weekdays.className = "vd-datepicker-weekdays";
|
|
7739
|
-
|
|
8360
|
+
weekdays.setAttribute("role", "row");
|
|
8361
|
+
DAYS.forEach(function(d) {
|
|
7740
8362
|
const span = document.createElement("span");
|
|
8363
|
+
span.setAttribute("role", "columnheader");
|
|
8364
|
+
span.setAttribute("aria-label", d);
|
|
7741
8365
|
span.textContent = d;
|
|
7742
8366
|
weekdays.appendChild(span);
|
|
7743
8367
|
});
|
|
7744
|
-
|
|
7745
|
-
const grid = document.createElement("div");
|
|
7746
|
-
grid.className = "vd-datepicker-days";
|
|
8368
|
+
gridWrap.appendChild(weekdays);
|
|
7747
8369
|
const firstDay = new Date(viewYear, viewMonth, 1).getDay();
|
|
7748
8370
|
const daysInMonth = new Date(viewYear, viewMonth + 1, 0).getDate();
|
|
7749
8371
|
const daysInPrev = new Date(viewYear, viewMonth, 0).getDate();
|
|
8372
|
+
const cells = [];
|
|
7750
8373
|
for (let i = firstDay - 1; i >= 0; i--) {
|
|
7751
|
-
const
|
|
7752
|
-
|
|
8374
|
+
const dayNum = daysInPrev - i;
|
|
8375
|
+
const prevMonth = viewMonth === 0 ? 11 : viewMonth - 1;
|
|
8376
|
+
const prevYear = viewMonth === 0 ? viewYear - 1 : viewYear;
|
|
8377
|
+
const date = new Date(prevYear, prevMonth, dayNum);
|
|
8378
|
+
cells.push({ day: dayNum, outside: true, date });
|
|
7753
8379
|
}
|
|
7754
8380
|
for (let d = 1; d <= daysInMonth; d++) {
|
|
7755
8381
|
const date = new Date(viewYear, viewMonth, d);
|
|
7756
|
-
|
|
7757
|
-
grid.appendChild(btn);
|
|
8382
|
+
cells.push({ day: d, outside: false, date });
|
|
7758
8383
|
}
|
|
7759
8384
|
const totalCells = firstDay + daysInMonth;
|
|
7760
8385
|
const remaining = totalCells % 7 === 0 ? 0 : 7 - totalCells % 7;
|
|
7761
8386
|
for (let i = 1; i <= remaining; i++) {
|
|
7762
|
-
const
|
|
7763
|
-
|
|
8387
|
+
const date = new Date(viewYear, viewMonth + 1, i);
|
|
8388
|
+
cells.push({ day: i, outside: true, date });
|
|
7764
8389
|
}
|
|
7765
|
-
|
|
8390
|
+
for (let r = 0; r < cells.length; r += 7) {
|
|
8391
|
+
const row = document.createElement("div");
|
|
8392
|
+
row.className = "vd-datepicker-row";
|
|
8393
|
+
row.setAttribute("role", "row");
|
|
8394
|
+
for (let c = 0; c < 7; c++) {
|
|
8395
|
+
const cell = cells[r + c];
|
|
8396
|
+
row.appendChild(createDayBtn(cell.day, cell.outside, cell.date));
|
|
8397
|
+
}
|
|
8398
|
+
gridWrap.appendChild(row);
|
|
8399
|
+
}
|
|
8400
|
+
popup.appendChild(gridWrap);
|
|
7766
8401
|
} else if (viewMode === "months") {
|
|
7767
8402
|
const grid = document.createElement("div");
|
|
7768
8403
|
grid.className = "vd-datepicker-months";
|
|
@@ -7803,65 +8438,125 @@ module.exports = __toCommonJS(index_exports);
|
|
|
7803
8438
|
popup.appendChild(grid);
|
|
7804
8439
|
}
|
|
7805
8440
|
};
|
|
7806
|
-
const
|
|
7807
|
-
|
|
7808
|
-
|
|
7809
|
-
|
|
7810
|
-
|
|
7811
|
-
if (
|
|
7812
|
-
|
|
7813
|
-
btn.tabIndex = -1;
|
|
7814
|
-
return btn;
|
|
8441
|
+
const handleGridKeydown = (e) => {
|
|
8442
|
+
if (!popup.classList.contains("is-open") || viewMode !== "days") return;
|
|
8443
|
+
const grid = popup.querySelector(".vd-datepicker-grid");
|
|
8444
|
+
if (!grid || !grid.contains(e.target)) return;
|
|
8445
|
+
const key = e.key;
|
|
8446
|
+
if (key !== "ArrowLeft" && key !== "ArrowRight" && key !== "ArrowUp" && key !== "ArrowDown" && key !== "Home" && key !== "End" && key !== "PageUp" && key !== "PageDown" && key !== "Enter" && key !== " " && key !== "Escape") {
|
|
8447
|
+
return;
|
|
7815
8448
|
}
|
|
7816
|
-
if (
|
|
7817
|
-
|
|
7818
|
-
|
|
7819
|
-
|
|
7820
|
-
|
|
8449
|
+
if (key === "Escape") {
|
|
8450
|
+
e.preventDefault();
|
|
8451
|
+
e.stopPropagation();
|
|
8452
|
+
skipNextFocusOpen = true;
|
|
8453
|
+
close();
|
|
8454
|
+
input.focus();
|
|
8455
|
+
return;
|
|
7821
8456
|
}
|
|
7822
|
-
if (
|
|
7823
|
-
|
|
7824
|
-
selectedDate = date;
|
|
7825
|
-
viewYear = date.getFullYear();
|
|
7826
|
-
viewMonth = date.getMonth();
|
|
7827
|
-
input.value = formatDate(date);
|
|
7828
|
-
close();
|
|
7829
|
-
input.dispatchEvent(new CustomEvent("datepicker:select", {
|
|
7830
|
-
detail: { date, formatted: input.value },
|
|
7831
|
-
bubbles: true
|
|
7832
|
-
}));
|
|
7833
|
-
input.dispatchEvent(new Event("change", { bubbles: true }));
|
|
7834
|
-
});
|
|
8457
|
+
if (!focusedDate) {
|
|
8458
|
+
focusedDate = firstSelectableInMonth(viewYear, viewMonth);
|
|
7835
8459
|
}
|
|
7836
|
-
|
|
8460
|
+
if (key === "Enter" || key === " ") {
|
|
8461
|
+
e.preventDefault();
|
|
8462
|
+
if (focusedDate && !isDisabled(focusedDate)) {
|
|
8463
|
+
selectDate(new Date(focusedDate.getFullYear(), focusedDate.getMonth(), focusedDate.getDate()));
|
|
8464
|
+
}
|
|
8465
|
+
return;
|
|
8466
|
+
}
|
|
8467
|
+
e.preventDefault();
|
|
8468
|
+
let next = new Date(focusedDate.getFullYear(), focusedDate.getMonth(), focusedDate.getDate());
|
|
8469
|
+
let skipDir = 1;
|
|
8470
|
+
if (key === "ArrowLeft") {
|
|
8471
|
+
next = addDays(next, -1);
|
|
8472
|
+
skipDir = -1;
|
|
8473
|
+
} else if (key === "ArrowRight") {
|
|
8474
|
+
next = addDays(next, 1);
|
|
8475
|
+
skipDir = 1;
|
|
8476
|
+
} else if (key === "ArrowUp") {
|
|
8477
|
+
next = addDays(next, -7);
|
|
8478
|
+
skipDir = -1;
|
|
8479
|
+
} else if (key === "ArrowDown") {
|
|
8480
|
+
next = addDays(next, 7);
|
|
8481
|
+
skipDir = 1;
|
|
8482
|
+
} else if (key === "Home") {
|
|
8483
|
+
next = startOfWeekSunday(next);
|
|
8484
|
+
skipDir = 1;
|
|
8485
|
+
} else if (key === "End") {
|
|
8486
|
+
next = endOfWeekSunday(next);
|
|
8487
|
+
skipDir = -1;
|
|
8488
|
+
} else if (key === "PageUp") {
|
|
8489
|
+
next = addMonthsClamped(next, -1);
|
|
8490
|
+
skipDir = -1;
|
|
8491
|
+
} else if (key === "PageDown") {
|
|
8492
|
+
next = addMonthsClamped(next, 1);
|
|
8493
|
+
skipDir = 1;
|
|
8494
|
+
}
|
|
8495
|
+
next = skipDisabled(next, skipDir, 400);
|
|
8496
|
+
if (next.getMonth() !== viewMonth || next.getFullYear() !== viewYear) {
|
|
8497
|
+
viewYear = next.getFullYear();
|
|
8498
|
+
viewMonth = next.getMonth();
|
|
8499
|
+
const cl = ensureMonthInRange(viewYear, viewMonth);
|
|
8500
|
+
viewYear = cl.y;
|
|
8501
|
+
viewMonth = cl.m;
|
|
8502
|
+
}
|
|
8503
|
+
focusedDate = next;
|
|
8504
|
+
render();
|
|
8505
|
+
requestAnimationFrame(focusFocusedDay);
|
|
7837
8506
|
};
|
|
7838
8507
|
const open = () => {
|
|
8508
|
+
viewMode = "days";
|
|
8509
|
+
if (selectedDate) {
|
|
8510
|
+
viewYear = selectedDate.getFullYear();
|
|
8511
|
+
viewMonth = selectedDate.getMonth();
|
|
8512
|
+
}
|
|
8513
|
+
const cl = ensureMonthInRange(viewYear, viewMonth);
|
|
8514
|
+
viewYear = cl.y;
|
|
8515
|
+
viewMonth = cl.m;
|
|
8516
|
+
if (selectedDate) {
|
|
8517
|
+
focusedDate = new Date(selectedDate.getFullYear(), selectedDate.getMonth(), selectedDate.getDate());
|
|
8518
|
+
} else {
|
|
8519
|
+
focusedDate = firstSelectableInMonth(viewYear, viewMonth);
|
|
8520
|
+
}
|
|
7839
8521
|
render();
|
|
7840
8522
|
popup.classList.add("is-open");
|
|
7841
8523
|
input.setAttribute("aria-expanded", "true");
|
|
8524
|
+
requestAnimationFrame(focusFocusedDay);
|
|
7842
8525
|
};
|
|
7843
8526
|
const close = () => {
|
|
7844
8527
|
popup.classList.remove("is-open");
|
|
7845
8528
|
input.setAttribute("aria-expanded", "false");
|
|
7846
8529
|
viewMode = "days";
|
|
7847
8530
|
};
|
|
7848
|
-
const focusHandler = () =>
|
|
8531
|
+
const focusHandler = () => {
|
|
8532
|
+
if (skipNextFocusOpen) {
|
|
8533
|
+
skipNextFocusOpen = false;
|
|
8534
|
+
return;
|
|
8535
|
+
}
|
|
8536
|
+
open();
|
|
8537
|
+
};
|
|
7849
8538
|
const outsideHandler = (e) => {
|
|
7850
8539
|
if (!wrapper.contains(e.target)) close();
|
|
7851
8540
|
};
|
|
7852
8541
|
const escHandler = (e) => {
|
|
7853
|
-
if (e.key === "Escape"
|
|
8542
|
+
if (e.key === "Escape" && popup.classList.contains("is-open")) {
|
|
8543
|
+
skipNextFocusOpen = true;
|
|
8544
|
+
close();
|
|
8545
|
+
input.focus();
|
|
8546
|
+
}
|
|
7854
8547
|
};
|
|
7855
8548
|
input.addEventListener("focus", focusHandler);
|
|
7856
8549
|
document.addEventListener("click", outsideHandler, true);
|
|
7857
8550
|
document.addEventListener("keydown", escHandler);
|
|
8551
|
+
popup.addEventListener("keydown", handleGridKeydown);
|
|
7858
8552
|
input.setAttribute("aria-haspopup", "dialog");
|
|
7859
8553
|
input.setAttribute("aria-expanded", "false");
|
|
7860
8554
|
input.setAttribute("autocomplete", "off");
|
|
7861
8555
|
cleanup.push(
|
|
7862
8556
|
() => input.removeEventListener("focus", focusHandler),
|
|
7863
8557
|
() => document.removeEventListener("click", outsideHandler, true),
|
|
7864
|
-
() => document.removeEventListener("keydown", escHandler)
|
|
8558
|
+
() => document.removeEventListener("keydown", escHandler),
|
|
8559
|
+
() => popup.removeEventListener("keydown", handleGridKeydown)
|
|
7865
8560
|
);
|
|
7866
8561
|
this.instances.set(input, { cleanup, open, close, popup });
|
|
7867
8562
|
},
|