@lanrenbang/basecoat-ultra 0.1.2
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-cn.md +54 -0
- package/CHANGELOG.md +54 -0
- package/LICENSE +21 -0
- package/README-cn.md +186 -0
- package/README.md +173 -0
- package/dist/css/basecoat.cdn.css +7389 -0
- package/dist/css/basecoat.cdn.min.css +2 -0
- package/dist/css/basecoat.css +1797 -0
- package/dist/css/datepicker.css +382 -0
- package/dist/css/datepicker.min.css +1 -0
- package/dist/css/resizable.css +96 -0
- package/dist/css/resizable.min.css +1 -0
- package/dist/js/accordion.js +20 -0
- package/dist/js/accordion.min.js +13 -0
- package/dist/js/all.js +17 -0
- package/dist/js/all.min.js +17 -0
- package/dist/js/basecoat.js +75 -0
- package/dist/js/basecoat.min.js +56 -0
- package/dist/js/carousel.js +104 -0
- package/dist/js/carousel.min.js +41 -0
- package/dist/js/catppuccin-theme-switcher.js +136 -0
- package/dist/js/catppuccin-theme-switcher.min.js +73 -0
- package/dist/js/command.js +132 -0
- package/dist/js/command.min.js +76 -0
- package/dist/js/datepicker.js +2367 -0
- package/dist/js/datepicker.min.js +1422 -0
- package/dist/js/dialog.js +20 -0
- package/dist/js/dialog.min.js +11 -0
- package/dist/js/dropdown-menu.js +148 -0
- package/dist/js/dropdown-menu.min.js +75 -0
- package/dist/js/input-otp.js +94 -0
- package/dist/js/input-otp.min.js +38 -0
- package/dist/js/lighting.js +80 -0
- package/dist/js/lighting.min.js +44 -0
- package/dist/js/popover.js +72 -0
- package/dist/js/popover.min.js +34 -0
- package/dist/js/resizable.js +534 -0
- package/dist/js/resizable.min.js +284 -0
- package/dist/js/select.js +246 -0
- package/dist/js/select.min.js +131 -0
- package/dist/js/sheet.js +85 -0
- package/dist/js/sheet.min.js +40 -0
- package/dist/js/sidebar.js +87 -0
- package/dist/js/sidebar.min.js +53 -0
- package/dist/js/slider.js +18 -0
- package/dist/js/slider.min.js +10 -0
- package/dist/js/tabs.js +53 -0
- package/dist/js/tabs.min.js +40 -0
- package/dist/js/toast.js +137 -0
- package/dist/js/toast.min.js +83 -0
- package/dist/js/toggle.js +36 -0
- package/dist/js/toggle.min.js +20 -0
- package/dist/theme/catppuccin/index.css +448 -0
- package/dist/theme/catppuccin/index.min.css +1 -0
- package/package.json +46 -0
package/dist/js/sheet.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
const toggleSheet = (trigger) => {
|
|
3
|
+
const targetId = trigger.getAttribute("aria-controls") || trigger.dataset.target;
|
|
4
|
+
if (!targetId) return;
|
|
5
|
+
const sheet = document.getElementById(targetId);
|
|
6
|
+
if (!sheet) return;
|
|
7
|
+
const isOpen = sheet.getAttribute("aria-hidden") === "false";
|
|
8
|
+
sheet.querySelector(".sheet-content, .drawer-content");
|
|
9
|
+
if (isOpen) {
|
|
10
|
+
closeSheet(sheet);
|
|
11
|
+
} else {
|
|
12
|
+
openSheet(sheet, trigger);
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
const openSheet = (sheet, trigger) => {
|
|
16
|
+
sheet.setAttribute("aria-hidden", "false");
|
|
17
|
+
sheet.offsetHeight;
|
|
18
|
+
const content = sheet.querySelector(".sheet-content, .drawer-content");
|
|
19
|
+
if (content) {
|
|
20
|
+
content.dataset.state = "open";
|
|
21
|
+
}
|
|
22
|
+
if (trigger) {
|
|
23
|
+
trigger.setAttribute("aria-expanded", "true");
|
|
24
|
+
sheet.dataset.triggerId = trigger.id || "";
|
|
25
|
+
}
|
|
26
|
+
document.body.style.overflow = "hidden";
|
|
27
|
+
};
|
|
28
|
+
const closeSheet = (sheet) => {
|
|
29
|
+
const content = sheet.querySelector(".sheet-content, .drawer-content");
|
|
30
|
+
if (content) {
|
|
31
|
+
content.dataset.state = "closed";
|
|
32
|
+
const transitionDuration = parseFloat(window.getComputedStyle(content).transitionDuration) * 1e3 || 300;
|
|
33
|
+
setTimeout(() => {
|
|
34
|
+
if (content.dataset.state === "closed") {
|
|
35
|
+
sheet.setAttribute("aria-hidden", "true");
|
|
36
|
+
document.body.style.overflow = "";
|
|
37
|
+
if (sheet.dataset.triggerId) {
|
|
38
|
+
const trigger = document.getElementById(sheet.dataset.triggerId);
|
|
39
|
+
trigger?.focus();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}, transitionDuration);
|
|
43
|
+
} else {
|
|
44
|
+
sheet.setAttribute("aria-hidden", "true");
|
|
45
|
+
document.body.style.overflow = "";
|
|
46
|
+
}
|
|
47
|
+
const triggerId = sheet.dataset.triggerId;
|
|
48
|
+
if (triggerId) {
|
|
49
|
+
const trigger = document.getElementById(triggerId);
|
|
50
|
+
trigger?.setAttribute("aria-expanded", "false");
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
document.addEventListener("click", (e) => {
|
|
54
|
+
const trigger = e.target.closest('[data-toggle="sheet"], [data-toggle="drawer"]');
|
|
55
|
+
if (trigger) {
|
|
56
|
+
e.preventDefault();
|
|
57
|
+
if (!trigger.id) {
|
|
58
|
+
trigger.id = "trigger-" + Math.random().toString(36).substr(2, 9);
|
|
59
|
+
}
|
|
60
|
+
toggleSheet(trigger);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
document.addEventListener("click", (e) => {
|
|
64
|
+
if (e.target.matches(".sheet, .drawer")) {
|
|
65
|
+
closeSheet(e.target);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
document.addEventListener("keydown", (e) => {
|
|
69
|
+
if (e.key === "Escape") {
|
|
70
|
+
const openSheets = document.querySelectorAll('.sheet[aria-hidden="false"], .drawer[aria-hidden="false"]');
|
|
71
|
+
openSheets.forEach(closeSheet);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
document.addEventListener("click", (e) => {
|
|
75
|
+
const closeBtn = e.target.closest("[data-close]");
|
|
76
|
+
if (closeBtn) {
|
|
77
|
+
const sheet = closeBtn.closest(".sheet, .drawer");
|
|
78
|
+
if (sheet) {
|
|
79
|
+
closeSheet(sheet);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
if (!window.basecoat) window.basecoat = {};
|
|
84
|
+
window.basecoat.sheet = { open: openSheet, close: closeSheet };
|
|
85
|
+
})();
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
const d = (t) => {
|
|
3
|
+
const e = t.getAttribute("aria-controls") || t.dataset.target;
|
|
4
|
+
if (!e) return;
|
|
5
|
+
const n = document.getElementById(e);
|
|
6
|
+
if (!n) return;
|
|
7
|
+
const a = n.getAttribute("aria-hidden") === "false";
|
|
8
|
+
n.querySelector(".sheet-content, .drawer-content"), a ? o(n) : r(n, t);
|
|
9
|
+
}, r = (t, e) => {
|
|
10
|
+
t.setAttribute("aria-hidden", "false"), t.offsetHeight;
|
|
11
|
+
const n = t.querySelector(".sheet-content, .drawer-content");
|
|
12
|
+
n && (n.dataset.state = "open"), e && (e.setAttribute("aria-expanded", "true"), t.dataset.triggerId = e.id || ""), document.body.style.overflow = "hidden";
|
|
13
|
+
}, o = (t) => {
|
|
14
|
+
const e = t.querySelector(".sheet-content, .drawer-content");
|
|
15
|
+
if (e) {
|
|
16
|
+
e.dataset.state = "closed";
|
|
17
|
+
const a = parseFloat(window.getComputedStyle(e).transitionDuration) * 1e3 || 300;
|
|
18
|
+
setTimeout(() => {
|
|
19
|
+
e.dataset.state === "closed" && (t.setAttribute("aria-hidden", "true"), document.body.style.overflow = "", t.dataset.triggerId && document.getElementById(t.dataset.triggerId)?.focus());
|
|
20
|
+
}, a);
|
|
21
|
+
} else
|
|
22
|
+
t.setAttribute("aria-hidden", "true"), document.body.style.overflow = "";
|
|
23
|
+
const n = t.dataset.triggerId;
|
|
24
|
+
n && document.getElementById(n)?.setAttribute("aria-expanded", "false");
|
|
25
|
+
};
|
|
26
|
+
document.addEventListener("click", (t) => {
|
|
27
|
+
const e = t.target.closest('[data-toggle="sheet"], [data-toggle="drawer"]');
|
|
28
|
+
e && (t.preventDefault(), e.id || (e.id = "trigger-" + Math.random().toString(36).substr(2, 9)), d(e));
|
|
29
|
+
}), document.addEventListener("click", (t) => {
|
|
30
|
+
t.target.matches(".sheet, .drawer") && o(t.target);
|
|
31
|
+
}), document.addEventListener("keydown", (t) => {
|
|
32
|
+
t.key === "Escape" && document.querySelectorAll('.sheet[aria-hidden="false"], .drawer[aria-hidden="false"]').forEach(o);
|
|
33
|
+
}), document.addEventListener("click", (t) => {
|
|
34
|
+
const e = t.target.closest("[data-close]");
|
|
35
|
+
if (e) {
|
|
36
|
+
const n = e.closest(".sheet, .drawer");
|
|
37
|
+
n && o(n);
|
|
38
|
+
}
|
|
39
|
+
}), window.basecoat || (window.basecoat = {}), window.basecoat.sheet = { open: r, close: o };
|
|
40
|
+
})();
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
if (!window.history.__basecoatPatched) {
|
|
3
|
+
const originalPushState = window.history.pushState;
|
|
4
|
+
window.history.pushState = function(...args) {
|
|
5
|
+
originalPushState.apply(this, args);
|
|
6
|
+
window.dispatchEvent(new Event("basecoat:locationchange"));
|
|
7
|
+
};
|
|
8
|
+
const originalReplaceState = window.history.replaceState;
|
|
9
|
+
window.history.replaceState = function(...args) {
|
|
10
|
+
originalReplaceState.apply(this, args);
|
|
11
|
+
window.dispatchEvent(new Event("basecoat:locationchange"));
|
|
12
|
+
};
|
|
13
|
+
window.history.__basecoatPatched = true;
|
|
14
|
+
}
|
|
15
|
+
const initSidebar = (sidebarComponent) => {
|
|
16
|
+
const initialOpen = sidebarComponent.dataset.initialOpen !== "false";
|
|
17
|
+
const initialMobileOpen = sidebarComponent.dataset.initialMobileOpen === "true";
|
|
18
|
+
const breakpoint = parseInt(sidebarComponent.dataset.breakpoint) || 768;
|
|
19
|
+
let open = breakpoint > 0 ? window.innerWidth >= breakpoint ? initialOpen : initialMobileOpen : initialOpen;
|
|
20
|
+
const updateCurrentPageLinks = () => {
|
|
21
|
+
const currentPath = window.location.pathname.replace(/\/$/, "");
|
|
22
|
+
sidebarComponent.querySelectorAll("a").forEach((link) => {
|
|
23
|
+
if (link.hasAttribute("data-ignore-current")) return;
|
|
24
|
+
if (link.getAttribute("href") === "#") {
|
|
25
|
+
link.removeAttribute("aria-current");
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const linkPath = new URL(link.href).pathname.replace(/\/$/, "");
|
|
29
|
+
if (linkPath === currentPath) {
|
|
30
|
+
link.setAttribute("aria-current", "page");
|
|
31
|
+
} else {
|
|
32
|
+
link.removeAttribute("aria-current");
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
const updateState = () => {
|
|
37
|
+
sidebarComponent.setAttribute("aria-hidden", !open);
|
|
38
|
+
if (open) {
|
|
39
|
+
sidebarComponent.removeAttribute("inert");
|
|
40
|
+
} else {
|
|
41
|
+
sidebarComponent.setAttribute("inert", "");
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
const setState = (state) => {
|
|
45
|
+
open = state;
|
|
46
|
+
updateState();
|
|
47
|
+
};
|
|
48
|
+
const sidebarId = sidebarComponent.id;
|
|
49
|
+
document.addEventListener("basecoat:sidebar", (event) => {
|
|
50
|
+
if (event.detail?.id && event.detail.id !== sidebarId) return;
|
|
51
|
+
switch (event.detail?.action) {
|
|
52
|
+
case "open":
|
|
53
|
+
setState(true);
|
|
54
|
+
break;
|
|
55
|
+
case "close":
|
|
56
|
+
setState(false);
|
|
57
|
+
break;
|
|
58
|
+
default:
|
|
59
|
+
setState(!open);
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
sidebarComponent.addEventListener("click", (event) => {
|
|
64
|
+
const target = event.target;
|
|
65
|
+
const nav = sidebarComponent.querySelector("nav");
|
|
66
|
+
const isMobile = window.innerWidth < breakpoint;
|
|
67
|
+
if (isMobile && (target.closest("a, button") && !target.closest("[data-keep-mobile-sidebar-open]"))) {
|
|
68
|
+
if (document.activeElement) document.activeElement.blur();
|
|
69
|
+
setState(false);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
if (target === sidebarComponent || nav && !nav.contains(target)) {
|
|
73
|
+
if (document.activeElement) document.activeElement.blur();
|
|
74
|
+
setState(false);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
window.addEventListener("popstate", updateCurrentPageLinks);
|
|
78
|
+
window.addEventListener("basecoat:locationchange", updateCurrentPageLinks);
|
|
79
|
+
updateState();
|
|
80
|
+
updateCurrentPageLinks();
|
|
81
|
+
sidebarComponent.dataset.sidebarInitialized = true;
|
|
82
|
+
sidebarComponent.dispatchEvent(new CustomEvent("basecoat:initialized"));
|
|
83
|
+
};
|
|
84
|
+
if (window.basecoat) {
|
|
85
|
+
window.basecoat.register("sidebar", ".sidebar:not([data-sidebar-initialized])", initSidebar);
|
|
86
|
+
}
|
|
87
|
+
})();
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
if (!window.history.__basecoatPatched) {
|
|
3
|
+
const t = window.history.pushState;
|
|
4
|
+
window.history.pushState = function(...i) {
|
|
5
|
+
t.apply(this, i), window.dispatchEvent(new Event("basecoat:locationchange"));
|
|
6
|
+
};
|
|
7
|
+
const r = window.history.replaceState;
|
|
8
|
+
window.history.replaceState = function(...i) {
|
|
9
|
+
r.apply(this, i), window.dispatchEvent(new Event("basecoat:locationchange"));
|
|
10
|
+
}, window.history.__basecoatPatched = !0;
|
|
11
|
+
}
|
|
12
|
+
const u = (t) => {
|
|
13
|
+
const r = t.dataset.initialOpen !== "false", i = t.dataset.initialMobileOpen === "true", s = parseInt(t.dataset.breakpoint) || 768;
|
|
14
|
+
let c = s > 0 ? window.innerWidth >= s ? r : i : r;
|
|
15
|
+
const o = () => {
|
|
16
|
+
const a = window.location.pathname.replace(/\/$/, "");
|
|
17
|
+
t.querySelectorAll("a").forEach((e) => {
|
|
18
|
+
if (e.hasAttribute("data-ignore-current")) return;
|
|
19
|
+
if (e.getAttribute("href") === "#") {
|
|
20
|
+
e.removeAttribute("aria-current");
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
new URL(e.href).pathname.replace(/\/$/, "") === a ? e.setAttribute("aria-current", "page") : e.removeAttribute("aria-current");
|
|
24
|
+
});
|
|
25
|
+
}, l = () => {
|
|
26
|
+
t.setAttribute("aria-hidden", !c), c ? t.removeAttribute("inert") : t.setAttribute("inert", "");
|
|
27
|
+
}, n = (a) => {
|
|
28
|
+
c = a, l();
|
|
29
|
+
}, w = t.id;
|
|
30
|
+
document.addEventListener("basecoat:sidebar", (a) => {
|
|
31
|
+
if (!(a.detail?.id && a.detail.id !== w))
|
|
32
|
+
switch (a.detail?.action) {
|
|
33
|
+
case "open":
|
|
34
|
+
n(!0);
|
|
35
|
+
break;
|
|
36
|
+
case "close":
|
|
37
|
+
n(!1);
|
|
38
|
+
break;
|
|
39
|
+
default:
|
|
40
|
+
n(!c);
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
}), t.addEventListener("click", (a) => {
|
|
44
|
+
const e = a.target, d = t.querySelector("nav");
|
|
45
|
+
if (window.innerWidth < s && e.closest("a, button") && !e.closest("[data-keep-mobile-sidebar-open]")) {
|
|
46
|
+
document.activeElement && document.activeElement.blur(), n(!1);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
(e === t || d && !d.contains(e)) && (document.activeElement && document.activeElement.blur(), n(!1));
|
|
50
|
+
}), window.addEventListener("popstate", o), window.addEventListener("basecoat:locationchange", o), l(), o(), t.dataset.sidebarInitialized = !0, t.dispatchEvent(new CustomEvent("basecoat:initialized"));
|
|
51
|
+
};
|
|
52
|
+
window.basecoat && window.basecoat.register("sidebar", ".sidebar:not([data-sidebar-initialized])", u);
|
|
53
|
+
})();
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
const initSlider = (slider) => {
|
|
3
|
+
const update = () => {
|
|
4
|
+
const value = slider.value;
|
|
5
|
+
const min = slider.min ? parseFloat(slider.min) : 0;
|
|
6
|
+
const max = slider.max ? parseFloat(slider.max) : 100;
|
|
7
|
+
const percentage = (value - min) / (max - min) * 100;
|
|
8
|
+
slider.style.setProperty("--slider-value", `${percentage}%`);
|
|
9
|
+
};
|
|
10
|
+
slider.addEventListener("input", update);
|
|
11
|
+
update();
|
|
12
|
+
slider.dataset.sliderInitialized = true;
|
|
13
|
+
slider.dispatchEvent(new CustomEvent("basecoat:initialized"));
|
|
14
|
+
};
|
|
15
|
+
if (window.basecoat) {
|
|
16
|
+
window.basecoat.register("slider", 'input[type="range"].slider:not([data-slider-initialized]), input[type="range"].input:not([data-slider-initialized])', initSlider);
|
|
17
|
+
}
|
|
18
|
+
})();
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
const n = (t) => {
|
|
3
|
+
const a = () => {
|
|
4
|
+
const i = t.value, e = t.min ? parseFloat(t.min) : 0, o = t.max ? parseFloat(t.max) : 100, s = (i - e) / (o - e) * 100;
|
|
5
|
+
t.style.setProperty("--slider-value", `${s}%`);
|
|
6
|
+
};
|
|
7
|
+
t.addEventListener("input", a), a(), t.dataset.sliderInitialized = !0, t.dispatchEvent(new CustomEvent("basecoat:initialized"));
|
|
8
|
+
};
|
|
9
|
+
window.basecoat && window.basecoat.register("slider", 'input[type="range"].slider:not([data-slider-initialized]), input[type="range"].input:not([data-slider-initialized])', n);
|
|
10
|
+
})();
|
package/dist/js/tabs.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
const initTabs = (tabsComponent) => {
|
|
3
|
+
const tablist = tabsComponent.querySelector('[role="tablist"]');
|
|
4
|
+
if (!tablist) return;
|
|
5
|
+
const tabs = Array.from(tablist.querySelectorAll('[role="tab"]'));
|
|
6
|
+
const panels = tabs.map((tab) => document.getElementById(tab.getAttribute("aria-controls"))).filter(Boolean);
|
|
7
|
+
const selectTab = (tabToSelect) => {
|
|
8
|
+
tabs.forEach((tab, index) => {
|
|
9
|
+
tab.setAttribute("aria-selected", "false");
|
|
10
|
+
tab.setAttribute("tabindex", "-1");
|
|
11
|
+
if (panels[index]) panels[index].hidden = true;
|
|
12
|
+
});
|
|
13
|
+
tabToSelect.setAttribute("aria-selected", "true");
|
|
14
|
+
tabToSelect.setAttribute("tabindex", "0");
|
|
15
|
+
const activePanel = document.getElementById(tabToSelect.getAttribute("aria-controls"));
|
|
16
|
+
if (activePanel) activePanel.hidden = false;
|
|
17
|
+
};
|
|
18
|
+
tablist.addEventListener("click", (event) => {
|
|
19
|
+
const clickedTab = event.target.closest('[role="tab"]');
|
|
20
|
+
if (clickedTab) selectTab(clickedTab);
|
|
21
|
+
});
|
|
22
|
+
tablist.addEventListener("keydown", (event) => {
|
|
23
|
+
const currentTab = event.target;
|
|
24
|
+
if (!tabs.includes(currentTab)) return;
|
|
25
|
+
let nextTab;
|
|
26
|
+
const currentIndex = tabs.indexOf(currentTab);
|
|
27
|
+
switch (event.key) {
|
|
28
|
+
case "ArrowRight":
|
|
29
|
+
nextTab = tabs[(currentIndex + 1) % tabs.length];
|
|
30
|
+
break;
|
|
31
|
+
case "ArrowLeft":
|
|
32
|
+
nextTab = tabs[(currentIndex - 1 + tabs.length) % tabs.length];
|
|
33
|
+
break;
|
|
34
|
+
case "Home":
|
|
35
|
+
nextTab = tabs[0];
|
|
36
|
+
break;
|
|
37
|
+
case "End":
|
|
38
|
+
nextTab = tabs[tabs.length - 1];
|
|
39
|
+
break;
|
|
40
|
+
default:
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
event.preventDefault();
|
|
44
|
+
selectTab(nextTab);
|
|
45
|
+
nextTab.focus();
|
|
46
|
+
});
|
|
47
|
+
tabsComponent.dataset.tabsInitialized = true;
|
|
48
|
+
tabsComponent.dispatchEvent(new CustomEvent("basecoat:initialized"));
|
|
49
|
+
};
|
|
50
|
+
if (window.basecoat) {
|
|
51
|
+
window.basecoat.register("tabs", ".tabs:not([data-tabs-initialized])", initTabs);
|
|
52
|
+
}
|
|
53
|
+
})();
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
const o = (s) => {
|
|
3
|
+
const n = s.querySelector('[role="tablist"]');
|
|
4
|
+
if (!n) return;
|
|
5
|
+
const t = Array.from(n.querySelectorAll('[role="tab"]')), c = t.map((e) => document.getElementById(e.getAttribute("aria-controls"))).filter(Boolean), l = (e) => {
|
|
6
|
+
t.forEach((a, i) => {
|
|
7
|
+
a.setAttribute("aria-selected", "false"), a.setAttribute("tabindex", "-1"), c[i] && (c[i].hidden = !0);
|
|
8
|
+
}), e.setAttribute("aria-selected", "true"), e.setAttribute("tabindex", "0");
|
|
9
|
+
const r = document.getElementById(e.getAttribute("aria-controls"));
|
|
10
|
+
r && (r.hidden = !1);
|
|
11
|
+
};
|
|
12
|
+
n.addEventListener("click", (e) => {
|
|
13
|
+
const r = e.target.closest('[role="tab"]');
|
|
14
|
+
r && l(r);
|
|
15
|
+
}), n.addEventListener("keydown", (e) => {
|
|
16
|
+
const r = e.target;
|
|
17
|
+
if (!t.includes(r)) return;
|
|
18
|
+
let a;
|
|
19
|
+
const i = t.indexOf(r);
|
|
20
|
+
switch (e.key) {
|
|
21
|
+
case "ArrowRight":
|
|
22
|
+
a = t[(i + 1) % t.length];
|
|
23
|
+
break;
|
|
24
|
+
case "ArrowLeft":
|
|
25
|
+
a = t[(i - 1 + t.length) % t.length];
|
|
26
|
+
break;
|
|
27
|
+
case "Home":
|
|
28
|
+
a = t[0];
|
|
29
|
+
break;
|
|
30
|
+
case "End":
|
|
31
|
+
a = t[t.length - 1];
|
|
32
|
+
break;
|
|
33
|
+
default:
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
e.preventDefault(), l(a), a.focus();
|
|
37
|
+
}), s.dataset.tabsInitialized = !0, s.dispatchEvent(new CustomEvent("basecoat:initialized"));
|
|
38
|
+
};
|
|
39
|
+
window.basecoat && window.basecoat.register("tabs", ".tabs:not([data-tabs-initialized])", o);
|
|
40
|
+
})();
|
package/dist/js/toast.js
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
let toaster;
|
|
3
|
+
const toasts = /* @__PURE__ */ new WeakMap();
|
|
4
|
+
let isPaused = false;
|
|
5
|
+
const ICONS = {
|
|
6
|
+
success: '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/></svg>',
|
|
7
|
+
error: '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="m15 9-6 6"/><path d="m9 9 6 6"/></svg>',
|
|
8
|
+
info: '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/></svg>',
|
|
9
|
+
warning: '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg>'
|
|
10
|
+
};
|
|
11
|
+
function initToaster(toasterElement) {
|
|
12
|
+
if (toasterElement.dataset.toasterInitialized) return;
|
|
13
|
+
toaster = toasterElement;
|
|
14
|
+
toaster.addEventListener("mouseenter", pauseAllTimeouts);
|
|
15
|
+
toaster.addEventListener("mouseleave", resumeAllTimeouts);
|
|
16
|
+
toaster.addEventListener("click", (event) => {
|
|
17
|
+
const actionLink = event.target.closest(".toast footer a");
|
|
18
|
+
const actionButton = event.target.closest(".toast footer button");
|
|
19
|
+
if (actionLink || actionButton) {
|
|
20
|
+
closeToast(event.target.closest(".toast"));
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
toaster.querySelectorAll(".toast:not([data-toast-initialized])").forEach(initToast);
|
|
24
|
+
toaster.dataset.toasterInitialized = "true";
|
|
25
|
+
toaster.dispatchEvent(new CustomEvent("basecoat:initialized"));
|
|
26
|
+
}
|
|
27
|
+
function initToast(element) {
|
|
28
|
+
if (element.dataset.toastInitialized) return;
|
|
29
|
+
const duration = parseInt(element.dataset.duration);
|
|
30
|
+
const timeoutDuration = duration !== -1 ? duration || (element.dataset.category === "error" ? 5e3 : 3e3) : -1;
|
|
31
|
+
const state = {
|
|
32
|
+
remainingTime: timeoutDuration,
|
|
33
|
+
timeoutId: null,
|
|
34
|
+
startTime: null
|
|
35
|
+
};
|
|
36
|
+
if (timeoutDuration !== -1) {
|
|
37
|
+
if (isPaused) {
|
|
38
|
+
state.timeoutId = null;
|
|
39
|
+
} else {
|
|
40
|
+
state.startTime = Date.now();
|
|
41
|
+
state.timeoutId = setTimeout(() => closeToast(element), timeoutDuration);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
toasts.set(element, state);
|
|
45
|
+
element.dataset.toastInitialized = "true";
|
|
46
|
+
}
|
|
47
|
+
function pauseAllTimeouts() {
|
|
48
|
+
if (isPaused) return;
|
|
49
|
+
isPaused = true;
|
|
50
|
+
toaster.querySelectorAll('.toast:not([aria-hidden="true"])').forEach((element) => {
|
|
51
|
+
if (!toasts.has(element)) return;
|
|
52
|
+
const state = toasts.get(element);
|
|
53
|
+
if (state.timeoutId) {
|
|
54
|
+
clearTimeout(state.timeoutId);
|
|
55
|
+
state.timeoutId = null;
|
|
56
|
+
state.remainingTime -= Date.now() - state.startTime;
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
function resumeAllTimeouts() {
|
|
61
|
+
if (!isPaused) return;
|
|
62
|
+
isPaused = false;
|
|
63
|
+
toaster.querySelectorAll('.toast:not([aria-hidden="true"])').forEach((element) => {
|
|
64
|
+
if (!toasts.has(element)) return;
|
|
65
|
+
const state = toasts.get(element);
|
|
66
|
+
if (state.remainingTime !== -1 && !state.timeoutId) {
|
|
67
|
+
if (state.remainingTime > 0) {
|
|
68
|
+
state.startTime = Date.now();
|
|
69
|
+
state.timeoutId = setTimeout(() => closeToast(element), state.remainingTime);
|
|
70
|
+
} else {
|
|
71
|
+
closeToast(element);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
function closeToast(element) {
|
|
77
|
+
if (!toasts.has(element)) return;
|
|
78
|
+
const state = toasts.get(element);
|
|
79
|
+
clearTimeout(state.timeoutId);
|
|
80
|
+
toasts.delete(element);
|
|
81
|
+
if (element.contains(document.activeElement)) document.activeElement.blur();
|
|
82
|
+
element.setAttribute("aria-hidden", "true");
|
|
83
|
+
element.addEventListener("transitionend", () => element.remove(), { once: true });
|
|
84
|
+
}
|
|
85
|
+
function createToast(config) {
|
|
86
|
+
const {
|
|
87
|
+
category = "info",
|
|
88
|
+
title,
|
|
89
|
+
description,
|
|
90
|
+
action,
|
|
91
|
+
cancel,
|
|
92
|
+
duration,
|
|
93
|
+
icon
|
|
94
|
+
} = config;
|
|
95
|
+
const iconHtml = icon || category && ICONS[category] || "";
|
|
96
|
+
const titleHtml = title ? `<h2>${title}</h2>` : "";
|
|
97
|
+
const descriptionHtml = description ? `<p>${description}</p>` : "";
|
|
98
|
+
const actionHtml = action?.href ? `<a href="${action.href}" class="btn" data-toast-action>${action.label}</a>` : action?.onclick ? `<button type="button" class="btn" data-toast-action onclick="${action.onclick}">${action.label}</button>` : "";
|
|
99
|
+
const cancelHtml = cancel ? `<button type="button" class="btn-outline h-6 text-xs px-2.5 rounded-sm" data-toast-cancel onclick="${cancel?.onclick}">${cancel.label}</button>` : "";
|
|
100
|
+
const footerHtml = actionHtml || cancelHtml ? `<footer>${actionHtml}${cancelHtml}</footer>` : "";
|
|
101
|
+
const html = `
|
|
102
|
+
<div
|
|
103
|
+
class="toast"
|
|
104
|
+
role="${category === "error" ? "alert" : "status"}"
|
|
105
|
+
aria-atomic="true"
|
|
106
|
+
${category ? `data-category="${category}"` : ""}
|
|
107
|
+
${duration !== void 0 ? `data-duration="${duration}"` : ""}
|
|
108
|
+
>
|
|
109
|
+
<div class="toast-content">
|
|
110
|
+
${iconHtml}
|
|
111
|
+
<section>
|
|
112
|
+
${titleHtml}
|
|
113
|
+
${descriptionHtml}
|
|
114
|
+
</section>
|
|
115
|
+
${footerHtml}
|
|
116
|
+
</div>
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
`;
|
|
120
|
+
const template = document.createElement("template");
|
|
121
|
+
template.innerHTML = html.trim();
|
|
122
|
+
return template.content.firstChild;
|
|
123
|
+
}
|
|
124
|
+
document.addEventListener("basecoat:toast", (event) => {
|
|
125
|
+
if (!toaster) {
|
|
126
|
+
console.error("Cannot create toast: toaster container not found on page.");
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
const config = event.detail?.config || {};
|
|
130
|
+
const toastElement = createToast(config);
|
|
131
|
+
toaster.appendChild(toastElement);
|
|
132
|
+
});
|
|
133
|
+
if (window.basecoat) {
|
|
134
|
+
window.basecoat.register("toaster", "#toaster:not([data-toaster-initialized])", initToaster);
|
|
135
|
+
window.basecoat.register("toast", ".toast:not([data-toast-initialized])", initToast);
|
|
136
|
+
}
|
|
137
|
+
})();
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
let o;
|
|
3
|
+
const n = /* @__PURE__ */ new WeakMap();
|
|
4
|
+
let s = !1;
|
|
5
|
+
const g = {
|
|
6
|
+
success: '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/></svg>',
|
|
7
|
+
error: '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="m15 9-6 6"/><path d="m9 9 6 6"/></svg>',
|
|
8
|
+
info: '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/></svg>',
|
|
9
|
+
warning: '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg>'
|
|
10
|
+
};
|
|
11
|
+
function w(t) {
|
|
12
|
+
t.dataset.toasterInitialized || (o = t, o.addEventListener("mouseenter", p), o.addEventListener("mouseleave", v), o.addEventListener("click", (e) => {
|
|
13
|
+
const i = e.target.closest(".toast footer a"), a = e.target.closest(".toast footer button");
|
|
14
|
+
(i || a) && c(e.target.closest(".toast"));
|
|
15
|
+
}), o.querySelectorAll(".toast:not([data-toast-initialized])").forEach(l), o.dataset.toasterInitialized = "true", o.dispatchEvent(new CustomEvent("basecoat:initialized")));
|
|
16
|
+
}
|
|
17
|
+
function l(t) {
|
|
18
|
+
if (t.dataset.toastInitialized) return;
|
|
19
|
+
const e = parseInt(t.dataset.duration), i = e !== -1 ? e || (t.dataset.category === "error" ? 5e3 : 3e3) : -1, a = {
|
|
20
|
+
remainingTime: i,
|
|
21
|
+
timeoutId: null,
|
|
22
|
+
startTime: null
|
|
23
|
+
};
|
|
24
|
+
i !== -1 && (s ? a.timeoutId = null : (a.startTime = Date.now(), a.timeoutId = setTimeout(() => c(t), i))), n.set(t, a), t.dataset.toastInitialized = "true";
|
|
25
|
+
}
|
|
26
|
+
function p() {
|
|
27
|
+
s || (s = !0, o.querySelectorAll('.toast:not([aria-hidden="true"])').forEach((t) => {
|
|
28
|
+
if (!n.has(t)) return;
|
|
29
|
+
const e = n.get(t);
|
|
30
|
+
e.timeoutId && (clearTimeout(e.timeoutId), e.timeoutId = null, e.remainingTime -= Date.now() - e.startTime);
|
|
31
|
+
}));
|
|
32
|
+
}
|
|
33
|
+
function v() {
|
|
34
|
+
s && (s = !1, o.querySelectorAll('.toast:not([aria-hidden="true"])').forEach((t) => {
|
|
35
|
+
if (!n.has(t)) return;
|
|
36
|
+
const e = n.get(t);
|
|
37
|
+
e.remainingTime !== -1 && !e.timeoutId && (e.remainingTime > 0 ? (e.startTime = Date.now(), e.timeoutId = setTimeout(() => c(t), e.remainingTime)) : c(t));
|
|
38
|
+
}));
|
|
39
|
+
}
|
|
40
|
+
function c(t) {
|
|
41
|
+
if (!n.has(t)) return;
|
|
42
|
+
const e = n.get(t);
|
|
43
|
+
clearTimeout(e.timeoutId), n.delete(t), t.contains(document.activeElement) && document.activeElement.blur(), t.setAttribute("aria-hidden", "true"), t.addEventListener("transitionend", () => t.remove(), { once: !0 });
|
|
44
|
+
}
|
|
45
|
+
function k(t) {
|
|
46
|
+
const {
|
|
47
|
+
category: e = "info",
|
|
48
|
+
title: i,
|
|
49
|
+
description: a,
|
|
50
|
+
action: r,
|
|
51
|
+
cancel: d,
|
|
52
|
+
duration: u,
|
|
53
|
+
icon: b
|
|
54
|
+
} = t, T = b || e && g[e] || "", $ = i ? `<h2>${i}</h2>` : "", I = a ? `<p>${a}</p>` : "", h = r?.href ? `<a href="${r.href}" class="btn" data-toast-action>${r.label}</a>` : r?.onclick ? `<button type="button" class="btn" data-toast-action onclick="${r.onclick}">${r.label}</button>` : "", m = d ? `<button type="button" class="btn-outline h-6 text-xs px-2.5 rounded-sm" data-toast-cancel onclick="${d?.onclick}">${d.label}</button>` : "", x = h || m ? `<footer>${h}${m}</footer>` : "", E = `
|
|
55
|
+
<div
|
|
56
|
+
class="toast"
|
|
57
|
+
role="${e === "error" ? "alert" : "status"}"
|
|
58
|
+
aria-atomic="true"
|
|
59
|
+
${e ? `data-category="${e}"` : ""}
|
|
60
|
+
${u !== void 0 ? `data-duration="${u}"` : ""}
|
|
61
|
+
>
|
|
62
|
+
<div class="toast-content">
|
|
63
|
+
${T}
|
|
64
|
+
<section>
|
|
65
|
+
${$}
|
|
66
|
+
${I}
|
|
67
|
+
</section>
|
|
68
|
+
${x}
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
`, f = document.createElement("template");
|
|
73
|
+
return f.innerHTML = E.trim(), f.content.firstChild;
|
|
74
|
+
}
|
|
75
|
+
document.addEventListener("basecoat:toast", (t) => {
|
|
76
|
+
if (!o) {
|
|
77
|
+
console.error("Cannot create toast: toaster container not found on page.");
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const e = t.detail?.config || {}, i = k(e);
|
|
81
|
+
o.appendChild(i);
|
|
82
|
+
}), window.basecoat && (window.basecoat.register("toaster", "#toaster:not([data-toaster-initialized])", w), window.basecoat.register("toast", ".toast:not([data-toast-initialized])", l));
|
|
83
|
+
})();
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
const initToggle = (toggle) => {
|
|
3
|
+
toggle.addEventListener("click", (e) => {
|
|
4
|
+
if (toggle.disabled || toggle.getAttribute("aria-disabled") === "true") return;
|
|
5
|
+
const isPressed = toggle.getAttribute("aria-pressed") === "true";
|
|
6
|
+
toggle.setAttribute("aria-pressed", !isPressed);
|
|
7
|
+
});
|
|
8
|
+
toggle.dataset.toggleInitialized = true;
|
|
9
|
+
};
|
|
10
|
+
const initToggleGroup = (group) => {
|
|
11
|
+
const type = group.dataset.type || "single";
|
|
12
|
+
group.addEventListener("click", (event) => {
|
|
13
|
+
const toggle = event.target.closest(".toggle");
|
|
14
|
+
if (!toggle || !group.contains(toggle)) return;
|
|
15
|
+
if (toggle.disabled || toggle.getAttribute("aria-disabled") === "true") return;
|
|
16
|
+
const isPressed = toggle.getAttribute("aria-pressed") === "true";
|
|
17
|
+
if (type === "single") {
|
|
18
|
+
if (!isPressed) {
|
|
19
|
+
group.querySelectorAll(".toggle").forEach((t) => {
|
|
20
|
+
if (t !== toggle) t.setAttribute("aria-pressed", "false");
|
|
21
|
+
});
|
|
22
|
+
toggle.setAttribute("aria-pressed", "true");
|
|
23
|
+
} else {
|
|
24
|
+
toggle.setAttribute("aria-pressed", "false");
|
|
25
|
+
}
|
|
26
|
+
} else {
|
|
27
|
+
toggle.setAttribute("aria-pressed", !isPressed);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
group.dataset.toggleGroupInitialized = true;
|
|
31
|
+
};
|
|
32
|
+
if (window.basecoat) {
|
|
33
|
+
window.basecoat.register("toggle", ".toggle:not(.toggle-group .toggle):not([data-toggle-initialized])", initToggle);
|
|
34
|
+
window.basecoat.register("toggle-group", ".toggle-group:not([data-toggle-group-initialized])", initToggleGroup);
|
|
35
|
+
}
|
|
36
|
+
})();
|