UNPKG

@tachui/modifiers

Version:

Essential styling modifiers for tachUI framework

787 lines (786 loc) 30.6 kB
var T = Object.defineProperty; var M = (v, a, i) => a in v ? T(v, a, { enumerable: !0, configurable: !0, writable: !0, value: i }) : v[a] = i; var g = (v, a, i) => M(v, typeof a != "symbol" ? a + "" : a, i); import { isSignal as u, isComputed as m, createEffect as y, getThemeSignal as $ } from "@tachui/core/reactive"; import { ModifierPriority as E } from "@tachui/core/modifiers/types"; import { shouldExpandForInfinity as P, dimensionToCSS as S, isInfinity as C } from "@tachui/core/constants/layout"; class L { constructor(a) { this.properties = a; } /** * Helper to resolve reactive properties */ resolveReactiveProps(a, i) { const t = {}; for (const [e, n] of Object.entries(a)) u(n) || m(n), t[e] = n; return t; } /** * Apply a single style change to an element with reactive support */ applyStyleChange(a, i, t) { if (a instanceof HTMLElement) { const e = this.toCSSProperty(i); if (u(t) || m(t)) y(() => { const n = t(), s = String(n); if (s.includes("!important")) { const o = s.replace(/\s*!important\s*$/, "").trim(); a.style.setProperty(e, o, "important"); } else a.style.setProperty(e, s); }); else { const n = String(t); if (n.includes("!important")) { const s = n.replace(/\s*!important\s*$/, "").trim(); a.style.setProperty(e, s, "important"); } else a.style.setProperty(e, n); } } } /** * Convert camelCase property to CSS kebab-case */ toCSSProperty(a) { return a.replace(/([A-Z])/g, "-$1").toLowerCase(); } /** * Convert value to CSS value string */ toCSSValue(a) { return typeof a == "number" ? `${a}px` : String(a); } /** * Convert value to CSS value string with property-specific handling */ toCSSValueForProperty(a, i) { return typeof i == "number" ? [ "opacity", "z-index", "line-height", "flex-grow", "flex-shrink", "order", "column-count", "font-weight" ].includes(a) ? String(i) : `${i}px` : ([ "filter", // CSS filter strings should not be processed "transform", // CSS transform strings "clip-path" // CSS clip-path strings ].includes(a), String(i)); } /** * Apply multiple CSS properties to an element with reactive support */ applyStyles(a, i) { if (a instanceof HTMLElement || a.style) { const t = (a instanceof HTMLElement, a.style); for (const [e, n] of Object.entries(i)) if (n !== void 0) { const s = this.toCSSProperty(e); if (u(n) || m(n)) y(() => { const o = n(), r = this.toCSSValueForProperty( s, o ); if (t.setProperty) if (typeof r == "string" && r.includes("!important")) { const l = r.replace(/\s*!important\s*$/, "").trim(); t.setProperty(s, l, "important"); } else t.setProperty(s, r); else t[s] = r; }); else { const o = this.toCSSValueForProperty(s, n); if (t.setProperty) if (typeof o == "string" && o.includes("!important")) { const r = o.replace(/\s*!important\s*$/, "").trim(); t.setProperty(s, r, "important"); } else t.setProperty(s, o); else t[s] = o; } } } } /** * Add CSS classes to an element */ addClasses(a, i) { a instanceof HTMLElement && a.classList.add(...i); } /** * Remove CSS classes from an element */ removeClasses(a, i) { a instanceof HTMLElement && a.classList.remove(...i); } /** * Create a style computation context */ createStyleContext(a, i, t) { return { componentId: a, element: i, modifiers: t, signals: /* @__PURE__ */ new Set(), cleanup: [] }; } } class V extends L { constructor() { super(...arguments); g(this, "type", "layout"); g(this, "priority", E.LAYOUT); } apply(i, t) { if (!i.element || !t.element) return; const e = this.createStyleContext( t.componentId, t.element, [] ), n = this.computeLayoutStyles( this.properties, e ); this.applyStyles(t.element, n); const s = this.properties; s.offset && t.element instanceof HTMLElement && this.applyOffsetTransform(t.element, s.offset), s.aspectRatio && t.element instanceof HTMLElement && this.applyAspectRatio(t.element, s.aspectRatio), s.scaleEffect && t.element instanceof HTMLElement && this.applyScaleTransform(t.element, s.scaleEffect), s.position && t.element instanceof HTMLElement && this.applyAbsolutePosition(t.element, s.position), s.zIndex !== void 0 && t.element instanceof HTMLElement && this.applyZIndex(t.element, s.zIndex); } applyOffsetTransform(i, t) { const { x: e, y: n } = t; if (u(e) || m(e) || u(n) || m(n)) y(() => { const s = u(e) || m(e) ? e() : e ?? 0, o = u(n) || m(n) ? n() : n ?? 0, r = this.toCSSValue(s), l = this.toCSSValue(o), c = `translate(${r}, ${l})`, p = (i.style.transform || "").split(" ").filter((h) => h && !h.startsWith("translate(")).join(" "), d = p ? `${p} ${c}` : c; i.style.transform = d; }); else { const s = e ?? 0, o = n ?? 0, r = this.toCSSValue(s), l = this.toCSSValue(o), c = `translate(${r}, ${l})`, p = (i.style.transform || "").split(" ").filter((h) => h && !h.startsWith("translate(")).join(" "), d = p ? `${p} ${c}` : c; i.style.transform = d; } } applyAspectRatio(i, t) { const { ratio: e, contentMode: n } = t; e !== void 0 && (u(e) || m(e) ? y(() => { const s = typeof e == "function" ? e() : e; i.style.aspectRatio = String(s); }) : i.style.aspectRatio = String(e), n === "fill" ? i.style.objectFit = "cover" : i.style.objectFit = "contain"); } // Phase 3 - Epic: Butternut Transform Methods applyScaleTransform(i, t) { const { x: e, y: n, anchor: s } = t, o = e ?? 1, r = n ?? o; if (u(o) || m(o) || u(r) || m(r)) y(() => { const l = u(o) || m(o) ? o() : o, c = u(r) || m(r) ? r() : r, f = `scale(${l}, ${c})`; i.style.transformOrigin = this.getTransformOrigin( s || "center" ); const d = (i.style.transform || "").replace(/\s*scale\([^)]*\)\s*/g, " ").replace(/\s+/g, " ").trim(), h = d ? `${d} ${f}` : f; i.style.transform = h; }); else { const l = `scale(${o}, ${r})`; i.style.transformOrigin = this.getTransformOrigin( s || "center" ); const f = (i.style.transform || "").replace(/\s*scale\([^)]*\)\s*/g, " ").replace(/\s+/g, " ").trim(), p = f ? `${f} ${l}` : l; i.style.transform = p; } } applyAbsolutePosition(i, t) { const { x: e, y: n } = t; if (i.style.position = "absolute", u(e) || m(e) || u(n) || m(n)) y(() => { const s = u(e) || m(e) ? e() : e ?? 0, o = u(n) || m(n) ? n() : n ?? 0; i.style.left = this.toCSSValue(s), i.style.top = this.toCSSValue(o); }); else { const s = e ?? 0, o = n ?? 0; i.style.left = this.toCSSValue(s), i.style.top = this.toCSSValue(o); } } applyZIndex(i, t) { u(t) || m(t) ? y(() => { const e = t(); i.style.zIndex = String(e); }) : i.style.zIndex = String(t); } getTransformOrigin(i) { return { center: "center center", top: "center top", topLeading: "left top", topTrailing: "right top", bottom: "center bottom", bottomLeading: "left bottom", bottomTrailing: "right bottom", leading: "left center", trailing: "right center" }[i] || "center center"; } computeLayoutStyles(i, t) { const e = {}; if (i.frame) { const n = i.frame, s = P(n); if (Object.assign(e, s.cssProps), n.width !== void 0) { const o = S(n.width); o !== void 0 && !C(n.width) && !s.expandWidth && (e.width = o); } if (n.height !== void 0) { const o = S(n.height); o !== void 0 && !C(n.height) && !s.expandHeight && (e.height = o); } if (n.minWidth !== void 0) { const o = S(n.minWidth); o !== void 0 && (e.minWidth = o); } if (n.maxWidth !== void 0 && !C(n.maxWidth)) { const o = S(n.maxWidth); o !== void 0 && (e.maxWidth = o); } else C(n.maxWidth) && (e.maxWidth = "none", e.flexGrow = "1 !important", e.flexShrink = "1 !important", e.flexBasis = "0% !important", e.alignSelf = "stretch !important"); if (n.minHeight !== void 0) { const o = S(n.minHeight); o !== void 0 && (e.minHeight = o); } if (n.maxHeight !== void 0 && !C(n.maxHeight)) { const o = S(n.maxHeight); o !== void 0 && (e.maxHeight = o); } else C(n.maxHeight) && (e.maxHeight = "none", e.flexGrow = "1 !important", e.flexShrink = "1 !important", e.flexBasis = "0% !important", e.alignSelf = "stretch !important"); } if (i.padding !== void 0) if (typeof i.padding == "number") e.padding = this.toCSSValue(i.padding); else { const n = i.padding; n.top !== void 0 && (e.paddingTop = this.toCSSValue(n.top)), n.right !== void 0 && (e.paddingRight = this.toCSSValue(n.right)), n.bottom !== void 0 && (e.paddingBottom = this.toCSSValue(n.bottom)), n.left !== void 0 && (e.paddingLeft = this.toCSSValue(n.left)); } if (i.margin !== void 0) if (typeof i.margin == "number") e.margin = this.toCSSValue(i.margin); else { const n = i.margin; n.top !== void 0 && (e.marginTop = this.toCSSValue(n.top)), n.right !== void 0 && (e.marginRight = this.toCSSValue(n.right)), n.bottom !== void 0 && (e.marginBottom = this.toCSSValue(n.bottom)), n.left !== void 0 && (e.marginLeft = this.toCSSValue(n.left)); } if (i.alignment) switch (i.alignment) { case "leading": e.textAlign = "left", e.alignItems = "flex-start"; break; case "center": e.textAlign = "center", e.alignItems = "center"; break; case "trailing": e.textAlign = "right", e.alignItems = "flex-end"; break; case "top": e.alignItems = "flex-start"; break; case "bottom": e.alignItems = "flex-end"; break; } if (i.layoutPriority !== void 0) { const n = Number(i.layoutPriority); n > 0 ? (e.flexShrink = "0", e.flexGrow = String(Math.max(1, n / 10)), e.zIndex = String(n), e.gridRowEnd = `span ${String(Math.min(10, Math.max(1, Math.ceil(n / 10))))}`, e.gridColumnEnd = `span ${String(Math.min(10, Math.max(1, Math.ceil(n / 10))))}`) : n === 0 ? (e.flexShrink = "1", e.flexGrow = "1") : (e.flexShrink = String(Math.abs(n)), e.flexGrow = "0", e.zIndex = String(n)), e && typeof e == "object" && "setProperty" in e && e.setProperty("--layout-priority", String(n)); } if (i.offset, i.aspectRatio) { const { ratio: n, contentMode: s } = i.aspectRatio; n !== void 0 && (e.aspectRatio = typeof n == "number" ? String(n) : n, s === "fill" ? e.objectFit = "cover" : e.objectFit = "contain"); } if (i.fixedSize) { const { horizontal: n, vertical: s } = i.fixedSize; n && (e.flexShrink = "0", e.width = "max-content"), s && (e.flexShrink = "0", e.height = "max-content"); } return e; } } class I extends L { constructor() { super(...arguments); g(this, "type", "appearance"); g(this, "priority", E.APPEARANCE); } apply(i, t) { if (!i.element || !t.element) return; const e = this.createStyleContext( t.componentId, t.element, [] ), n = this.resolveReactiveProps( this.properties, e ); this.applyAssetBasedStyles(t.element, n); const s = this.computeAppearanceStyles(n); this.applyStyles(t.element, s); } /** * Apply Asset-based styles with theme reactivity */ applyAssetBasedStyles(i, t) { const e = $(); t.foregroundColor && this.isAsset(t.foregroundColor) && y(() => { e(); const n = t.foregroundColor.resolve(); this.applyStyleChange(i, "color", n); }), t.backgroundColor && this.isAsset(t.backgroundColor) && y(() => { e(); const n = t.backgroundColor.resolve(); this.applyStyleChange(i, "backgroundColor", n); }), t.border?.color && this.isAsset(t.border.color) && y(() => { e(); const n = t.border.color.resolve(); this.applyStyleChange(i, "borderColor", n); }); } /** * Check if a value is an Asset object (including Asset proxies) */ isAsset(i) { return i != null && typeof i == "object" && "resolve" in i && typeof i.resolve == "function"; } computeAppearanceStyles(i) { const t = {}; if (i.foregroundColor && !this.isAsset(i.foregroundColor) && (t.color = i.foregroundColor), i.backgroundColor && !this.isAsset(i.backgroundColor) && (t.backgroundColor = i.backgroundColor), i.opacity !== void 0 && (t.opacity = i.opacity), i.font) { const n = i.font; n.family && (typeof n.family == "object" && n.family !== null && "resolve" in n.family ? t.fontFamily = n.family.resolve() : t.fontFamily = n.family), n.size && (t.fontSize = this.toCSSValue(n.size)), n.weight && (t.fontWeight = String(n.weight)), n.style && (t.fontStyle = n.style); } if (i.cornerRadius !== void 0 && (t.borderRadius = this.toCSSValue(i.cornerRadius)), i.border) { const n = i.border; n.width !== void 0 && (t.borderWidth = this.toCSSValue(n.width)), n.color && !this.isAsset(n.color) && (t.borderColor = n.color), n.style && (t.borderStyle = n.style); } if (i.shadow) { const n = i.shadow, s = n.x || 0, o = n.y || 0, r = n.radius || 0, l = n.color || "rgba(0,0,0,0.25)"; t.boxShadow = `${s}px ${o}px ${r}px ${l}`; } if (i.clipped && (t.overflow = "hidden"), i.clipShape) { const { shape: n, parameters: s } = i.clipShape; switch (n) { case "circle": t.clipPath = "circle(50%)"; break; case "ellipse": { const o = s?.radiusX || "50%", r = s?.radiusY || "50%"; t.clipPath = `ellipse(${o} ${r} at center)`; break; } case "rect": { const o = s?.inset || 0; t.clipPath = `inset(${o}px)`; break; } case "polygon": { const o = s?.points || "0% 0%, 100% 0%, 100% 100%, 0% 100%"; t.clipPath = `polygon(${o})`; break; } } } const e = []; return i.blur !== void 0 && e.push(`blur(${i.blur}px)`), i.brightness !== void 0 && e.push(`brightness(${i.brightness})`), i.contrast !== void 0 && e.push(`contrast(${i.contrast})`), i.saturation !== void 0 && e.push(`saturate(${i.saturation})`), i.hueRotation !== void 0 && e.push(`hue-rotate(${i.hueRotation}deg)`), i.grayscale !== void 0 && e.push(`grayscale(${i.grayscale})`), i.colorInvert !== void 0 && e.push(`invert(${i.colorInvert})`), e.length > 0 && (t.filter = e.join(" ")), t; } } class R extends L { constructor() { super(...arguments); g(this, "type", "interaction"); g(this, "priority", E.INTERACTION); } apply(i, t) { if (!t.element) return; const e = this.properties; e.onTap && t.element.addEventListener("click", e.onTap), e.onHover && (t.element.addEventListener("mouseenter", () => e.onHover(!0)), t.element.addEventListener("mouseleave", () => e.onHover(!1))), e.onMouseEnter && t.element.addEventListener("mouseenter", e.onMouseEnter), e.onMouseLeave && t.element.addEventListener("mouseleave", e.onMouseLeave), e.onMouseDown && t.element.addEventListener("mousedown", e.onMouseDown), e.onMouseUp && t.element.addEventListener("mouseup", e.onMouseUp), e.onDragStart && t.element.addEventListener("dragstart", e.onDragStart), e.onDragOver && t.element.addEventListener("dragover", e.onDragOver), e.onDragLeave && t.element.addEventListener("dragleave", e.onDragLeave), e.onDrop && t.element.addEventListener("drop", e.onDrop), e.onDoubleClick && t.element.addEventListener("dblclick", e.onDoubleClick), e.onContextMenu && t.element.addEventListener("contextmenu", e.onContextMenu), e.onFocus && (t.element.addEventListener("focus", () => e.onFocus(!0)), t.element.addEventListener("blur", () => e.onFocus(!1))), e.onBlur && t.element.addEventListener("blur", () => e.onBlur(!1)), e.onKeyPress && t.element.addEventListener("keypress", e.onKeyPress), e.onKeyDown && t.element.addEventListener("keydown", e.onKeyDown), e.onKeyUp && t.element.addEventListener("keyup", e.onKeyUp), e.onScroll && t.element.addEventListener("scroll", e.onScroll, { passive: !0 }), e.onWheel && t.element.addEventListener("wheel", e.onWheel, { passive: !1 }), e.onInput && t.element.addEventListener("input", e.onInput), e.onChange && t.element.addEventListener("change", (n) => { const s = n.target, o = s.value || s.textContent || ""; e.onChange(o, n); }), e.onCopy && t.element.addEventListener("copy", e.onCopy), e.onCut && t.element.addEventListener("cut", e.onCut), e.onPaste && t.element.addEventListener("paste", e.onPaste), e.onSelect && t.element.addEventListener("select", e.onSelect), e.disabled !== void 0 && t.element instanceof HTMLElement && (e.disabled ? (t.element.setAttribute("disabled", "true"), t.element.style.pointerEvents = "none", t.element.style.opacity = "0.6") : (t.element.removeAttribute("disabled"), t.element.style.pointerEvents = "", t.element.style.opacity = "")), e.draggable !== void 0 && t.element instanceof HTMLElement && (t.element.draggable = e.draggable), e.accessibilityLabel && t.element.setAttribute("aria-label", e.accessibilityLabel), e.accessibilityHint && t.element.setAttribute("aria-describedby", e.accessibilityHint), e.onLongPressGesture && this.setupLongPressGesture(t.element, e.onLongPressGesture), e.keyboardShortcut && this.setupKeyboardShortcut(t.element, e.keyboardShortcut), e.focused !== void 0 && this.setupFocusManagement(t.element, e.focused), e.focusable && this.setupFocusable(t.element, e.focusable), e.onContinuousHover && this.setupContinuousHover(t.element, e.onContinuousHover), e.allowsHitTesting !== void 0 && this.setupHitTesting(t.element, e.allowsHitTesting); } // Phase 4 Advanced Gesture Methods /** * Setup long press gesture with timing and distance constraints */ setupLongPressGesture(i, t) { const e = t.minimumDuration ?? 500, n = t.maximumDistance ?? 10; let s, o = null, r = !1; const l = () => { s && (clearTimeout(s), s = void 0), r && t.onPressingChanged && t.onPressingChanged(!1), r = !1, o = null; }, c = (h) => { const b = h; o = { x: b.clientX, y: b.clientY }, r = !0, t.onPressingChanged && t.onPressingChanged(!0), s = window.setTimeout(() => { r && o && (t.perform(), l()); }, e); }, f = (h) => { const b = h; if (!o || !r) return; Math.sqrt( Math.pow(b.clientX - o.x, 2) + Math.pow(b.clientY - o.y, 2) ) > n && l(); }, p = () => { l(); }, d = () => { l(); }; i.addEventListener("pointerdown", c), i.addEventListener("pointermove", f), i.addEventListener("pointerup", p), i.addEventListener( "pointercancel", d ), i._longPressCleanup = l; } /** * Setup keyboard shortcut handling */ setupKeyboardShortcut(i, t) { const e = t.modifiers ?? [], n = (s) => { const o = { cmd: e.includes("cmd") || e.includes("meta"), ctrl: e.includes("ctrl"), shift: e.includes("shift"), alt: e.includes("alt") }, r = { cmd: s.metaKey || s.ctrlKey, // Handle both Mac (meta) and PC (ctrl) ctrl: s.ctrlKey, shift: s.shiftKey, alt: s.altKey }, l = s.key.toLowerCase() === t.key.toLowerCase(), c = Object.entries(o).every( ([f, p]) => p === r[f] ); l && c && (s.preventDefault(), t.action()); }; document.addEventListener("keydown", n), i._keyboardShortcutCleanup = () => { document.removeEventListener("keydown", n); }; } /** * Setup focus management with reactive binding */ setupFocusManagement(i, t) { if (!(i instanceof HTMLElement)) return; const e = i; e.hasAttribute("tabindex") || e.setAttribute("tabindex", "0"), u(t) || m(t) ? y(() => { t() ? e.focus() : e.blur(); }) : t && e.focus(); } /** * Setup focusable behavior */ setupFocusable(i, t) { if (!(i instanceof HTMLElement)) return; const e = i; t.isFocusable === !1 ? e.setAttribute("tabindex", "-1") : e.hasAttribute("tabindex") || e.setAttribute("tabindex", "0"), t.interactions?.includes("activate") && e.addEventListener("keydown", (n) => { (n.key === "Enter" || n.key === " ") && (n.preventDefault(), e.click()); }), t.interactions?.includes("edit") && (e.setAttribute("role", "textbox"), e.setAttribute("contenteditable", "true")); } /** * Setup continuous hover tracking with coordinates */ setupContinuousHover(i, t) { const e = t.coordinateSpace ?? "local", n = (o) => { const r = o; let l, c; if (e === "local") { const f = i.getBoundingClientRect(); l = r.clientX - f.left, c = r.clientY - f.top; } else l = r.clientX, c = r.clientY; t.perform({ x: l, y: c }); }, s = () => { t.perform(null); }; i.addEventListener("mousemove", n), i.addEventListener("mouseleave", s), i._continuousHoverCleanup = () => { i.removeEventListener("mousemove", n), i.removeEventListener( "mouseleave", s ); }; } /** * Setup hit testing control */ setupHitTesting(i, t) { i instanceof HTMLElement && (i.style.pointerEvents = t ? "" : "none"); } } class O extends L { constructor() { super(...arguments); g(this, "type", "animation"); g(this, "priority", E.ANIMATION); } apply(i, t) { if (!t.element) return; const e = this.properties; if (e.transition) { const n = e.transition, s = n.property || "all", o = n.duration || 300, r = n.easing || "ease", l = n.delay || 0; t.element instanceof HTMLElement && (t.element.style.transition = `${s} ${o}ms ${r} ${l}ms`); } if (e.animation && t.element instanceof HTMLElement) { const n = e.animation; if (n.keyframes) { const s = `tachui-animation-${t.componentId}-${Date.now()}`, o = this.createKeyframeRule( s, n.keyframes ); this.addKeyframesToStylesheet(o); const r = n.duration || 1e3, l = n.easing || "ease", c = n.iterations || 1, f = n.direction || "normal"; t.element.style.animation = `${s} ${r}ms ${l} ${c} ${f}`; } } if (e.transform && t.element instanceof HTMLElement && (u(e.transform) || m(e.transform) ? y(() => { const n = e.transform(); t.element instanceof HTMLElement && (t.element.style.transform = n); }) : t.element.style.transform = e.transform), e.rotationEffect && t.element instanceof HTMLElement) { const { angle: n, anchor: s } = e.rotationEffect, r = { center: "50% 50%", top: "50% 0%", topLeading: "0% 0%", topTrailing: "100% 0%", bottom: "50% 100%", bottomLeading: "0% 100%", bottomTrailing: "100% 100%", leading: "0% 50%", trailing: "100% 50%" }[s || "center"] || "50% 50%", l = `rotate(${n}deg)`; if (u(n) || m(n)) y(() => { const f = `rotate(${typeof n == "function" ? n() : n}deg)`; if (t.element instanceof HTMLElement) { t.element.style.transformOrigin = r; const d = (t.element.style.transform || "").split(" ").filter((b) => b && !b.startsWith("rotate(")).join(" "), h = d ? `${d} ${f}` : f; t.element.style.transform = h; } }); else if (t.element instanceof HTMLElement) { t.element.style.transformOrigin = r; const f = (t.element.style.transform || "").split(" ").filter((d) => d && !d.startsWith("rotate(")).join(" "), p = f ? `${f} ${l}` : l; t.element.style.transform = p; } } e.overlay && t.element instanceof HTMLElement && this.applyOverlay(t.element, e.overlay, t); } applyOverlay(i, t, e) { const { content: n, alignment: s = "center" } = t; (i.style.position === "" || i.style.position === "static") && (i.style.position = "relative"); const o = document.createElement("div"); o.style.position = "absolute", o.style.pointerEvents = "none"; const r = this.getOverlayAlignment(s); if (Object.assign(o.style, r), typeof n == "function") { const l = n(); if (l && typeof l.render == "function") { const c = l.render(); c.element && o.appendChild(c.element); } } else if (n && typeof n.render == "function") { const l = n.render(); l.element && o.appendChild(l.element); } else n instanceof HTMLElement && o.appendChild(n); i.appendChild(o); } getOverlayAlignment(i) { const t = { center: { top: "50%", left: "50%", transform: "translate(-50%, -50%)" }, top: { top: "0", left: "50%", transform: "translateX(-50%)" }, bottom: { bottom: "0", left: "50%", transform: "translateX(-50%)" }, leading: { top: "50%", left: "0", transform: "translateY(-50%)" }, trailing: { top: "50%", right: "0", transform: "translateY(-50%)" }, topLeading: { top: "0", left: "0" }, topTrailing: { top: "0", right: "0" }, bottomLeading: { bottom: "0", left: "0" }, bottomTrailing: { bottom: "0", right: "0" } }; return t[i] || t.center; } createKeyframeRule(i, t) { let e = `@keyframes ${i} { `; for (const [n, s] of Object.entries(t)) { e += ` ${n} { `; for (const [o, r] of Object.entries(s)) { const l = this.toCSSProperty(o); e += ` ${l}: ${r}; `; } e += ` } `; } return e += "}", e; } addKeyframesToStylesheet(i) { let t = document.querySelector( "#tachui-animations" ); t || (t = document.createElement("style"), t.id = "tachui-animations", document.head.appendChild(t)), t.appendChild(document.createTextNode(i)); } } class D extends L { constructor() { super(...arguments); g(this, "type", "lifecycle"); g(this, "priority", E.CUSTOM); g(this, "activeAbortController"); } apply(i, t) { if (!t.element) return; const e = this.properties; this.activeAbortController && this.activeAbortController.abort(), (e.onAppear || e.onDisappear) && this.setupLifecycleObserver(t.element, e), e.task && this.setupTask(t, e.task), e.refreshable && this.setupRefreshable(t.element, e.refreshable); } setupLifecycleObserver(i, t) { const e = new IntersectionObserver( (n) => { n.forEach((s) => { s.isIntersecting && t.onAppear ? t.onAppear() : !s.isIntersecting && t.onDisappear && t.onDisappear(); }); }, { threshold: 0.1, // Trigger when 10% of element is visible rootMargin: "10px" // Add some margin for better UX } ); e.observe(i), this.addCleanup(() => { e.disconnect(); }); } setupTask(i, t) { if (!t) return; this.activeAbortController = new AbortController(); const { signal: e } = this.activeAbortController; (async () => { try { if (e.aborted) return; const s = t.operation(); s instanceof Promise && await s; } catch (s) { if (e.aborted) return; console.error("TachUI Task Error:", s); } })(), this.addCleanup(() => { this.activeAbortController && this.activeAbortController.abort(); }); } setupRefreshable(i, t) { if (!t) return; let e = !1, n = 0, s = 0; const o = 70, r = document.createElement("div"); if (r.style.cssText = ` position: absolute; top: -50px; left: 50%; transform: translateX(-50%); width: 30px; height: 30px; border: 2px solid #ccc; border-top: 2px solid #007AFF; border-radius: 50%; animation: tachui-spin 1s linear infinite; opacity: 0; transition: opacity 0.3s ease; z-index: 1000; `, !document.querySelector("#tachui-refresh-styles")) { const d = document.createElement("style"); d.id = "tachui-refresh-styles", d.textContent = ` @keyframes tachui-spin { 0% { transform: translateX(-50%) rotate(0deg); } 100% { transform: translateX(-50%) rotate(360deg); } } `, document.head.appendChild(d); } const l = i.parentElement || i; l instanceof HTMLElement && (l.style.position = "relative", l.appendChild(r)); const c = (d) => { e || (s = d.touches[0].clientY); }, f = (d) => { if (e) return; const h = d.touches[0].clientY; if (n = Math.max(0, h - s), n > 20) { d.preventDefault(); const b = Math.min(n / o, 1); r.style.opacity = String(b * 0.8), r.style.top = `${-50 + b * 20}px`; } }, p = async () => { if (e || n < o) { r.style.opacity = "0", r.style.top = "-50px", n = 0; return; } e = !0, r.style.opacity = "1", r.style.top = "10px"; try { await t.onRefresh(); } catch (d) { console.error("TachUI Refresh Error:", d); } finally { e = !1, r.style.opacity = "0", r.style.top = "-50px", n = 0; } }; i.addEventListener("touchstart", c, { passive: !1 }), i.addEventListener("touchmove", f, { passive: !1 }), i.addEventListener("touchend", p), this.addCleanup(() => { i.removeEventListener( "touchstart", c ), i.removeEventListener("touchmove", f), i.removeEventListener("touchend", p), r.parentElement && r.parentElement.removeChild(r); }); } addCleanup(i) { this.properties._cleanupFunctions || (this.properties._cleanupFunctions = []), this.properties._cleanupFunctions.push(i); } } export { I as A, L as B, R as I, V as L, O as a, D as b }; //# sourceMappingURL=base-CkGf4b9G.js.map