@xscriptor/xcomponents 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/CODE_OF_CONDUCT.md +35 -0
  2. package/CONTRIBUTING.md +64 -0
  3. package/LICENSE +21 -0
  4. package/README.md +127 -0
  5. package/SECURITY.md +25 -0
  6. package/dist/chunk-2OAXRRVQ.mjs +150 -0
  7. package/dist/chunk-2OAXRRVQ.mjs.map +1 -0
  8. package/dist/chunk-42XPBYTL.mjs +186 -0
  9. package/dist/chunk-42XPBYTL.mjs.map +1 -0
  10. package/dist/chunk-5G4P2E76.mjs +66 -0
  11. package/dist/chunk-5G4P2E76.mjs.map +1 -0
  12. package/dist/chunk-FZRTAML3.mjs +1 -0
  13. package/dist/chunk-FZRTAML3.mjs.map +1 -0
  14. package/dist/chunk-NY22GB3E.mjs +311 -0
  15. package/dist/chunk-NY22GB3E.mjs.map +1 -0
  16. package/dist/chunk-QCMWPIG7.mjs +320 -0
  17. package/dist/chunk-QCMWPIG7.mjs.map +1 -0
  18. package/dist/chunk-U27ZVCP7.mjs +247 -0
  19. package/dist/chunk-U27ZVCP7.mjs.map +1 -0
  20. package/dist/components/content/index.css +132 -0
  21. package/dist/components/content/index.css.map +1 -0
  22. package/dist/components/content/index.d.mts +17 -0
  23. package/dist/components/content/index.d.ts +17 -0
  24. package/dist/components/content/index.js +102 -0
  25. package/dist/components/content/index.js.map +1 -0
  26. package/dist/components/content/index.mjs +7 -0
  27. package/dist/components/content/index.mjs.map +1 -0
  28. package/dist/components/forms/index.css +307 -0
  29. package/dist/components/forms/index.css.map +1 -0
  30. package/dist/components/forms/index.d.mts +68 -0
  31. package/dist/components/forms/index.d.ts +68 -0
  32. package/dist/components/forms/index.js +357 -0
  33. package/dist/components/forms/index.js.map +1 -0
  34. package/dist/components/forms/index.mjs +9 -0
  35. package/dist/components/forms/index.mjs.map +1 -0
  36. package/dist/components/gallery/index.css +229 -0
  37. package/dist/components/gallery/index.css.map +1 -0
  38. package/dist/components/gallery/index.d.mts +29 -0
  39. package/dist/components/gallery/index.d.ts +29 -0
  40. package/dist/components/gallery/index.js +187 -0
  41. package/dist/components/gallery/index.js.map +1 -0
  42. package/dist/components/gallery/index.mjs +9 -0
  43. package/dist/components/gallery/index.mjs.map +1 -0
  44. package/dist/components/index.css +1181 -0
  45. package/dist/components/index.css.map +1 -0
  46. package/dist/components/index.d.mts +8 -0
  47. package/dist/components/index.d.ts +8 -0
  48. package/dist/components/index.js +1317 -0
  49. package/dist/components/index.js.map +1 -0
  50. package/dist/components/index.mjs +50 -0
  51. package/dist/components/index.mjs.map +1 -0
  52. package/dist/components/layout/index.css +168 -0
  53. package/dist/components/layout/index.css.map +1 -0
  54. package/dist/components/layout/index.d.mts +55 -0
  55. package/dist/components/layout/index.d.ts +55 -0
  56. package/dist/components/layout/index.js +224 -0
  57. package/dist/components/layout/index.js.map +1 -0
  58. package/dist/components/layout/index.mjs +11 -0
  59. package/dist/components/layout/index.mjs.map +1 -0
  60. package/dist/components/navigation/index.css +229 -0
  61. package/dist/components/navigation/index.css.map +1 -0
  62. package/dist/components/navigation/index.d.mts +76 -0
  63. package/dist/components/navigation/index.d.ts +76 -0
  64. package/dist/components/navigation/index.js +347 -0
  65. package/dist/components/navigation/index.js.map +1 -0
  66. package/dist/components/navigation/index.mjs +7 -0
  67. package/dist/components/navigation/index.mjs.map +1 -0
  68. package/dist/components/social/index.css +116 -0
  69. package/dist/components/social/index.css.map +1 -0
  70. package/dist/components/social/index.d.mts +55 -0
  71. package/dist/components/social/index.d.ts +55 -0
  72. package/dist/components/social/index.js +280 -0
  73. package/dist/components/social/index.js.map +1 -0
  74. package/dist/components/social/index.mjs +21 -0
  75. package/dist/components/social/index.mjs.map +1 -0
  76. package/dist/index.css +1181 -0
  77. package/dist/index.css.map +1 -0
  78. package/dist/index.d.mts +8 -0
  79. package/dist/index.d.ts +8 -0
  80. package/dist/index.js +1317 -0
  81. package/dist/index.js.map +1 -0
  82. package/dist/index.mjs +50 -0
  83. package/dist/index.mjs.map +1 -0
  84. package/package.json +86 -0
@@ -0,0 +1,55 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React, { HTMLAttributes } from 'react';
3
+
4
+ type XFooterLink = {
5
+ label: string;
6
+ href: string;
7
+ };
8
+ type CopyrightConfig = {
9
+ text?: string;
10
+ showYear?: boolean;
11
+ customYear?: number | string;
12
+ yearFirst?: boolean;
13
+ };
14
+ type XFooterProps = {
15
+ links: XFooterLink[];
16
+ copyright?: CopyrightConfig;
17
+ layout?: "horizontal" | "vertical";
18
+ columns?: 1 | 2 | 3 | 4;
19
+ colors?: {
20
+ bg?: string;
21
+ text?: string;
22
+ accent?: string;
23
+ border?: string;
24
+ };
25
+ className?: string;
26
+ };
27
+ declare function XFooter({ links, copyright, layout, columns, colors, className, }: XFooterProps): react_jsx_runtime.JSX.Element;
28
+
29
+ interface XSeparatorProps {
30
+ orientation?: 'horizontal' | 'vertical';
31
+ variant?: 'solid' | 'dashed' | 'dotted';
32
+ isFaded?: boolean;
33
+ hasX?: boolean;
34
+ xColor?: string;
35
+ xBg?: string;
36
+ thickness?: string;
37
+ color?: string;
38
+ gap?: string;
39
+ className?: string;
40
+ }
41
+ declare function XSeparator({ orientation, variant, isFaded, hasX, xColor, xBg, thickness, color, gap, className }: XSeparatorProps): react_jsx_runtime.JSX.Element;
42
+
43
+ type XZigZagLayoutProps = HTMLAttributes<HTMLDivElement> & {
44
+ children: React.ReactNode;
45
+ startSide?: "left" | "right";
46
+ gap?: number | string;
47
+ offset?: number | string;
48
+ textAlign?: "inherit" | "side" | "left" | "right";
49
+ showLine?: boolean;
50
+ lineColor?: string;
51
+ lineThickness?: number | string;
52
+ };
53
+ declare function XZigZagLayout({ children, className, style, startSide, gap, offset, textAlign, showLine, lineColor, lineThickness, ...rest }: XZigZagLayoutProps): react_jsx_runtime.JSX.Element;
54
+
55
+ export { type CopyrightConfig, XFooter, type XFooterLink, type XFooterProps, XSeparator, type XSeparatorProps, XZigZagLayout, type XZigZagLayoutProps };
@@ -0,0 +1,224 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/components/layout/index.ts
31
+ var layout_exports = {};
32
+ __export(layout_exports, {
33
+ XFooter: () => XFooter,
34
+ XSeparator: () => XSeparator,
35
+ XZigZagLayout: () => XZigZagLayout
36
+ });
37
+ module.exports = __toCommonJS(layout_exports);
38
+
39
+ // src/components/layout/xfooter/XFooter.tsx
40
+ var import_link = __toESM(require("next/link"));
41
+
42
+ // src/components/layout/xfooter/XFooter.module.css
43
+ var XFooter_default = {};
44
+
45
+ // src/components/layout/xfooter/XFooter.tsx
46
+ var import_jsx_runtime = require("react/jsx-runtime");
47
+ function XFooter({
48
+ links,
49
+ copyright,
50
+ layout = "horizontal",
51
+ columns = 1,
52
+ colors,
53
+ className = ""
54
+ }) {
55
+ const customStyles = {
56
+ "--xf-bg": colors?.bg,
57
+ "--xf-text": colors?.text,
58
+ "--xf-accent": colors?.accent,
59
+ "--xf-border": colors?.border,
60
+ "--xf-cols": layout === "horizontal" ? columns : 1
61
+ };
62
+ const currentYear = copyright?.customYear || (/* @__PURE__ */ new Date()).getFullYear();
63
+ const copyLabel = copyright?.text || "Xscriptor";
64
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("footer", { className: `${XFooter_default.XFooter} ${className}`, style: customStyles, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: XFooter_default.container, children: [
65
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("nav", { className: layout === "vertical" ? XFooter_default.navVertical : XFooter_default.nav, children: links.map((link, idx) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_link.default, { href: link.href, className: XFooter_default.link, children: link.label }, idx)) }),
66
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: XFooter_default.copyright, children: [
67
+ "\xA9 ",
68
+ copyright?.yearFirst ? `${currentYear} ${copyLabel}` : `${copyLabel} ${currentYear}`
69
+ ] })
70
+ ] }) });
71
+ }
72
+
73
+ // src/components/layout/xseparator/XSeparator.module.css
74
+ var XSeparator_default = {};
75
+
76
+ // src/components/layout/xseparator/XSeparator.tsx
77
+ var import_jsx_runtime2 = require("react/jsx-runtime");
78
+ function XSeparator({
79
+ orientation = "horizontal",
80
+ variant = "solid",
81
+ isFaded = false,
82
+ hasX = false,
83
+ xColor,
84
+ xBg = "white",
85
+ thickness = "1px",
86
+ color = "#e2e8f0",
87
+ gap = "1rem",
88
+ className = ""
89
+ }) {
90
+ const dynamicStyles = {
91
+ "--separator-color": color,
92
+ "--separator-thickness": thickness,
93
+ "--separator-margin": gap,
94
+ "--x-color": xColor || color,
95
+ // Si no se define xColor, usa el color de la línea
96
+ "--x-bg": xBg
97
+ };
98
+ const classes = [
99
+ XSeparator_default.separator,
100
+ orientation === "vertical" ? XSeparator_default.vertical : XSeparator_default.horizontal,
101
+ variant !== "solid" && XSeparator_default[variant],
102
+ isFaded && XSeparator_default.faded
103
+ ].filter(Boolean).join(" ");
104
+ const line = /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("hr", { className: classes, style: dynamicStyles });
105
+ if (!hasX) return line;
106
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: `${XSeparator_default.separatorContainer} ${className}`, style: dynamicStyles, children: [
107
+ line,
108
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: XSeparator_default.iconWrapper, children: "\u2715" })
109
+ ] });
110
+ }
111
+
112
+ // src/components/layout/xzigzaglayout/XZigZagLayout.tsx
113
+ var import_react = require("react");
114
+
115
+ // src/components/layout/xzigzaglayout/XZigZagLayout.module.css
116
+ var XZigZagLayout_default = {};
117
+
118
+ // src/components/layout/xzigzaglayout/XZigZagLayout.tsx
119
+ var import_jsx_runtime3 = require("react/jsx-runtime");
120
+ function XZigZagLayout({
121
+ children,
122
+ className,
123
+ style,
124
+ startSide = "left",
125
+ gap,
126
+ offset,
127
+ textAlign = "inherit",
128
+ showLine = false,
129
+ lineColor = "#cccccc",
130
+ lineThickness = 2,
131
+ ...rest
132
+ }) {
133
+ const items = import_react.Children.toArray(children).filter(Boolean);
134
+ const containerRef = (0, import_react.useRef)(null);
135
+ const itemsRef = (0, import_react.useRef)([]);
136
+ const pathRef = (0, import_react.useRef)(null);
137
+ const [points, setPoints] = (0, import_react.useState)([]);
138
+ const [pathLength, setPathLength] = (0, import_react.useState)(0);
139
+ const [drawProgress, setDrawProgress] = (0, import_react.useState)(0);
140
+ const calculatePoints = (0, import_react.useCallback)(() => {
141
+ if (!containerRef.current) return;
142
+ const containerRect = containerRef.current.getBoundingClientRect();
143
+ const newPoints = itemsRef.current.filter(Boolean).map((el) => {
144
+ const rect = el.getBoundingClientRect();
145
+ return {
146
+ x: rect.left + rect.width / 2 - containerRect.left,
147
+ y: rect.top + rect.height / 2 - containerRect.top
148
+ };
149
+ });
150
+ if (newPoints.length > 0) {
151
+ newPoints.unshift({ x: newPoints[0].x, y: 0 });
152
+ newPoints.push({ x: newPoints[newPoints.length - 1].x, y: containerRect.height });
153
+ }
154
+ setPoints(newPoints);
155
+ }, []);
156
+ (0, import_react.useEffect)(() => {
157
+ if (!showLine || !containerRef.current) return;
158
+ const observer = new ResizeObserver(() => calculatePoints());
159
+ observer.observe(containerRef.current);
160
+ calculatePoints();
161
+ return () => observer.disconnect();
162
+ }, [showLine, calculatePoints]);
163
+ (0, import_react.useEffect)(() => {
164
+ if (pathRef.current) setPathLength(pathRef.current.getTotalLength());
165
+ }, [points]);
166
+ (0, import_react.useEffect)(() => {
167
+ if (!showLine) return;
168
+ const handleScroll = () => {
169
+ if (!containerRef.current) return;
170
+ const { top, height } = containerRef.current.getBoundingClientRect();
171
+ const windowHeight = window.innerHeight;
172
+ const start = windowHeight / 2;
173
+ const progress = (start - top) / height;
174
+ setDrawProgress(Math.min(Math.max(progress, 0), 1));
175
+ };
176
+ window.addEventListener("scroll", handleScroll);
177
+ handleScroll();
178
+ return () => window.removeEventListener("scroll", handleScroll);
179
+ }, [showLine]);
180
+ const cssVars = {};
181
+ if (gap !== void 0) cssVars["--x-zigzag-gap"] = typeof gap === "number" ? `${gap}px` : gap;
182
+ if (offset !== void 0) cssVars["--x-zigzag-offset"] = typeof offset === "number" ? `${offset}px` : offset;
183
+ const mergedStyle = { ...style, ...cssVars };
184
+ const pathD = points.length > 0 ? `M ${points[0].x} ${points[0].y} ` + points.slice(1).map((p) => `L ${p.x} ${p.y}`).join(" ") : "";
185
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
186
+ "div",
187
+ {
188
+ ref: containerRef,
189
+ ...rest,
190
+ className: [XZigZagLayout_default.layout, className].filter(Boolean).join(" "),
191
+ style: mergedStyle,
192
+ children: [
193
+ showLine && points.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("svg", { className: XZigZagLayout_default.svgLine, xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
194
+ "path",
195
+ {
196
+ ref: pathRef,
197
+ d: pathD,
198
+ fill: "none",
199
+ stroke: lineColor,
200
+ strokeWidth: lineThickness,
201
+ strokeDasharray: pathLength,
202
+ strokeDashoffset: pathLength - pathLength * drawProgress,
203
+ style: { transition: "stroke-dashoffset 0.1s ease-out" }
204
+ }
205
+ ) }),
206
+ items.map((child, index) => {
207
+ const isStartLeft = startSide === "left";
208
+ const alignLeft = isStartLeft ? index % 2 === 0 : index % 2 !== 0;
209
+ const alignmentClass = textAlign === "side" ? alignLeft ? XZigZagLayout_default.textLeft : XZigZagLayout_default.textRight : textAlign === "left" ? XZigZagLayout_default.textLeft : textAlign === "right" ? XZigZagLayout_default.textRight : "";
210
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: `${XZigZagLayout_default.item} ${alignLeft ? XZigZagLayout_default.left : XZigZagLayout_default.right} ${alignmentClass}`, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { ref: (el) => {
211
+ itemsRef.current[index] = el;
212
+ }, className: XZigZagLayout_default.contentWrapper, children: child }) }, index);
213
+ })
214
+ ]
215
+ }
216
+ );
217
+ }
218
+ // Annotate the CommonJS export names for ESM import in node:
219
+ 0 && (module.exports = {
220
+ XFooter,
221
+ XSeparator,
222
+ XZigZagLayout
223
+ });
224
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/layout/index.ts","../../../src/components/layout/xfooter/XFooter.tsx","../../../src/components/layout/xfooter/XFooter.module.css","../../../src/components/layout/xseparator/XSeparator.module.css","../../../src/components/layout/xseparator/XSeparator.tsx","../../../src/components/layout/xzigzaglayout/XZigZagLayout.tsx","../../../src/components/layout/xzigzaglayout/XZigZagLayout.module.css"],"sourcesContent":["export { XFooter } from \"./xfooter\";\nexport { XSeparator } from \"./xseparator\";\nexport { XZigZagLayout } from \"./xzigzaglayout\";\nexport type { XFooterProps, XFooterLink, CopyrightConfig } from \"./xfooter\";\nexport type { XSeparatorProps } from \"./xseparator\";\nexport type { XZigZagLayoutProps } from \"./xzigzaglayout\";\n","import Link from \"next/link\";\nimport { CSSProperties } from \"react\";\nimport styles from \"./XFooter.module.css\";\n\nexport type XFooterLink = {\n label: string;\n href: string;\n};\n\nexport type CopyrightConfig = {\n text?: string;\n showYear?: boolean;\n customYear?: number | string;\n yearFirst?: boolean;\n};\n\nexport type XFooterProps = {\n links: XFooterLink[];\n copyright?: CopyrightConfig; \n layout?: \"horizontal\" | \"vertical\";\n columns?: 1 | 2 | 3 | 4;\n colors?: {\n bg?: string;\n text?: string;\n accent?: string;\n border?: string;\n };\n className?: string;\n};\nexport default function XFooter({\n links,\n copyright,\n layout = \"horizontal\",\n columns = 1,\n colors,\n className = \"\",\n}: XFooterProps) {\n \n const customStyles = {\n \"--xf-bg\": colors?.bg,\n \"--xf-text\": colors?.text,\n \"--xf-accent\": colors?.accent,\n \"--xf-border\": colors?.border,\n \"--xf-cols\": layout === \"horizontal\" ? columns : 1,\n } as CSSProperties;\n\n const currentYear = copyright?.customYear || new Date().getFullYear();\n const copyLabel = copyright?.text || \"Xscriptor\";\n\n return (\n <footer className={`${styles.XFooter} ${className}`} style={customStyles}>\n <div className={styles.container}>\n {/* Los links se organizan en el grid definido por --xf-cols */}\n <nav className={layout === \"vertical\" ? styles.navVertical : styles.nav}>\n {links.map((link, idx) => (\n <Link key={idx} href={link.href} className={styles.link}>\n {link.label}\n </Link>\n ))}\n </nav>\n\n {/* El copyright queda fuera del nav, por lo que hereda el centrado del container */}\n <div className={styles.copyright}>\n © {copyright?.yearFirst \n ? `${currentYear} ${copyLabel}` \n : `${copyLabel} ${currentYear}`}\n </div>\n </div>\n </footer>\n );\n}",".XFooter {\n width: 100%;\n background-color: var(--xf-bg, transparent);\n color: var(--xf-text, #333);\n padding: var(--xf-py, 0.9rem) 0.6rem;\n}\n\n.container {\n max-width: 1280px;\n margin: 0 auto;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 0.6rem; /* Espacio entre los links y el copyright */\n}\n\n/* El nav es el que maneja las columnas de los links */\n.nav {\n display: grid;\n gap: 0.5rem 1.5rem; \n grid-template-columns: repeat(var(--xf-cols, 1), minmax(0, auto));\n justify-content: center;\n text-align: center;\n width: 100%;\n}\n\n.navVertical {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 0.75rem;\n}\n\n.link {\n color: var(--xf-accent, inherit);\n text-decoration: none;\n font-size: 0.9rem;\n transition: opacity 0.2s;\n white-space: nowrap; /* Evita que los links se rompan en dos líneas */\n}\n\n.link:hover {\n opacity: 0.7;\n}\n\n/* El copyright siempre irá al final y centrado por el flex del .container */\n.copyright {\n font-size: 0.75rem;\n opacity: 0.6;\n width: 100%;\n text-align: center;\n}",".separatorContainer {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n /* Variables para la X con fallbacks */\n --x-color: var(--separator-color); \n --x-bg: white;\n}\n\n.iconWrapper {\n position: absolute;\n left: 50%;\n top: 50%;\n transform: translate(-50%, -50%);\n background-color: var(--x-bg);\n padding: 0 10px;\n \n /* Aplicamos el color dinámico */\n color: var(--x-color);\n \n font-family: system-ui, sans-serif;\n font-weight: bold;\n font-size: 1.2rem;\n line-height: 1;\n user-select: none;\n}\n\n.separator {\n --separator-color: #e2e8f0;\n --separator-thickness: 1px;\n --separator-margin: 1rem;\n \n border: 0;\n background-color: var(--separator-color);\n}\n\n/* Variantes de Estilo */\n.dashed {\n background-color: transparent !important;\n border-bottom: var(--separator-thickness) dashed var(--separator-color);\n}\n\n.dotted {\n background-color: transparent !important;\n border-bottom: var(--separator-thickness) dotted var(--separator-color);\n}\n\n/* Efecto Desvanecido (Fading) */\n/* Usamos mask-image para que funcione con cualquier color de fondo */\n.faded {\n mask-image: linear-gradient(\n to right, \n transparent, \n black 20%, \n black 80%, \n transparent\n );\n}\n\n/* Ajuste para desvanecido vertical */\n.vertical.faded {\n mask-image: linear-gradient(\n to bottom, \n transparent, \n black 20%, \n black 80%, \n transparent\n );\n}\n\n.horizontal {\n width: 100%;\n height: var(--separator-thickness);\n margin: var(--separator-margin) 0;\n}\n\n.vertical {\n width: var(--separator-thickness);\n height: 100%;\n display: inline-block;\n margin: 0 var(--separator-margin);\n vertical-align: middle;\n}","import React from 'react';\nimport styles from './XSeparator.module.css';\n\nexport interface XSeparatorProps {\n orientation?: 'horizontal' | 'vertical';\n variant?: 'solid' | 'dashed' | 'dotted';\n isFaded?: boolean;\n hasX?: boolean;\n xColor?: string; // Nuevo: Color de la X\n xBg?: string; // Nuevo: Fondo detrás de la X (para el recorte)\n thickness?: string;\n color?: string;\n gap?: string;\n className?: string;\n}\n\nexport default function XSeparator({\n orientation = 'horizontal',\n variant = 'solid',\n isFaded = false,\n hasX = false,\n xColor, \n xBg = 'white',\n thickness = '1px',\n color = '#e2e8f0',\n gap = '1rem',\n className = ''\n}: XSeparatorProps) {\n \n const dynamicStyles = {\n '--separator-color': color,\n '--separator-thickness': thickness,\n '--separator-margin': gap,\n '--x-color': xColor || color, // Si no se define xColor, usa el color de la línea\n '--x-bg': xBg,\n } as React.CSSProperties;\n\n const classes = [\n styles.separator,\n orientation === 'vertical' ? styles.vertical : styles.horizontal,\n variant !== 'solid' && styles[variant],\n isFaded && styles.faded,\n ].filter(Boolean).join(' ');\n\n const line = <hr className={classes} style={dynamicStyles} />;\n\n if (!hasX) return line;\n\n return (\n <div className={`${styles.separatorContainer} ${className}`} style={dynamicStyles}>\n {line}\n <div className={styles.iconWrapper}>\n ✕\n </div>\n </div>\n );\n}","import React, { Children, HTMLAttributes, useEffect, useRef, useState, useCallback } from \"react\";\nimport styles from \"./XZigZagLayout.module.css\";\n\nexport type XZigZagLayoutProps = HTMLAttributes<HTMLDivElement> & {\n children: React.ReactNode;\n startSide?: \"left\" | \"right\";\n gap?: number | string;\n offset?: number | string;\n textAlign?: \"inherit\" | \"side\" | \"left\" | \"right\";\n showLine?: boolean;\n lineColor?: string;\n lineThickness?: number | string;\n};\n\nexport default function XZigZagLayout({\n children,\n className,\n style,\n startSide = \"left\",\n gap,\n offset,\n textAlign = \"inherit\",\n showLine = false,\n lineColor = \"#cccccc\",\n lineThickness = 2,\n ...rest\n}: XZigZagLayoutProps) {\n const items = Children.toArray(children).filter(Boolean);\n const containerRef = useRef<HTMLDivElement>(null);\n const itemsRef = useRef<(HTMLDivElement | null)[]>([]);\n const pathRef = useRef<SVGPathElement>(null);\n\n const [points, setPoints] = useState<{ x: number; y: number }[]>([]);\n const [pathLength, setPathLength] = useState(0);\n const [drawProgress, setDrawProgress] = useState(0);\n\n // Calcula el centro de cada elemento para dibujar los puntos\n const calculatePoints = useCallback(() => {\n if (!containerRef.current) return;\n const containerRect = containerRef.current.getBoundingClientRect();\n\n const newPoints = itemsRef.current.filter(Boolean).map((el) => {\n const rect = el!.getBoundingClientRect();\n return {\n x: rect.left + rect.width / 2 - containerRect.left,\n y: rect.top + rect.height / 2 - containerRect.top,\n };\n });\n\n if (newPoints.length > 0) {\n newPoints.unshift({ x: newPoints[0].x, y: 0 }); // Inicia arriba\n newPoints.push({ x: newPoints[newPoints.length - 1].x, y: containerRect.height }); // Termina abajo\n }\n\n setPoints(newPoints);\n }, []);\n\n useEffect(() => {\n if (!showLine || !containerRef.current) return;\n const observer = new ResizeObserver(() => calculatePoints());\n observer.observe(containerRef.current);\n calculatePoints();\n return () => observer.disconnect();\n }, [showLine, calculatePoints]);\n\n useEffect(() => {\n if (pathRef.current) setPathLength(pathRef.current.getTotalLength());\n }, [points]);\n\n useEffect(() => {\n if (!showLine) return;\n const handleScroll = () => {\n if (!containerRef.current) return;\n const { top, height } = containerRef.current.getBoundingClientRect();\n const windowHeight = window.innerHeight;\n const start = windowHeight / 2;\n const progress = (start - top) / height;\n\n setDrawProgress(Math.min(Math.max(progress, 0), 1));\n };\n\n window.addEventListener(\"scroll\", handleScroll);\n handleScroll();\n return () => window.removeEventListener(\"scroll\", handleScroll);\n }, [showLine]);\n\n const cssVars: Record<string, string> = {};\n if (gap !== undefined) cssVars[\"--x-zigzag-gap\"] = typeof gap === \"number\" ? `${gap}px` : gap;\n if (offset !== undefined) cssVars[\"--x-zigzag-offset\"] = typeof offset === \"number\" ? `${offset}px` : offset;\n\n const mergedStyle: React.CSSProperties = { ...style, ...cssVars };\n\n const pathD = points.length > 0\n ? `M ${points[0].x} ${points[0].y} ` + points.slice(1).map((p) => `L ${p.x} ${p.y}`).join(\" \")\n : \"\";\n\n return (\n <div\n ref={containerRef}\n {...rest}\n className={[styles.layout, className].filter(Boolean).join(\" \")}\n style={mergedStyle}\n >\n {showLine && points.length > 0 && (\n <svg className={styles.svgLine} xmlns=\"http://www.w3.org/2000/svg\">\n <path\n ref={pathRef}\n d={pathD}\n fill=\"none\"\n stroke={lineColor}\n strokeWidth={lineThickness}\n strokeDasharray={pathLength}\n strokeDashoffset={pathLength - pathLength * drawProgress}\n style={{ transition: \"stroke-dashoffset 0.1s ease-out\" }}\n />\n </svg>\n )}\n\n {items.map((child, index) => {\n const isStartLeft = startSide === \"left\";\n const alignLeft = isStartLeft ? index % 2 === 0 : index % 2 !== 0;\n const alignmentClass =\n textAlign === \"side\"\n ? alignLeft ? styles.textLeft : styles.textRight\n : textAlign === \"left\" ? styles.textLeft : textAlign === \"right\" ? styles.textRight : \"\";\n\n return (\n <div key={index} className={`${styles.item} ${alignLeft ? styles.left : styles.right} ${alignmentClass}`}>\n {/* El wrapper interno nos permite medir exactamente dónde queda el contenido */}\n <div ref={(el) => { itemsRef.current[index] = el; }} className={styles.contentWrapper}>\n {child}\n </div>\n </div>\n );\n })}\n </div>\n );\n}",".layout {\n width: min(100%, 72rem);\n margin: 0 auto;\n display: flex;\n flex-direction: column;\n gap: var(--x-zigzag-gap, 0.5rem);\n padding-inline: clamp(0.5rem, 2vw, 1rem);\n position: relative; \n}\n\n/* Nuevos estilos para el SVG de la línea */\n.svgLine {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n pointer-events: none;\n z-index: 0;\n}\n\n.item {\n width: 100%;\n display: grid;\n grid-template-columns: repeat(12, minmax(0, 1fr));\n}\n\n.item > * {\n width: 100%;\n text-align: inherit;\n}\n\n/* Wrapper transparente que envuelve al child */\n.contentWrapper {\n width: 100%;\n}\n\n.textLeft > * {\n text-align: left;\n}\n\n.textRight > * {\n text-align: right;\n}\n\n.left > * {\n grid-column: 2 / 8;\n}\n\n.right > * {\n grid-column: 6 / 12;\n}\n\n@media (max-width: 768px) {\n /* En lugar de ocupar las 12 columnas, los hacemos un poco más angostos para que sus centros se desfasen */\n .left > * {\n grid-column: 1 / 11;\n }\n\n .right > * {\n grid-column: 3 / 13;\n }\n}"],"mappings":"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","names":["Link","import_jsx_runtime","import_jsx_runtime"]}
@@ -0,0 +1,11 @@
1
+ import {
2
+ XFooter,
3
+ XSeparator,
4
+ XZigZagLayout
5
+ } from "../../chunk-42XPBYTL.mjs";
6
+ export {
7
+ XFooter,
8
+ XSeparator,
9
+ XZigZagLayout
10
+ };
11
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,229 @@
1
+ /* src/components/navigation/xnavbar/XNavbar.module.css */
2
+ .header {
3
+ height: 100%;
4
+ display: flex;
5
+ align-items: center;
6
+ justify-content: space-between;
7
+ padding: 2rem 3rem;
8
+ background: var(--bg);
9
+ color: var(--text);
10
+ font-size: 1.25rem;
11
+ z-index: 60;
12
+ }
13
+ @media (min-width: 640px) {
14
+ .header {
15
+ padding-inline: 2rem;
16
+ }
17
+ }
18
+ @media (min-width: 768px) {
19
+ .header {
20
+ padding-inline: 3rem;
21
+ }
22
+ }
23
+ @media (min-width: 1024px) {
24
+ .header {
25
+ padding-inline: 5rem;
26
+ }
27
+ }
28
+ @media (min-width: 1280px) {
29
+ .header {
30
+ padding-inline: 12rem;
31
+ }
32
+ }
33
+ .desktopNav {
34
+ display: none;
35
+ align-items: center;
36
+ width: 100%;
37
+ grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
38
+ padding-bottom: 0.5rem;
39
+ }
40
+ @media (min-width: 768px) {
41
+ .desktopNav {
42
+ display: grid;
43
+ }
44
+ }
45
+ .desktopLinksLeft,
46
+ .desktopLinksRight {
47
+ display: flex;
48
+ align-items: center;
49
+ gap: 1.5rem;
50
+ min-width: 0;
51
+ }
52
+ .desktopLinksLeft {
53
+ justify-content: flex-end;
54
+ }
55
+ .desktopLinksRight {
56
+ justify-content: flex-start;
57
+ }
58
+ .logoSlot {
59
+ display: flex;
60
+ justify-content: center;
61
+ align-items: center;
62
+ }
63
+ .logoWrapper {
64
+ position: relative;
65
+ margin-inline: 1rem;
66
+ display: flex;
67
+ align-items: center;
68
+ }
69
+ .logoBtn {
70
+ font-weight: 700;
71
+ font-size: 1.5rem;
72
+ line-height: 1;
73
+ user-select: none;
74
+ background: none;
75
+ border: none;
76
+ cursor: pointer;
77
+ color: var(--text);
78
+ padding: 0;
79
+ }
80
+ .iconTray {
81
+ position: absolute;
82
+ top: 50%;
83
+ transform: translateY(-50%);
84
+ pointer-events: none;
85
+ }
86
+ .iconTrayRight {
87
+ left: 100%;
88
+ padding-left: 0.75rem;
89
+ }
90
+ .iconTrayLeft {
91
+ right: 100%;
92
+ padding-right: 0.75rem;
93
+ }
94
+ .navLink {
95
+ padding: 0.25rem;
96
+ border-bottom: 2px solid transparent;
97
+ transition:
98
+ border-color 0.2s,
99
+ opacity 0.2s,
100
+ color 0.2s;
101
+ color: var(--xnav-link-color, var(--text));
102
+ text-decoration: none;
103
+ white-space: nowrap;
104
+ }
105
+ .navLink:hover {
106
+ color: var(--xnav-link-hover, var(--xnav-link-color, var(--text)));
107
+ opacity: var(--xnav-link-hover-opacity, 0.7);
108
+ }
109
+ .navLinkActive {
110
+ border-bottom-color: var(--xnav-link-active, var(--xnav-link-color, var(--text)));
111
+ font-weight: 600;
112
+ }
113
+ .navLinkExternal::after {
114
+ content: " \2197";
115
+ font-size: 0.7em;
116
+ opacity: 0.6;
117
+ }
118
+ .mobileToggle {
119
+ display: flex;
120
+ align-items: center;
121
+ justify-content: center;
122
+ }
123
+ @media (min-width: 768px) {
124
+ .mobileToggle {
125
+ display: none;
126
+ }
127
+ }
128
+ .hamburgerBtn {
129
+ width: 2.5rem;
130
+ height: 2rem;
131
+ display: flex;
132
+ flex-direction: column;
133
+ align-items: center;
134
+ justify-content: space-between;
135
+ background: none;
136
+ border: none;
137
+ cursor: pointer;
138
+ position: relative;
139
+ z-index: 80;
140
+ padding: 0;
141
+ }
142
+ .bar {
143
+ width: var(--xnav-bar-w, 2rem);
144
+ height: var(--xnav-bar-h, 3px);
145
+ background: var(--xnav-bar-color, var(--text));
146
+ border-radius: 2px;
147
+ }
148
+ .mobileOverlay {
149
+ position: fixed;
150
+ inset: 0;
151
+ width: 100vw;
152
+ height: 100svh;
153
+ background: var(--bg);
154
+ color: var(--text);
155
+ display: flex;
156
+ flex-direction: column;
157
+ align-items: center;
158
+ justify-content: center;
159
+ gap: 2rem;
160
+ font-size: 2.5rem;
161
+ z-index: 9999;
162
+ }
163
+ .mobileCloseBtn {
164
+ position: fixed;
165
+ top: 2rem;
166
+ left: 1rem;
167
+ width: 2.5rem;
168
+ height: 2rem;
169
+ display: flex;
170
+ align-items: center;
171
+ justify-content: center;
172
+ background: none;
173
+ border: none;
174
+ cursor: pointer;
175
+ color: var(--xnav-bar-color, var(--text));
176
+ z-index: 10000;
177
+ -webkit-tap-highlight-color: transparent;
178
+ }
179
+ .closeBar {
180
+ display: block;
181
+ position: absolute;
182
+ width: 2rem;
183
+ height: 3px;
184
+ border-radius: 2px;
185
+ background: currentColor;
186
+ }
187
+ .mobileLogo {
188
+ font-weight: 700;
189
+ font-size: 3rem;
190
+ user-select: none;
191
+ pointer-events: none;
192
+ }
193
+ .mobileNavLink {
194
+ font-size: 2.5rem;
195
+ color: var(--xnav-link-color, var(--text));
196
+ text-decoration: none;
197
+ border-bottom: 2px solid transparent;
198
+ transition:
199
+ border-color 0.2s,
200
+ color 0.2s,
201
+ opacity 0.2s;
202
+ padding: 0.25rem;
203
+ }
204
+ .mobileNavLink:hover {
205
+ color: var(--xnav-link-hover, var(--xnav-link-color, var(--text)));
206
+ opacity: var(--xnav-link-hover-opacity, 0.7);
207
+ }
208
+ .mobileNavLinkActive {
209
+ font-weight: 600;
210
+ border-bottom-color: var(--xnav-link-active, var(--xnav-link-color, var(--text)));
211
+ }
212
+ .themeToggleMobile {
213
+ margin-top: 1rem;
214
+ font-size: 1rem;
215
+ padding: 0.5rem 1rem;
216
+ border: 1px solid var(--border);
217
+ border-radius: 0.375rem;
218
+ display: flex;
219
+ align-items: center;
220
+ gap: 0.5rem;
221
+ background: none;
222
+ color: var(--text);
223
+ cursor: pointer;
224
+ transition: opacity 0.2s;
225
+ }
226
+ .themeToggleMobile:hover {
227
+ opacity: 0.7;
228
+ }
229
+ /*# sourceMappingURL=index.css.map */
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/navigation/xnavbar/XNavbar.module.css"],"sourcesContent":["/* ────────────────────────────────────────────\n XNavbar.module.css\n Navbar completamente libre de Tailwind.\n Usa variables CSS del tema global (--bg, --text, --border, --accent).\n ──────────────────────────────────────────── */\n\n/* ── Header / contenedor raíz ── */\n.header {\n height: 100%;\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 2rem 3rem;\n background: var(--bg);\n color: var(--text);\n font-size: 1.25rem;\n z-index: 60;\n}\n\n@media (min-width: 640px) { .header { padding-inline: 2rem; } }\n@media (min-width: 768px) { .header { padding-inline: 3rem; } }\n@media (min-width: 1024px) { .header { padding-inline: 5rem; } }\n@media (min-width: 1280px) { .header { padding-inline: 12rem; } }\n\n/* ── Desktop nav ── */\n.desktopNav {\n display: none;\n align-items: center;\n width: 100%;\n grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);\n padding-bottom: 0.5rem;\n}\n\n@media (min-width: 768px) {\n .desktopNav {\n display: grid;\n }\n}\n\n.desktopLinksLeft,\n.desktopLinksRight {\n display: flex;\n align-items: center;\n gap: 1.5rem;\n min-width: 0;\n}\n\n.desktopLinksLeft {\n justify-content: flex-end;\n}\n\n.desktopLinksRight {\n justify-content: flex-start;\n}\n\n.logoSlot {\n display: flex;\n justify-content: center;\n align-items: center;\n}\n\n/* ── Logo / botón central (desktop) ── */\n.logoWrapper {\n position: relative;\n margin-inline: 1rem;\n display: flex;\n align-items: center;\n}\n\n.logoBtn {\n font-weight: 700;\n font-size: 1.5rem;\n line-height: 1;\n user-select: none;\n background: none;\n border: none;\n cursor: pointer;\n color: var(--text);\n padding: 0;\n}\n\n/* ── Tray de íconos hover (sun/moon) ── */\n.iconTray {\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n pointer-events: none;\n}\n\n.iconTrayRight {\n left: 100%;\n padding-left: 0.75rem;\n}\n\n.iconTrayLeft {\n right: 100%;\n padding-right: 0.75rem;\n}\n\n/* ── NavLink (desktop) ── */\n.navLink {\n padding: 0.25rem;\n border-bottom: 2px solid transparent;\n transition: border-color 0.2s, opacity 0.2s, color 0.2s;\n color: var(--xnav-link-color, var(--text));\n text-decoration: none;\n white-space: nowrap;\n}\n\n.navLink:hover {\n color: var(--xnav-link-hover, var(--xnav-link-color, var(--text)));\n opacity: var(--xnav-link-hover-opacity, 0.7);\n}\n\n.navLinkActive {\n border-bottom-color: var(--xnav-link-active, var(--xnav-link-color, var(--text)));\n font-weight: 600;\n}\n\n/* External link indicator */\n.navLinkExternal::after {\n content: \" ↗\";\n font-size: 0.7em;\n opacity: 0.6;\n}\n\n/* ── Mobile hamburger ── */\n.mobileToggle {\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n@media (min-width: 768px) {\n .mobileToggle {\n display: none;\n }\n}\n\n.hamburgerBtn {\n width: 2.5rem;\n height: 2rem;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: space-between;\n background: none;\n border: none;\n cursor: pointer;\n position: relative;\n z-index: 80;\n padding: 0;\n}\n\n.bar {\n width: var(--xnav-bar-w, 2rem);\n height: var(--xnav-bar-h, 3px);\n background: var(--xnav-bar-color, var(--text));\n border-radius: 2px;\n}\n\n/* ── Mobile overlay (portal) ── */\n.mobileOverlay {\n position: fixed;\n inset: 0;\n width: 100vw;\n height: 100svh;\n background: var(--bg);\n color: var(--text);\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 2rem;\n font-size: 2.5rem;\n z-index: 9999;\n}\n\n.mobileCloseBtn {\n position: fixed;\n top: 2rem;\n left: 1rem;\n width: 2.5rem;\n height: 2rem;\n display: flex;\n align-items: center;\n justify-content: center;\n background: none;\n border: none;\n cursor: pointer;\n /* hereda el mismo color que las barras del hamburguesa */\n color: var(--xnav-bar-color, var(--text));\n z-index: 10000;\n -webkit-tap-highlight-color: transparent;\n}\n\n.closeBar {\n display: block;\n position: absolute;\n width: 2rem;\n height: 3px;\n border-radius: 2px;\n background: currentColor;\n}\n\n.mobileLogo {\n font-weight: 700;\n font-size: 3rem;\n user-select: none;\n pointer-events: none;\n}\n\n.mobileNavLink {\n font-size: 2.5rem;\n color: var(--xnav-link-color, var(--text));\n text-decoration: none;\n border-bottom: 2px solid transparent;\n transition: border-color 0.2s, color 0.2s, opacity 0.2s;\n padding: 0.25rem;\n}\n\n.mobileNavLink:hover {\n color: var(--xnav-link-hover, var(--xnav-link-color, var(--text)));\n opacity: var(--xnav-link-hover-opacity, 0.7);\n}\n\n.mobileNavLinkActive {\n font-weight: 600;\n border-bottom-color: var(--xnav-link-active, var(--xnav-link-color, var(--text)));\n}\n\n/* ── Botón tema (móvil) ── */\n.themeToggleMobile {\n margin-top: 1rem;\n font-size: 1rem;\n padding: 0.5rem 1rem;\n border: 1px solid var(--border);\n border-radius: 0.375rem;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n background: none;\n color: var(--text);\n cursor: pointer;\n transition: opacity 0.2s;\n}\n\n.themeToggleMobile:hover {\n opacity: 0.7;\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,76 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+
4
+ type NavLinkItem = {
5
+ /** Ruta destino */
6
+ url: string;
7
+ /** Texto visible */
8
+ title: string;
9
+ /** Si es true abre en pestaña nueva y muestra el indicador ↗ */
10
+ external?: boolean;
11
+ };
12
+ /**
13
+ * ReactNode estático O función de render (size, color?) => ReactNode.
14
+ * La función recibe el tamaño y el color vigente para que el ícono
15
+ * pueda adaptarse dinámicamente a los props del navbar.
16
+ */
17
+ type IconRenderer = ReactNode | ((size: number, color?: string) => ReactNode);
18
+ type ThemeToggleIcons = {
19
+ /** Ícono/renderer hacia tema oscuro (ReactNode o función) */
20
+ toDark: IconRenderer;
21
+ /** Ícono/renderer hacia tema claro (ReactNode o función) */
22
+ toLight: IconRenderer;
23
+ };
24
+ type XNavbarProps = {
25
+ /** Links que aparecen a la izquierda del logo en desktop */
26
+ linksLeft?: NavLinkItem[];
27
+ /** Links que aparecen a la derecha del logo en desktop */
28
+ linksRight?: NavLinkItem[];
29
+ /** Contenido del botón central (texto o JSX). Por defecto: "X" */
30
+ logo?: ReactNode;
31
+ /** Si true el logo actúa como toggle de tema (comportamiento original). Default: true */
32
+ logoAsThemeToggle?: boolean;
33
+ /** Callback custom si logoAsThemeToggle es false */
34
+ onLogoClick?: () => void;
35
+ /** Íconos para el toggle de tema. Si no se pasa, no se mostrará hint de ícono */
36
+ themeIcons?: ThemeToggleIcons;
37
+ /** Tema inicial. Default: "light" */
38
+ defaultTheme?: "light" | "dark";
39
+ /** Key de localStorage para persistencia del tema. Default: "theme" */
40
+ storageKey?: string;
41
+ /** Color base de los enlaces (Inicio, Contacto, etc.). Default: var(--text) */
42
+ linkColor?: string;
43
+ /** Color al hacer hover sobre los enlaces. Default: opacidad reducida del linkColor */
44
+ linkHoverColor?: string;
45
+ /** Color del borde inferior del enlace activo. Default: linkColor */
46
+ linkActiveColor?: string;
47
+ /** Color base de los íconos. Acepta cualquier valor CSS: hex, hsl, "var(--accent)", etc.
48
+ * Si no se pasa, los íconos heredan el color del texto (currentColor). */
49
+ iconColor?: string;
50
+ /** Color que toman los íconos al hacer hover sobre el logo. Default: iconColor */
51
+ iconHoverColor?: string;
52
+ /** Tamaño en px que se pasa a IconRenderer cuando es función. Default: 22 */
53
+ iconSize?: number;
54
+ /** Color de las 3 barras (y la X de cierre móvil). Acepta cualquier valor CSS. Default: var(--text) */
55
+ hamburgerColor?: string;
56
+ /** Ancho de las barras. Cualquier unidad CSS. Default: "2rem" */
57
+ hamburgerBarWidth?: string;
58
+ /** Grosor (altura) de las barras. Cualquier unidad CSS. Default: "3px" */
59
+ hamburgerBarThickness?: string;
60
+ /** Inyecta variables CSS extra directamente en el style del <header>.
61
+ * Útil para pasar tokens del tema: { '--xnav-icon-color': 'var(--accent)' } */
62
+ cssVars?: Record<string, string>;
63
+ /** aria-label del botón hamburguesa cuando está cerrado. Default: "Abrir menú" */
64
+ labelOpen?: string;
65
+ /** aria-label del botón hamburguesa cuando está abierto. Default: "Cerrar menú" */
66
+ labelClose?: string;
67
+ /** Texto del botón de tema oscuro en menú móvil. Default: "Oscuro" */
68
+ labelDark?: string;
69
+ /** Texto del botón de tema claro en menú móvil. Default: "Claro" */
70
+ labelLight?: string;
71
+ /** className extra que se añade al <header> */
72
+ className?: string;
73
+ };
74
+ declare function XNavbar({ linksLeft, linksRight, logo, logoAsThemeToggle, onLogoClick, themeIcons, defaultTheme, storageKey, linkColor, linkHoverColor, linkActiveColor, iconColor, iconHoverColor, iconSize, hamburgerColor, hamburgerBarWidth, hamburgerBarThickness, cssVars, labelOpen, labelClose, labelDark, labelLight, className, }: XNavbarProps): react_jsx_runtime.JSX.Element;
75
+
76
+ export { type IconRenderer, type NavLinkItem, type ThemeToggleIcons, XNavbar, type XNavbarProps };