@vanduo-oss/framework 1.5.0 → 1.6.0
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/CHANGELOG.md +27 -0
- package/README.md +33 -6
- package/css/components/expanding-cards.css +94 -25
- package/css/components/navbar.css +11 -0
- package/css/components/popover.css +97 -0
- package/css/components/theme-customizer.css +53 -0
- package/css/core/colors-fib-base.css +524 -0
- package/css/core/colors-palette.css +786 -0
- package/css/core/colors.css +54 -46
- package/css/core/tokens.css +19 -19
- package/css/vanduo.css +8 -1
- package/dist/build-info.json +3 -3
- package/dist/vanduo-core.css +1588 -86
- package/dist/vanduo-core.css.map +1 -1
- package/dist/vanduo-core.min.css +2 -2
- package/dist/vanduo-core.min.css.map +1 -1
- package/dist/vanduo.cjs.js +394 -9
- package/dist/vanduo.cjs.js.map +3 -3
- package/dist/vanduo.cjs.min.js +16 -10
- package/dist/vanduo.cjs.min.js.map +4 -4
- package/dist/vanduo.css +1588 -86
- package/dist/vanduo.css.map +1 -1
- package/dist/vanduo.esm.js +394 -9
- package/dist/vanduo.esm.js.map +3 -3
- package/dist/vanduo.esm.min.js +16 -10
- package/dist/vanduo.esm.min.js.map +4 -4
- package/dist/vanduo.js +394 -9
- 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 +16 -10
- package/dist/vanduo.min.js.map +4 -4
- package/js/components/doc-search.js +9 -4
- package/js/components/expanding-cards.js +15 -3
- package/js/components/popover.js +295 -0
- package/js/components/search.js +108 -0
- package/js/components/theme-customizer.js +54 -1
- package/js/index.js +2 -0
- package/js/utils/helpers.js +12 -4
- package/package.json +7 -4
package/dist/vanduo.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! Vanduo v1.
|
|
1
|
+
/*! Vanduo v1.6.0 | Built: 2026-06-27T15:48:08.659Z | git:9384f14 | development */
|
|
2
2
|
|
|
3
3
|
// js/utils/lifecycle.js
|
|
4
4
|
(function() {
|
|
@@ -176,7 +176,7 @@
|
|
|
176
176
|
// js/vanduo.js
|
|
177
177
|
(function() {
|
|
178
178
|
"use strict";
|
|
179
|
-
const VANDUO_VERSION = true ? "1.
|
|
179
|
+
const VANDUO_VERSION = true ? "1.6.0" : "0.0.0-dev";
|
|
180
180
|
const hasOwn = Object.prototype.hasOwnProperty;
|
|
181
181
|
const Vanduo2 = {
|
|
182
182
|
version: VANDUO_VERSION,
|
|
@@ -4305,6 +4305,7 @@
|
|
|
4305
4305
|
const ThemeCustomizer = {
|
|
4306
4306
|
// Storage keys
|
|
4307
4307
|
STORAGE_KEYS: {
|
|
4308
|
+
PALETTE: "vanduo-palette",
|
|
4308
4309
|
PRIMARY: "vanduo-primary-color",
|
|
4309
4310
|
NEUTRAL: "vanduo-neutral-color",
|
|
4310
4311
|
RADIUS: "vanduo-radius",
|
|
@@ -4313,6 +4314,7 @@
|
|
|
4313
4314
|
},
|
|
4314
4315
|
// Default values
|
|
4315
4316
|
DEFAULTS: {
|
|
4317
|
+
PALETTE: "open-color",
|
|
4316
4318
|
PRIMARY_LIGHT: "black",
|
|
4317
4319
|
PRIMARY_DARK: "amber",
|
|
4318
4320
|
NEUTRAL: "charcoal",
|
|
@@ -4320,7 +4322,12 @@
|
|
|
4320
4322
|
FONT: "ubuntu",
|
|
4321
4323
|
THEME: "system"
|
|
4322
4324
|
},
|
|
4323
|
-
//
|
|
4325
|
+
// Palette options (the Open Color default + the optional Fibonacci palette)
|
|
4326
|
+
PALETTE_OPTIONS: {
|
|
4327
|
+
"open-color": { name: "Open Color", description: "The Open Color palette (MIT) \u2014 the Vanduo default." },
|
|
4328
|
+
"fibonacci": { name: "Fibonacci", description: 'Golden-angle generated palette \u2014 optional, opt in via data-palette="fibonacci".' }
|
|
4329
|
+
},
|
|
4330
|
+
// Primary color definitions (palette-aware: shown over the active palette)
|
|
4324
4331
|
PRIMARY_COLORS: {
|
|
4325
4332
|
"black": { name: "Black", color: "#000000" },
|
|
4326
4333
|
"red": { name: "Red", color: "#fa5252" },
|
|
@@ -4364,6 +4371,7 @@
|
|
|
4364
4371
|
THEME_MODES: ["system", "dark", "light"],
|
|
4365
4372
|
// State
|
|
4366
4373
|
state: {
|
|
4374
|
+
palette: null,
|
|
4367
4375
|
primary: null,
|
|
4368
4376
|
neutral: null,
|
|
4369
4377
|
radius: null,
|
|
@@ -4464,6 +4472,7 @@
|
|
|
4464
4472
|
* Load preferences from localStorage
|
|
4465
4473
|
*/
|
|
4466
4474
|
loadPreferences: function() {
|
|
4475
|
+
this.state.palette = this.getStorageValue(this.STORAGE_KEYS.PALETTE, this.DEFAULTS.PALETTE);
|
|
4467
4476
|
this.state.theme = this.getStorageValue(this.STORAGE_KEYS.THEME, this.DEFAULTS.THEME);
|
|
4468
4477
|
this.state.primary = this.getStorageValue(this.STORAGE_KEYS.PRIMARY, this.getDefaultPrimary(this.state.theme));
|
|
4469
4478
|
this._normalizeDefaultPrimaryIfStaleWithStoredTheme();
|
|
@@ -4481,12 +4490,25 @@
|
|
|
4481
4490
|
* Apply all preferences
|
|
4482
4491
|
*/
|
|
4483
4492
|
applyAllPreferences: function() {
|
|
4493
|
+
this.applyPalette(this.state.palette);
|
|
4484
4494
|
this.applyPrimary(this.state.primary);
|
|
4485
4495
|
this.applyNeutral(this.state.neutral);
|
|
4486
4496
|
this.applyRadius(this.state.radius);
|
|
4487
4497
|
this.applyFont(this.state.font);
|
|
4488
4498
|
this.applyTheme(this.state.theme);
|
|
4489
4499
|
},
|
|
4500
|
+
/**
|
|
4501
|
+
* Apply color palette (Fibonacci default / Open Color optional)
|
|
4502
|
+
*/
|
|
4503
|
+
applyPalette: function(paletteKey) {
|
|
4504
|
+
if (!this.PALETTE_OPTIONS[paletteKey]) {
|
|
4505
|
+
paletteKey = this.DEFAULTS.PALETTE;
|
|
4506
|
+
}
|
|
4507
|
+
this.state.palette = paletteKey;
|
|
4508
|
+
document.documentElement.setAttribute("data-palette", paletteKey);
|
|
4509
|
+
this.savePreference(this.STORAGE_KEYS.PALETTE, paletteKey);
|
|
4510
|
+
this.dispatchEvent("palette-change", { palette: paletteKey });
|
|
4511
|
+
},
|
|
4490
4512
|
/**
|
|
4491
4513
|
* Apply primary color
|
|
4492
4514
|
*/
|
|
@@ -4689,6 +4711,12 @@
|
|
|
4689
4711
|
if (!this.elements.panel) return;
|
|
4690
4712
|
if (this.elements.panel.getAttribute("data-customizer-initialized") === "true") return;
|
|
4691
4713
|
this.elements.panel.setAttribute("data-customizer-initialized", "true");
|
|
4714
|
+
this.elements.panel.querySelectorAll("[data-palette]").forEach((btn) => {
|
|
4715
|
+
this.addListener(btn, "click", () => {
|
|
4716
|
+
this.applyPalette(btn.dataset.palette);
|
|
4717
|
+
this.updateUI();
|
|
4718
|
+
});
|
|
4719
|
+
});
|
|
4692
4720
|
this.elements.panel.querySelectorAll("[data-color]").forEach((swatch) => {
|
|
4693
4721
|
this.addListener(swatch, "click", () => {
|
|
4694
4722
|
this.applyPrimary(swatch.dataset.color);
|
|
@@ -4748,6 +4776,10 @@
|
|
|
4748
4776
|
}
|
|
4749
4777
|
return "#000000";
|
|
4750
4778
|
};
|
|
4779
|
+
let paletteOptions = "";
|
|
4780
|
+
for (const [key, value] of Object.entries(this.PALETTE_OPTIONS)) {
|
|
4781
|
+
paletteOptions += `<button class="tc-palette-btn${key === this.state.palette ? " is-active" : ""}" data-palette="${esc(key)}" title="${esc(value.description)}">${esc(value.name)}</button>`;
|
|
4782
|
+
}
|
|
4751
4783
|
let primarySwatches = "";
|
|
4752
4784
|
for (const [key, value] of Object.entries(this.PRIMARY_COLORS)) {
|
|
4753
4785
|
primarySwatches += `<button class="tc-color-swatch${key === this.state.primary ? " is-active" : ""}" data-color="${esc(key)}" style="--vd-swatch-color: ${safeColor(value.color)}" title="${esc(value.name)}"></button>`;
|
|
@@ -4773,6 +4805,12 @@
|
|
|
4773
4805
|
</div>
|
|
4774
4806
|
<div class="tc-body">
|
|
4775
4807
|
|
|
4808
|
+
<div class="tc-section">
|
|
4809
|
+
<label class="tc-label">Palette</label>
|
|
4810
|
+
<div class="tc-palette-group">
|
|
4811
|
+
${paletteOptions}
|
|
4812
|
+
</div>
|
|
4813
|
+
</div>
|
|
4776
4814
|
<div class="tc-section">
|
|
4777
4815
|
<label class="tc-label">Primary Color</label>
|
|
4778
4816
|
<div class="tc-color-grid">
|
|
@@ -4938,6 +4976,9 @@
|
|
|
4938
4976
|
*/
|
|
4939
4977
|
updateUI: function() {
|
|
4940
4978
|
if (!this.elements.panel) return;
|
|
4979
|
+
this.elements.panel.querySelectorAll("[data-palette]").forEach((btn) => {
|
|
4980
|
+
btn.classList.toggle("is-active", btn.dataset.palette === this.state.palette);
|
|
4981
|
+
});
|
|
4941
4982
|
this.elements.panel.querySelectorAll("[data-color]").forEach((swatch) => {
|
|
4942
4983
|
swatch.classList.toggle("is-active", swatch.dataset.color === this.state.primary);
|
|
4943
4984
|
});
|
|
@@ -4956,6 +4997,7 @@
|
|
|
4956
4997
|
* Reset all preferences to defaults
|
|
4957
4998
|
*/
|
|
4958
4999
|
reset: function() {
|
|
5000
|
+
this.applyPalette(this.DEFAULTS.PALETTE);
|
|
4959
5001
|
this.applyTheme(this.DEFAULTS.THEME);
|
|
4960
5002
|
this.applyPrimary(this.getDefaultPrimary(this.DEFAULTS.THEME));
|
|
4961
5003
|
this.applyNeutral(this.DEFAULTS.NEUTRAL);
|
|
@@ -4974,6 +5016,7 @@
|
|
|
4974
5016
|
* Programmatically set preferences
|
|
4975
5017
|
*/
|
|
4976
5018
|
setPreferences: function(prefs) {
|
|
5019
|
+
if (prefs.palette) this.applyPalette(prefs.palette);
|
|
4977
5020
|
if (prefs.primary) this.applyPrimary(prefs.primary);
|
|
4978
5021
|
if (prefs.neutral) this.applyNeutral(prefs.neutral);
|
|
4979
5022
|
if (prefs.radius) this.applyRadius(prefs.radius);
|
|
@@ -6431,9 +6474,8 @@
|
|
|
6431
6474
|
return escaped;
|
|
6432
6475
|
}
|
|
6433
6476
|
function escapeHtml2(text) {
|
|
6434
|
-
|
|
6435
|
-
|
|
6436
|
-
return div.innerHTML;
|
|
6477
|
+
if (text === null || text === void 0) return "";
|
|
6478
|
+
return String(text).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
6437
6479
|
}
|
|
6438
6480
|
function navigate(direction) {
|
|
6439
6481
|
let newIndex = state.activeIndex + direction;
|
|
@@ -7763,7 +7805,7 @@
|
|
|
7763
7805
|
setActive(card);
|
|
7764
7806
|
};
|
|
7765
7807
|
const onKeydown = function(e) {
|
|
7766
|
-
if (e.key !== "ArrowLeft" && e.key !== "ArrowRight" && e.key !== "Home" && e.key !== "End") {
|
|
7808
|
+
if (e.key !== "ArrowLeft" && e.key !== "ArrowRight" && e.key !== "ArrowUp" && e.key !== "ArrowDown" && e.key !== "Home" && e.key !== "End") {
|
|
7767
7809
|
return;
|
|
7768
7810
|
}
|
|
7769
7811
|
const cards = getCards().filter(function(c) {
|
|
@@ -7778,10 +7820,14 @@
|
|
|
7778
7820
|
});
|
|
7779
7821
|
}
|
|
7780
7822
|
if (idx < 0) idx = 0;
|
|
7781
|
-
|
|
7823
|
+
const isVertical = window.getComputedStyle(container).flexDirection === "column";
|
|
7824
|
+
if (!isVertical && (e.key === "ArrowUp" || e.key === "ArrowDown")) {
|
|
7825
|
+
return;
|
|
7826
|
+
}
|
|
7827
|
+
if (e.key === "ArrowLeft" || e.key === "ArrowUp") {
|
|
7782
7828
|
e.preventDefault();
|
|
7783
7829
|
setActive(cards[Math.max(0, idx - 1)]);
|
|
7784
|
-
} else if (e.key === "ArrowRight") {
|
|
7830
|
+
} else if (e.key === "ArrowRight" || e.key === "ArrowDown") {
|
|
7785
7831
|
e.preventDefault();
|
|
7786
7832
|
setActive(cards[Math.min(cards.length - 1, idx + 1)]);
|
|
7787
7833
|
} else if (e.key === "Home") {
|
|
@@ -10646,6 +10692,345 @@
|
|
|
10646
10692
|
window.VanduoSpotlight = Spotlight;
|
|
10647
10693
|
})();
|
|
10648
10694
|
|
|
10695
|
+
// js/components/popover.js
|
|
10696
|
+
(function() {
|
|
10697
|
+
"use strict";
|
|
10698
|
+
const PLACEMENTS = ["top", "bottom", "left", "right"];
|
|
10699
|
+
const TRIGGERS = ["click", "hover", "focus"];
|
|
10700
|
+
const DEFAULT_GAP = 8;
|
|
10701
|
+
function resolvePlacement(preferred) {
|
|
10702
|
+
return PLACEMENTS.indexOf(preferred) !== -1 ? preferred : "bottom";
|
|
10703
|
+
}
|
|
10704
|
+
function resolveTrigger(value) {
|
|
10705
|
+
if (!value) return ["click", "focus"];
|
|
10706
|
+
return value.split(/\s+/).filter(function(t) {
|
|
10707
|
+
return TRIGGERS.indexOf(t) !== -1;
|
|
10708
|
+
});
|
|
10709
|
+
}
|
|
10710
|
+
function findPanel(trigger) {
|
|
10711
|
+
const targetSelector = trigger.getAttribute("data-vd-popover-target");
|
|
10712
|
+
if (!targetSelector) return null;
|
|
10713
|
+
const doc = trigger.ownerDocument || document;
|
|
10714
|
+
const panel = doc.querySelector(targetSelector);
|
|
10715
|
+
if (!panel) return null;
|
|
10716
|
+
if (!panel.classList.contains("vd-popover-panel")) {
|
|
10717
|
+
panel.classList.add("vd-popover-panel");
|
|
10718
|
+
}
|
|
10719
|
+
return panel;
|
|
10720
|
+
}
|
|
10721
|
+
const Popover = {
|
|
10722
|
+
instances: /* @__PURE__ */ new Map(),
|
|
10723
|
+
_globalCleanups: [],
|
|
10724
|
+
init: function(root) {
|
|
10725
|
+
const scope = root || document;
|
|
10726
|
+
const triggers = scope.querySelectorAll ? scope.querySelectorAll(".vd-popover-trigger") : document.querySelectorAll(".vd-popover-trigger");
|
|
10727
|
+
Array.prototype.forEach.call(triggers, function(trigger) {
|
|
10728
|
+
if (Popover.instances.has(trigger)) return;
|
|
10729
|
+
Popover.initInstance(trigger);
|
|
10730
|
+
});
|
|
10731
|
+
if (Popover._globalCleanups.length === 0) {
|
|
10732
|
+
const outsideClick = function(event) {
|
|
10733
|
+
Popover.instances.forEach(function(inst, trigger) {
|
|
10734
|
+
if (inst.trigger !== "click") return;
|
|
10735
|
+
if (inst.panel.contains(event.target) || trigger.contains(event.target)) return;
|
|
10736
|
+
Popover.hide(trigger);
|
|
10737
|
+
});
|
|
10738
|
+
};
|
|
10739
|
+
const escHandler = function(event) {
|
|
10740
|
+
if (event.key !== "Escape") return;
|
|
10741
|
+
let lastOpen = null;
|
|
10742
|
+
Popover.instances.forEach(function(inst, trigger) {
|
|
10743
|
+
if (inst.panel.hasAttribute("hidden") === false) lastOpen = trigger;
|
|
10744
|
+
});
|
|
10745
|
+
if (lastOpen) Popover.hide(lastOpen);
|
|
10746
|
+
};
|
|
10747
|
+
document.addEventListener("click", outsideClick, true);
|
|
10748
|
+
document.addEventListener("keydown", escHandler);
|
|
10749
|
+
Popover._globalCleanups.push(function() {
|
|
10750
|
+
document.removeEventListener("click", outsideClick, true);
|
|
10751
|
+
});
|
|
10752
|
+
Popover._globalCleanups.push(function() {
|
|
10753
|
+
document.removeEventListener("keydown", escHandler);
|
|
10754
|
+
});
|
|
10755
|
+
}
|
|
10756
|
+
},
|
|
10757
|
+
initInstance: function(trigger) {
|
|
10758
|
+
const panel = findPanel(trigger);
|
|
10759
|
+
if (!panel) return;
|
|
10760
|
+
const cleanup = [];
|
|
10761
|
+
const placement = resolvePlacement(trigger.getAttribute("data-vd-popover-placement"));
|
|
10762
|
+
const triggers = resolveTrigger(trigger.getAttribute("data-vd-popover-trigger"));
|
|
10763
|
+
const allowFlip = trigger.getAttribute("data-vd-popover-flip") !== "false";
|
|
10764
|
+
if (!panel.id) {
|
|
10765
|
+
panel.id = "vd-popover-" + Math.random().toString(36).slice(2, 9);
|
|
10766
|
+
}
|
|
10767
|
+
if (!panel.hasAttribute("role")) panel.setAttribute("role", "dialog");
|
|
10768
|
+
if (!panel.hasAttribute("aria-modal")) panel.setAttribute("aria-modal", "false");
|
|
10769
|
+
trigger.setAttribute("aria-haspopup", "dialog");
|
|
10770
|
+
trigger.setAttribute("aria-expanded", "false");
|
|
10771
|
+
trigger.setAttribute("aria-controls", panel.id);
|
|
10772
|
+
if (triggers.indexOf("click") !== -1) {
|
|
10773
|
+
const clickHandler = function(event) {
|
|
10774
|
+
event.stopPropagation();
|
|
10775
|
+
const expanded = trigger.getAttribute("aria-expanded") === "true";
|
|
10776
|
+
if (expanded) Popover.hide(trigger);
|
|
10777
|
+
else {
|
|
10778
|
+
Popover._closeOthers(trigger);
|
|
10779
|
+
Popover.show(trigger);
|
|
10780
|
+
}
|
|
10781
|
+
};
|
|
10782
|
+
trigger.addEventListener("click", clickHandler);
|
|
10783
|
+
cleanup.push(function() {
|
|
10784
|
+
trigger.removeEventListener("click", clickHandler);
|
|
10785
|
+
});
|
|
10786
|
+
}
|
|
10787
|
+
if (triggers.indexOf("hover") !== -1) {
|
|
10788
|
+
const enterHandler = function() {
|
|
10789
|
+
Popover.show(trigger);
|
|
10790
|
+
};
|
|
10791
|
+
const leaveHandler = function() {
|
|
10792
|
+
setTimeout(function() {
|
|
10793
|
+
if (!panel.matches(":hover") && !trigger.matches(":hover")) Popover.hide(trigger);
|
|
10794
|
+
}, 80);
|
|
10795
|
+
};
|
|
10796
|
+
trigger.addEventListener("mouseenter", enterHandler);
|
|
10797
|
+
trigger.addEventListener("mouseleave", leaveHandler);
|
|
10798
|
+
panel.addEventListener("mouseenter", enterHandler);
|
|
10799
|
+
panel.addEventListener("mouseleave", leaveHandler);
|
|
10800
|
+
cleanup.push(function() {
|
|
10801
|
+
trigger.removeEventListener("mouseenter", enterHandler);
|
|
10802
|
+
});
|
|
10803
|
+
cleanup.push(function() {
|
|
10804
|
+
trigger.removeEventListener("mouseleave", leaveHandler);
|
|
10805
|
+
});
|
|
10806
|
+
cleanup.push(function() {
|
|
10807
|
+
panel.removeEventListener("mouseenter", enterHandler);
|
|
10808
|
+
});
|
|
10809
|
+
cleanup.push(function() {
|
|
10810
|
+
panel.removeEventListener("mouseleave", leaveHandler);
|
|
10811
|
+
});
|
|
10812
|
+
}
|
|
10813
|
+
if (triggers.indexOf("focus") !== -1) {
|
|
10814
|
+
const focusHandler = function() {
|
|
10815
|
+
Popover.show(trigger);
|
|
10816
|
+
};
|
|
10817
|
+
const blurHandler = function(event) {
|
|
10818
|
+
if (panel.contains(event.relatedTarget)) return;
|
|
10819
|
+
Popover.hide(trigger);
|
|
10820
|
+
};
|
|
10821
|
+
trigger.addEventListener("focus", focusHandler);
|
|
10822
|
+
trigger.addEventListener("blur", blurHandler);
|
|
10823
|
+
cleanup.push(function() {
|
|
10824
|
+
trigger.removeEventListener("focus", focusHandler);
|
|
10825
|
+
});
|
|
10826
|
+
cleanup.push(function() {
|
|
10827
|
+
trigger.removeEventListener("blur", blurHandler);
|
|
10828
|
+
});
|
|
10829
|
+
}
|
|
10830
|
+
const resizeHandler = function() {
|
|
10831
|
+
Popover.flipPlacement(trigger);
|
|
10832
|
+
};
|
|
10833
|
+
window.addEventListener("resize", resizeHandler);
|
|
10834
|
+
window.addEventListener("scroll", resizeHandler, true);
|
|
10835
|
+
cleanup.push(function() {
|
|
10836
|
+
window.removeEventListener("resize", resizeHandler);
|
|
10837
|
+
});
|
|
10838
|
+
cleanup.push(function() {
|
|
10839
|
+
window.removeEventListener("scroll", resizeHandler, true);
|
|
10840
|
+
});
|
|
10841
|
+
Popover.instances.set(trigger, {
|
|
10842
|
+
panel,
|
|
10843
|
+
cleanup,
|
|
10844
|
+
placement,
|
|
10845
|
+
trigger: triggers.join(" "),
|
|
10846
|
+
allowFlip
|
|
10847
|
+
});
|
|
10848
|
+
},
|
|
10849
|
+
show: function(trigger) {
|
|
10850
|
+
const inst = Popover.instances.get(trigger);
|
|
10851
|
+
if (!inst) return;
|
|
10852
|
+
inst.panel.hidden = false;
|
|
10853
|
+
requestAnimationFrame(function() {
|
|
10854
|
+
Popover.position(trigger, inst.panel, inst.placement);
|
|
10855
|
+
trigger.setAttribute("aria-expanded", "true");
|
|
10856
|
+
inst.panel.setAttribute("data-placement", inst.placement);
|
|
10857
|
+
trigger.dispatchEvent(new CustomEvent("popover:show", {
|
|
10858
|
+
bubbles: true,
|
|
10859
|
+
detail: { trigger, placement: inst.placement }
|
|
10860
|
+
}));
|
|
10861
|
+
});
|
|
10862
|
+
},
|
|
10863
|
+
hide: function(trigger) {
|
|
10864
|
+
const inst = Popover.instances.get(trigger);
|
|
10865
|
+
if (!inst) return;
|
|
10866
|
+
inst.panel.hidden = true;
|
|
10867
|
+
trigger.setAttribute("aria-expanded", "false");
|
|
10868
|
+
trigger.dispatchEvent(new CustomEvent("popover:hide", {
|
|
10869
|
+
bubbles: true,
|
|
10870
|
+
detail: { trigger }
|
|
10871
|
+
}));
|
|
10872
|
+
},
|
|
10873
|
+
_closeOthers: function(currentTrigger) {
|
|
10874
|
+
Popover.instances.forEach(function(_inst, trigger) {
|
|
10875
|
+
if (trigger !== currentTrigger) Popover.hide(trigger);
|
|
10876
|
+
});
|
|
10877
|
+
},
|
|
10878
|
+
position: function(trigger, panel, placement) {
|
|
10879
|
+
const rect = trigger.getBoundingClientRect();
|
|
10880
|
+
const popRect = panel.getBoundingClientRect();
|
|
10881
|
+
const gap = DEFAULT_GAP;
|
|
10882
|
+
let top;
|
|
10883
|
+
let left;
|
|
10884
|
+
const win = panel.ownerDocument.defaultView || window;
|
|
10885
|
+
const scrollX = win.pageXOffset || 0;
|
|
10886
|
+
const scrollY = win.pageYOffset || 0;
|
|
10887
|
+
switch (placement) {
|
|
10888
|
+
case "top":
|
|
10889
|
+
top = rect.top - popRect.height - gap + scrollY;
|
|
10890
|
+
left = rect.left + (rect.width - popRect.width) / 2 + scrollX;
|
|
10891
|
+
break;
|
|
10892
|
+
case "left":
|
|
10893
|
+
top = rect.top + (rect.height - popRect.height) / 2 + scrollY;
|
|
10894
|
+
left = rect.left - popRect.width - gap + scrollX;
|
|
10895
|
+
break;
|
|
10896
|
+
case "right":
|
|
10897
|
+
top = rect.top + (rect.height - popRect.height) / 2 + scrollY;
|
|
10898
|
+
left = rect.right + gap + scrollX;
|
|
10899
|
+
break;
|
|
10900
|
+
default:
|
|
10901
|
+
top = rect.bottom + gap + scrollY;
|
|
10902
|
+
left = rect.left + (rect.width - popRect.width) / 2 + scrollX;
|
|
10903
|
+
}
|
|
10904
|
+
left = Math.max(8, Math.min(left, win.innerWidth - popRect.width - 8));
|
|
10905
|
+
top = Math.max(8, top);
|
|
10906
|
+
panel.style.position = "absolute";
|
|
10907
|
+
panel.style.top = top + "px";
|
|
10908
|
+
panel.style.left = left + "px";
|
|
10909
|
+
},
|
|
10910
|
+
flipPlacement: function(trigger) {
|
|
10911
|
+
const inst = Popover.instances.get(trigger);
|
|
10912
|
+
if (!inst || !inst.allowFlip) return;
|
|
10913
|
+
if (inst.panel.hidden) return;
|
|
10914
|
+
const win = inst.panel.ownerDocument.defaultView || window;
|
|
10915
|
+
const rect = trigger.getBoundingClientRect();
|
|
10916
|
+
const popRect = inst.panel.getBoundingClientRect();
|
|
10917
|
+
const gap = DEFAULT_GAP;
|
|
10918
|
+
let flipped = null;
|
|
10919
|
+
const current = inst.placement;
|
|
10920
|
+
if (current === "top" && rect.top - popRect.height - gap < 0) flipped = "bottom";
|
|
10921
|
+
else if (current === "bottom" && rect.bottom + popRect.height + gap > win.innerHeight) flipped = "top";
|
|
10922
|
+
else if (current === "left" && rect.left - popRect.width - gap < 0) flipped = "right";
|
|
10923
|
+
else if (current === "right" && rect.right + popRect.width + gap > win.innerWidth) flipped = "left";
|
|
10924
|
+
if (flipped) {
|
|
10925
|
+
inst.placement = flipped;
|
|
10926
|
+
Popover.position(trigger, inst.panel, flipped);
|
|
10927
|
+
inst.panel.setAttribute("data-placement", flipped);
|
|
10928
|
+
}
|
|
10929
|
+
},
|
|
10930
|
+
destroy: function(trigger) {
|
|
10931
|
+
const inst = Popover.instances.get(trigger);
|
|
10932
|
+
if (!inst) return;
|
|
10933
|
+
inst.cleanup.forEach(function(fn) {
|
|
10934
|
+
fn();
|
|
10935
|
+
});
|
|
10936
|
+
Popover.hide(trigger);
|
|
10937
|
+
trigger.removeAttribute("aria-haspopup");
|
|
10938
|
+
trigger.removeAttribute("aria-expanded");
|
|
10939
|
+
trigger.removeAttribute("aria-controls");
|
|
10940
|
+
Popover.instances.delete(trigger);
|
|
10941
|
+
},
|
|
10942
|
+
destroyAll: function(root) {
|
|
10943
|
+
const triggers = [];
|
|
10944
|
+
Popover.instances.forEach(function(_inst, trigger) {
|
|
10945
|
+
if (!root || trigger.closest && trigger.closest(root)) triggers.push(trigger);
|
|
10946
|
+
});
|
|
10947
|
+
triggers.forEach(function(trigger) {
|
|
10948
|
+
Popover.destroy(trigger);
|
|
10949
|
+
});
|
|
10950
|
+
if (Popover.instances.size === 0) {
|
|
10951
|
+
Popover._globalCleanups.forEach(function(fn) {
|
|
10952
|
+
fn();
|
|
10953
|
+
});
|
|
10954
|
+
Popover._globalCleanups = [];
|
|
10955
|
+
}
|
|
10956
|
+
}
|
|
10957
|
+
};
|
|
10958
|
+
if (typeof window !== "undefined") {
|
|
10959
|
+
if (typeof window.Vanduo !== "undefined" && typeof window.Vanduo.register === "function") {
|
|
10960
|
+
window.Vanduo.register("popover", Popover);
|
|
10961
|
+
}
|
|
10962
|
+
window.VanduoPopover = Popover;
|
|
10963
|
+
}
|
|
10964
|
+
})();
|
|
10965
|
+
|
|
10966
|
+
// js/components/search.js
|
|
10967
|
+
(function() {
|
|
10968
|
+
"use strict";
|
|
10969
|
+
const DEFAULT_LIMIT = 10;
|
|
10970
|
+
const sources = /* @__PURE__ */ new Map();
|
|
10971
|
+
function register(source) {
|
|
10972
|
+
if (!source || typeof source.name !== "string" || source.name.length === 0) {
|
|
10973
|
+
throw new Error("VanduoSearch.register: source.name is required");
|
|
10974
|
+
}
|
|
10975
|
+
if (typeof source.fetch !== "function") {
|
|
10976
|
+
throw new Error("VanduoSearch.register: source.fetch must be a function");
|
|
10977
|
+
}
|
|
10978
|
+
if (sources.has(source.name)) {
|
|
10979
|
+
throw new Error('VanduoSearch.register: source "' + source.name + '" already registered');
|
|
10980
|
+
}
|
|
10981
|
+
sources.set(source.name, Object.freeze({
|
|
10982
|
+
name: source.name,
|
|
10983
|
+
label: source.label || source.name,
|
|
10984
|
+
icon: source.icon || null,
|
|
10985
|
+
limit: typeof source.limit === "number" ? source.limit : DEFAULT_LIMIT,
|
|
10986
|
+
fetch: source.fetch
|
|
10987
|
+
}));
|
|
10988
|
+
}
|
|
10989
|
+
function unregister(name) {
|
|
10990
|
+
return sources.delete(name);
|
|
10991
|
+
}
|
|
10992
|
+
function list() {
|
|
10993
|
+
return Object.freeze(Array.from(sources.values()));
|
|
10994
|
+
}
|
|
10995
|
+
function query(text, options) {
|
|
10996
|
+
options = options || {};
|
|
10997
|
+
const signal = options.signal;
|
|
10998
|
+
const limitPerSource = typeof options.limitPerSource === "number" ? options.limitPerSource : null;
|
|
10999
|
+
const queryText = (text || "").trim();
|
|
11000
|
+
const allSources = Array.from(sources.values());
|
|
11001
|
+
if (queryText.length === 0) {
|
|
11002
|
+
return Promise.resolve({
|
|
11003
|
+
text: queryText,
|
|
11004
|
+
sources: allSources.map(function(src) {
|
|
11005
|
+
return { name: src.name, label: src.label, results: [] };
|
|
11006
|
+
})
|
|
11007
|
+
});
|
|
11008
|
+
}
|
|
11009
|
+
const promises = allSources.map(function(src) {
|
|
11010
|
+
const effectiveLimit = limitPerSource != null ? limitPerSource : src.limit;
|
|
11011
|
+
return Promise.resolve().then(function() {
|
|
11012
|
+
return src.fetch(queryText, { signal, limit: effectiveLimit });
|
|
11013
|
+
}).then(function(results) {
|
|
11014
|
+
const safe = Array.isArray(results) ? results : [];
|
|
11015
|
+
return { name: src.name, label: src.label, results: safe };
|
|
11016
|
+
}).catch(function(error) {
|
|
11017
|
+
if (error && error.name === "AbortError") throw error;
|
|
11018
|
+
return { name: src.name, label: src.label, results: [], error: error.message || "fetch failed" };
|
|
11019
|
+
});
|
|
11020
|
+
});
|
|
11021
|
+
return Promise.all(promises).then(function(perSource) {
|
|
11022
|
+
return { text: queryText, sources: perSource };
|
|
11023
|
+
});
|
|
11024
|
+
}
|
|
11025
|
+
const Search = { register, unregister, list, query };
|
|
11026
|
+
if (typeof window !== "undefined") {
|
|
11027
|
+
if (typeof window.Vanduo !== "undefined" && typeof window.Vanduo.register === "function") {
|
|
11028
|
+
window.Vanduo.register("search", Search);
|
|
11029
|
+
}
|
|
11030
|
+
window.VanduoSearch = Search;
|
|
11031
|
+
}
|
|
11032
|
+
})();
|
|
11033
|
+
|
|
10649
11034
|
// js/index.js
|
|
10650
11035
|
var Vanduo = window.Vanduo;
|
|
10651
11036
|
var index_default = Vanduo;
|