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,743 lines (1,742 loc) 47 kB
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 };