@tachui/primitives
Version:
Basic UI components for tachUI framework
475 lines (474 loc) • 15.6 kB
JavaScript
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
};