@base-framework/ui
Version:
This is a UI package that adds components and atoms that use Tailwind CSS and a theme based on Shadcn.
1,743 lines (1,742 loc) • 47 kB
JavaScript
import { Button as y, Div as o, On as F, Span as v, Th as R, UseParent as E, I as H, Thead as Q, Tr as X, Table as W, P as p, Li as D, Time as q, Nav as S, Ul as b, Section as P, Canvas as K } from "@base-framework/atoms";
import { Atom as d, Component as h, Data as L, DateTime as G, router as x, NavLink as O, DataTracker as z, Jot as V, base as I, Dom as B } from "@base-framework/base";
import { B as C, I as N } from "./buttons-CVEwmPAi.js";
import { Icons as w } from "./icons.es.js";
import { TableBody as _, ScrollableTableBody as J, List as Z, IntervalTimer as ee } from "@base-framework/organisms";
import { C as te, I as se, H as ae } from "./inputs-nzivW9Dr.js";
import { A as ie, P as ne } from "./calendar-BDqm833e.js";
d((t, e) => ({
class: "flex items-center px-4 py-2",
...t,
children: e
}));
d(({ value: t, label: e }) => y({
class: "inline-flex flex-auto items-center justify-center whitespace-nowrap rounded-md px-8 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow",
onState: ["performance", { active: t }],
dataSet: ["performance", ["state", t, "active"]],
click: (s, { state: a }) => a.performance = t
}, e));
class et extends h {
/**
* This will declare the props for the compiler.
*
* @returns {void}
*/
declareProps() {
this.class = "";
}
/**
* This will render the component.
*
* @returns {object}
*/
render() {
return o({ class: this.class || "" }, this.children);
}
}
const oe = (t) => {
const e = new Date(t, 11, 31), s = new Date(t, 0, 1);
return e.getDay() === 4 || // December 31 is a Thursday
s.getDay() === 4;
}, le = (t) => {
const e = new Date(t.valueOf()), s = (e.getDay() + 6) % 7;
e.setDate(e.getDate() - s + 3);
const a = e.getFullYear(), i = new Date(a, 0, 4);
i.setDate(i.getDate() - (i.getDay() + 6) % 7);
const n = Math.ceil((e - i) / 6048e5) + 1;
return n > 52 && !oe(a) ? {
weekNumber: 1,
year: a + 1
} : {
weekNumber: n,
year: a
};
}, re = (t, e, s) => {
if (s === 0) return [];
const a = new Date(t, e, 0).getDate();
return Array.from(
{ length: s },
(i, n) => new Date(t, e - 1, a - s + n + 1)
);
}, ce = (t, e, s) => Array.from({ length: s }, (a, i) => new Date(t, e + 1, i + 1)), T = (t, e) => {
const s = new Date(e, 0, 4), a = (s.getDay() + 6) % 7, i = new Date(s);
i.setDate(s.getDate() - a);
const n = new Date(i);
return n.setDate(i.getDate() + (t - 1) * 7), n;
}, tt = (t, e) => {
const s = new Date(t, e, 1).getDay(), a = new Date(t, e + 1, 0).getDate(), i = [];
let n = [];
for (let l = 1 - s; l <= a; l++) {
const u = new Date(t, e, l);
n.push(l > 0 ? u : null), (n.length === 7 || l === a) && (i.push([...n]), n = []);
}
return i;
}, st = (t, e) => {
const s = new Date(t, e + 1, 0).getDate(), a = [];
let i = [];
for (let n = 1; n <= s; n++)
i.push(new Date(t, e, n)), i.length === 7 && (a.push(i), i = []);
return i.length > 0 && a.push(i), a;
}, de = (t, e, s) => {
const a = /* @__PURE__ */ new Date();
return a.getDate() === t && a.getMonth() === e && a.getFullYear() === s;
}, he = ({ day: t, month: e, year: s, weekNumber: a, selectWeek: i }) => {
const n = de(t, e, s);
return y({
text: t || "",
disabled: !t,
class: `
px-2 py-1 text-center rounded-md
${n ? "bg-accent text-accent-foreground" : ""}
hover:bg-primary hover:text-primary-foreground
`,
click: () => i(a, s)
});
}, ue = (t, e) => {
const s = new Date(t, e, 1).getDay(), a = new Date(t, e + 1, 0).getDate(), i = re(t, e, s), n = Array.from({ length: a }, (r, m) => new Date(t, e, m + 1)), l = (i.length + n.length) % 7, u = l === 0 ? 0 : 7 - l, c = ce(t, e, u), f = [...i, ...n, ...c], g = [];
for (let r = 0; r < f.length; r += 7) {
const m = f.slice(r, r + 7), k = m.find((Y) => Y) || new Date(t, e, 1), { weekNumber: A, year: U } = le(k);
g.push({
weekNumber: A,
year: U,
days: m
});
}
return g;
}, fe = ({ selectWeek: t }) => F("month", (e, s, { data: a }) => {
const { year: i, month: n, currentDate: l } = a, u = ue(i, n);
return o(
{ class: "grid grid-cols-8 gap-1 text-sm px-4 py-2" },
[
// Header row: "Week" label + day-of-week labels
o({ class: "text-xs text-center col-span-1 text-muted-foreground flex items-center" }, "Week"),
o(
{
class: "grid grid-cols-7 col-span-7 text-center text-muted-foreground items-center"
},
["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"].map(
(c) => v({ class: "px-1 py-1", text: c })
)
),
// Render each "week" row
...u.map(
({ weekNumber: c, days: f, year: g }) => o({
class: "grid grid-cols-8 col-span-8 items-center ring-primary rounded-sm px-1",
onSet: ["currentWeek", {
ring: c
}]
}, [
// Left column: ISO week number
o({
class: "font-medium text-center col-span-1 rounded-sm cursor-pointer",
click: () => t(c, g),
// If you have a 'currentWeek' state, you can highlight it with 'onSet'
onSet: ["currentWeek", {
"text-primary-foreground": c,
"bg-primary": c
}],
text: c ? `W${c}` : ""
}),
// The 7 cells for each day in the row
o(
{ class: "grid grid-cols-7 col-span-7 text-center" },
f.map(
(r) => he({
year: (r == null ? void 0 : r.getFullYear()) || null,
month: (r == null ? void 0 : r.getMonth()) || null,
day: (r == null ? void 0 : r.getDate()) || null,
weekNumber: c,
selectWeek: t
})
)
)
])
)
]
);
}), M = ({ label: t, click: e }) => C(
{
class: `
inline-flex items-center justify-center h-7 w-7 bg-transparent p-0
opacity-50 hover:opacity-100 text-muted-foreground absolute
${t === "Previous" ? "left-1" : "right-1"}
focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2
`,
click: e,
"aria-label": `${t} month`,
variant: "icon",
icon: t === "Previous" ? w.chevron.single.left : w.chevron.single.right
}
), ge = ({ next: t, previous: e }) => o({ class: "flex flex-auto min-h-12 text-sm font-medium relative justify-center items-center" }, [
v("[[monthName]] [[year]]"),
M({
label: "Previous",
click: e
}),
M({
label: "Next",
click: t
})
]);
class at extends h {
/**
* This will declare the props for the compiler.
*
* @returns {void}
*/
declareProps() {
this.selectedDate = null, this.selectedWeek = null, this.selectedCallBack = null;
}
/**
* Initializes the calendar data.
*
* @returns {Data}
*/
setData() {
const e = /* @__PURE__ */ new Date(), s = this.selectedWeek || this.calculateCurrentWeek(e), a = T(s, e.getFullYear());
return new L({
monthName: this.getMonthName(a.getMonth()),
year: a.getFullYear(),
month: a.getMonth(),
currentDate: a.getDate(),
currentWeek: s
});
}
/**
* Determines the current selected date.
*
* @param {Date} today
* @returns {Date}
*/
getSelectedDate(e) {
const s = this.selectedDate ? new Date(this.selectedDate) : e;
return new Date(s.getFullYear(), s.getMonth(), s.getDate());
}
/**
* Calculates the ISO week number for a given date.
*
* @param {Date} date
* @returns {number}
*/
calculateCurrentWeek(e) {
const s = new Date(e.valueOf()), a = (e.getDay() + 6) % 7;
s.setDate(s.getDate() - a + 3);
const i = s.valueOf();
return s.setMonth(0, 1), s.getDay() !== 4 && s.setMonth(0, 1 + (4 - s.getDay() + 7) % 7), 1 + Math.ceil((i - s) / 6048e5);
}
/**
* Gets the name of the month.
*
* @param {number} month
* @returns {string}
*/
getMonthName(e) {
return G.monthNames[e];
}
/**
* Updates the calendar to show the previous month.
*
* @returns {void}
*/
goToPreviousMonth() {
const e = this.data;
let { year: s, month: a } = e;
a === 0 ? (a = 11, s--) : a--, this.setDate(a, s);
}
/**
* Updates the calendar to show the next month.
*
* @returns {void}
*/
goToNextMonth() {
const e = this.data;
let { year: s, month: a } = e;
a === 11 ? (a = 0, s++) : a++, this.setDate(a, s);
}
/**
* Sets the selected date.
*
* @param {number} month
* @param {number} year
* @param {number|null} [date=null]
* @returns {void}
*/
setDate(e, s, a) {
this.data.set({
year: s,
month: e,
monthName: this.getMonthName(e)
}), a && (this.data.currentDate = a);
}
/**
* Handles week selection.
*
* @param {number} weekNumber
* @returns {void}
*/
selectWeek(e, s) {
this.data.currentWeek = e;
const a = T(e, s);
this.setDate(a.getMonth(), a.getFullYear(), a.getDate()), typeof this.selectedCallBack == "function" && this.selectedCallBack(e);
}
/**
* Renders the WeekCalendar component.
*
* @returns {object}
*/
render() {
return o({ class: "week-calendar-container border rounded-md bg-background p-3" }, [
ge({
next: () => this.goToNextMonth(),
previous: () => this.goToPreviousMonth()
}),
fe({
selectWeek: (e, s) => this.selectWeek(e, s)
})
]);
}
}
const me = (t, e) => {
const s = t.toggleAllSelectedRows();
e.state.checked = !s;
}, pe = (t) => R({ class: `cursor-pointer py-3 px-4 text-base w-10 ${t.class || ""}` }, [
E((e) => new te({ class: "mr-2", onChange: (s, a) => me(e, a) }))
]), we = ({ align: t, sortable: e, key: s, label: a, sort: i, class: n }) => {
const l = t || "justify-start";
return R({
class: `cursor-pointer py-3 px-4 text-base ${n || ""}`,
click: e && (() => i(s))
}, [
o({ class: `flex flex-auto w-full items-center ${l}` }, [
v(a),
e && H({ class: "ml-2", html: w.arrows.upDown })
])
]);
}, $ = (t) => Q([
X({
class: "text-muted-foreground border-b",
map: [
t.headers,
(e) => e.label === "checkbox" ? pe({ toggle: t.toggle }) : we({
align: e.align,
sortable: e.sortable,
key: e.key,
label: e.label,
sort: t.sort
})
]
})
]), be = ({ key: t, rows: e, selectRow: s, rowItem: a }) => new _({
cache: "list",
key: t,
items: e,
rowItem: (i) => a(i, s),
class: "divide-y divide-border"
});
class ke extends h {
/**
* Initializes component data.
*
* @returns {Data}
*/
setData() {
return new L({
selectedRows: [],
selected: !1
});
}
/**
* This will toggle all selected rows.
*
* @returns {boolean}
*/
toggleAllSelectedRows() {
const e = this.list.getRows(), s = this.data.selectedRows.length === e.length, a = s ? [] : e;
return this.data.selectedRows = a, this.updateSelected(), this.updateTable(!s), s;
}
/**
* This will update the selected state.
*
* @returns {void}
*/
updateSelected() {
const e = this.data.get("selectedRows");
this.data.selected = e.length > 0;
}
/**
* This will get the selected rows.
*
* @returns {Array<object>}
*/
getSelectedRows() {
return this.data.get("selectedRows");
}
/**
* This will update the table rows.
*
* @protected
* @param {boolean} selected
* @returns {void}
*/
updateTable(e) {
const s = this.list.getRows();
s.forEach((a) => a.selected = e), this.list.setRows(s);
}
/**
* Handles row selection.
*
* @param {object} row
*/
selectRow(e) {
const s = e.selected ?? !1;
e.selected = !s;
const a = this.data.get("selectedRows"), i = e.selected ? [...a, e] : a.filter((n) => n !== e);
this.data.selectedRows = i, this.updateSelected();
}
/**
* Renders the DataTable component.
*
* @returns {object}
*/
render() {
const e = this.rows, s = this.border !== !1 ? "border" : "";
return o({ class: "w-full" }, [
o({ class: `w-full rounded-md ${s} overflow-x-auto` }, [
W({ class: "w-full" }, [
// @ts-ignore
this.headers && $({ headers: this.headers, sort: (a) => this.sortRows(a) }),
// @ts-ignore
this.customHeader ?? null,
be({
// @ts-ignore
key: this.key,
rows: e,
// @ts-ignore
selectRow: this.selectRow.bind(this),
// @ts-ignore
rowItem: this.rowItem
})
])
])
]);
}
/**
* This will remove items from the list.
*
* @public
* @param {array} items
* @returns {void}
*/
remove(e) {
this.list.remove(e);
}
/**
* This will set the items in the list.
*
* @public
* @param {array} rows
* @returns {void}
*/
setRows(e) {
this.list.setRows(e);
}
/**
* This will append items to the list.
*
* @public
* @param {array|object} items
* @returns {void}
*/
append(e) {
this.list.append(e);
}
/**
* This will mingle the new items with the old items.
*
* @public
* @param {Array<Object>} newItems
* @param {boolean} withDelete
* @returns {void}
*/
mingle(e, s = !1) {
this.list.mingle(e, s);
}
/**
* This will prepend items to the list.
*
* @public
* @param {array|object} items
* @returns {void}
*/
prepend(e) {
this.list.prepend(e);
}
/**
* This will remove the selected rows.
*
* @returns {void}
*/
beforeDestroy() {
this.data.selectedRows = [];
}
}
const xe = (t) => new J({
cache: "list",
scrollContainer: t.scrollContainer,
loadMoreItems: t.loadMoreItems,
offset: t.offset,
limit: t.limit,
key: t.key,
tableData: t.tableData,
items: t.items,
rowItem: (e) => t.rowItem(e, t.selectRow),
class: "divide-y divide-border"
});
class ye extends ke {
/**
* Renders the DataTable component.
*
* @returns {object}
*/
render() {
const e = this.rows, s = this.border !== !1 ? "border" : "";
return o({ class: "w-full" }, [
o({ class: `w-full rounded-md ${s} overflow-x-auto` }, [
W({ class: "w-full" }, [
// @ts-ignore
this.headers && $({ headers: this.headers, sort: (a) => this.sortRows(a) }),
// @ts-ignore
this.customHeader ?? null,
xe({
// @ts-ignore
scrollContainer: this.scrollContainer,
// @ts-ignore
loadMoreItems: this.loadMoreItems,
// @ts-ignore
offset: this.offset,
// @ts-ignore
limit: this.limit,
// @ts-ignore
class: this.class,
// @ts-ignore
tableData: this.tableData,
// @ts-ignore
key: this.key,
items: e,
// @ts-ignore
selectRow: this.selectRow.bind(this),
// @ts-ignore
rowItem: this.rowItem
})
])
])
]);
}
/**
* Refreshes the list.
*
* @returns {void}
*/
refresh() {
this.list.refresh();
}
}
const it = d((t) => new ye(
{
cache: t.cache ?? "list",
tableData: t.data,
scrollContainer: t.scrollContainer,
loadMoreItems: t.loadMoreItems,
offset: t.offset,
limit: t.limit,
class: t.class,
key: t.key,
rows: t.rows,
rowItem: t.rowItem,
headers: t.headers,
customHeader: t.customHeader,
border: t.border
}
)), ve = d(({ name: t, email: e }) => o({ class: "min-w-0 flex-auto" }, [
p({ class: "text-base font-semibold leading-6 m-0" }, t),
p({ class: "truncate text-sm leading-5 text-muted-foreground m-0" }, e)
])), De = () => o({ class: "flex items-center gap-x-1.5" }, [
o({ class: "flex-none rounded-full bg-emerald-500/20 p-1" }, [
o({ class: "h-1.5 w-1.5 rounded-full bg-emerald-500" })
]),
p({ class: "text-xs leading-5 text-gray-500" }, "Online")
]), Se = (t) => p({ class: "text-xs leading-5 text-muted-foreground" }, [
v("Last seen "),
q({ datetime: t }, "3h ago")
]), Le = (t, e) => t === "online" ? De() : Se(e), Ce = d(({ role: t, lastSeen: e, status: s }) => o({ class: "hidden shrink-0 sm:flex sm:flex-col sm:items-end" }, [
p({ class: "text-sm leading-6 m-0" }, t),
Le(s, e)
])), Ie = (t) => t.split(" ").map((s) => s[0]).join(""), Be = d((t) => D({ class: "fadeIn flex justify-between gap-x-6 py-4 px-4 rounded-md hover:bg-muted/50" }, [
o({ class: "flex min-w-0 gap-x-4" }, [
ie({ src: t.image, alt: t.name, fallbackText: Ie(t.name) }),
ve({ name: t.name, email: t.email })
]),
Ce({
role: t.role,
lastSeen: t.lastSeen,
status: t.status
})
])), nt = d((t) => new Z({
cache: "list",
key: "name",
items: t.users,
role: "list",
class: "divide-y divide-border",
rowItem: Be
})), Te = (t, e) => e.includes(t), Me = (t, e, s) => t.exact ? s === e : Te(e, s), Re = ({ text: t, href: e, exact: s, hidden: a }) => new O({
text: t,
href: e,
exact: s,
dataSet: ["selected", ["state", !0, "active"]],
class: `${a ? "hidden" : "inline-flex"} items-center justify-center whitespace-nowrap px-3 py-1.5 text-sm font-medium transition-all rounded-md focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-ring focus-visible:ring-offset-background hover:bg-primary hover:text-primary-foreground disabled:opacity-50 disabled:pointer-events-none data-[state=active]:bg-primary data-[state=active]:text-primary-foreground data-[state=active]:shadow-sm`
});
class ot extends h {
/**
* This will declare the props for the compiler.
*
* @returns {void}
*/
declareProps() {
this.options = [], this.class = "";
}
/**
* This will configure the links.
*/
beforeSetup() {
this.links = [];
}
/**
* This will render the component.
*
* @returns {object}
*/
render() {
return S(
{ class: `flex items-center justify-center p-2 text-muted-foreground rounded-md ${this.class || ""}` },
[
b({
class: "flex space-x-4",
map: [this.options, (e) => this.addLink(e)],
watch: {
value: ["[[path]]", x.data],
callBack: this.updateLinks.bind(this)
}
})
]
);
}
/**
* This will update the links.
*
* @returns {void}
*/
afterSetup() {
const e = x.data.path;
this.updateLinks(e);
}
/**
* This will update the links based on the current path.
*
* @param {string} path
* @returns {void}
*/
updateLinks(e) {
let s = !1;
this.deactivateAllLinks();
for (const a of this.links) {
if (!a.rendered)
continue;
Me(a, a.getLinkPath(), e) ? (this.updateLink(a, !0), s = !0) : this.updateLink(a, !1);
}
!s && this.links[0] && this.updateLink(this.links[0], !0);
}
/**
* This will deactivate all links.
*
* @returns {void}
*/
deactivateAllLinks() {
for (const e of this.links)
this.updateLink(e, !1);
}
/**
* This will update the link's active state.
*
* @param {object} link
* @param {boolean} selected
* @returns {void}
*/
updateLink(e, s) {
e.update(s);
}
/**
* This will add a link to the navigation.
*
* @param {object} option
* @returns {object}
*/
addLink({ label: e, href: s, exact: a, hidden: i }) {
const n = Re({ text: e, href: s, exact: a, hidden: i });
return this.links.push(n), n;
}
/**
* This will clear the links.
*
* @returns {void}
*/
beforeDestroy() {
this.links = [];
}
}
const lt = d((t) => {
const e = t.margin || "m-4 ml-0";
return o({ class: `flex-none ${e}` }, [
C({
variant: "icon",
class: "back-button",
click: () => {
if (window.history.length > 2) {
window.history.back();
return;
}
t.backUrl && app.navigate(t.backUrl);
}
}, [
N(w.arrows.left)
])
]);
});
class j extends h {
/**
* This will declare the props for the compiler.
*
* @returns {void}
*/
declareProps() {
this.class = "";
}
/**
* This will render the component.
*
* @returns {object}
*/
render() {
return o(
{
class: this.getClassName(),
onSet: ["loading", {
loading: !0
}]
},
[
this.addBody()
]
);
}
/**
* This will get the overlay className.
*
* @returns {string}
*/
getClassName() {
return "overlay fixed top-[0px] left-0 bottom-0 right-0 flex-col bg-background z-20 lg:z-10 flex flex-auto lg:left-[64px] lg:top-0 overflow-y-auto will-change-contents " + (this.class || "");
}
/**
* This will setup and render the component.
*
* @param {object} container
* @returns {void}
*/
setContainer(e) {
this.container = app.root;
}
/**
* This will setup the overlay states.
*
* @returns {object}
*/
setupStates() {
return {
loading: !1
};
}
/**
* This will set the loading state.= to true.
*
* @returns {void}
*/
addLoading() {
this.state.loading = !0;
}
/**
* This will set the loading state to false.
*
* @returns {void}
*/
removeLoading() {
this.state.loading = !1;
}
/**
* This will add the body of the overlay.
*
* @returns {object}
*/
addBody() {
return o({ class: "body fadeIn flex flex-auto flex-col" }, this.getContents());
}
/**
* This will get the body contents.
*
* @returns {array|null}
*/
getContents() {
return this.children;
}
}
z.addType("dockableOverlay", (t) => {
if (!t)
return;
const e = t.component;
e && e.rendered === !0 && e.state.docked === !1 && e.destroy();
});
class rt extends j {
/**
* This will stop presistence.
*
* @returns {void}
*/
onCreated() {
this.dockSize = this.maxSize || 1024;
}
/**
* This will render the component.
*
* @returns {object}
*/
render() {
const e = this.container;
return o(
{
onState: [
["loading", {
loading: !0
}],
["docked", (s, a) => {
s ? (a.className = this.getDockedClassName(), e.appendChild(a), document.documentElement.style.overflowY = "auto") : (a.className = this.getClassName(), app.root.appendChild(a), document.documentElement.style.overflowY = "hidden");
}]
]
},
[
this.addBody()
]
);
}
/**
* This will get the docked className.
*
* @returns {string}
*/
getDockedClassName() {
return "flex flex-auto flex-col bg-background flex will-change-contents " + (this.class || "");
}
/**
* This will setup and render the component.
*
* @param {object} container
* @returns {void}
*/
setup(e) {
this.container = e, this.initialize();
}
/**
* This will setup the overlay states.
*
* @returns {object}
*/
setupStates() {
return {
loading: !1,
docked: this.canDock()
};
}
/**
* This will check the dock size.
*
* @returns {void}
*/
afterSetup() {
z.add(
this.container,
"dockableOverlay",
{
component: this
}
), this.onResize();
}
/**
* This will setup the overlay events.
*
* @returns {Array<object>}
*/
setupEvents() {
return [
["resize", window, () => this.onResize()]
];
}
/**
* This will check if the overlay can dock.
*
* @returns {boolean}
*/
canDock() {
return window.innerWidth >= this.dockSize;
}
/**
* This will handle the overlay resize.
*
* @returns {void}
*/
onResize() {
this.state.docked = this.canDock();
}
/**
* This will resume scrolling when the overlay is being removed.
*
* @returns {void}
*/
beforeDestroy() {
document.documentElement.style.overflowY = "auto";
}
}
class ct extends j {
/**
* This will get the overlay type.
*
* @returns {string}
*/
getClassName() {
return "overlay relative inline top-[0px] left-0 bottom-0 right-0 flex-col bg-background z-20 lg:left-[64px] lg:top-0 will-change-contents " + (this.class || "");
}
/**
* This will setup and render the component.
*
* @param {object} container
* @returns {void}
*/
setup(e) {
this.container = e, this.initialize();
}
}
const We = d(({ index: t, click: e, state: s }, a) => D({
class: "p-2 cursor-pointer hover:bg-muted/50",
onState: [
[s, "selectedIndex", {
"bg-accent": t,
"text-white": t
}]
],
click: () => e(t)
}, a)), Pe = d(({ selectOption: t, state: e }) => b({
class: "border rounded-md list-none m-0 p-0 max-h-[400px] overflow-y-auto",
for: ["filteredOptions", (s, a) => We({ index: a, click: t, state: e }, s.label)]
})), Oe = d((t) => o({ class: "relative flex items-center" }, [
se({
cache: "input",
placeholder: t.placeholder ?? "Search...",
bind: [t.state, "searchQuery"],
keyup: (e, s) => {
s.state.open = !0, typeof t.filterOptions == "function" && t.filterOptions(), s.dropdown.updatePosition();
},
pointerup: (e, s) => s.toggleDropdown(),
keydown: (e) => typeof t.handleKeyDown == "function" && t.handleKeyDown(e)
}),
t.icon && o({ class: "absolute right-0 mr-2" }, [
N(t.icon)
])
])), ze = (t) => o({
class: "relative flex fle-auto flex-col",
onState: ["open", (e, s, a) => {
if (e)
return new ne({
cache: "dropdown",
parent: a,
button: a.input,
size: "xl"
}, [
Pe(t)
]);
}]
}), dt = V(
{
/**
* This will set up the data object.
*
* @returns {object} - The data object.
*/
setData() {
const t = this.options || [];
return new L({
options: t,
filteredOptions: t
});
},
/**
* This will set up the state object.
*
* @returns {object} - The state object.
*/
state() {
return {
searchQuery: "",
selectedIndex: -1,
open: !1
};
},
/**
* This will set the selected index by query.
*
* @returns {void}
*/
setSelectedIndexByQuery() {
const t = this.data.filteredOptions;
let { searchQuery: e } = this.state;
e = e.toLowerCase();
const s = t.findIndex((a) => a.label.toLowerCase() === e);
s >= 0 && (this.state.selectedIndex = s);
},
/**
* This will filter the options.
*
* @returns {void}
*/
filterOptions() {
const t = this.state.searchQuery.toLowerCase();
if (t === "" || t.length === 0) {
this.data.filteredOptions = this.data.options;
return;
}
const e = this.data.get("options");
this.data.filteredOptions = e.filter(
(s) => s.label.toLowerCase().includes(t)
);
},
/**
* This will get the selected value.
*
* @returns {object}
*/
getValue() {
const { selectedIndex: t } = this.state;
return t < 0 ? null : this.data.get(`filteredOptions[${t}]`);
},
/**
* This will select an option.
*
* @param {number} index - The index of the option.
* @returns {void}
*/
selectOption(t) {
this.state.selectedIndex = t;
const e = this.data.get(`filteredOptions[${t}]`);
this.state.searchQuery = e.label, this.state.open = !1, typeof this.onSelect == "function" && this.onSelect(e);
},
/**
* Toggles the dropdown open state.
*/
toggleDropdown() {
this.state.toggle("open"), this.state.open && this.setSelectedIndexByQuery();
},
/**
* This will handle key down events.
*
* @param {object} event - The event object.
* @returns {void}
*/
handleKeyDown(t) {
const e = this.data.filteredOptions, { selectedIndex: s } = this.state;
t.key === "ArrowDown" ? (t.preventDefault(), this.state.selectedIndex = Math.min(s + 1, e.length - 1)) : t.key === "ArrowUp" ? (t.preventDefault(), this.state.selectedIndex = Math.max(s - 1, 0)) : t.key === "Enter" && s >= 0 && (t.preventDefault(), this.selectOption(s));
},
/**
* This will render the component.
*
* @returns {object} - The rendered component.
*/
render() {
return o({ class: "relative w-full max-w-md" }, [
Oe({
// @ts-ignore
state: this.state,
// @ts-ignore
icon: this.icon,
// @ts-ignore
placeholder: this.placeholder,
// @ts-ignore
filterOptions: this.filterOptions.bind(this),
// @ts-ignore
handleKeyDown: this.handleKeyDown.bind(this)
}),
ze({
// @ts-ignore
state: this.state,
// @ts-ignore
setSelected: this.setSelectedIndexByQuery.bind(this),
// @ts-ignore
selectOption: this.selectOption.bind(this)
})
]);
}
}
), Ne = (t) => D(
{
class: "inline-flex flex-auto items-center justify-center whitespace-nowrap rounded-sm text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-primary data-[state=active]:text-primary-foreground data-[state=active]:shadow-sm",
dataSet: ["selected", ["state", t.value, "active"]]
},
[
y({
class: "flex flex-auto justify-center items-center px-3 py-1.5",
onSet: ["selected", { selected: t.value }],
click: (e) => t.callBack(t.value)
}, t.label)
]
), $e = (t, e) => (t.callBack = e, Ne(t)), je = (t) => S({ class: `tab items-center justify-center rounded-md bg-muted p-1 text-muted-foreground ${t.class}` }, [
b({ class: "flex flex-auto flex-row", map: [t.options, (e) => $e(e, t.callBack)] })
]);
class ht extends h {
/**
* This will declare the props for the compiler.
*
* @returns {void}
*/
declareProps() {
this.options = [], this.class = "", this.callBack = null;
}
/**
* This will render the component.
*
* @returns {object}
*/
render() {
const e = this.select.bind(this);
return o({ class: "" }, [
je({
class: this.class,
options: this.options,
callBack: e
}),
P({
class: "tab-content",
onState: ["selected", this.updateContent.bind(this)]
})
]);
}
/**
* This will get the first value.
*
* @returns {*}
*/
getFirstValue() {
var e;
return (e = this.options[0]) == null ? void 0 : e.value;
}
/**
* This will update the component.
*
* @returns {void}
*/
update() {
const e = this.state.get("selected");
this.select(null), this.select(e);
}
/**
* This will select a value.
*
* @param {*} value
* @returns {void}
*/
select(e) {
this.state.selected = e;
}
/**
* This will update the content.
*
* @param {*} value
* @returns {object}
*/
updateContent(e) {
const s = this.options;
if (!s || s.length < 1)
return;
const a = s[0];
for (const i of s)
if (i.value === e)
return i.layout;
return a.layout;
}
/**
* This will setup the states.
*
* @returns {object}
*/
setupStates() {
const e = this.callBack, s = typeof e;
return {
selected: {
state: this.getFirstValue(),
callBack(a) {
s === "function" && e(a);
}
}
};
}
}
const Ae = (t) => D(
{
class: "inline-flex flex-auto items-center justify-center whitespace-nowrap rounded-sm text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-primary data-[state=active]:text-primary-foreground data-[state=active]:shadow-sm",
dataSet: ["selected", ["state", t.value, "active"]]
},
[
y({
class: "flex flex-auto justify-center items-center px-3 py-1.5 disabled:opacity-50 disabled:cursor-not-allowed",
onSet: ["selected", { selected: t.value }],
click: (e) => t.callBack(t.value),
disabled: t.disabled
}, t.label)
]
), Ue = (t, e) => (t.callBack = e, Ae(t)), Ye = (t) => S({ class: `tab items-center justify-center rounded-md bg-muted p-1 text-muted-foreground ${t.class}` }, [
b({ class: "flex flex-auto flex-row", map: [t.options, (e) => Ue(e, t.callBack)] })
]);
class ut extends h {
/**
* This will declare the props for the compiler.
*
* @returns {void}
*/
declareProps() {
this.options = [], this.class = "", this.onSelect = null;
}
/**
* This will render the component.
*
* @returns {object}
*/
render() {
const e = this.select.bind(this);
return Ye({
class: this.class,
options: this.options,
callBack: e
});
}
/**
* This will select a value.
*
* @param {*} value
* @returns {void}
*/
select(e) {
this.state.selected = e, typeof this.onSelect == "function" && this.onSelect(e, this.parent);
}
/**
* This will setup the states.
*
* @returns {object}
*/
setupStates() {
var e;
return {
selected: ((e = this.options[0]) == null ? void 0 : e.value) || null
};
}
}
const Fe = (t, e) => new RegExp(`${t}($|/|\\.).*`).test(e), Ee = (t, e) => {
const s = t.getLinkPath();
return t.exact ? e === s : Fe(s, e);
}, He = ({ text: t, href: e, exact: s }) => new O({
text: t,
href: e,
exact: s,
dataSet: ["selected", ["state", !0, "active"]],
class: "inline-flex flex-auto items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-primary data-[state=active]:text-primary-foreground data-[state=active]:shadow-sm"
});
class Qe extends h {
/**
* This will declare the props for the compiler.
*
* @returns {void}
*/
declareProps() {
this.options = [], this.class = "", this.onSelect = null;
}
/**
* This will configure the links.
*/
beforeSetup() {
this.links = [];
}
/**
* This will render the component.
*
* @returns {object}
*/
render() {
return S({ class: `tab items-center justify-center rounded-md bg-muted p-1 text-muted-foreground ${this.class}` }, [
b({
class: "flex flex-auto flex-row",
map: [this.options, (e) => this.addLink(e)],
watch: {
value: ["[[path]]", x.data],
callBack: this.updateLinks.bind(this)
}
})
]);
}
/**
* This will update the links.
*
* @returns {void}
*/
afterSetup() {
const e = x.data.path;
this.updateLinks(e);
}
/**
* This will update the links.
*
* @param {string} value
* @returns {void}
*/
updateLinks(e) {
let s = !1, a = this.links[0];
this.deactivateAllLinks();
for (const i of this.links)
if (i.rendered !== !1 && (s = Ee(i, e), s === !0)) {
this.updateLink(i, !0);
break;
}
s !== !0 && a && this.updateLink(a, !0);
}
/**
* This will deactivate all links.
*
* @returns {void}
*/
deactivateAllLinks() {
for (const e of this.links)
this.updateLink(e, !1);
}
/**
* This will update the link.
*
* @param {object} link
* @param {boolean} selected
* @returns {void}
*/
updateLink(e, s) {
e.update(s);
}
/**
* This will add a link.
*
* @param {object} option
* @returns {object}
*/
addLink({ label: e, href: s, exact: a }) {
const i = He({ text: e, href: s, exact: a });
return this.links.push(i), i;
}
/**
* This will remove all the links.
*
* @returns {void}
*/
beforeDestroy() {
this.links = [];
}
}
class ft extends h {
/**
* This will declare the props for the compiler.
*
* @returns {void}
*/
declareProps() {
this.options = [], this.class = "";
}
/**
* This will render the component.
*
* @returns {object}
*/
render() {
return o({ class: "tab-panel" }, [
new Qe({
class: this.class,
options: this.options
}),
P({
class: "tab-content",
switch: this.addGroup()
})
]);
}
/**
* This will add the group.
*
* @returns {array}
*/
addGroup() {
let e;
const s = [], a = this.options;
for (let i = 0, n = a.length; i < n; i++)
e = a[i], s.push(
{
uri: e.uri || e.href,
component: e.component,
title: e.title || null,
persist: !0
}
);
return s;
}
}
class Xe extends h {
/**
* Runs before rendering, sets up defaults, a timer for drawing,
* and basic canvas properties.
*
* @returns {void}
*/
onCreated() {
this.lineWidth = this.lineWidth || 3, this.lineColor = this.lineColor || "#000000", this.canvas = null, this.ctx = null, this.status = "stopped";
const e = 1e3 / 60;
this.timer = new ee(e, this.draw.bind(this)), this.width = 0, this.height = 0, this.signed = !1, this.mouse = { x: 0, y: 0, status: "up" }, this.margin = this.margin || { x: 40, y: 60 }, this.targetSize = this.targetSize || { width: 740, height: 345 }, this.baseLineWidth = this.baseLineWidth || 2, this.baseStrokeColor = this.baseStrokeColor || "#000000";
}
/**
* Renders a <canvas> element.
*
* @returns {object} Layout definition for the canvas.
*/
render() {
return K({
style: "touch-action: none; -webkit-user-select: none; -webkit-touch-callout: none;"
});
}
/**
* Called before the component is destroyed. Stops the timer
* to prevent memory leaks or ongoing animation.
*
* @returns {void}
*/
beforeDestroy() {
this.stopTimer();
}
/**
* Called after component setup. Initializes canvas context,
* schedules a resize, and draws the initial content.
*
* @returns {void}
*/
afterSetup() {
this.canvas = this.panel, this.ctx = this.canvas.getContext("2d"), window.setTimeout(() => {
this.resize(), this.draw();
}, 1);
}
/**
* Defines the DOM events to set up for this canvas component.
*
* @returns {Array} An array of [eventName, element, callback] definitions.
*/
setupEvents() {
const e = this.panel, s = this.pointerPosition.bind(this), a = this.pointerUp.bind(this), i = this.pointerDown.bind(this), n = this.resize.bind(this), l = { passive: !1 };
return [
["pointermove", e, s, l],
["pointerup", e, a],
["pointerdown", e, i, l],
["pointerout", e, a],
["resize", window, n]
];
}
/**
* Calculates and saves the current pointer position in canvas coordinates.
*
* @param {Event} e The event object (mouse or touch).
* @returns {void}
*/
getEventPosition(e) {
let s, a;
const i = this.canvas, n = i.width / parseInt(i.style.width), l = i.getBoundingClientRect();
if (e.touches && e.touches.length) {
const f = e.touches[0];
s = f.clientX, a = f.clientY;
} else
s = e.x || e.clientX, a = e.y || e.clientY;
const u = parseInt((s - l.left) * n), c = parseInt((a - l.top) * n);
this.mouse.x = u, this.mouse.y = c;
}
/**
* Called when the pointer goes down on the canvas.
* Begins a new path, sets the mouse status, and starts the timer.
*
* @param {Event} e The event object.
* @returns {void}
*/
pointerDown(e) {
e.preventDefault(), e.stopPropagation(), this.getEventPosition(e);
const { ctx: s, mouse: a } = this;
s.beginPath(), s.moveTo(a.x, a.y), a.status = "down", this.startTimer();
}
/**
* Called when the pointer goes up or leaves the canvas area.
* Closes the path and stops the drawing timer.
*
* @param {Event} e The event object.
* @returns {void}
*/
pointerUp(e) {
e.preventDefault(), e.stopPropagation(), this.ctx.closePath(), this.mouse.status = "up", this.stopTimer();
}
/**
* Tracks pointer movement, updates position in real time.
*
* @param {Event} e The event object.
* @returns {void}
*/
pointerPosition(e) {
this.getEventPosition(e), this.mouse.status === "down" && (e.preventDefault(), e.stopPropagation());
}
/**
* Resizes the canvas, preserves existing drawing by converting
* it to a data URL, then re-drawing.
*
* @returns {void}
*/
resize() {
const { canvas: e, ctx: s } = this, a = e.toDataURL();
if (this.scale(), this.setupBackground(s), a !== "data:,") {
const i = new window.Image();
I.on("load", i, function n() {
s.drawImage(i, 0, 0), I.off("load", i, n);
}), i.src = a;
}
this.draw();
}
/**
* Returns a JPEG data URL of the current canvas content.
*
* @returns {string} The signature image as a data URL.
*/
getImage() {
return this.canvas.toDataURL("image/jpeg", 0.7);
}
/**
* (Deprecated approach) Resize the canvas to the container size
* without scaling logic.
*
* @returns {void}
*/
noScaleResize() {
const e = B.getSize(container);
this.width = canvas.width = e.width, this.height = canvas.height = e.height;
}
/**
* Scales the canvas to fit within its container, preserving aspect ratio
* relative to this.targetSize.
*
* @returns {void}
*/
scale() {
const e = this.canvas, s = this.container, a = B.getSize(s), i = this.targetSize, n = i.width, l = i.height;
let u = n + "px", c = l + "px";
if (this.width = e.width = n, this.height = e.height = l, a.width !== 0 && a.height !== 0) {
const f = a.width, g = a.height, r = f / n, m = g / l, k = Math.min(r, m);
u = n * k + "px", c = l * k + "px";
}
e.style.width = u, e.style.height = c;
}
/**
* Main drawing loop. If the mouse is down, adds a line
* from the last point to the current pointer position.
*
* @returns {void}
*/
draw() {
this.mouse.status === "down" && this.addLine(this.ctx, this.mouse.x, this.mouse.y, this.lineColor);
}
/**
* Draws the baseline at the bottom of the canvas.
*
* @param {CanvasRenderingContext2D} ctx The canvas 2D context.
* @returns {void}
*/
drawBottomLine(e) {
const s = this.canvas;
e.globalAlpha = 1, e.shadowBlur = 0;
const a = this.margin.x, i = this.height - this.margin.y;
e.beginPath(), e.moveTo(a, i), e.lineTo(s.width - this.margin.x, i), e.lineWidth = this.baseLineWidth, e.strokeStyle = this.baseStrokeColor, e.stroke(), e.closePath();
}
/**
* Adds a line to the current path, updating the 'signed' status.
*
* @param {CanvasRenderingContext2D} ctx The canvas context.
* @param {number} px The x-coordinate.
* @param {number} py The y-coordinate.
* @param {string} color The stroke color.
* @returns {void}
*/
addLine(e, s, a, i) {
this.signed || (this.signed = !0);
const n = Math.round(s), l = Math.round(a);
e.lineWidth = this.lineWidth, e.strokeStyle = i, e.lineTo(n, l), e.stroke();
}
/**
* Clears the canvas, sets signed to false, and re-initializes
* the background for a fresh signature.
*
* @returns {void}
*/
reset() {
this.signed = !1;
const { ctx: e } = this;
e.clearRect(0, 0, this.width, this.height), this.setupBackground(e);
}
/**
* Fills the canvas background with white and draws the baseline.
*
* @param {CanvasRenderingContext2D} ctx The canvas context.
* @returns {void}
*/
setupBackground(e) {
e.fillStyle = "transparent", e.fillRect(0, 0, this.width, this.height), this.drawBottomLine(e);
}
/**
* Starts the drawing timer so new lines can be added as pointer moves.
*
* @returns {void}
*/
startTimer() {
this.stopTimer(), this.draw(), this.timer.start(), this.status = "started";
}
/**
* Stops the drawing timer.
*
* @returns {void}
*/
stopTimer() {
this.timer.stop(), this.status = "stopped";
}
}
class gt extends h {
/**
* Sets up default properties for the signature panel.
*
* @returns {void}
*/
declareProps() {
this.data = null, this.lineColor = null, this.lineWidth = null, this.baseLineWidth = null, this.baseStrokeColor = null, this.margin = null, this.targetSize = null, this.callBackData = null, this.pointerUp = null, this.path = null, this.canvasLayer = null;
}
/**
* Renders the main layout for the signature panel,
* including a hidden input and a reset button.
*
* @returns {object} The layout object for the component.
*/
render() {
return o({ class: "signature-panel relative flex flex-auto overflow-hidden select-none" }, [
ae({
cache: "hiddenInput",
required: !0,
bind: this.path + ".data"
}),
o({ class: "absolute top-2 right-2" }, [
C({
variant: "icon",
icon: w.circleX,
click: this.reset.bind(this)
})
]),
new Xe({
cache: "canvasLayer",
margin: this.margin,
targetSize: this.targetSize,
lineColor: this.lineColor,
lineWidth: this.lineWidth,
baseLineWidth: this.baseLineWidth,
baseStrokeColor: this.baseStrokeColor,
pointerUpCallBack: this.pointerUp,
callBackData: this.callBackData
})
]);
}
/**
* Called after component setup. Resizes the signature canvas once
* everything is ready.
*
* @returns {void}
*/
afterSetup() {
this.canvasLayer.resize();
}
/**
* Gets the signature image from the canvas layer, as a data URL.
*
* @returns {string} The signature image data URL.
*/
getImage() {
return this.canvasLayer.getImage();
}
/**
* Checks if the user has drawn anything on the signature canvas.
*
* @returns {boolean} True if the canvas has been signed, otherwise false.
*/
isSigned() {
return this.canvasLayer ? this.canvasLayer.signed : !1;
}
/**
* Resets the signature canvas to a blank state.
*
* @param {Event} [e] The event object (if called by a click event).
* @returns {void}
*/
reset(e) {
if (this.canvasLayer)
return this.canvasLayer.reset();
}
}
export {
lt as B,
pe as C,
be as D,
we as H,
ct as I,
ot as N,
j as O,
et as P,
it as S,
$ as T,
Be as U,
at as W,
ce as a,
T as b,
le as c,
tt as d,
st as e,
he as f,
re as g,
fe as h,
ge as i,
ke as j,
nt as k,
rt as l,
dt as m,
ht as n,
ut as o,
Qe as p,
ft as q,
gt as r
};