@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,640 lines (1,639 loc) • 45.8 kB
JavaScript
import { Div as n, H5 as Q, P as m, I as p, Li as V, Span as a, Ul as q, Button as f, OnState as A, Label as H, H2 as v, Form as X, Header as D, Footer as L, A as Y, H3 as Z, Checkbox as ee, Input as x, Img as te, Nav as se, UseParent as _, OnStateOpen as P, Time as oe, Dialog as ne } from "@base-framework/atoms";
import { Atom as c, Component as w, Html as M, Dom as le, base as re, Data as I, Builder as W, Jot as C, Events as $, DateTime as F } from "@base-framework/base";
import { P as k, b as ie, R as ae } from "./range-calendar-UXMh98a5.js";
import { C as ce, F as ue, a as y } from "./veil-B1pwIy-D.js";
import { B as h, I as g } from "./buttons-CHEs54Wl.js";
import { Icons as d } from "./icons.es.js";
import { Timer as de, List as he, DynamicTime as fe } from "@base-framework/organisms";
import { F as N } from "./format-DnofNaaz.js";
const z = {
info: {
borderColor: "border-blue-500",
bgColor: "bg-muted/10",
iconColor: "text-blue-500"
},
warning: {
bgColor: "bg-muted/10",
borderColor: "border-warning",
iconColor: "text-warning"
},
destructive: {
bgColor: "bg-muted/10",
borderColor: "border-destructive",
iconColor: "text-red-500"
},
success: {
bgColor: "bg-muted/10",
borderColor: "border-emerald-500",
iconColor: "text-emerald-500"
},
default: {
borderColor: "border",
bgColor: "bg-muted/10",
iconColor: "text-muted-foreground"
}
}, me = (e, t) => n({ class: `flex items-center justify-center h-6 w-6 mr-3 ${t}` }, [
p({ html: e })
]), pe = (e) => Q({ class: "font-semibold" }, e), ge = (e) => m({ class: "text-sm text-muted-foreground" }, e), kt = c(({ title: e, description: t, icon: s, type: o = "default" }) => {
const { borderColor: l, bgColor: r, iconColor: i } = z[o] || z.default;
return n({ class: `flex items-start p-4 border rounded-lg ${r} ${l}` }, [
// Icon and content
s && me(s, i),
n({ class: "flex flex-col" }, [
pe(e),
ge(t)
])
]);
});
class St extends w {
/**
* This will declare the props for the compiler.
*
* @returns {void}
*/
declareProps() {
this.removingClass = "";
}
/**
* This will remove the component from the DOM after a delay.
*
* @returns {void}
*/
remove() {
this.prepareDestroy(), this.removeContext();
const t = this.panel, s = this.removingClass;
if (!s) {
M.removeElement(t);
return;
}
le.addClass(t, s), re.on("animationend", t, (o) => M.removeElement(t));
}
}
const be = (e) => a({ class: "ml-auto text-xs tracking-widest opacity-60" }, e), xe = (e) => a({ class: "flex w-4 h-4", html: e }), we = (e) => a({ class: "flex-auto" }, e), ye = (e, t) => V({
class: "relative flex cursor-pointer hover:bg-muted/50 select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
click: () => t(e)
}, [
e.icon && xe(e.icon),
we(e.label),
e.shortcut && be(e.shortcut)
]), ve = (e, t) => q({ class: "grid gap-2" }, [
e.map((s) => ye(s, t))
]), Ce = (e) => n({ class: "w-full z-10" }, [
n({
class: "max-h-60 border rounded-md overflow-y-auto p-1 grid gap-2 divide-y divide-border",
for: ["groups", (t) => ve(t, e)]
})
]), ke = ({ label: e, icon: t, toggleDropdown: s }) => f({
cache: "button",
class: `inline-flex items-center justify-between rounded-md border
px-2 py-2 text-sm font-medium hover:bg-muted
focus:outline-none transition duration-150 ease-in-out`,
click: s
}, [
e && a(e),
t && p({ html: t })
]), Se = ({ onSelect: e }) => n([
A(
"open",
(t, s, o) => t ? new k({
cache: "dropdown",
parent: o,
button: o.button
}, [
Ce(e)
]) : null
)
]);
class Dt extends w {
/**
* This will declare the props for the compiler.
*
* @returns {void}
*/
declareProps() {
this.label = null, this.icon = null, this.onSelect = null, this.groups = [];
}
/**
* Initializes component data.
*
* @returns {Data}
*/
setData() {
return new I({
groups: this.groups || []
});
}
/**
* Initializes the component state.
*
* @returns {object}
*/
setupStates() {
return {
open: !1,
selectedItem: null
};
}
/**
* Toggles the dropdown open state.
*
* @returns {void}
*/
toggleDropdown() {
this.state.toggle("open");
}
/**
* Handles item selection within the dropdown.
*
* @param {object} item - The selected item object
* @returns {void}
*/
handleSelect(t) {
this.state.selectedItem = t, this.state.open = !1, typeof this.onSelect == "function" && this.onSelect(t);
}
/**
* Renders the Dropdown component.
*
* @returns {object}
*/
render() {
return n({ class: "relative" }, [
ke({
label: this.label,
icon: this.icon,
toggleDropdown: this.toggleDropdown.bind(this)
}),
Se({ onSelect: this.handleSelect.bind(this) })
]);
}
}
const De = c((e, t) => n({ ...e, class: "flex flex-auto flex-col space-y-2" }, t)), Ie = c((e, t) => H({ ...e, class: "flex auto text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" }, t)), $e = c((e, t) => m({ ...e, class: "text-sm text-muted-foreground italic" }, t)), Te = c((e, t) => m({ ...e, class: "text-sm text-destructive" }, t)), It = c((e, t = []) => ce({ class: "space-y-0", margin: "m-0", padding: "p-0" }, [
e.title && v({ class: "text-lg font-semibold py-4 px-6" }, e.title),
e.description && m({ class: "text-sm text-muted-foreground pb-4 px-6 max-w-[700px]" }, e.description),
...t
])), $t = c((e, t = []) => ue({ label: e.label, description: e.description, class: "py-4 px-6", border: e.border }, [
n({ class: "flex flex-col space-y-6" }, t)
])), Tt = c((e, t = []) => {
const s = e.border ? "border-t" : "";
return n({ ...e, class: `flex flex-col pb-4 px-6 space-y-4 ${s} ${e.class || ""}` }, t);
}), Be = (e) => e.tag === "input" || e.tag === "select" || e.tag === "textarea", G = (e, t, s) => e.map((o) => !o || (o.children && o.children.length > 0 && (o.children = G(o.children, t, s)), !o.required) ? o : Be(o) ? {
...o,
aria: {
invalid: ["hasError"]
},
invalid: s,
input: t
} : o), Fe = c((e, t) => {
const l = G(t, (r) => {
r.target.checkValidity() && e.setError(null);
}, (r) => {
e.setError(r.target.validationMessage);
});
return n({
...e,
class: "w-full"
}, l);
}), Bt = y(
{
/**
* The initial state of the FormField.
*
* @member {object} state
* @returns {object}
*/
state() {
return {
error: null,
hasError: !1,
value: this.defaultValue ?? ""
};
},
/**
* Renders the FormField component.
*
* @returns {object}
*/
render() {
const e = this.name, t = this.getId(`${e}`), { label: s, description: o } = this, l = (r) => {
this.state.error = r, this.state.hasError = !!r;
};
return n({ class: "flex flex-auto space-y-4" }, [
De([
Ie({ htmlFor: t }, s),
Fe({
id: t,
name: e,
value: this.state.value,
setError: l
}, this.children),
o && $e({ id: this.getId("description") }, o),
n({ onState: ["error", (r) => r && Te(r)] })
])
]);
}
}
), Ae = (e, t, s = null) => {
e.target.checkValidity() && (e.preventDefault(), s && s(e, t));
}, J = c(
(e, t) => X({ ...e, submit: (s, o) => Ae(s, o, e.submit), class: `w-full ${e.class ?? ""}` }, t)
), Ft = c((e, t) => n({ ...e, class: `space-y-6 p-4 md:p-6 divide-y ${e.class || ""}` }, t)), At = c((e, t = []) => n({ class: "space-y-3 py-4" }, [
e.title && v({ class: "font-semibold" }, e.title),
...t
])), Lt = (e, t) => n({ class: "flex justify-between" }, [
a({ class: "text-muted-foreground" }, e),
a(t)
]), Pt = (e, t) => n({ class: "flex" }, [
a({ class: "text-muted-foreground mr-8 w-24 truncate text-nowrap" }, e),
a(t)
]), Le = ({ title: e, description: t, back: s, icon: o, options: l = [] }) => D({ class: "modal-header bg-background/80 backdrop-blur-md sticky flex flex-none items-center py-4 px-6 z-10" }, [
/**
* Back Button
*/
s && h({ variant: "icon", icon: d.arrows.left, class: "mr-2 p-0 flex sm:hidden", click: (r, i) => i.close() }),
/**
* Icon
*/
o && n({ class: "mr-2 w-12 h-12 rounded-full bg-muted flex flex-none items-center justify-center" }, [g(o)]),
/**
* Title and Description
*/
n({ class: "flex flex-auto flex-row justify-between w-full ml-2 gap-2" }, [
n({ class: "flex flex-auto flex-col" }, [
v({ class: "text-lg font-semibold m-0 truncate" }, e),
t && n({ class: "text-sm text-muted-foreground truncate" }, t)
]),
...l
])
]), Pe = c((e, t) => n({
popover: "manual",
class: `modal m-auto top-0 right-0 bottom-0 left-0 fixed z-20 grid w-full h-full max-h-screen gap-2 lg:border bg-background text-foreground shadow-xl break-words p-0 ${e.class}`,
click: (s, o) => {
s.target === o.panel && (s.preventDefault(), s.stopPropagation(), o.state.open = !1);
}
}, [
J({ class: "modal-content relative bg-background z-[1] flex flex-auto flex-col space-y-4", submit: (s, o) => e.onSubmit && e.onSubmit(o) }, [
Le(e),
n({ class: "modal-body flex flex-grow flex-col overflow-y-auto py-0 px-6 z-0" }, t),
L({ class: "modal-footer sticky bg-background/80 backdrop-blur-md flex flex-none justify-between py-4 px-6 z-10" }, e.buttons)
])
])), Me = (e) => W.render(e, app.root);
class Mt extends w {
/**
* This will declare the props for the compiler.
*
* @returns {void}
*/
declareProps() {
this.title = null, this.description = null, this.size = null, this.type = null, this.hidePrimaryButton = !1, this.icon = null, this.onSubmit = null, this.onClose = null, this.back = !1;
}
/**
* This will render the modal component.
*
* @returns {object}
*/
render() {
const t = this.getMainClass(), s = this.title || "", o = this.description || null;
return Pe(
{
class: t,
title: s,
description: o,
options: this.headerOptions(),
buttons: this.getButtons(),
onSubmit: (l) => {
let r = !0;
this.onSubmit && (r = this.onSubmit(l)), r !== !1 && this.destroy();
},
icon: this.icon,
back: this.back ?? !1,
aria: { expanded: ["open"] }
},
this.children
);
}
/**
* This will setup the states.
*
* @returns {object}
*/
setupStates() {
return {
open: {
state: !1,
callBack: (t) => {
t || this.destroy();
}
}
};
}
/**
* This will get the header options.
*
* @returns {Array<object>}
*/
headerOptions() {
return [];
}
/**
* This will get the buttons for the modal.
*
* @returns {array}
*/
getButtons() {
return [
h({ variant: "outline", click: () => this.destroy() }, "Cancel"),
this.hidePrimaryButton !== !0 && h({ variant: "primary", type: "submit" }, "Save")
];
}
/**
* This will check if the click was outside the component.
*
* @param {object} element
* @returns {boolean}
*/
isOutsideClick(t) {
return !this.panel.contains(t);
}
/**
* This will get the size class.
*
* @returns {string}
*/
getSizeClass() {
switch (this.size) {
// case 'sm':
// return 'sm max-w-[646px]';
case "lg":
return "lg max-w-[900px]";
case "xl":
return "xl max-w-[1400px]";
default:
return "md max-w-[760px]";
}
}
/**
* This will get the type class.
*
* @returns {string}
*/
getTypeClass() {
switch (this.type) {
case "right":
return "right right-0";
case "left":
return "left left-0";
default:
return "";
}
}
/**
* This will get the modal class.
*
* @returns {string}
*/
getMainClass() {
return this.getSizeClass() + " " + this.getTypeClass();
}
/**
* This will override the set up to use the app shell.
*
* @param {object} container
*/
setContainer(t) {
this.container = app.root;
}
/**
* This will open the modal.
*
* @returns {void}
*/
open() {
Me(this), this.showModal();
}
/**
* This will destroy the modal.
*
* @returns {void}
*/
close() {
this.destroy();
}
/**
* This will show the modal.
*
* @protected
* @returns {void}
*/
showModal() {
globalThis.setTimeout(() => this.panel.showPopover(), 10), this.state.open = !0, document.documentElement.style.overflowY = "hidden";
}
/**
* This will hide the modal.
*
* @protected
* @returns {void}
*/
beforeDestroy() {
this.panel.hidePopover(), this.state.open = !1, typeof this.onClose == "function" && this.onClose(this), document.documentElement.style.overflowY = "auto";
}
}
const E = {
info: {
bgColor: "bg-muted/10",
borderColor: "border-blue-500",
iconColor: "text-blue-500"
},
warning: {
bgColor: "bg-muted/10",
borderColor: "border-warning",
iconColor: "text-warning"
},
destructive: {
bgColor: "bg-muted/10",
borderColor: "border-destructive",
iconColor: "text-red-500"
},
success: {
bgColor: "bg-muted/10",
borderColor: "border-emerald-500",
iconColor: "text-emerald-500"
},
default: {
bgColor: "bg-muted/10",
borderColor: "border",
iconColor: "text-muted-foreground"
}
}, Ne = (e) => D({ class: "flex justify-center" }, [
Z({ class: "text-lg font-bold mb-0" }, e)
]), ze = c(({ href: e, class: t }, s) => Y({
class: `bg-popover text-popover-foreground relative flex flex-auto flex-col justify-start shadow-lg pointer-events-auto p-4 border rounded-md min-w-[340px] max-w-[450px] mt-4 ${t}`,
href: e,
animateIn: "pullRightIn",
animateOut: "pullRight",
role: "alert"
}, s)), Ee = c(({ close: e, class: t }, s) => n({
class: `pullRightIn bg-popover text-popover-foreground relative flex flex-auto flex-col justify-start shadow-lg pointer-events-auto p-4 border rounded-md min-w-[340px] max-w-[450px] mt-4 ${t}`,
click: () => e(),
animateIn: "pullRightIn",
animateOut: "pullRight",
role: "alert"
}, s));
class je extends w {
/**
* This will declare the props for the compiler.
*
* @returns {void}
*/
declareProps() {
this.secondaryAction = null, this.primaryAction = null, this.primary = !1, this.secondary = !1, this.title = null, this.description = null, this.icon = null, this.onClick = null;
}
/**
* This will be called when the component is created.
*
* @returns {void}
*/
onCreated() {
this.duration = this.duration || 4e3;
}
/**
* This will render the component.
*
* @returns {object}
*/
render() {
const { bgColor: t, borderColor: s, iconColor: o } = this.getTypeStyles(), l = this.href || null, r = this.getChildren(o);
return l ? ze({
href: l,
class: `${t} ${s}`
}, r) : Ee({
close: this.close.bind(this),
class: `${t} ${s}`
}, r);
}
/**
* This will be called after the component is set up.
*
* @returns {void}
*/
afterSetup() {
const t = this.duration;
t !== "infinite" && (this.timer = new de(t, this.close.bind(this)), this.timer.start());
}
/**
* This will get the style properties based on the notification type.
*
* @returns {object}
*/
getTypeStyles() {
const t = this.type || "default";
return E[t] || E.default;
}
/**
* This will get the buttons for the notification.
*
* @returns {array}
*/
getButtons() {
return [
n({ class: "flex flex-row mt-6 gap-2" }, [
this.secondary && h({ variant: "outline", click: () => this.secondaryAction && this.secondaryAction() }, this.secondary),
this.primary && h({ click: () => this.primaryAction && this.primaryAction() }, this.primary)
])
];
}
/**
* This will get the children for the notification.
*
* @param {string} iconColor
* @returns {array}
*/
getChildren(t) {
return [
n({ class: "flex items-start" }, [
this.icon && p({ class: `mr-4 ${t}`, html: this.icon }),
n({ class: "flex flex-auto flex-col" }, [
n({ class: "flex flex-auto flex-row items-center w-full pr-12" }, [
this.title && Ne(this.title)
]),
m({ class: "text-base text-muted-foreground m-0 pr-12" }, this.description),
(this.primary || this.secondary) && L({ class: "margin-top-24 flex align-center" }, this.getButtons())
])
]),
h({
class: "absolute top-[12px] right-[12px]",
variant: "icon",
icon: d.x,
click: this.close.bind(this)
})
];
}
/**
* This will close the notification.
*
* @param {object} e The event object.
* @returns {void}
*/
close(t) {
t && t.stopPropagation(), this.duration !== "infinite" && this.timer.stop(), this.onClick && this.onClick(), this.destroy();
}
}
let Oe = 0;
class Nt extends w {
/**
* This will render the component.
*
* @returns {object}
*/
render() {
return n({ class: "notification-container pointer-events-none inset-auto bg-transparent backdrop:bg-transparent overflow-visible fixed bottom-[80px] right-0 z-50 p-5", popover: "manual" }, [
new he({
cache: "list",
key: "id",
role: "list",
rowItem: (t) => new je(t)
})
]);
}
/**
* This will add a notification.
*
* @param {object} props
* @returns {void}
*/
addNotice(t = {}) {
t.id = Oe++, t.callBack = () => this.removeNotice(t), this.list.append([t]), this.panel.hidePopover(), this.panel.showPopover();
}
/**
* This will remove a notification.
*
* @param {object} notice
* @returns {void}
*/
removeNotice(t) {
this.list.delete(t.id);
}
}
const j = globalThis.matchMedia, T = c(({ value: e, label: t, icon: s }) => f({
class: 'text-sm gap-1 font-medium leading-none disabled:cursor-not-allowed disabled:opacity-70 flex flex-col items-center justify-between rounded-md border-2 bg-popover p-4 hover:bg-accent hover:text-accent-foreground data-[state="active"]:border-primary [&:has([data-state="active"])]:border-primary',
onState: ["method", { active: e }],
dataSet: ["method", ["state", e, "active"]],
click: (o, { state: l }) => {
l.method = e, localStorage.setItem("theme", e), e === "system" && localStorage.removeItem("theme"), Ue(e);
}
}, [
g(s),
a(t)
])), Ue = (e) => {
const t = document.documentElement;
if (e === "system" && (e = globalThis.matchMedia?.("(prefers-color-scheme: dark)").matches ? "dark" : "light"), j && !j("(prefers-color-scheme: " + e + ")").matches) {
t.classList.add(e);
return;
}
const s = e === "light" ? "dark" : "light";
t.classList.remove(s);
}, zt = C(
{
/**
* This will render the component.
*
* @returns {object}
*/
render() {
return n({ class: "flex flex-auto flex-col" }, [
n({ class: "grid grid-cols-3 gap-4" }, [
T({ label: "System", value: "system", icon: d.adjustments.horizontal }),
T({ label: "Light", value: "light", icon: d.sun }),
T({ label: "Dark", value: "dark", icon: d.moon })
])
]);
},
/**
* This will setup the states.
*
* @returns {object}
*/
state() {
return {
method: globalThis.localStorage.getItem("theme") ?? "system"
};
}
}
), Et = y(
{
/**
* The initial state of the Toggle.
*
* @returns {object}
*/
state() {
return {
active: this.active ?? !1
};
},
/**
* This is added to check the checkbox after the component is rendered.
* to see if the bind updated the checked value.
*
* @returns {void}
*/
after() {
this.state.active = this.checkbox.checked;
},
/**
* Renders the Toggle component.
*
* @returns {object}
*/
render() {
return f({
class: "relative inline-flex h-6 w-11 min-w-11 items-center rounded-full bg-muted transition-colors focus:outline-none",
onState: ["active", { "bg-primary": !0, "bg-muted": !1 }],
click: (t, { state: s }) => {
s.toggle("active"), this.checkbox.checked = s.active, this.change && this.change(s.active, t, this);
}
}, [
ee({
cache: "checkbox",
class: "opacity-0 absolute top-0 left-0 bottom-0 right-0 w-full h-full",
/**
* This will add the default checked before binding.
* If binding it will override the default checked value.
*/
checked: this.state.active,
bind: this.bind,
required: this.required
}),
a({
class: "absolute h-5 w-5 bg-background rounded-full shadow-md transform transition-transform",
onState: ["active", { "translate-x-[22px]": !0, "translate-x-[2px]": !1 }]
})
]);
}
}
), S = {
ONLINE: "online",
OFFLINE: "offline",
BUSY: "busy",
AWAY: "away"
}, b = {
ONLINE: "bg-green-500",
OFFLINE: "bg-gray-500",
BUSY: "bg-red-500",
AWAY: "bg-yellow-500"
}, Re = (e = "") => (e = e.toUpperCase(), b[e] || b.OFFLINE), jt = (e) => n({
class: `absolute bottom-0 right-0 w-3 h-3 border-2 rounded-full ${Re(e)}`
}), Ot = ({ propName: e = "status" } = {}) => n({
class: "absolute bottom-0 right-0 w-3 h-3 border-2 rounded-full",
onSet: [e, {
[b.ONLINE]: S.ONLINE,
[b.OFFLINE]: S.OFFLINE,
[b.BUSY]: S.BUSY,
[b.AWAY]: S.AWAY
}]
}), Ut = C(
{
/**
* Get the initial state for the component.
*
* @returns {object} Initial state for the component
*/
state() {
return {
// @ts-ignore
loaded: !!this.src
};
},
/**
* This will open the file browse dialog.
*
* @returns {void}
*/
openFileBrowse() {
const e = this.input;
e && (e.value = "", $.trigger("click", e));
},
/**
* Get the URL for the uploaded file.
*
* @param {File} file - The file to get the URL for.
* @returns {string} The object URL for the file.
*/
getFileUrl(e) {
return this.url && URL.revokeObjectURL(this.url), this.url = URL.createObjectURL(e);
},
/**
* Render the component.
*
* @returns {object} Rendered component
*/
render() {
const e = "logo-upload", t = this.onChange || null;
return n({ class: "flex-none items-center" }, [
x({
id: e,
cache: "input",
type: "file",
accept: "image/*",
class: "hidden",
change: (s) => {
const o = s.target.files?.[0];
o && t && (this.state.loaded = !1, t(o, this.parent), this.src = this.getFileUrl(o), this.state.loaded = !0);
}
}),
n({
class: "relative w-32 h-32 rounded-full border flex items-center justify-center cursor-pointer hover:bg-muted transition-colors duration-150 overflow-hidden group",
click: (s) => {
s.preventDefault(), s.stopPropagation(), this.openFileBrowse();
}
}, [
A(
"loaded",
(s) => s ? te({
// @ts-ignore
src: this.src,
class: "absolute inset-0 w-full h-full object-cover rounded-full"
}) : H({
htmlFor: e,
class: "z-10 flex flex-col items-center justify-center text-sm text-muted-foreground group-hover:text-primary"
}, [
g(d.upload),
n("Upload logo")
])
)
])
]);
}
}
), Ve = (e, t) => Y(
{
href: e,
"aria-current": t === "Breadcrumb" && "page",
// Only set aria-current on the last item
class: "text-muted-foreground font-medium hover:text-foreground"
},
[a(t)]
), qe = () => g({
class: "mx-3 text-muted-foreground",
"aria-hidden": !0,
size: "xs"
}, d.chevron.single.right), He = (e) => n({ class: "flex items-center" }, [
e.href ? Ve(e.href, e.label) : a(e.label),
e.separator && qe()
]), Rt = C(
{
/**
* Set initial data
*
* @returns {Data}
*/
setData() {
return new I({
// @ts-ignore
items: this.items || []
});
},
/**
* Render Breadcrumb Component
*
* @returns {object}
*/
render() {
const e = this.data.items.length - 1;
return se(
{
"aria-label": "Breadcrumb",
class: "flex items-center space-x-1 text-sm"
},
[
n({
role: "list",
class: "flex items-center",
for: ["items", (t, s) => He({
href: t.href,
label: t.label,
separator: s < e
})]
})
]
);
}
}
), O = {
xs: "h-1 w-1",
sm: "h-2 w-2",
md: "h-4 w-4",
lg: "h-8 w-8",
xl: "h-12 w-12",
"2xl": "h-16 w-16",
"3xl": "h-24 w-24",
default: "h-4 w-4"
}, Ye = (e) => O[e] || O.default, _e = ({ index: e, size: t }) => n({ class: `${t} rounded-full bg-muted cursor-pointer` }, [
a({
class: "block w-full h-full rounded-full transition-colors",
onSet: ["activeIndex", {
"bg-primary": e,
"shadow-md": e
}],
click: (s, { data: o, onClick: l }) => {
o.activeIndex = e, l && l(e);
}
})
]), We = (e, t) => Array.from({ length: e }, (s, o) => _e({
index: o,
size: t
})), Vt = C(
{
/**
* Defines component data (props).
*
* @returns {Data}
*/
setData() {
return new I({
// @ts-ignore
count: this.count || 4,
// total dots
// @ts-ignore
activeIndex: this.activeIndex || 0
});
},
/**
* Renders the dots.
*
* @returns {object}
*/
render() {
const e = this.gap || "gap-2", t = Ye(this.size || "sm"), s = We(this.data.count, t);
return n(
{ class: "flex justify-center items-center py-2" },
[
n({ class: `flex ${e}` }, s)
]
);
}
}
), Ge = ({ toggleDropdown: e }) => f(
{
cache: "button",
class: "relative z-[2] inline-flex items-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 border bg-input hover:bg-muted h-10 px-4 py-2 justify-between",
click: e
},
[
a({ onState: ["selectedLabel", (t) => t || "Select item..."] }),
p({ html: d.chevron.upDown })
]
), Je = (e, t, s) => V({
class: "flex flex-auto items-center cursor-pointer p-2 hover:bg-muted/50 rounded-sm",
click: () => t(e),
onState: [s, "selectedValue", { "bg-secondary": e.value }]
}, [
e.icon && a({ class: "mr-2 flex items-baseline" }, [g({ size: "xs" }, e.icon)]),
a({ class: "text-base font-normal" }, e.label)
]), Ke = (e, t) => n({ class: "w-full border rounded-md" }, [
q({ class: "max-h-60 overflow-y-auto p-2 grid gap-1", for: ["items", (s) => Je(s, e, t)] })
]), Qe = ({ onSelect: e, state: t }) => n({ class: "flex flex-auto flex-col" }, [
A(
"open",
(s, o, l) => s ? new k({
cache: "dropdown",
parent: l,
button: l.button
}, [
Ke(e, t)
]) : null
)
]), qt = C(
{
/**
* This will set up the data.
*
* @returns {Data}
*/
setData() {
return new I({
// @ts-ignore
items: this.items || []
});
},
/**
* This will set up the states.
*
* @returns {object}
*/
state() {
return {
open: !1,
selectedLabel: "",
selectedValue: ""
};
},
/**
* This will set the state item.
*
* @param {object} item
* @returns {void}
*/
setStateItem(e) {
const t = this.state;
t.selectedValue = e.value, t.selectedLabel = e.label, t.open = !1;
},
/**
* Handles the selection of an item.
*
* @param {object} item
* @returns {void}
*/
select(e) {
this.setStateItem(e), typeof this.onSelect == "function" && this.onSelect(e, this.parent);
},
/**
* Selects the first item in the list.
*
* @returns {void}
*/
selectFirstItem() {
const e = this.data.items[0];
this.select(e);
},
/**
* Toggles the dropdown open state.
*
* @returns {void}
*/
toggleDropdown() {
this.state.toggle("open");
},
/**
* This will run after the component is set up.
*
* @returns {void}
*/
after() {
if (this.selectFirst === !0 && this.state.selectedValue === "") {
const e = this.data.items[0];
e && this.setStateItem(e);
}
},
/**
* This will render the component.
*
* @returns {object}
*/
render() {
const e = this.class || "", t = this.maxWidth || "max-w-[250px]", s = this.width || "w-full";
return n({ class: `relative ${s} flex flex-auto flex-col ${t} ${e}` }, [
// @ts-ignore
Ge({ toggleDropdown: this.toggleDropdown.bind(this) }),
Qe({
// @ts-ignore
state: this.state,
// @ts-ignore
onSelect: this.select.bind(this)
}),
// Hidden required input for form validation
// @ts-ignore
this.required && x({
class: "opacity-0 absolute top-0 left-0 z-[1]",
type: "text",
// @ts-ignore
name: this.name,
required: !0,
// @ts-ignore
value: ["[[selectedValue]]", this.state]
})
]);
}
}
), K = ({ icon: e, click: t, ariaLabel: s }) => h({
variant: "icon",
class: "flex flex-none",
click: t,
icon: e,
"aria-label": s
}), Xe = ({ click: e }) => K({
icon: d.circleMinus,
click: e,
ariaLabel: "Decrement"
}), Ze = ({ click: e }) => K({
icon: d.circlePlus,
click: e,
ariaLabel: "Increment"
}), et = ({ bind: e, min: t, max: s, readonly: o = !1 }) => _(({ state: l }) => x({
value: ["[[count]]", l],
bind: e,
blur: (r, { state: i }) => {
let u = parseInt(r.target.value, 10);
isNaN(u) && (u = t ?? 0), t !== void 0 && (u = Math.max(u, t)), s !== void 0 && (u = Math.min(u, s)), i.count = u;
},
class: "flex flex-auto text-lg font-medium bg-input text-center border min-w-0",
readonly: o,
min: t,
max: s,
type: "number",
"aria-label": "Counter"
})), Ht = y(
{
/**
* Initial state for the counter component.
*
* @member {object} state
*/
state() {
return {
count: {
state: this.initialCount ?? 0,
callBack: (e) => this.change && this.change(e)
}
};
},
/**
* Renders the Counter component.
*
* @returns {object}
*/
render() {
const e = this.class ?? "";
return n({ class: `flex flex-auto items-center justify-between space-x-4 p-4 ${e}` }, [
Xe({ click: () => this.state.decrement("count") }),
et({
bind: this.bind,
readonly: this.readonly,
min: this.min,
max: this.max
}),
Ze({ click: () => this.state.increment("count") })
]);
}
}
), tt = ({ bind: e, required: t }) => x({
cache: "input",
class: "opacity-0 absolute top-0 left-0 w-full h-full pointer-events-none",
bind: e,
required: t
}), st = ({ bind: e, required: t, toggleOpen: s }) => f({
class: "relative flex items-center gap-2 w-full justify-between border bg-input hover:bg-muted rounded-md h-10 px-4 py-2",
click: s
}, [
tt({ bind: e, required: t }),
a({
onState: ["selectedDate", (o) => o ? F.format("standard", o) : "Pick a date"]
}),
p({ html: d.calendar.days })
]), ot = ({ handleDateSelect: e, blockPriorDates: t }) => P(
(s, o, l) => new k({
cache: "dropdown",
parent: l,
button: l.panel,
size: "fit"
}, [
new ie({
selectedDate: l.state.selectedDate,
selectedCallBack: e,
blockPriorDates: t
})
])
), Yt = y(
{
/**
* The initial state of the DatePicker.
*
* @member {object} state
*/
state() {
return {
selectedDate: this.selectedDate ?? null,
open: !1
};
},
/**
* This is added to check the input after the component is rendered.
* to see if the bind updated the input value.
*
* @returns {void}
*/
after() {
this.input.value && (this.state.selectedDate = this.input.value);
},
/**
* Renders the DatePicker component.
*
* @returns {object}
*/
render() {
const e = (s, { state: o }) => o.toggle("open"), t = (s) => {
this.state.selectedDate = s, this.state.open = !1, this.input.value = s, $.trigger("change", this.input), typeof this.onChange == "function" && this.onChange(s);
};
return n({ class: "relative w-full max-w-[320px]" }, [
st({
toggleOpen: e,
bind: this.bind,
required: this.required
}),
ot({
handleDateSelect: t,
blockPriorDates: this.blockPriorDates || !1
})
]);
}
}
), nt = ({ bind: e, required: t }) => x({
cache: "input",
class: "opacity-0 absolute top-0 left-0 w-full h-full pointer-events-none",
bind: e,
required: t
}), lt = ({ bind: e, required: t, toggleOpen: s }) => f({
class: "relative flex items-center gap-2 w-full justify-between border bg-input hover:bg-muted rounded-md h-10 px-4 py-2",
click: s
}, [
nt({ bind: e, required: t }),
_(({ state: o }) => [
a(N.date(["[[start]]", o], "Start Date")),
a(" - "),
a(N.date(["[[end]]", o], "End Date"))
]),
p({ html: d.calendar.days })
]), rt = ({ handleDateSelect: e, blockPriorDates: t }) => P((s, o, l) => new k({
cache: "dropdown",
parent: l,
button: l.panel,
size: "xl"
}, [
new ae({
startDate: l.state.start,
endDate: l.state.end,
onRangeSelect: e,
blockPriorDates: t
})
])), _t = y(
{
/**
* The initial state of the DateRangePicker.
*
* @member {object} state
*/
state() {
return {
start: this.start ?? null,
end: this.end ?? null,
open: !1
};
},
/**
* This is added to check the input after the component is rendered.
* to see if the bind updated the input value.
*
* @returns {void}
*/
after() {
if (this.input.value) {
const e = this.input.value.split("-");
this.state.start = e[0], this.state.end = e[1];
}
},
/**
* Renders the DatePicker component.
*
* @returns {object}
*/
render() {
const e = (s, { state: o }) => o.toggle("open"), t = (s, o) => {
this.state.start = s, this.state.end = o, this.state.open = !1, this.input.value = `${s}-${o}`, $.trigger("change", this.input), typeof this.onChange == "function" && this.onChange({ start: s, end: o }, this.parent);
};
return n({ class: "relative w-full max-w-[320px]" }, [
lt({
toggleOpen: e,
bind: this.bind,
required: this.required
}),
rt({
handleDateSelect: t,
blockPriorDates: this.blockPriorDates || !1
})
]);
}
}
), Wt = ({ dateTime: e = "", remoteTimeZone: t = "America/Denver", filter: s = null }) => oe([
new fe({
dateTime: e,
filter: s || ((o) => {
const l = F.getLocalTime(o, !0, !1, t);
return F.getTimeFrame(l);
})
})
]);
function it({ bind: e, required: t }) {
return x({
cache: "input",
class: "opacity-0 absolute top-0 left-0 w-full h-full pointer-events-none",
bind: e,
required: t
});
}
function at({ bind: e, required: t, toggleOpen: s }) {
return f(
{
class: "relative flex items-center gap-2 w-full justify-between border bg-input hover:bg-muted rounded-md h-10 px-4 py-2",
click: s
},
[
it({ bind: e, required: t }),
a({
onState: ["selectedTime", (o) => o || "Pick a time"]
}),
p({ html: d.clock })
]
);
}
function B({ items: e, handleTimeSelect: t, state: s, stateValue: o, pad: l = !1 }) {
return n(
{ class: "flex flex-col max-h-[200px] overflow-y-auto" },
e.map((r) => {
let i = l ? r.toString().padStart(2, "0") : r.toString();
return f({
text: i,
class: "hover:bg-muted/50 rounded-md px-2 py-1",
click: () => t({ [o]: i }),
onState: [s, o, { "bg-muted": i }]
});
})
);
}
function ct({ handleTimeSelect: e }) {
return P(
(t, s, o) => new k(
{
cache: "dropdown",
parent: o,
button: o.panel,
size: "fit"
},
[
n(
{ class: "flex flex-auto flex-col border rounded-md shadow-md" },
[
n(
{ class: "grid grid-cols-3 gap-2 p-4 text-center max-h-[220px] min-w-[240px]" },
[
// Hours column
B({
items: Array.from({ length: 12 }, (l, r) => r + 1),
handleTimeSelect: e,
state: o.state,
stateValue: "hour",
pad: !0
}),
// Minutes column
B({
items: Array.from({ length: 60 }, (l, r) => r),
handleTimeSelect: e,
state: o.state,
stateValue: "minute",
pad: !0
}),
// AM/PM column
B({
items: ["AM", "PM"],
handleTimeSelect: e,
state: o.state,
stateValue: "meridian"
})
]
)
]
)
]
)
);
}
function U(e) {
if (!e)
return { hour: null, minute: null, meridian: null };
const t = /^(\d{1,2}):(\d{2})(?::(\d{2}))?\s?(AM|PM)?$/i, s = e.match(t);
if (!s)
return { hour: null, minute: null, meridian: null };
let [, o, l, , r] = s, i = parseInt(o, 10), u = parseInt(l, 10);
return i < 0 || i > 23 || u < 0 || u > 59 ? { hour: null, minute: null, meridian: null } : (r ? (r = r.toUpperCase(), r === "PM" && i < 12 ? i += 12 : r === "AM" && i === 12 && (i = 12)) : i === 0 ? (r = "AM", i = 12) : i < 12 ? r = "AM" : i === 12 ? r = "PM" : (r = "PM", i -= 12), {
hour: i.toString().padStart(2, "0"),
minute: u.toString().padStart(2, "0"),
meridian: r
});
}
const Gt = y(
{
/**
* The initial shallow state of the TimePicker.
*
* @member {object} state
*/
state() {
const e = this.selectedTime ?? null, { hour: t, minute: s, meridian: o } = U(e);
return {
selectedTime: e,
open: !1,
hour: t,
minute: s,
meridian: o
};
},
/**
* Updates the state after the input is rendered.
*
* @returns {void}
*/
after() {
if (this.input.value) {
const { hour: e, minute: t, meridian: s } = U(this.input.value);
this.state.set({
hour: e,
minute: t,
meridian: s,
selectedTime: this.input.value
});
}
},
/**
* Renders the TimePicker component.
*
* @returns {object}
*/
render() {
const e = (s, { state: o }) => o.toggle("open"), t = ({ hour: s, minute: o, meridian: l }) => {
if (s && (this.state.hour = s), o && (this.state.minute = o), l && (this.state.meridian = l), this.state.hour && this.state.minute && this.state.meridian) {
const r = `${this.state.hour}:${this.state.minute} ${this.state.meridian}`;
this.state.selectedTime = r, this.state.open = !1, this.input.value = r, $.trigger("change", this.input), typeof this.change == "function" && this.change(r);
}
};
return n(
{ class: "relative w-full max-w-[320px]" },
[
at({
toggleOpen: e,
bind: this.bind,
required: this.required
}),
ct({
handleTimeSelect: t
})
]
);
}
}
), ut = (e, t) => n({ class: `hidden md:flex items-start justify-center w-6 h-6 mr-3 ${t}` }, [
g({ size: "lg" }, e)
]), dt = ({ title: e }) => D({ class: "flex flex-auto items-center" }, [
v({ class: "text-lg font-semibold" }, e)
]), ht = c((e, t) => ne(
{
class: `fixed pullUpIn z-30 w-[98%] border md:w-full max-w-lg bg-popover text-foreground shadow-lg duration-200
rounded-lg flex flex-auto flex-col
bottom-4 top-auto inset-auto m-auto md:bottom-0 md:top-0 left-0 right-0 ${e.class}`,
click: e.click,
aria: { expanded: ["open"] }
},
[
n({ class: "flex flex-auto p-6 pb-12 md:pb-6" }, [
// Icon and content
e.icon && ut(e.icon, e.iconColor),
n({ class: "flex flex-auto flex-col gap-4" }, [
n({ class: "flex flex-auto flex-col space-y-2" }, [
dt(e),
e.description && m({ class: "flex flex-auto flex-col text-sm text-muted-foreground" }, e.description),
n({ class: "flex flex-auto flex-col text-sm text-muted-foreground" }, t)
]),
e.buttons && L({ class: "flex flex-col-reverse sm:flex-row sm:justify-end mt-6 gap-2 sm:gap-0 sm:space-x-2" }, e.buttons)
])
])
]
)), ft = (e) => W.render(e, app.root), R = {
info: {
borderColor: "border-blue-500",
bgColor: "bg-muted/10",
iconColor: "text-blue-500"
},
warning: {
bgColor: "bg-muted/10",
borderColor: "border-warning",
iconColor: "text-warning"
},
destructive: {
bgColor: "bg-muted/10",
borderColor: "border-destructive",
iconColor: "text-red-500"
},
success: {
bgColor: "bg-muted/10",
borderColor: "border-emerald-500",
iconColor: "text-emerald-500"
},
default: {
borderColor: "border",
bgColor: "bg-muted/10",
iconColor: "text-muted-foreground"
}
};
class mt extends w {
/**
* This will declare the props for the compiler.
*
* @returns {void}
*/
declareProps() {
this.title = null, this.description = null, this.type = "", this.icon = null, this.onClose = null, this.hideFooter = !1, this.buttons = null;
}
/**
* This will render the modal component.
*
* @returns {object}
*/
render() {
const t = (u) => {
u.target === this.panel && this.close();
}, { borderColor: s, bgColor: o, iconColor: l } = R[this.type] || R.default, r = `${this.getMainClass()} ${o} ${s}`, i = this.title || "Dialog Title";
return ht({
class: r,
title: i,
click: t,
icon: this.icon,
iconColor: l,
description: this.description,
buttons: this.getButtons()
}, this.children);
}
/**
* This will get the buttons for the modal.
*
* @returns {array}
*/
getButtons() {
return this.hideFooter ? null : this.buttons ? this.buttons : [
h({ variant: "outline", click: () => this.close() }, "Close")
];
}
/**
* This will setup the states.
*
* @returns {object}
*/
setupStates() {
return {
open: !1
};
}
/**
* This will get the modal class.
*
* @returns {string}
*/
getMainClass() {
return "";
}
/**
* This will open the modal.
*
* @returns {void}
*/
open() {
ft(this), this.panel.showModal(), this.state.open = !0;
}
/**
* This will close the modal.
*
* @returns {void}
*/
close() {
this.state.open = !1, this.panel.close(), typeof this.onClose == "function" && this.onClose(), this.destroy();
}
}
class Jt extends mt {
/**
* This will declare the props for the compiler.
*
* @returns {void}
*/
declareProps() {
this.confirmTextLabel = null, this.confirmed = null;
}
/**
* This will get the buttons for the modal.
*
* @returns {array}
*/
getButtons() {
const t = this.confirmTextLabel || "Confirm";
return [
h({ variant: "outline", click: () => this.close() }, "Cancel"),
h({ variant: "primary", click: () => this.confirm() }, t)
];
}
/**
* This will confirm the action.
*
* @returns {void}
*/
confirm() {
this.confirmed && this.confirmed(), this.close();
}
}
const Kt = c((e, t = []) => n({ class: "w-full max-w-md p-6 m-auto" }, [
J({ class: "flex flex-auto flex-col" }, [
n({ class: "flex flex-auto flex-col space-y-4" }, [
n({ class: "flex flex-auto items-center justify-center" }, [
e.icon && n({ class: "w-16 h-16 mb-2 text-primary" }, [
g(e.icon)
])
]),
D({ class: "py-4 text-center" }, [
v({ class: "text-xl font-bold" }, e.title),
m({ class: "pb-8 text-muted-foreground" }, e.description || ""),
...t
])
])
])
]));
export {
kt as A,
Rt as B,
Pt as C,
St as D,
Yt as E,
De as F,
_t as G,
Wt as H,
Gt as I,
Jt as J,
ht as K,
Ut as L,
Mt as M,
Nt as N,
mt as O,
Ze as P,
Kt as Q,
Lt as S,
zt as T,
ye as a,
Dt as b,
Ce as c,
Ie as d,
$e as e,
Te as f,
It as g,
$t as h,
Tt as i,
Fe as j,
Bt as k,
J as l,
Ft as m,
At as n,
je as o,
Et as p,
jt as q,
Ot as r,
S as s,
b as t,
Re as u,
Vt as v,
qt as w,
Xe as x,
et as y,
Ht as z
};