UNPKG

@tachui/modifiers

Version:

Essential styling modifiers for tachUI framework

775 lines (774 loc) 23.7 kB
var b = Object.defineProperty; var S = (o, r, e) => r in o ? b(o, r, { enumerable: !0, configurable: !0, writable: !0, value: e }) : o[r] = e; var c = (o, r, e) => S(o, typeof r != "symbol" ? r + "" : r, e); import { B as m } from "./base-CkGf4b9G.js"; import { isSignal as l, isComputed as f, createEffect as g } from "@tachui/core/reactive"; import { BaseModifier as w } from "./base.js"; class y extends m { // Optimized priority for layout modifiers constructor(e) { super(e); c(this, "type", "flexbox"); c(this, "priority", 60); } apply(e, t) { if (!t.element) return; const i = this.computeFlexboxStyles(this.properties); this.applyStyles(t.element, i); } computeFlexboxStyles(e) { const t = {}, i = (n) => typeof n == "number" ? `${n}px` : typeof n == "string" ? /^-?\d*\.?\d+(px|rem|em|%|fr|vw|vh|vmin|vmax)$/.test(n) || [ "auto", "content", "max-content", "min-content", "fit-content", "initial", "inherit", "unset", "none" ].includes(n) ? n : `${n}px` : String(n); return e.display !== void 0 && (t.display = e.display), e.flexGrow !== void 0 && (t.flexGrow = e.flexGrow.toString()), e.flexShrink !== void 0 && (t.flexShrink = e.flexShrink.toString()), e.flexBasis !== void 0 && (t.flexBasis = i(e.flexBasis)), e.flex !== void 0 && (t.flex = typeof e.flex == "number" ? e.flex.toString() : e.flex), e.justifyContent !== void 0 && (t.justifyContent = e.justifyContent), e.alignItems !== void 0 && (t.alignItems = e.alignItems), e.alignContent !== void 0 && (t.alignContent = e.alignContent), e.alignSelf !== void 0 && (t.alignSelf = e.alignSelf), e.flexDirection !== void 0 && (t.flexDirection = e.flexDirection), e.flexWrap !== void 0 && (t.flexWrap = e.flexWrap), e.flexFlow !== void 0 && (t.flexFlow = e.flexFlow), e.gap !== void 0 && (t.gap = i(e.gap)), e.rowGap !== void 0 && (t.rowGap = i(e.rowGap)), e.columnGap !== void 0 && (t.columnGap = i(e.columnGap)), e.placeItems !== void 0 && (t.placeItems = e.placeItems), e.placeContent !== void 0 && (t.placeContent = e.placeContent), e.placeSelf !== void 0 && (t.placeSelf = e.placeSelf), t; } } function d(o) { return new y(o); } function $(o) { return new y({ flexGrow: o }); } function D(o) { return new y({ flexShrink: o }); } function _(o) { return new y({ flexBasis: o }); } function G(o) { return new y({ justifyContent: o }); } function F(o) { return new y({ alignItems: o }); } function A(o) { return new y({ alignSelf: o }); } function T(o) { return new y({ gap: o }); } function R(o) { return new y({ flexDirection: o }); } function z(o) { return new y({ flexWrap: o }); } const Z = { /** * Standard flex container * Sets display: flex for basic flex container */ container: () => d({ display: "flex" }), /** * Inline flex container * Sets display: inline-flex for inline flex behavior */ inline: () => d({ display: "inline-flex" }), /** * Horizontal layout with center alignment * Perfect for nav bars, button groups */ hcenter: () => d({ display: "flex", flexDirection: "row", justifyContent: "center", alignItems: "center" }), /** * Vertical layout with center alignment * Perfect for cards, modals, centered content */ vcenter: () => d({ display: "flex", flexDirection: "column", justifyContent: "center", alignItems: "center" }), /** * Space between layout * Common for headers, footers, navigation */ spaceBetween: () => d({ display: "flex", justifyContent: "space-between", alignItems: "center" }), /** * Space around layout * For even distribution with edge spacing */ spaceAround: () => d({ display: "flex", justifyContent: "space-around", alignItems: "center" }), /** * Column stack with spacing * For vertical component stacks */ vstack: () => d({ display: "flex", flexDirection: "column", gap: 16 }), /** * Row with spacing * For horizontal component layouts */ hstack: () => d({ display: "flex", flexDirection: "row", gap: 16, alignItems: "center" }), /** * Card layout * Column with internal spacing */ card: () => d({ display: "flex", flexDirection: "column", gap: 12 }), /** * Form layout * Column with form-appropriate spacing */ form: () => d({ display: "flex", flexDirection: "column", gap: 20 }), /** * Button group * Horizontal with tight spacing */ buttonGroup: () => d({ display: "flex", flexDirection: "row", gap: 8, alignItems: "center" }), /** * Sidebar layout * Vertical with stretch alignment */ sidebar: () => d({ display: "flex", flexDirection: "column", alignItems: "stretch" }), /** * Responsive wrap * Wrapping layout with gaps */ wrap: () => d({ display: "flex", flexWrap: "wrap", gap: 16 }), /** * Full flex item * Grows and shrinks to fill space */ fill: () => d({ flex: 1 }), /** * Fixed flex item * Doesn't grow or shrink */ fixed: () => d({ flexGrow: 0, flexShrink: 0 }), /** * Stretch alignment * Items stretch to container height */ stretch: () => d({ display: "flex", alignItems: "stretch" }) }; class E extends m { constructor() { super(...arguments); c(this, "type", "offset"); c(this, "priority", 35); } // High priority for transform operations apply(e, t) { if (!t.element) return; const { x: i, y: n = 0 } = this.properties; l(i) || f(i) || l(n) || f(n) ? g(() => { const s = l(i) || f(i) ? i() : i, a = l(n) || f(n) ? n() : n; this.applyOffset(t.element, s, a); }) : this.applyOffset(t.element, i, n); } applyOffset(e, t, i) { const n = this.toCSSValue(t), s = this.toCSSValue(i), a = `translate(${n}, ${s})`, p = (e.style.transform || "").replace(/\s*translate(?!Z\(0\))[XYZ3d]*\([^)]*\)\s*/g, " ").replace(/\s+/g, " ").trim(), v = p ? `${p} ${a}` : a; e.style.transform = v; } /** * Development mode validation */ validateOffset(e, t) { if (typeof process < "u" && process.env.NODE_ENV === "development") { typeof e != "number" && !l(e) && !f(e) && console.warn( `OffsetModifier: x value must be a number or reactive signal. Got: ${typeof e}` ), t !== void 0 && typeof t != "number" && !l(t) && !f(t) && console.warn( `OffsetModifier: y value must be a number or reactive signal. Got: ${typeof t}` ); const i = (n, s) => { const a = l(n) || f(n) ? n.peek?.() || n() : n; typeof a == "number" && (Math.abs(a) > 1e3 && console.warn( "OffsetModifier: Very large offset values may cause layout issues" ), a !== Math.round(a * 100) / 100 && console.info( "OffsetModifier: Consider rounding offset values to 2 decimal places for better performance" )); }; i(e), t !== void 0 && i(t); } } } function B(o, r) { const e = new E({ x: o, y: r ?? 0 }); return typeof process < "u" && process.env.NODE_ENV === "development" && e.validateOffset(o, r), e; } class M extends m { constructor() { super(...arguments); c(this, "type", "scaleEffect"); c(this, "priority", 35); } // High priority for transform operations apply(e, t) { if (!t.element) return; const { x: i, y: n, anchor: s = "center" } = this.properties, a = n ?? i; typeof process < "u" && process.env.NODE_ENV === "development" && this.validateScale(i, a, s), l(i) || f(i) || l(a) || f(a) ? g(() => { const u = l(i) || f(i) ? i() : i, p = l(a) || f(a) ? a() : a; this.applyScale( t.element, u, p, s ); }) : this.applyScale(t.element, i, a, s); } applyScale(e, t, i, n) { const s = `scale(${t}, ${i})`; e.style.transformOrigin = this.getTransformOrigin(n); const u = (e.style.transform || "").replace(/\s*scale[XYZ3d]*\([^)]*\)\s*/g, " ").replace(/\s+/g, " ").trim(), p = u ? `${u} ${s}`.trim() : s; e.style.transform = p; } getTransformOrigin(e) { 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" }[e]; } /** * Development mode validation */ validateScale(e, t, i) { if (typeof process < "u" && process.env.NODE_ENV === "development") { typeof e != "number" && !l(e) && !f(e) && console.warn( `ScaleEffectModifier: x value must be a number or reactive signal. Got: ${typeof e}` ), typeof t != "number" && !l(t) && !f(t) && console.warn( `ScaleEffectModifier: y value must be a number or reactive signal. Got: ${typeof t}` ); const n = [ "center", "top", "topLeading", "topTrailing", "bottom", "bottomLeading", "bottomTrailing", "leading", "trailing" ]; n.includes(i) || console.warn( `ScaleEffectModifier: Invalid anchor "${i}". Valid anchors:`, n ); const s = (a, u) => { const p = l(a) || f(a) ? a.peek?.() || a() : a; typeof p == "number" && (p <= 0 && console.warn( `ScaleEffectModifier: ${u} scale value ${p} will make element invisible` ), p > 10 && console.warn( `ScaleEffectModifier: Large ${u} scale (${p}) may impact performance and cause visual issues` ), p !== Math.round(p * 100) / 100 && console.info( `ScaleEffectModifier: Consider rounding ${u} scale to 2 decimal places for better performance` )); }; s(e, "x"), s(t, "y"); } } } function j(o, r, e = "center") { return new M({ x: o, y: r, anchor: e }); } class x extends m { constructor() { super(...arguments); c(this, "type", "aspectRatio"); c(this, "priority", 20); } // Medium priority for layout properties apply(e, t) { if (!t.element) return; const { ratio: i, contentMode: n } = this.properties; typeof process < "u" && process.env.NODE_ENV === "development" && this.validateAspectRatio(i, n), i !== void 0 ? l(i) || f(i) ? g(() => { const s = i(); this.applyAspectRatio( t.element, s, n ); }) : this.applyAspectRatio( t.element, i, n ) : this.applyContentMode(t.element, n); } applyAspectRatio(e, t, i) { e.style.aspectRatio = String(t), this.applyContentMode(e, i); } applyContentMode(e, t) { t === "fill" ? (e.style.objectFit = "cover", this.isMediaElement(e) || (e.style.width = "100%", e.style.height = "100%")) : (e.style.objectFit = "contain", this.isMediaElement(e) || (e.style.maxWidth = "100%", e.style.maxHeight = "100%")); } isMediaElement(e) { return ["IMG", "VIDEO", "CANVAS", "SVG", "IFRAME"].includes(e.tagName); } /** * Development mode validation */ validateAspectRatio(e, t) { if (typeof process < "u" && process.env.NODE_ENV === "development") { if (e !== void 0) { typeof e != "number" && !l(e) && !f(e) && console.warn( `AspectRatioModifier: ratio must be a number or reactive signal. Got: ${typeof e}` ); const n = l(e) || f(e) ? e.peek?.() || e() : e; typeof n == "number" && (n <= 0 && console.warn( `AspectRatioModifier: ratio must be positive. Got: ${n}` ), n > 100 && console.warn( `AspectRatioModifier: Very large ratio (${n}) may cause layout issues` ), n < 0.01 && console.warn( `AspectRatioModifier: Very small ratio (${n}) may cause layout issues` )); } const i = ["fit", "fill"]; i.includes(t) || console.warn( `AspectRatioModifier: Invalid content mode "${t}". Valid modes:`, i ); } } } /** * Get common aspect ratios */ c(x, "COMMON_RATIOS", { square: 1, portrait: 3 / 4, landscape: 4 / 3, widescreen: 16 / 9, ultrawide: 21 / 9, golden: 1.618, photo: 3 / 2 }); function H(o, r = "fit") { return new x({ ratio: o, contentMode: r }); } class I extends m { constructor() { super(...arguments); c(this, "type", "fixedSize"); c(this, "priority", 25); } // Medium priority for layout properties apply(e, t) { if (!t.element) return; const { horizontal: i, vertical: n } = this.properties; typeof process < "u" && process.env.NODE_ENV === "development" && this.validateFixedSize(i, n), this.applyFixedSize(t.element, i, n); } applyFixedSize(e, t, i) { t && (e.style.maxWidth = "max-content", e.style.width = "max-content", e.style.flexShrink = "0", e.style.flexBasis = "auto", this.isTextElement(e) && (e.style.whiteSpace = "nowrap")), i && (e.style.maxHeight = "max-content", e.style.height = "max-content", this.isFlexItem(e) && (e.style.alignSelf = "flex-start")), t && i && (e.style.display = e.style.display || "inline-block"); } isTextElement(e) { return [ "P", "SPAN", "DIV", "H1", "H2", "H3", "H4", "H5", "H6", "LABEL" ].includes(e.tagName) && e.childNodes.length > 0 || e.childNodes.length > 0 && Array.from(e.childNodes).some( (i) => i.nodeType === Node.TEXT_NODE ); } isFlexItem(e) { const t = e.parentElement; if (!t) return !1; const i = getComputedStyle(t).display; return i === "flex" || i === "inline-flex"; } /** * Development mode validation */ validateFixedSize(e, t) { typeof process < "u" && process.env.NODE_ENV === "development" && (typeof e != "boolean" && console.warn( `FixedSizeModifier: horizontal must be a boolean. Got: ${typeof e}` ), typeof t != "boolean" && console.warn( `FixedSizeModifier: vertical must be a boolean. Got: ${typeof t}` ), !e && !t && console.warn( "FixedSizeModifier: Both horizontal and vertical are false - this modifier has no effect" ), e && t ? console.info( "FixedSizeModifier: Element will be sized to its content in both dimensions (like display: inline-block)" ) : e ? console.info( "FixedSizeModifier: Element width will be fixed to content size (prevents text wrapping)" ) : t && console.info( "FixedSizeModifier: Element height will be fixed to content size" )); } } function L(o = !0, r = !0) { return new I({ horizontal: o, vertical: r }); } class C extends m { constructor() { super(...arguments); c(this, "type", "position"); c(this, "priority", 50); } // Highest priority to override other positioning apply(e, t) { if (!t.element) return; const { position: i } = this.properties; typeof process < "u" && process.env.NODE_ENV === "development" && this.validatePosition(i), l(i) || f(i) ? g(() => { const n = i(); this.applyPosition(t.element, n); }) : this.applyPosition(t.element, i); } applyPosition(e, t) { e.style.position = t, this.applyPositionOptimizations(e, t); } applyPositionOptimizations(e, t) { if (typeof process < "u" && process.env.NODE_ENV === "development") switch (t) { case "absolute": this.warnIfMissingPositionedParent(e); break; case "fixed": console.info( "PositionModifier: Fixed positioning relative to viewport. Consider impact on mobile layouts." ); break; case "sticky": this.warnIfMissingStickyProperties(e); break; case "relative": break; case "static": this.warnIfHasPositioningProperties(e); break; } (t === "absolute" || t === "fixed") && (e.style.zIndex || (e.style.zIndex = "0"), e.style.transform || (e.style.transform = "translateZ(0)")); } warnIfMissingPositionedParent(e) { let t = e.parentElement, i = !1; for (; t && t !== document.body; ) { if (getComputedStyle(t).position !== "static") { i = !0; break; } t = t.parentElement; } i || console.warn( "PositionModifier: Absolutely positioned element may not have expected behavior without a positioned parent (relative, absolute, or fixed)" ); } warnIfMissingStickyProperties(e) { const t = getComputedStyle(e); t.top !== "auto" || t.right !== "auto" || t.bottom !== "auto" || t.left !== "auto" || console.warn( "PositionModifier: Sticky positioning requires at least one of top, right, bottom, or left to be set" ); } warnIfHasPositioningProperties(e) { const t = getComputedStyle(e); (t.top !== "auto" || t.right !== "auto" || t.bottom !== "auto" || t.left !== "auto") && console.warn( "PositionModifier: Static positioning ignores top, right, bottom, and left properties" ); } /** * Development mode validation */ validatePosition(e) { if (typeof process < "u" && process.env.NODE_ENV === "development") { const t = l(e) || f(e); if (!t && typeof e != "string") { console.warn( `PositionModifier: position must be a string or reactive signal. Got: ${typeof e}` ); return; } const i = t ? e.peek?.() || e() : e, n = [ "static", "relative", "absolute", "fixed", "sticky" ]; n.includes(i) || console.warn( `PositionModifier: Invalid position value "${i}". Valid values:`, n ), i === "sticky" && console.info( "PositionModifier: Sticky positioning may need vendor prefixes for older browsers" ); } } } function X(o) { return new C({ position: o }); } class h extends m { constructor() { super(...arguments); c(this, "type", "zIndex"); c(this, "priority", 45); } // High priority for layering apply(e, t) { if (!t.element) return; const { zIndex: i } = this.properties; typeof process < "u" && process.env.NODE_ENV === "development" && this.validateZIndex(i), l(i) || f(i) ? g(() => { const n = i(); this.applyZIndex(t.element, n); }) : this.applyZIndex(t.element, i); } applyZIndex(e, t) { e.style.zIndex = String(t), this.ensureStackingContext(e, t); } ensureStackingContext(e, t) { const s = getComputedStyle(e).position !== "static", a = this.isFlexItem(e), u = this.isGridItem(e); !s && !a && !u && (e.style.position = "relative", typeof process < "u" && process.env.NODE_ENV === "development" && console.info( "ZIndexModifier: Set position: relative on element to enable z-index stacking" )), typeof process < "u" && process.env.NODE_ENV === "development" && this.provideStackingInsights(e, t); } isFlexItem(e) { const t = e.parentElement; if (!t) return !1; const i = getComputedStyle(t).display; return i === "flex" || i === "inline-flex"; } isGridItem(e) { const t = e.parentElement; if (!t) return !1; const i = getComputedStyle(t).display; return i === "grid" || i === "inline-grid"; } provideStackingInsights(e, t) { t < 0 ? console.info( "ZIndexModifier: Negative z-index will layer behind the normal stacking order" ) : t > 1e3 && console.warn( `ZIndexModifier: Very high z-index (${t}) may cause stacking conflicts. Consider using semantic ranges.` ), this.checkStackingContext(e); } checkStackingContext(e) { const t = getComputedStyle(e), n = [ { prop: "opacity", value: t.opacity, creates: t.opacity !== "1" }, { prop: "transform", value: t.transform, creates: t.transform !== "none" }, { prop: "filter", value: t.filter, creates: t.filter !== "none" }, { prop: "isolation", value: t.isolation, creates: t.isolation === "isolate" }, { prop: "mix-blend-mode", value: t.mixBlendMode, creates: t.mixBlendMode !== "normal" } ].filter((s) => s.creates); n.length > 0 && console.info( "ZIndexModifier: Element creates new stacking context due to:", n.map((s) => `${s.prop}: ${s.value}`).join(", ") ); } /** * Development mode validation */ validateZIndex(e) { if (typeof process < "u" && process.env.NODE_ENV === "development") { const t = l(e) || f(e); if (!t && typeof e != "number") { console.warn( `ZIndexModifier: zIndex must be a number or reactive signal. Got: ${typeof e}` ); return; } const i = t ? e.peek?.() || e() : e; typeof i == "number" && (Number.isInteger(i) || console.warn( `ZIndexModifier: z-index should be an integer. Got: ${i}` ), (i > Number.MAX_SAFE_INTEGER || i < Number.MIN_SAFE_INTEGER) && console.warn( `ZIndexModifier: z-index value ${i} is outside safe integer range` )); } } } /** * Common z-index values for semantic layering */ c(h, "COMMON_LAYERS", { background: -1, base: 0, content: 1, navigation: 100, dropdown: 200, overlay: 300, modal: 400, tooltip: 500, toast: 600, debug: 9999 }); function Y(o) { return new h({ zIndex: o }); } class N extends w { constructor() { super(...arguments); c(this, "type", "overlay"); c(this, "priority", 10); } // Apply late so positioning is relative to final layout apply(e, t) { if (!t.element) return; const i = t.element; if (!i.style) return; const { content: n, alignment: s = "center" } = this.properties; this.applyOverlay(i, n, s, t); } applyOverlay(e, t, i, n) { (e.style.position === "" || e.style.position === "static") && (e.style.position = "relative"); const s = document.createElement("div"); s.style.position = "absolute", s.style.pointerEvents = "none"; const a = this.getOverlayAlignment(i); Object.assign(s.style, a), this.renderContent(s, t), e.appendChild(s); } renderContent(e, t) { if (typeof t == "function") { const i = t(); if (i && typeof i.render == "function") { const n = i.render(); n.element && e.appendChild(n.element); } } else if (t && typeof t.render == "function") { const i = t.render(); i.element && e.appendChild(i.element); } else t && (t instanceof HTMLElement || t.appendChild) && e.appendChild(t); } getOverlayAlignment(e) { const t = { center: { top: "50%", left: "50%", transform: "translate(-50%, -50%)" }, top: { top: "0px", left: "50%", transform: "translateX(-50%)" }, bottom: { bottom: "0px", left: "50%", transform: "translateX(-50%)" }, leading: { top: "50%", left: "0px", transform: "translateY(-50%)" }, trailing: { top: "50%", right: "0px", transform: "translateY(-50%)" }, topLeading: { top: "0px", left: "0px" }, topTrailing: { top: "0px", right: "0px" }, bottomLeading: { bottom: "0px", left: "0px" }, bottomTrailing: { bottom: "0px", right: "0px" } }; return t[e] || t.center; } } function W(o, r = "center") { return new N({ content: o, alignment: r }); } export { x as A, y as F, E as O, C as P, M as S, h as Z, $ as a, D as b, _ as c, F as d, A as e, d as f, T as g, R as h, z as i, G as j, Z as k, H as l, I as m, L as n, B as o, X as p, N as q, W as r, j as s, Y as z }; //# sourceMappingURL=overlay-DDiSLprp.js.map