@base-framework/ui
Version:
This is a UI package that adds components and atoms that use Tailwind CSS and a theme based on Shadcn.
502 lines (501 loc) • 13.9 kB
JavaScript
import { Div as i, Img as j, Span as P, Button as I, OnState as W } from "@base-framework/atoms";
import { Component as N, Data as Y, Atom as z, DateTime as B } from "@base-framework/base";
import { B as p } from "./buttons-Cm9etaEG.js";
import { Icons as S } from "./icons.es.js";
const H = (e, t) => {
const n = e ? e.getBoundingClientRect() : { top: 0, bottom: 0, left: 0 }, s = t.getBoundingClientRect(), r = 10, a = globalThis.scrollX, l = globalThis.scrollY;
let c = n.left + a, g = n.bottom + l;
const d = globalThis.innerHeight - n.bottom, h = n.top;
return c + s.width > globalThis.innerWidth && (c = globalThis.innerWidth - s.width - r), d < s.height && h > d ? g = n.top + l - s.height - r : d < s.height && (g = n.bottom + l - (s.height - d) - r), { x: c, y: g };
};
class ht extends N {
/**
* This will set up the data.
*
* @returns {object}
*/
setData() {
const t = this.parent.data || new Y();
return t.set({
position: { x: 0, y: 0 }
}), t;
}
/**
* This will get the class size.
*
* @returns {string}
*/
getSize() {
switch (this.size || "lg") {
// @ts-ignore
case "sm":
return "w-48";
// @ts-ignore
case "md":
return "w-64";
case "lg":
return "w-[250px]";
// @ts-ignore
case "xl":
return "w-96";
// @ts-ignore
case "2xl":
return "w-[400px]";
// @ts-ignore
case "fit":
return "w-fit";
// @ts-ignore
case "full":
return "w-full";
}
}
/**
* This will render the modal component.
*
* @returns {object}
*/
render() {
const t = this.getSize();
return i({
class: `absolute inset-auto fadeIn mt-2 rounded-md p-0 shadow-lg bg-popover min-h-12 backdrop:bg-transparent text-inherit r z-30 ${t}`,
popover: "manual",
toggle: (n, { state: s }) => n.newState === "closed" ? s.open = !1 : null,
style: "top: [[position.y]]px; left: [[position.x]]px"
}, this.children);
}
/**
* This will setup the states.
*
* @returns {object}
*/
setupStates() {
return {
open: {
id: this.parent.getId(),
callBack: (s) => {
this.state.open === !1 && this.destroy();
}
}
};
}
/**
* Updates the dropdown position.
*
* @returns {void}
*/
updatePosition() {
const t = this.button ?? null, n = this.panel, s = H(t, n);
this.data.position = s;
}
/**
* This will run after the setup.
*
* @returns {void}
*/
afterSetup() {
this.panel.showPopover(), this.updatePosition();
}
/**
* This will check if the element clicked was in the
* component of the button.
*
* @param {object} element
* @returns {boolean}
*/
isOutsideClick(t) {
return !this.panel.contains(t) && this.button && !this.button.contains(t);
}
/**
* This will set up the events.
*
* @returns {array}
*/
setupEvents() {
return [
["click", document, (t) => {
this.isOutsideClick(t.target) && (this.state.open = !1);
}],
["resize", globalThis, (t) => this.updatePosition()],
["scroll", document, (t) => this.updatePosition()]
];
}
/**
* This will override the set up to use the app shell.
*
* @param {object} container
*/
setContainer(t) {
this.container = app.root;
}
/**
* This will hide the popover before destroying.
*
* @returns {void}
*/
beforeDestroy() {
this.panel.hidePopover();
}
}
const R = z(({ src: e, alt: t }) => e ? j({
class: "absolute w-full h-full rounded-full object-cover fadeIn",
src: e,
alt: t,
/**
* If there's an error loading the image, hide it.
*/
error: (n) => n.target.style.display = "none"
}) : null), X = (e) => e && (Array.isArray(e) && (e = e.join(" ")), typeof e != "string" && (e = String(e)), e.split(" ").map((t) => t.charAt(0)).join("").toUpperCase()), O = (e) => !e || e.length < 2 ? e : X(e), E = (e) => P([e, (t, n) => {
n.textContent = O(t);
}]), T = {
xs: "h-6 w-6",
sm: "h-8 w-8",
md: "h-12 w-12",
lg: "h-16 w-16",
xl: "h-24 w-24",
"2xl": "h-32 w-32",
"3xl": "h-48 w-48",
"4xl": "h-64 w-64",
default: "h-12 w-12"
}, k = {
xs: "text-[7px]",
sm: "text-xs",
md: "text-base",
lg: "text-xl",
xl: "text-2xl",
"2xl": "text-3xl",
"3xl": "text-4xl",
"4xl": "text-5xl",
default: "text-base"
}, G = (e) => T[e] || T.default, L = (e) => k[e] || k.default, U = (e, t = null, n = "md") => {
const s = O(e), r = L(n);
return i(
{
class: `
flex items-center justify-center w-full h-full rounded-full
bg-muted text-muted-foreground font-medium
${r}
`
},
[
t ? E(t) : P({ class: "uppercase" }, s)
]
);
}, dt = z(({ src: e, alt: t, fallbackText: n, watcherFallback: s, size: r }) => {
const a = G(r);
return i(
{
class: `relative flex items-center justify-center ${a}`
},
[
R({ src: e, alt: t }),
U(n, s, r)
]
);
}), _ = ({ currentYear: e, onSelect: t }) => i(
{ class: "grid grid-cols-3 gap-2" },
B.monthNames.map(
(n, s) => p(
{
click: () => t(s),
variant: "ghost",
"aria-label": `Select ${n} ${e}`
},
n.substring(0, 3)
)
)
), D = (e) => (e *= 1, e < 10 ? `0${e}` : String(e)), q = (e) => (e.indexOf("T") === -1 && e.indexOf(" ") === -1 && (e += "T00:00:01"), e.replace(" ", "T"), e), x = (e, t, n) => `${e}-${D(t + 1)}-${D(n)}`, J = (e) => e ? "bg-accent text-primary" : "", K = (e) => e ? "text-muted-foreground opacity-50" : "", Q = (e, t) => e === t, V = (e, t) => Q(e, t) ? "bg-primary text-primary-foreground" : "", Z = (e, t, n, s) => {
const r = V(t, s);
return r || (e ? J(e) : n ? K(n) : "text-foreground");
}, C = (e) => {
const {
day: t,
currentDate: n,
date: s,
isToday: r,
isOutsideMonth: a,
select: l,
disabled: c
} = e;
return I(
{
class: `
flex items-center justify-center h-9 w-auto p-0 font-normal text-sm rounded-md
${Z(r, n, a, s)}
hover:bg-muted/50 hover:text-muted-foreground focus:z-10
disabled:pointer-events-none disabled:opacity-50
`,
disabled: c || t === null,
"aria-label": t ? `Day ${t}` : null,
// Only call select if it's not disabled.
click: () => !c && l(s)
},
t.toString()
);
}, M = (e, t, n, s) => e === s.date && t === s.month && n === s.year, tt = (e, t, n, s = !1) => {
const { year: r, month: a } = e, l = x(r, a, e.date), c = new Date(r, a, 1).getDay(), g = new Date(r, a + 1, 0).getDate(), d = new Date(r, a, 0).getDate(), h = [], y = a === 0 ? 11 : a - 1, w = a === 0 ? r - 1 : r;
for (let o = c - 1; o >= 0; o--) {
const u = d - o, f = M(u, y, w, t), m = new Date(w, y, u) < new Date(t.year, t.month, t.date), F = s && m;
h.push(
C({
day: u,
currentDate: l,
date: x(w, y, u),
isToday: f,
isOutsideMonth: !0,
select: n,
disabled: F
})
);
}
for (let o = 1; o <= g; o++) {
const u = M(o, a, r, t), f = new Date(r, a, o) < new Date(t.year, t.month, t.date), m = s && f;
h.push(
C({
day: o,
currentDate: l,
date: x(r, a, o),
isToday: u,
isOutsideMonth: !1,
select: n,
disabled: m
})
);
}
const v = a === 11 ? 0 : a + 1, b = a === 11 ? r + 1 : r, A = (7 - h.length % 7) % 7;
for (let o = 1; o <= A; o++) {
const u = M(o, v, b, t), f = new Date(b, v, o) < new Date(t.year, t.month, t.date), m = s && f;
h.push(
C({
day: o,
currentDate: l,
date: x(b, v, o),
isToday: u,
isOutsideMonth: !0,
select: n,
disabled: m
})
);
}
return h;
}, $ = ({ label: e, click: t }) => p(
{
class: `
inline-flex items-center justify-center h-7 w-7 bg-transparent p-0
opacity-50 hover:opacity-100 text-muted-foreground absolute
${e === "Previous" ? "left-1" : "right-1"}
focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2
`,
click: t,
"aria-label": `${e} month`,
variant: "icon",
icon: e === "Previous" ? S.chevron.single.left : S.chevron.single.right
}
), et = ({ onMonthClick: e, onYearClick: t, next: n, previous: s }) => i({ class: "flex items-center justify-center space-x-2 relative min-h-12 text-sm font-medium" }, [
p({ click: e, variant: "ghost", "aria-label": "Select month" }, "[[monthName]]"),
p({ click: t, variant: "ghost", "aria-label": "Select year" }, "[[current.year]]"),
$({ label: "Previous", click: s }),
$({ label: "Next", click: n })
]), nt = (e) => i(
{ class: "flex items-center justify-center h-9 w-auto text-[0.8rem] font-normal text-muted-foreground" },
e
), st = () => ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"].map(nt), rt = (e) => i({ class: "rdp w-full space-y-1" }, [
et({
onMonthClick: e.onMonthClick,
onYearClick: e.onYearClick,
next: e.next,
previous: e.previous
}),
i({
class: "flex flex-auto flex-col w-full",
onSet: [
"currentDate",
() => [
i({ class: "grid grid-cols-7" }, st()),
i(
{ class: "grid grid-cols-7" },
tt(
e.current,
e.today,
e.select,
e.blockPriorDates
)
)
]
]
})
]), at = ({ currentMonth: e, currentYear: t, onSelect: n }) => {
const s = t - 50, r = Array.from({ length: 101 }, (a, l) => s + l);
return i(
{ class: "grid grid-cols-4 gap-2 overflow-y-auto max-h-72" },
r.map(
(a) => p(
{
click: () => n(a),
variant: "ghost",
"aria-label": `Select ${a}`
},
a.toString()
)
)
);
};
class gt extends N {
/**
* This will declare the props for the compiler.
*
* @returns {void}
*/
declareProps() {
this.selectedDate = null, this.selectedCallBack = null, this.blockPriorDates = !1;
}
/**
* This will get the selected data.
*
* @param {object} today
* @returns {Date}
*/
getSelectedDate(t) {
const n = this.selectedDate ? new Date(q(this.selectedDate)) : t;
return new Date(n.getFullYear(), n.getMonth(), n.getDate());
}
/**
* This will set up the data for the calendar.
*
* @returns {Data}
*/
setData() {
const t = /* @__PURE__ */ new Date(), n = this.getSelectedDate(t), s = n.getMonth();
return new Y({
monthName: this.getMonthName(s),
currentDate: `${n.getFullYear()}-${s + 1}-${n.getDate()}`,
current: {
date: n.getDate(),
year: n.getFullYear(),
month: s
},
today: {
date: t.getDate(),
month: t.getMonth(),
year: t.getFullYear()
}
});
}
/**
* This will set up the states for the calendar.
*
* @return {object}
*/
setupStates() {
return {
view: "calendar"
// 'calendar' | 'months' | 'years'
};
}
/**
* This will get the name of the month.
*
* @param {number} month
* @returns {string}
*/
getMonthName(t) {
return B.monthNames[t];
}
/**
* This will go to the previous month.
*
* @returns {void}
*/
goToPreviousMonth() {
const t = this.data;
let n = t.current.month, s = t.current.year;
n === 0 ? (n = 11, s--) : n--, this.setCurrentDate(n, s);
}
/**
* This will go to the next month.
*
* @returns {void}
*/
goToNextMonth() {
const t = this.data;
let n = t.current.month, s = t.current.year;
n === 11 ? (n = 0, s++) : n++, this.setCurrentDate(n, s);
}
/**
* This will set the current month and year.
*
* @param {number} month
* @param {number} year
* @param {number} [date=null]
* @returns {void}
*/
setCurrentDate(t, n, s = null) {
const r = this.data;
r.current.month = t, r.current.year = n, typeof s == "number" && (r.current.date = D(s)), r.currentDate = `${n}-${D(t + 1)}-${r.current.date}`, r.monthName = this.getMonthName(t);
}
/**
* This will select a date.
*
* @param {string} date
* @returns {void}
*/
selectDate(t) {
const n = /* @__PURE__ */ new Date(t + "T00:00:00");
this.setCurrentDate(n.getMonth(), n.getFullYear(), n.getDate()), typeof this.selectedCallBack == "function" && this.selectedCallBack(this.data.currentDate);
}
/**
* This will render the calendar.
*
* @returns {object}
*/
render() {
return i({ class: "calendar-container p-3 rounded-md border min-w-80" }, [
W("view", (t) => {
switch (t) {
case "months":
return _(
{
currentYear: this.data.current.year,
onSelect: (n) => {
this.setCurrentDate(n, this.data.current.year), this.state.view = "calendar";
}
}
);
case "years":
return at(
{
currentMonth: this.data.current.month,
currentYear: this.data.current.year,
onSelect: (n) => {
this.setCurrentDate(this.data.current.month, n), this.state.view = "calendar";
}
}
);
default:
return rt({
current: this.data.current,
today: this.data.today,
select: (n) => this.selectDate(n),
next: () => this.goToNextMonth(),
previous: () => this.goToPreviousMonth(),
blockPriorDates: this.blockPriorDates || !1,
onMonthClick: () => this.state.view = "months",
onYearClick: () => this.state.view = "years"
});
}
})
]);
}
}
export {
dt as A,
tt as C,
C as D,
x as F,
rt as M,
ht as P,
nt as a,
gt as b,
q as c,
H as g,
D as p
};