@vanduo-oss/framework 1.5.1 → 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 +18 -2
- package/README.md +30 -7
- 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 +1509 -62
- 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 +387 -6
- 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 +1509 -62
- package/dist/vanduo.css.map +1 -1
- package/dist/vanduo.esm.js +387 -6
- 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 +387 -6
- 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/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.cjs.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
|
var __defProp = Object.defineProperty;
|
|
3
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -201,7 +201,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
201
201
|
// js/vanduo.js
|
|
202
202
|
(function() {
|
|
203
203
|
"use strict";
|
|
204
|
-
const VANDUO_VERSION = true ? "1.
|
|
204
|
+
const VANDUO_VERSION = true ? "1.6.0" : "0.0.0-dev";
|
|
205
205
|
const hasOwn = Object.prototype.hasOwnProperty;
|
|
206
206
|
const Vanduo2 = {
|
|
207
207
|
version: VANDUO_VERSION,
|
|
@@ -4330,6 +4330,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
4330
4330
|
const ThemeCustomizer = {
|
|
4331
4331
|
// Storage keys
|
|
4332
4332
|
STORAGE_KEYS: {
|
|
4333
|
+
PALETTE: "vanduo-palette",
|
|
4333
4334
|
PRIMARY: "vanduo-primary-color",
|
|
4334
4335
|
NEUTRAL: "vanduo-neutral-color",
|
|
4335
4336
|
RADIUS: "vanduo-radius",
|
|
@@ -4338,6 +4339,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
4338
4339
|
},
|
|
4339
4340
|
// Default values
|
|
4340
4341
|
DEFAULTS: {
|
|
4342
|
+
PALETTE: "open-color",
|
|
4341
4343
|
PRIMARY_LIGHT: "black",
|
|
4342
4344
|
PRIMARY_DARK: "amber",
|
|
4343
4345
|
NEUTRAL: "charcoal",
|
|
@@ -4345,7 +4347,12 @@ module.exports = __toCommonJS(index_exports);
|
|
|
4345
4347
|
FONT: "ubuntu",
|
|
4346
4348
|
THEME: "system"
|
|
4347
4349
|
},
|
|
4348
|
-
//
|
|
4350
|
+
// Palette options (the Open Color default + the optional Fibonacci palette)
|
|
4351
|
+
PALETTE_OPTIONS: {
|
|
4352
|
+
"open-color": { name: "Open Color", description: "The Open Color palette (MIT) \u2014 the Vanduo default." },
|
|
4353
|
+
"fibonacci": { name: "Fibonacci", description: 'Golden-angle generated palette \u2014 optional, opt in via data-palette="fibonacci".' }
|
|
4354
|
+
},
|
|
4355
|
+
// Primary color definitions (palette-aware: shown over the active palette)
|
|
4349
4356
|
PRIMARY_COLORS: {
|
|
4350
4357
|
"black": { name: "Black", color: "#000000" },
|
|
4351
4358
|
"red": { name: "Red", color: "#fa5252" },
|
|
@@ -4389,6 +4396,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
4389
4396
|
THEME_MODES: ["system", "dark", "light"],
|
|
4390
4397
|
// State
|
|
4391
4398
|
state: {
|
|
4399
|
+
palette: null,
|
|
4392
4400
|
primary: null,
|
|
4393
4401
|
neutral: null,
|
|
4394
4402
|
radius: null,
|
|
@@ -4489,6 +4497,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
4489
4497
|
* Load preferences from localStorage
|
|
4490
4498
|
*/
|
|
4491
4499
|
loadPreferences: function() {
|
|
4500
|
+
this.state.palette = this.getStorageValue(this.STORAGE_KEYS.PALETTE, this.DEFAULTS.PALETTE);
|
|
4492
4501
|
this.state.theme = this.getStorageValue(this.STORAGE_KEYS.THEME, this.DEFAULTS.THEME);
|
|
4493
4502
|
this.state.primary = this.getStorageValue(this.STORAGE_KEYS.PRIMARY, this.getDefaultPrimary(this.state.theme));
|
|
4494
4503
|
this._normalizeDefaultPrimaryIfStaleWithStoredTheme();
|
|
@@ -4506,12 +4515,25 @@ module.exports = __toCommonJS(index_exports);
|
|
|
4506
4515
|
* Apply all preferences
|
|
4507
4516
|
*/
|
|
4508
4517
|
applyAllPreferences: function() {
|
|
4518
|
+
this.applyPalette(this.state.palette);
|
|
4509
4519
|
this.applyPrimary(this.state.primary);
|
|
4510
4520
|
this.applyNeutral(this.state.neutral);
|
|
4511
4521
|
this.applyRadius(this.state.radius);
|
|
4512
4522
|
this.applyFont(this.state.font);
|
|
4513
4523
|
this.applyTheme(this.state.theme);
|
|
4514
4524
|
},
|
|
4525
|
+
/**
|
|
4526
|
+
* Apply color palette (Fibonacci default / Open Color optional)
|
|
4527
|
+
*/
|
|
4528
|
+
applyPalette: function(paletteKey) {
|
|
4529
|
+
if (!this.PALETTE_OPTIONS[paletteKey]) {
|
|
4530
|
+
paletteKey = this.DEFAULTS.PALETTE;
|
|
4531
|
+
}
|
|
4532
|
+
this.state.palette = paletteKey;
|
|
4533
|
+
document.documentElement.setAttribute("data-palette", paletteKey);
|
|
4534
|
+
this.savePreference(this.STORAGE_KEYS.PALETTE, paletteKey);
|
|
4535
|
+
this.dispatchEvent("palette-change", { palette: paletteKey });
|
|
4536
|
+
},
|
|
4515
4537
|
/**
|
|
4516
4538
|
* Apply primary color
|
|
4517
4539
|
*/
|
|
@@ -4714,6 +4736,12 @@ module.exports = __toCommonJS(index_exports);
|
|
|
4714
4736
|
if (!this.elements.panel) return;
|
|
4715
4737
|
if (this.elements.panel.getAttribute("data-customizer-initialized") === "true") return;
|
|
4716
4738
|
this.elements.panel.setAttribute("data-customizer-initialized", "true");
|
|
4739
|
+
this.elements.panel.querySelectorAll("[data-palette]").forEach((btn) => {
|
|
4740
|
+
this.addListener(btn, "click", () => {
|
|
4741
|
+
this.applyPalette(btn.dataset.palette);
|
|
4742
|
+
this.updateUI();
|
|
4743
|
+
});
|
|
4744
|
+
});
|
|
4717
4745
|
this.elements.panel.querySelectorAll("[data-color]").forEach((swatch) => {
|
|
4718
4746
|
this.addListener(swatch, "click", () => {
|
|
4719
4747
|
this.applyPrimary(swatch.dataset.color);
|
|
@@ -4773,6 +4801,10 @@ module.exports = __toCommonJS(index_exports);
|
|
|
4773
4801
|
}
|
|
4774
4802
|
return "#000000";
|
|
4775
4803
|
};
|
|
4804
|
+
let paletteOptions = "";
|
|
4805
|
+
for (const [key, value] of Object.entries(this.PALETTE_OPTIONS)) {
|
|
4806
|
+
paletteOptions += `<button class="tc-palette-btn${key === this.state.palette ? " is-active" : ""}" data-palette="${esc(key)}" title="${esc(value.description)}">${esc(value.name)}</button>`;
|
|
4807
|
+
}
|
|
4776
4808
|
let primarySwatches = "";
|
|
4777
4809
|
for (const [key, value] of Object.entries(this.PRIMARY_COLORS)) {
|
|
4778
4810
|
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>`;
|
|
@@ -4798,6 +4830,12 @@ module.exports = __toCommonJS(index_exports);
|
|
|
4798
4830
|
</div>
|
|
4799
4831
|
<div class="tc-body">
|
|
4800
4832
|
|
|
4833
|
+
<div class="tc-section">
|
|
4834
|
+
<label class="tc-label">Palette</label>
|
|
4835
|
+
<div class="tc-palette-group">
|
|
4836
|
+
${paletteOptions}
|
|
4837
|
+
</div>
|
|
4838
|
+
</div>
|
|
4801
4839
|
<div class="tc-section">
|
|
4802
4840
|
<label class="tc-label">Primary Color</label>
|
|
4803
4841
|
<div class="tc-color-grid">
|
|
@@ -4963,6 +5001,9 @@ module.exports = __toCommonJS(index_exports);
|
|
|
4963
5001
|
*/
|
|
4964
5002
|
updateUI: function() {
|
|
4965
5003
|
if (!this.elements.panel) return;
|
|
5004
|
+
this.elements.panel.querySelectorAll("[data-palette]").forEach((btn) => {
|
|
5005
|
+
btn.classList.toggle("is-active", btn.dataset.palette === this.state.palette);
|
|
5006
|
+
});
|
|
4966
5007
|
this.elements.panel.querySelectorAll("[data-color]").forEach((swatch) => {
|
|
4967
5008
|
swatch.classList.toggle("is-active", swatch.dataset.color === this.state.primary);
|
|
4968
5009
|
});
|
|
@@ -4981,6 +5022,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
4981
5022
|
* Reset all preferences to defaults
|
|
4982
5023
|
*/
|
|
4983
5024
|
reset: function() {
|
|
5025
|
+
this.applyPalette(this.DEFAULTS.PALETTE);
|
|
4984
5026
|
this.applyTheme(this.DEFAULTS.THEME);
|
|
4985
5027
|
this.applyPrimary(this.getDefaultPrimary(this.DEFAULTS.THEME));
|
|
4986
5028
|
this.applyNeutral(this.DEFAULTS.NEUTRAL);
|
|
@@ -4999,6 +5041,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
4999
5041
|
* Programmatically set preferences
|
|
5000
5042
|
*/
|
|
5001
5043
|
setPreferences: function(prefs) {
|
|
5044
|
+
if (prefs.palette) this.applyPalette(prefs.palette);
|
|
5002
5045
|
if (prefs.primary) this.applyPrimary(prefs.primary);
|
|
5003
5046
|
if (prefs.neutral) this.applyNeutral(prefs.neutral);
|
|
5004
5047
|
if (prefs.radius) this.applyRadius(prefs.radius);
|
|
@@ -6456,9 +6499,8 @@ module.exports = __toCommonJS(index_exports);
|
|
|
6456
6499
|
return escaped;
|
|
6457
6500
|
}
|
|
6458
6501
|
function escapeHtml2(text) {
|
|
6459
|
-
|
|
6460
|
-
|
|
6461
|
-
return div.innerHTML;
|
|
6502
|
+
if (text === null || text === void 0) return "";
|
|
6503
|
+
return String(text).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
6462
6504
|
}
|
|
6463
6505
|
function navigate(direction) {
|
|
6464
6506
|
let newIndex = state.activeIndex + direction;
|
|
@@ -10675,6 +10717,345 @@ module.exports = __toCommonJS(index_exports);
|
|
|
10675
10717
|
window.VanduoSpotlight = Spotlight;
|
|
10676
10718
|
})();
|
|
10677
10719
|
|
|
10720
|
+
// js/components/popover.js
|
|
10721
|
+
(function() {
|
|
10722
|
+
"use strict";
|
|
10723
|
+
const PLACEMENTS = ["top", "bottom", "left", "right"];
|
|
10724
|
+
const TRIGGERS = ["click", "hover", "focus"];
|
|
10725
|
+
const DEFAULT_GAP = 8;
|
|
10726
|
+
function resolvePlacement(preferred) {
|
|
10727
|
+
return PLACEMENTS.indexOf(preferred) !== -1 ? preferred : "bottom";
|
|
10728
|
+
}
|
|
10729
|
+
function resolveTrigger(value) {
|
|
10730
|
+
if (!value) return ["click", "focus"];
|
|
10731
|
+
return value.split(/\s+/).filter(function(t) {
|
|
10732
|
+
return TRIGGERS.indexOf(t) !== -1;
|
|
10733
|
+
});
|
|
10734
|
+
}
|
|
10735
|
+
function findPanel(trigger) {
|
|
10736
|
+
const targetSelector = trigger.getAttribute("data-vd-popover-target");
|
|
10737
|
+
if (!targetSelector) return null;
|
|
10738
|
+
const doc = trigger.ownerDocument || document;
|
|
10739
|
+
const panel = doc.querySelector(targetSelector);
|
|
10740
|
+
if (!panel) return null;
|
|
10741
|
+
if (!panel.classList.contains("vd-popover-panel")) {
|
|
10742
|
+
panel.classList.add("vd-popover-panel");
|
|
10743
|
+
}
|
|
10744
|
+
return panel;
|
|
10745
|
+
}
|
|
10746
|
+
const Popover = {
|
|
10747
|
+
instances: /* @__PURE__ */ new Map(),
|
|
10748
|
+
_globalCleanups: [],
|
|
10749
|
+
init: function(root) {
|
|
10750
|
+
const scope = root || document;
|
|
10751
|
+
const triggers = scope.querySelectorAll ? scope.querySelectorAll(".vd-popover-trigger") : document.querySelectorAll(".vd-popover-trigger");
|
|
10752
|
+
Array.prototype.forEach.call(triggers, function(trigger) {
|
|
10753
|
+
if (Popover.instances.has(trigger)) return;
|
|
10754
|
+
Popover.initInstance(trigger);
|
|
10755
|
+
});
|
|
10756
|
+
if (Popover._globalCleanups.length === 0) {
|
|
10757
|
+
const outsideClick = function(event) {
|
|
10758
|
+
Popover.instances.forEach(function(inst, trigger) {
|
|
10759
|
+
if (inst.trigger !== "click") return;
|
|
10760
|
+
if (inst.panel.contains(event.target) || trigger.contains(event.target)) return;
|
|
10761
|
+
Popover.hide(trigger);
|
|
10762
|
+
});
|
|
10763
|
+
};
|
|
10764
|
+
const escHandler = function(event) {
|
|
10765
|
+
if (event.key !== "Escape") return;
|
|
10766
|
+
let lastOpen = null;
|
|
10767
|
+
Popover.instances.forEach(function(inst, trigger) {
|
|
10768
|
+
if (inst.panel.hasAttribute("hidden") === false) lastOpen = trigger;
|
|
10769
|
+
});
|
|
10770
|
+
if (lastOpen) Popover.hide(lastOpen);
|
|
10771
|
+
};
|
|
10772
|
+
document.addEventListener("click", outsideClick, true);
|
|
10773
|
+
document.addEventListener("keydown", escHandler);
|
|
10774
|
+
Popover._globalCleanups.push(function() {
|
|
10775
|
+
document.removeEventListener("click", outsideClick, true);
|
|
10776
|
+
});
|
|
10777
|
+
Popover._globalCleanups.push(function() {
|
|
10778
|
+
document.removeEventListener("keydown", escHandler);
|
|
10779
|
+
});
|
|
10780
|
+
}
|
|
10781
|
+
},
|
|
10782
|
+
initInstance: function(trigger) {
|
|
10783
|
+
const panel = findPanel(trigger);
|
|
10784
|
+
if (!panel) return;
|
|
10785
|
+
const cleanup = [];
|
|
10786
|
+
const placement = resolvePlacement(trigger.getAttribute("data-vd-popover-placement"));
|
|
10787
|
+
const triggers = resolveTrigger(trigger.getAttribute("data-vd-popover-trigger"));
|
|
10788
|
+
const allowFlip = trigger.getAttribute("data-vd-popover-flip") !== "false";
|
|
10789
|
+
if (!panel.id) {
|
|
10790
|
+
panel.id = "vd-popover-" + Math.random().toString(36).slice(2, 9);
|
|
10791
|
+
}
|
|
10792
|
+
if (!panel.hasAttribute("role")) panel.setAttribute("role", "dialog");
|
|
10793
|
+
if (!panel.hasAttribute("aria-modal")) panel.setAttribute("aria-modal", "false");
|
|
10794
|
+
trigger.setAttribute("aria-haspopup", "dialog");
|
|
10795
|
+
trigger.setAttribute("aria-expanded", "false");
|
|
10796
|
+
trigger.setAttribute("aria-controls", panel.id);
|
|
10797
|
+
if (triggers.indexOf("click") !== -1) {
|
|
10798
|
+
const clickHandler = function(event) {
|
|
10799
|
+
event.stopPropagation();
|
|
10800
|
+
const expanded = trigger.getAttribute("aria-expanded") === "true";
|
|
10801
|
+
if (expanded) Popover.hide(trigger);
|
|
10802
|
+
else {
|
|
10803
|
+
Popover._closeOthers(trigger);
|
|
10804
|
+
Popover.show(trigger);
|
|
10805
|
+
}
|
|
10806
|
+
};
|
|
10807
|
+
trigger.addEventListener("click", clickHandler);
|
|
10808
|
+
cleanup.push(function() {
|
|
10809
|
+
trigger.removeEventListener("click", clickHandler);
|
|
10810
|
+
});
|
|
10811
|
+
}
|
|
10812
|
+
if (triggers.indexOf("hover") !== -1) {
|
|
10813
|
+
const enterHandler = function() {
|
|
10814
|
+
Popover.show(trigger);
|
|
10815
|
+
};
|
|
10816
|
+
const leaveHandler = function() {
|
|
10817
|
+
setTimeout(function() {
|
|
10818
|
+
if (!panel.matches(":hover") && !trigger.matches(":hover")) Popover.hide(trigger);
|
|
10819
|
+
}, 80);
|
|
10820
|
+
};
|
|
10821
|
+
trigger.addEventListener("mouseenter", enterHandler);
|
|
10822
|
+
trigger.addEventListener("mouseleave", leaveHandler);
|
|
10823
|
+
panel.addEventListener("mouseenter", enterHandler);
|
|
10824
|
+
panel.addEventListener("mouseleave", leaveHandler);
|
|
10825
|
+
cleanup.push(function() {
|
|
10826
|
+
trigger.removeEventListener("mouseenter", enterHandler);
|
|
10827
|
+
});
|
|
10828
|
+
cleanup.push(function() {
|
|
10829
|
+
trigger.removeEventListener("mouseleave", leaveHandler);
|
|
10830
|
+
});
|
|
10831
|
+
cleanup.push(function() {
|
|
10832
|
+
panel.removeEventListener("mouseenter", enterHandler);
|
|
10833
|
+
});
|
|
10834
|
+
cleanup.push(function() {
|
|
10835
|
+
panel.removeEventListener("mouseleave", leaveHandler);
|
|
10836
|
+
});
|
|
10837
|
+
}
|
|
10838
|
+
if (triggers.indexOf("focus") !== -1) {
|
|
10839
|
+
const focusHandler = function() {
|
|
10840
|
+
Popover.show(trigger);
|
|
10841
|
+
};
|
|
10842
|
+
const blurHandler = function(event) {
|
|
10843
|
+
if (panel.contains(event.relatedTarget)) return;
|
|
10844
|
+
Popover.hide(trigger);
|
|
10845
|
+
};
|
|
10846
|
+
trigger.addEventListener("focus", focusHandler);
|
|
10847
|
+
trigger.addEventListener("blur", blurHandler);
|
|
10848
|
+
cleanup.push(function() {
|
|
10849
|
+
trigger.removeEventListener("focus", focusHandler);
|
|
10850
|
+
});
|
|
10851
|
+
cleanup.push(function() {
|
|
10852
|
+
trigger.removeEventListener("blur", blurHandler);
|
|
10853
|
+
});
|
|
10854
|
+
}
|
|
10855
|
+
const resizeHandler = function() {
|
|
10856
|
+
Popover.flipPlacement(trigger);
|
|
10857
|
+
};
|
|
10858
|
+
window.addEventListener("resize", resizeHandler);
|
|
10859
|
+
window.addEventListener("scroll", resizeHandler, true);
|
|
10860
|
+
cleanup.push(function() {
|
|
10861
|
+
window.removeEventListener("resize", resizeHandler);
|
|
10862
|
+
});
|
|
10863
|
+
cleanup.push(function() {
|
|
10864
|
+
window.removeEventListener("scroll", resizeHandler, true);
|
|
10865
|
+
});
|
|
10866
|
+
Popover.instances.set(trigger, {
|
|
10867
|
+
panel,
|
|
10868
|
+
cleanup,
|
|
10869
|
+
placement,
|
|
10870
|
+
trigger: triggers.join(" "),
|
|
10871
|
+
allowFlip
|
|
10872
|
+
});
|
|
10873
|
+
},
|
|
10874
|
+
show: function(trigger) {
|
|
10875
|
+
const inst = Popover.instances.get(trigger);
|
|
10876
|
+
if (!inst) return;
|
|
10877
|
+
inst.panel.hidden = false;
|
|
10878
|
+
requestAnimationFrame(function() {
|
|
10879
|
+
Popover.position(trigger, inst.panel, inst.placement);
|
|
10880
|
+
trigger.setAttribute("aria-expanded", "true");
|
|
10881
|
+
inst.panel.setAttribute("data-placement", inst.placement);
|
|
10882
|
+
trigger.dispatchEvent(new CustomEvent("popover:show", {
|
|
10883
|
+
bubbles: true,
|
|
10884
|
+
detail: { trigger, placement: inst.placement }
|
|
10885
|
+
}));
|
|
10886
|
+
});
|
|
10887
|
+
},
|
|
10888
|
+
hide: function(trigger) {
|
|
10889
|
+
const inst = Popover.instances.get(trigger);
|
|
10890
|
+
if (!inst) return;
|
|
10891
|
+
inst.panel.hidden = true;
|
|
10892
|
+
trigger.setAttribute("aria-expanded", "false");
|
|
10893
|
+
trigger.dispatchEvent(new CustomEvent("popover:hide", {
|
|
10894
|
+
bubbles: true,
|
|
10895
|
+
detail: { trigger }
|
|
10896
|
+
}));
|
|
10897
|
+
},
|
|
10898
|
+
_closeOthers: function(currentTrigger) {
|
|
10899
|
+
Popover.instances.forEach(function(_inst, trigger) {
|
|
10900
|
+
if (trigger !== currentTrigger) Popover.hide(trigger);
|
|
10901
|
+
});
|
|
10902
|
+
},
|
|
10903
|
+
position: function(trigger, panel, placement) {
|
|
10904
|
+
const rect = trigger.getBoundingClientRect();
|
|
10905
|
+
const popRect = panel.getBoundingClientRect();
|
|
10906
|
+
const gap = DEFAULT_GAP;
|
|
10907
|
+
let top;
|
|
10908
|
+
let left;
|
|
10909
|
+
const win = panel.ownerDocument.defaultView || window;
|
|
10910
|
+
const scrollX = win.pageXOffset || 0;
|
|
10911
|
+
const scrollY = win.pageYOffset || 0;
|
|
10912
|
+
switch (placement) {
|
|
10913
|
+
case "top":
|
|
10914
|
+
top = rect.top - popRect.height - gap + scrollY;
|
|
10915
|
+
left = rect.left + (rect.width - popRect.width) / 2 + scrollX;
|
|
10916
|
+
break;
|
|
10917
|
+
case "left":
|
|
10918
|
+
top = rect.top + (rect.height - popRect.height) / 2 + scrollY;
|
|
10919
|
+
left = rect.left - popRect.width - gap + scrollX;
|
|
10920
|
+
break;
|
|
10921
|
+
case "right":
|
|
10922
|
+
top = rect.top + (rect.height - popRect.height) / 2 + scrollY;
|
|
10923
|
+
left = rect.right + gap + scrollX;
|
|
10924
|
+
break;
|
|
10925
|
+
default:
|
|
10926
|
+
top = rect.bottom + gap + scrollY;
|
|
10927
|
+
left = rect.left + (rect.width - popRect.width) / 2 + scrollX;
|
|
10928
|
+
}
|
|
10929
|
+
left = Math.max(8, Math.min(left, win.innerWidth - popRect.width - 8));
|
|
10930
|
+
top = Math.max(8, top);
|
|
10931
|
+
panel.style.position = "absolute";
|
|
10932
|
+
panel.style.top = top + "px";
|
|
10933
|
+
panel.style.left = left + "px";
|
|
10934
|
+
},
|
|
10935
|
+
flipPlacement: function(trigger) {
|
|
10936
|
+
const inst = Popover.instances.get(trigger);
|
|
10937
|
+
if (!inst || !inst.allowFlip) return;
|
|
10938
|
+
if (inst.panel.hidden) return;
|
|
10939
|
+
const win = inst.panel.ownerDocument.defaultView || window;
|
|
10940
|
+
const rect = trigger.getBoundingClientRect();
|
|
10941
|
+
const popRect = inst.panel.getBoundingClientRect();
|
|
10942
|
+
const gap = DEFAULT_GAP;
|
|
10943
|
+
let flipped = null;
|
|
10944
|
+
const current = inst.placement;
|
|
10945
|
+
if (current === "top" && rect.top - popRect.height - gap < 0) flipped = "bottom";
|
|
10946
|
+
else if (current === "bottom" && rect.bottom + popRect.height + gap > win.innerHeight) flipped = "top";
|
|
10947
|
+
else if (current === "left" && rect.left - popRect.width - gap < 0) flipped = "right";
|
|
10948
|
+
else if (current === "right" && rect.right + popRect.width + gap > win.innerWidth) flipped = "left";
|
|
10949
|
+
if (flipped) {
|
|
10950
|
+
inst.placement = flipped;
|
|
10951
|
+
Popover.position(trigger, inst.panel, flipped);
|
|
10952
|
+
inst.panel.setAttribute("data-placement", flipped);
|
|
10953
|
+
}
|
|
10954
|
+
},
|
|
10955
|
+
destroy: function(trigger) {
|
|
10956
|
+
const inst = Popover.instances.get(trigger);
|
|
10957
|
+
if (!inst) return;
|
|
10958
|
+
inst.cleanup.forEach(function(fn) {
|
|
10959
|
+
fn();
|
|
10960
|
+
});
|
|
10961
|
+
Popover.hide(trigger);
|
|
10962
|
+
trigger.removeAttribute("aria-haspopup");
|
|
10963
|
+
trigger.removeAttribute("aria-expanded");
|
|
10964
|
+
trigger.removeAttribute("aria-controls");
|
|
10965
|
+
Popover.instances.delete(trigger);
|
|
10966
|
+
},
|
|
10967
|
+
destroyAll: function(root) {
|
|
10968
|
+
const triggers = [];
|
|
10969
|
+
Popover.instances.forEach(function(_inst, trigger) {
|
|
10970
|
+
if (!root || trigger.closest && trigger.closest(root)) triggers.push(trigger);
|
|
10971
|
+
});
|
|
10972
|
+
triggers.forEach(function(trigger) {
|
|
10973
|
+
Popover.destroy(trigger);
|
|
10974
|
+
});
|
|
10975
|
+
if (Popover.instances.size === 0) {
|
|
10976
|
+
Popover._globalCleanups.forEach(function(fn) {
|
|
10977
|
+
fn();
|
|
10978
|
+
});
|
|
10979
|
+
Popover._globalCleanups = [];
|
|
10980
|
+
}
|
|
10981
|
+
}
|
|
10982
|
+
};
|
|
10983
|
+
if (typeof window !== "undefined") {
|
|
10984
|
+
if (typeof window.Vanduo !== "undefined" && typeof window.Vanduo.register === "function") {
|
|
10985
|
+
window.Vanduo.register("popover", Popover);
|
|
10986
|
+
}
|
|
10987
|
+
window.VanduoPopover = Popover;
|
|
10988
|
+
}
|
|
10989
|
+
})();
|
|
10990
|
+
|
|
10991
|
+
// js/components/search.js
|
|
10992
|
+
(function() {
|
|
10993
|
+
"use strict";
|
|
10994
|
+
const DEFAULT_LIMIT = 10;
|
|
10995
|
+
const sources = /* @__PURE__ */ new Map();
|
|
10996
|
+
function register(source) {
|
|
10997
|
+
if (!source || typeof source.name !== "string" || source.name.length === 0) {
|
|
10998
|
+
throw new Error("VanduoSearch.register: source.name is required");
|
|
10999
|
+
}
|
|
11000
|
+
if (typeof source.fetch !== "function") {
|
|
11001
|
+
throw new Error("VanduoSearch.register: source.fetch must be a function");
|
|
11002
|
+
}
|
|
11003
|
+
if (sources.has(source.name)) {
|
|
11004
|
+
throw new Error('VanduoSearch.register: source "' + source.name + '" already registered');
|
|
11005
|
+
}
|
|
11006
|
+
sources.set(source.name, Object.freeze({
|
|
11007
|
+
name: source.name,
|
|
11008
|
+
label: source.label || source.name,
|
|
11009
|
+
icon: source.icon || null,
|
|
11010
|
+
limit: typeof source.limit === "number" ? source.limit : DEFAULT_LIMIT,
|
|
11011
|
+
fetch: source.fetch
|
|
11012
|
+
}));
|
|
11013
|
+
}
|
|
11014
|
+
function unregister(name) {
|
|
11015
|
+
return sources.delete(name);
|
|
11016
|
+
}
|
|
11017
|
+
function list() {
|
|
11018
|
+
return Object.freeze(Array.from(sources.values()));
|
|
11019
|
+
}
|
|
11020
|
+
function query(text, options) {
|
|
11021
|
+
options = options || {};
|
|
11022
|
+
const signal = options.signal;
|
|
11023
|
+
const limitPerSource = typeof options.limitPerSource === "number" ? options.limitPerSource : null;
|
|
11024
|
+
const queryText = (text || "").trim();
|
|
11025
|
+
const allSources = Array.from(sources.values());
|
|
11026
|
+
if (queryText.length === 0) {
|
|
11027
|
+
return Promise.resolve({
|
|
11028
|
+
text: queryText,
|
|
11029
|
+
sources: allSources.map(function(src) {
|
|
11030
|
+
return { name: src.name, label: src.label, results: [] };
|
|
11031
|
+
})
|
|
11032
|
+
});
|
|
11033
|
+
}
|
|
11034
|
+
const promises = allSources.map(function(src) {
|
|
11035
|
+
const effectiveLimit = limitPerSource != null ? limitPerSource : src.limit;
|
|
11036
|
+
return Promise.resolve().then(function() {
|
|
11037
|
+
return src.fetch(queryText, { signal, limit: effectiveLimit });
|
|
11038
|
+
}).then(function(results) {
|
|
11039
|
+
const safe = Array.isArray(results) ? results : [];
|
|
11040
|
+
return { name: src.name, label: src.label, results: safe };
|
|
11041
|
+
}).catch(function(error) {
|
|
11042
|
+
if (error && error.name === "AbortError") throw error;
|
|
11043
|
+
return { name: src.name, label: src.label, results: [], error: error.message || "fetch failed" };
|
|
11044
|
+
});
|
|
11045
|
+
});
|
|
11046
|
+
return Promise.all(promises).then(function(perSource) {
|
|
11047
|
+
return { text: queryText, sources: perSource };
|
|
11048
|
+
});
|
|
11049
|
+
}
|
|
11050
|
+
const Search = { register, unregister, list, query };
|
|
11051
|
+
if (typeof window !== "undefined") {
|
|
11052
|
+
if (typeof window.Vanduo !== "undefined" && typeof window.Vanduo.register === "function") {
|
|
11053
|
+
window.Vanduo.register("search", Search);
|
|
11054
|
+
}
|
|
11055
|
+
window.VanduoSearch = Search;
|
|
11056
|
+
}
|
|
11057
|
+
})();
|
|
11058
|
+
|
|
10678
11059
|
// js/index.js
|
|
10679
11060
|
var Vanduo = window.Vanduo;
|
|
10680
11061
|
var index_default = Vanduo;
|