UNPKG

@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
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 };