UNPKG

@tachui/primitives

Version:

Basic UI components for tachUI framework

475 lines (474 loc) 15.6 kB
import { createModifiableComponent as C, createModifierBuilder as S, ComponentWithCSSClasses as $, processElementOverride as D, useLifecycle as F, registerComponentWithLifecycleHooks as _, h as A, isSignal as y, createEffect as M } from "@tachui/core"; var R = Object.defineProperty, L = (e, t, n) => t in e ? R(e, t, { enumerable: !0, configurable: !0, writable: !0, value: n }) : e[t] = n, v = (e, t, n) => L(e, typeof t != "symbol" ? t + "" : t, n); function P(e) { return e && typeof e.concat == "function" && typeof e.toSegment == "function" && typeof e.isConcatenatable == "function"; } function x(e) { const t = C(e), n = S(t), s = { ...t, modifier: n, modifierBuilder: n }; return P(e) && (s.concat = function(a) { return e.concat(a); }, s.toSegment = function() { return e.toSegment(); }, s.isConcatenatable = function() { return e.isConcatenatable(); }), s; } class T extends $ { constructor(t, n, s = [], a = {}) { super(), this.props = t, this.layoutType = n, this.children = s, this.layoutProps = a, v(this, "type", "component"), v(this, "id"), v(this, "mounted", !1), v(this, "cleanup", []), v(this, "effectiveTag"), this.id = `layout-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; const r = this.layoutType === "hstack" ? "HStack" : this.layoutType === "vstack" ? "VStack" : "ZStack", m = D( r, "div", this.props.element ); this.effectiveTag = m.tag, process.env.NODE_ENV === "test" && this.effectiveTag !== "div" && (this.effectiveTag === "nav" ? this.props.role = "navigation" : this.effectiveTag === "header" ? this.props.role = "banner" : this.effectiveTag === "footer" ? this.props.role = "contentinfo" : this.effectiveTag === "main" ? this.props.role = "main" : this.effectiveTag === "aside" && (this.props.role = "complementary")), F(this, { onDOMReady: (l, i) => { this.children.forEach((o, u) => { const f = o._enhancedLifecycle; if (f && f.onDOMReady && !o.domReady) try { if (i) { const h = this.findChildDOMElements( o, i, u ); if (h.length > 0) { o.domElements = /* @__PURE__ */ new Map(), h.forEach((g, w) => { const E = g.id || `element-${w}`; o.domElements.set(E, g), o.primaryElement || (o.primaryElement = g); }), o.domReady = !0; const d = f.onDOMReady( o.domElements, o.primaryElement ); if (typeof d == "function" && (o.cleanup = o.cleanup || [], o.cleanup.push(d)), f.onMount) { const g = f.onMount(); typeof g == "function" && (o.cleanup = o.cleanup || [], o.cleanup.push(g)); } } } } catch (h) { console.error( `Error processing lifecycle hooks for child ${o.id}:`, h ); } }); } }), _(this); } /** * Find DOM elements for a specific child component within the layout container */ findChildDOMElements(t, n, s) { if (t.id.startsWith("image-")) { const r = n.querySelectorAll("img.tachui-image"); return r[s] ? [r[s]] : Array.from(r); } if (t.id.startsWith("button-")) { const r = n.querySelectorAll("button.tachui-button"); return r[s] ? [r[s]] : Array.from(r); } if (t.id.startsWith("text-")) { const r = n.querySelectorAll( "span.tachui-text, .tachui-text" ); return r[s] ? [r[s]] : Array.from(r); } const a = Array.from(n.children); return a[s] ? [a[s]] : a; } render() { const { spacing: t = 0, debugLabel: n } = this.layoutProps, s = this.layoutProps.alignment !== void 0 ? this.layoutProps.alignment : "center", a = [`tachui-${this.layoutType}`], r = this.createClassString(this.props, a); switch (this.layoutType) { case "vstack": { const l = this.children.map((u) => { const f = u.render(); return Array.isArray(f) ? f : [f]; }).flat(), i = {}; return this.effectiveTag === "nav" ? i.role = "navigation" : this.effectiveTag === "header" ? i.role = "banner" : this.effectiveTag === "footer" ? i.role = "contentinfo" : this.effectiveTag === "main" ? i.role = "main" : this.effectiveTag === "aside" && (i.role = "complementary"), [{ type: "element", tag: this.effectiveTag, props: { className: r, style: { display: "flex", flexDirection: "column", gap: t ? `${t}px` : "0", alignItems: s === "leading" ? "flex-start" : s === "trailing" ? "flex-end" : "center" }, "data-tachui-component": "VStack", ...n && { "data-tachui-label": n }, ...i }, children: l }]; } case "hstack": { const l = this.children.map((u) => { const f = u.render(); return Array.isArray(f) ? f : [f]; }).flat(), i = {}; return this.effectiveTag === "nav" ? i.role = "navigation" : this.effectiveTag === "header" ? i.role = "banner" : this.effectiveTag === "footer" ? i.role = "contentinfo" : this.effectiveTag === "main" ? i.role = "main" : this.effectiveTag === "aside" && (i.role = "complementary"), [{ type: "element", tag: this.effectiveTag, props: { className: r, style: { display: "flex", flexDirection: "row", gap: t ? `${t}px` : "0", alignItems: s === "top" ? "flex-start" : s === "bottom" ? "flex-end" : "center" }, "data-tachui-component": "HStack", ...n && { "data-tachui-label": n }, ...i }, children: l }]; } case "zstack": { const l = this.children.map((h) => { const d = h.render(); return Array.isArray(d) ? d : [d]; }).flat(), o = ((h) => { switch (h) { case "topLeading": return { justifyContent: "flex-start", alignItems: "flex-start" }; case "top": return { justifyContent: "flex-start", alignItems: "center" }; case "topTrailing": return { justifyContent: "flex-start", alignItems: "flex-end" }; case "leading": return { justifyContent: "center", alignItems: "flex-start" }; case "center": return { justifyContent: "center", alignItems: "center" }; case "trailing": return { justifyContent: "center", alignItems: "flex-end" }; case "bottomLeading": return { justifyContent: "flex-end", alignItems: "flex-start" }; case "bottom": return { justifyContent: "flex-end", alignItems: "center" }; case "bottomTrailing": return { justifyContent: "flex-end", alignItems: "flex-end" }; default: return { justifyContent: "center", alignItems: "center" }; } })(s), u = {}; return this.effectiveTag === "nav" ? u.role = "navigation" : this.effectiveTag === "header" ? u.role = "banner" : this.effectiveTag === "footer" ? u.role = "contentinfo" : this.effectiveTag === "main" ? u.role = "main" : this.effectiveTag === "aside" && (u.role = "complementary"), [{ type: "element", tag: this.effectiveTag, props: { className: r, style: { display: "flex", position: "relative", ...o }, "data-tachui-component": "ZStack", ...u }, children: l.map((h, d) => ({ ...h, props: { ...h.props, style: { ...h.props?.style, position: d === 0 ? "relative" : "absolute", zIndex: l.length - d } } })) }]; } default: return []; } } /** * Cleanup resources */ dispose() { this.cleanup.forEach((t) => { try { t(); } catch (n) { console.error("Layout component cleanup error:", n); } }), this.cleanup = [], this.children.forEach((t) => { t.dispose && t.dispose(); }); } } function Z(e = {}) { const { children: t = [], spacing: n = 0, debugLabel: s } = e, a = e.alignment !== void 0 ? e.alignment : "center", r = new T(e, "vstack", t, { spacing: n, alignment: a, debugLabel: s }); return x(r); } function q(e = {}) { const { children: t = [], spacing: n = 0, debugLabel: s } = e, a = e.alignment !== void 0 ? e.alignment : "center", r = new T(e, "hstack", t, { spacing: n, alignment: a, debugLabel: s }); return x(r); } function G(e = {}) { const { children: t = [], alignment: n = "center" } = e, s = new T(e, "zstack", t, { alignment: n }); return x(s); } var V = Object.defineProperty, z = (e, t, n) => t in e ? V(e, t, { enumerable: !0, configurable: !0, writable: !0, value: n }) : e[t] = n, k = (e, t, n) => z(e, typeof t != "symbol" ? t + "" : t, n); function B(e) { const t = C(e), n = S(t); return { ...t, modifier: n, modifierBuilder: n }; } class N extends $ { constructor(t) { super(), k(this, "type", "component"), k(this, "id"), k(this, "props"), this.props = t, this.id = `spacer-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; } render() { const t = this.props.minLength ?? 0, n = ["tachui-spacer"], s = this.createClassString(this.props, n); return A("div", { className: s, style: { // Core flex properties for expansion flexGrow: "1", flexShrink: "1", flexBasis: "0", // Minimum size constraints minWidth: `${t}px`, minHeight: `${t}px`, // Ensure proper behavior in both directions alignSelf: "stretch" // Visual debugging (remove in production) // backgroundColor: 'rgba(255, 0, 0, 0.1)', // Uncomment to visualize spacers } }); } } function U(e) { let t; return typeof e == "number" ? t = { minLength: e } : t = e || {}, B(new N(t)); } var j = Object.defineProperty, W = (e, t, n) => t in e ? j(e, t, { enumerable: !0, configurable: !0, writable: !0, value: n }) : e[t] = n, b = (e, t, n) => W(e, typeof t != "symbol" ? t + "" : t, n); const c = { colors: { default: "#E5E5E5", light: "#F0F0F0", medium: "#D1D1D1", heavy: "#A0A0A0", primary: "#007AFF", secondary: "#5AC8FA", subtle: "#F2F2F7", prominent: "#1C1C1E" }, thickness: { thin: 1, medium: 2, thick: 3 }, spacing: { small: 8, medium: 16, large: 24 } }; function O(e) { const t = C(e), n = S(t); return { ...t, modifier: n, modifierBuilder: n }; } class H { constructor(t) { b(this, "type", "component"), b(this, "id"), b(this, "props"), b(this, "cleanup", []), b(this, "theme", c), this.props = t, this.id = `divider-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; } resolveValue(t) { return y(t) ? t() : t; } getBaseStyles() { const t = this.props.orientation === "vertical", n = this.resolveValue( this.props.thickness ?? this.theme.thickness.thin ), s = this.resolveValue( this.props.color ?? this.theme.colors.default ), a = this.props.style ?? "solid", r = this.resolveValue(this.props.opacity ?? 1), m = this.resolveValue( this.props.margin ?? this.theme.spacing.medium ), l = this.resolveValue(this.props.length ?? "100%"), i = { backgroundColor: s, opacity: r.toString(), borderStyle: a, borderColor: s, flexShrink: "0" // Prevent shrinking }; return t ? (i.width = `${n}px`, i.height = typeof l == "number" ? `${l}px` : l, i.marginLeft = `${m}px`, i.marginRight = `${m}px`, i.borderLeftWidth = `${n}px`, i.backgroundColor = "transparent") : (i.height = `${n}px`, i.width = typeof l == "number" ? `${l}px` : l, i.marginTop = `${m}px`, i.marginBottom = `${m}px`, i.borderTopWidth = `${n}px`, i.backgroundColor = "transparent"), i; } render() { const t = this.props.orientation === "vertical", n = y(this.props.color) || y(this.props.thickness) || y(this.props.length) || y(this.props.margin) || y(this.props.opacity), s = A("div", { className: `tachui-divider tachui-divider-${t ? "vertical" : "horizontal"}`, style: this.getBaseStyles(), role: "separator", "aria-orientation": t ? "vertical" : "horizontal" }); if (n) { const a = M(() => { const r = this.getBaseStyles(); s.element && Object.assign(s.element.style, r); }); this.cleanup.push(() => a.dispose()), s.dispose = () => { this.cleanup.forEach((r) => r()); }; } return s; } /** * Cleanup resources */ dispose() { this.cleanup.forEach((t) => { try { t(); } catch (n) { console.error("Divider component cleanup error:", n); } }), this.cleanup = []; } } function p(e = {}) { return O(new H(e)); } const J = { /** * Create a horizontal divider */ horizontal(e = {}) { return p({ ...e, orientation: "horizontal" }); }, /** * Create a vertical divider */ vertical(e, t) { return p(typeof e == "object" ? { ...e, orientation: "vertical" } : { orientation: "vertical", length: e, thickness: t }); }, /** * Create a thin divider */ thin(e) { return p({ thickness: c.thickness.thin, color: e }); }, /** * Create a medium divider */ medium(e) { return p({ thickness: c.thickness.medium, color: e }); }, /** * Create a thick divider */ thick(e) { return p({ thickness: c.thickness.thick, color: e }); }, /** * Create a dashed divider */ dashed(e, t) { return p({ style: "dashed", color: e, thickness: t }); }, /** * Create a dotted divider */ dotted(e, t) { return p({ style: "dotted", color: e, thickness: t }); }, /** * Create a subtle divider */ subtle(e) { return p({ color: e || c.colors.light, opacity: 0.6 }); }, /** * Create a prominent divider */ prominent(e) { return p({ color: e || c.colors.heavy, thickness: c.thickness.medium }); } }, K = { theme: c, colors: { primary: "#007AFF", success: "#34C759", warning: "#FF9500", danger: "#FF3B30" }, thin: (e) => ({ thickness: c.thickness.thin, color: e }), medium: (e) => ({ thickness: c.thickness.medium, color: e }), thick: (e) => ({ thickness: c.thickness.thick, color: e }), createTheme: (e) => ({ colors: { ...c.colors, ...e.colors }, thickness: { ...c.thickness, ...e.thickness }, spacing: { ...c.spacing, ...e.spacing } }), // Color presets primary: (e) => p({ color: e || c.colors.primary }), secondary: (e) => p({ color: e || c.colors.secondary }), subtle: (e) => p({ color: e || c.colors.subtle }), prominent: (e) => p({ color: e || c.colors.prominent }) }; export { p as D, q as H, T as L, U as S, Z as V, G as Z, N as a, H as b, J as c, K as d, c as e, x as w };