@tachui/modifiers
Version:
Essential styling modifiers for tachUI framework
775 lines (774 loc) • 23.7 kB
JavaScript
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