@roax/ui 0.1.0 → 0.2.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.
package/dist/index.js CHANGED
@@ -29,11 +29,22 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
29
29
  // src/index.js
30
30
  var index_exports = {};
31
31
  __export(index_exports, {
32
+ BackButton: () => BackButton,
33
+ CardSkeleton: () => CardSkeleton,
32
34
  CustomTooltip: () => CustomTooltip,
33
35
  IconButton: () => IconButton,
36
+ MetricCard: () => MetricCard,
37
+ MetricsSkeleton: () => MetricsSkeleton,
38
+ Modal: () => Modal,
34
39
  OutlineButton: () => OutlineButton,
40
+ PaginatedGrid: () => PaginatedGrid,
41
+ PaginatedTable: () => PaginatedTable,
35
42
  SolidButton: () => SolidButton,
36
- TextButton: () => TextButton
43
+ TextButton: () => TextButton,
44
+ TextSkeleton: () => TextSkeleton,
45
+ formatDateRange: () => formatDateRange,
46
+ formatValue: () => formatValue,
47
+ getBadgeStyles: () => getBadgeStyles
37
48
  });
38
49
  module.exports = __toCommonJS(index_exports);
39
50
 
@@ -194,12 +205,305 @@ function IconButton({
194
205
  title && /* @__PURE__ */ React.createElement("span", { className: "ml-2 d-none d-md-block" }, title)
195
206
  ));
196
207
  }
208
+
209
+ // src/components/modal/Modal.jsx
210
+ var import_icons_react5 = __toESM(require("@coreui/icons-react"));
211
+ var import_react_pro5 = require("@coreui/react-pro");
212
+
213
+ // ../../node_modules/@coreui/icons/dist/esm/free/cil-arrow-bottom.js
214
+ var cilArrowBottom = ["512 512", "<polygon fill='var(--ci-primary-color, currentColor)' points='367.997 338.75 271.999 434.747 271.999 17.503 239.999 17.503 239.999 434.745 144.003 338.75 121.376 361.377 256 496 390.624 361.377 367.997 338.75' class='ci-primary'/>"];
215
+
216
+ // ../../node_modules/@coreui/icons/dist/esm/free/cil-arrow-left.js
217
+ var cilArrowLeft = ["512 512", "<polygon fill='var(--ci-primary-color, currentColor)' points='497.333 239.999 80.092 239.999 176.087 144.004 153.46 121.377 18.837 256 153.46 390.623 176.087 367.996 80.09 271.999 497.333 271.999 497.333 239.999' class='ci-primary'/>"];
218
+
219
+ // ../../node_modules/@coreui/icons/dist/esm/free/cil-arrow-top.js
220
+ var cilArrowTop = ["512 512", "<polygon fill='var(--ci-primary-color, currentColor)' points='390.624 150.625 256 16 121.376 150.625 144.004 173.252 240.001 77.254 240.001 495.236 272.001 495.236 272.001 77.257 367.996 173.252 390.624 150.625' class='ci-primary'/>"];
221
+
222
+ // ../../node_modules/@coreui/icons/dist/esm/free/cil-info.js
223
+ var cilInfo = ["512 512", "<rect width='34.924' height='34.924' x='256' y='95.998' fill='var(--ci-primary-color, currentColor)' class='ci-primary'/><path fill='var(--ci-primary-color, currentColor)' d='M16,496H496V16H16ZM48,48H464V464H48Z' class='ci-primary'/><path fill='var(--ci-primary-color, currentColor)' d='M285.313,359.032a18.123,18.123,0,0,1-15.6,8.966,18.061,18.061,0,0,1-17.327-23.157l35.67-121.277A49.577,49.577,0,0,0,194.7,190.572l-11.718,28.234,29.557,12.266,11.718-28.235a17.577,17.577,0,0,1,33.1,11.7l-35.67,121.277A50.061,50.061,0,0,0,269.709,400a50.227,50.227,0,0,0,43.25-24.853l15.1-25.913-27.646-16.115Z' class='ci-primary'/>"];
224
+
225
+ // ../../node_modules/@coreui/icons/dist/esm/free/cil-x.js
226
+ var cilX = ["512 512", "<polygon fill='var(--ci-primary-color, currentColor)' points='427.314 107.313 404.686 84.687 256 233.373 107.314 84.687 84.686 107.313 233.373 256 84.686 404.687 107.314 427.313 256 278.627 404.686 427.313 427.314 404.687 278.627 256 427.314 107.313' class='ci-primary'/>"];
227
+
228
+ // src/components/modal/Modal.jsx
229
+ function Modal({
230
+ title,
231
+ titleIcon,
232
+ visible,
233
+ setVisible,
234
+ alignment = "center",
235
+ size,
236
+ children
237
+ }) {
238
+ return /* @__PURE__ */ React.createElement(
239
+ import_react_pro5.CModal,
240
+ {
241
+ alignment,
242
+ visible,
243
+ onClose: () => setVisible(false),
244
+ size,
245
+ focus: true,
246
+ keyboard: true,
247
+ "aria-labelledby": "roax-modal-title"
248
+ },
249
+ /* @__PURE__ */ React.createElement(import_react_pro5.CModalHeader, { className: "position-relative" }, /* @__PURE__ */ React.createElement(import_react_pro5.CModalTitle, { id: "roax-modal-title", className: "d-flex align-items-center gap-2" }, titleIcon && /* @__PURE__ */ React.createElement(import_icons_react5.default, { icon: titleIcon, size: "lg", className: "text-muted" }), title), /* @__PURE__ */ React.createElement(
250
+ "button",
251
+ {
252
+ onClick: () => setVisible(false),
253
+ type: "button",
254
+ className: "position-absolute end-0 top-0 mt-3 me-3 p-0 bg-transparent border-0",
255
+ style: { fontSize: "1.25rem", color: "var(--cui-body-color)", zIndex: 10 },
256
+ "aria-label": "Cerrar"
257
+ },
258
+ /* @__PURE__ */ React.createElement(import_icons_react5.default, { icon: cilX, size: "lg" })
259
+ )),
260
+ /* @__PURE__ */ React.createElement(import_react_pro5.CModalBody, null, children)
261
+ );
262
+ }
263
+
264
+ // src/components/card/MetricCard.jsx
265
+ var import_react_pro6 = require("@coreui/react-pro");
266
+ var import_icons_react6 = __toESM(require("@coreui/icons-react"));
267
+
268
+ // src/components/card/card-utils.js
269
+ var formatValue = (val, unit = "", title = "") => {
270
+ if (val == null || typeof val !== "number" || val === 0) return "0";
271
+ if (title.includes("ROAS")) return `x ${val.toFixed(2)}`;
272
+ if (title.includes("CAC %")) return `${val.toFixed(2)}%`;
273
+ if (unit === "%" || title.includes("%")) return `${val.toFixed(2)}%`;
274
+ if (unit === "x") return `x ${val.toFixed(2)}`;
275
+ if (unit === "COP") return `COP ${Math.round(val).toLocaleString("es-CO")}`;
276
+ return val.toLocaleString(void 0, { minimumFractionDigits: 0, maximumFractionDigits: 2 });
277
+ };
278
+ var getBadgeStyles = (isPositive) => ({
279
+ backgroundColor: isPositive ? "#55ed7b" : "#f74a4a",
280
+ color: isPositive ? "#0b3e26" : "#842029",
281
+ borderRadius: "9999px",
282
+ padding: "4px 10px",
283
+ fontSize: "0.75rem",
284
+ fontWeight: 700,
285
+ display: "inline-flex",
286
+ alignItems: "center",
287
+ gap: "4px"
288
+ });
289
+ function formatDateRange(previousDateRange) {
290
+ if (!previousDateRange) return { formattedRange: "" };
291
+ const parts = previousDateRange.split(" - ");
292
+ const parseDate = (str) => {
293
+ const [year, month, day] = str.split("-").map(Number);
294
+ return new Date(year, month - 1, day);
295
+ };
296
+ const format = (date) => {
297
+ const day = String(date.getDate()).padStart(2, "0");
298
+ const month = date.toLocaleString("es-CO", { month: "short" }).replace(".", "");
299
+ const year = String(date.getFullYear()).slice(-2);
300
+ return `${month} ${day},${year}`;
301
+ };
302
+ const since = parseDate(parts[0]);
303
+ const until = parts[1] ? parseDate(parts[1]) : null;
304
+ const formattedRange = until ? `${format(since)} - ${format(until)}` : format(since);
305
+ return { formattedRange };
306
+ }
307
+
308
+ // src/components/card/MetricCard.jsx
309
+ var import_MetricCard = require("./MetricCard.scss");
310
+ function MetricCard({
311
+ title,
312
+ current,
313
+ previous,
314
+ change,
315
+ isPositive,
316
+ unit = "",
317
+ previousDateRange = "",
318
+ tooltipText = "",
319
+ backgroundColor
320
+ }) {
321
+ const isColored = !!backgroundColor;
322
+ const cardClass = `metric-card w-100 h-100 d-flex flex-column border-0${isColored ? " metric-card--colored" : ""}`;
323
+ return /* @__PURE__ */ React.createElement(
324
+ import_react_pro6.CCard,
325
+ {
326
+ className: cardClass,
327
+ style: isColored ? { background: backgroundColor } : void 0
328
+ },
329
+ /* @__PURE__ */ React.createElement(import_react_pro6.CCardBody, { className: "d-flex flex-column justify-content-between h-100 p-4 position-relative" }, tooltipText && /* @__PURE__ */ React.createElement("div", { className: "position-absolute top-0 end-0 m-2" }, /* @__PURE__ */ React.createElement(CustomTooltip, { content: tooltipText, placement: "top" }, /* @__PURE__ */ React.createElement(
330
+ import_icons_react6.default,
331
+ {
332
+ icon: cilInfo,
333
+ style: { cursor: "pointer", opacity: 0.5, width: 16, height: 16 }
334
+ }
335
+ ))), /* @__PURE__ */ React.createElement("p", { className: "metric-card__title m-0" }, title), /* @__PURE__ */ React.createElement("div", { className: "d-flex align-items-center gap-2 mt-1" }, /* @__PURE__ */ React.createElement("span", { className: "metric-card__value" }, formatValue(current, unit, title)), typeof change === "number" && isFinite(change) && current > 0 && /* @__PURE__ */ React.createElement("div", { style: getBadgeStyles(isPositive) }, /* @__PURE__ */ React.createElement(import_icons_react6.default, { icon: isPositive ? cilArrowTop : cilArrowBottom, size: "sm" }), Math.abs(change), "%")), /* @__PURE__ */ React.createElement("hr", { className: "metric-card__divider" }), (() => {
336
+ const { formattedRange } = formatDateRange(previousDateRange);
337
+ return /* @__PURE__ */ React.createElement("div", { className: "d-flex justify-content-between align-items-center metric-card__footer" }, /* @__PURE__ */ React.createElement("strong", null, formatValue(previous, unit, title)), /* @__PURE__ */ React.createElement("span", null, formattedRange));
338
+ })())
339
+ );
340
+ }
341
+
342
+ // src/components/pagination/PaginatedTable.jsx
343
+ var import_react_pro7 = require("@coreui/react-pro");
344
+ function PaginatedTable({
345
+ data = [],
346
+ itemsPerPage = 10,
347
+ currentPage = 1,
348
+ setCurrentPage = () => {
349
+ },
350
+ columns = [],
351
+ renderRow = () => null,
352
+ loading = false,
353
+ emptyMessage = "No hay datos disponibles."
354
+ }) {
355
+ const totalPages = Math.ceil(data.length / itemsPerPage);
356
+ const paginatedData = data.slice(
357
+ (currentPage - 1) * itemsPerPage,
358
+ currentPage * itemsPerPage
359
+ );
360
+ if (loading) {
361
+ return /* @__PURE__ */ React.createElement("div", { className: "text-center py-5" }, /* @__PURE__ */ React.createElement(import_react_pro7.CSpinner, { color: "secondary" }));
362
+ }
363
+ if (!data.length) {
364
+ return /* @__PURE__ */ React.createElement("div", { className: "text-center py-5 text-muted" }, emptyMessage);
365
+ }
366
+ const renderPagination = () => {
367
+ const pages = [];
368
+ for (let i = 1; i <= totalPages; i++) {
369
+ pages.push(
370
+ /* @__PURE__ */ React.createElement(
371
+ "button",
372
+ {
373
+ key: i,
374
+ onClick: () => setCurrentPage(i),
375
+ className: `px-3 py-1 rounded-pill border ${i === currentPage ? "bg-dark text-white" : "bg-white text-dark"}`
376
+ },
377
+ i
378
+ )
379
+ );
380
+ }
381
+ return /* @__PURE__ */ React.createElement("div", { className: "d-flex justify-content-center align-items-center gap-2 mt-3 flex-wrap" }, currentPage > 1 && /* @__PURE__ */ React.createElement(
382
+ "button",
383
+ {
384
+ onClick: () => setCurrentPage(currentPage - 1),
385
+ className: "px-3 py-1 rounded-pill border bg-white text-dark",
386
+ style: { minWidth: "80px", fontWeight: 500 }
387
+ },
388
+ "Anterior"
389
+ ), pages, currentPage < totalPages && /* @__PURE__ */ React.createElement(
390
+ "button",
391
+ {
392
+ onClick: () => setCurrentPage(currentPage + 1),
393
+ className: "px-3 py-1 rounded-pill border bg-white text-dark",
394
+ style: { minWidth: "80px", fontWeight: 500 }
395
+ },
396
+ "Siguiente"
397
+ ));
398
+ };
399
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(import_react_pro7.CTable, { hover: true, responsive: true }, /* @__PURE__ */ React.createElement(import_react_pro7.CTableHead, { className: "bg-dark text-white" }, /* @__PURE__ */ React.createElement(import_react_pro7.CTableRow, null, columns.map((col, idx) => /* @__PURE__ */ React.createElement(import_react_pro7.CTableHeaderCell, { key: idx }, col)))), /* @__PURE__ */ React.createElement(import_react_pro7.CTableBody, null, paginatedData.map(renderRow))), totalPages > 1 && renderPagination());
400
+ }
401
+
402
+ // src/components/pagination/PaginatedGrid.jsx
403
+ var import_react_pro8 = require("@coreui/react-pro");
404
+ function PaginatedGrid({
405
+ data = [],
406
+ itemsPerPage = 6,
407
+ currentPage = 1,
408
+ setCurrentPage = () => {
409
+ },
410
+ renderItem = () => null,
411
+ loading = false,
412
+ emptyMessage = "No hay elementos."
413
+ }) {
414
+ const totalPages = Math.ceil(data.length / itemsPerPage);
415
+ const paginatedData = data.slice(
416
+ (currentPage - 1) * itemsPerPage,
417
+ currentPage * itemsPerPage
418
+ );
419
+ if (loading) {
420
+ return /* @__PURE__ */ React.createElement("div", { className: "text-center py-5" }, /* @__PURE__ */ React.createElement(import_react_pro8.CSpinner, { color: "secondary" }));
421
+ }
422
+ if (!data.length) {
423
+ return /* @__PURE__ */ React.createElement("div", { className: "text-center py-5 text-muted" }, emptyMessage);
424
+ }
425
+ const renderPagination = () => {
426
+ const pages = [];
427
+ for (let i = 1; i <= totalPages; i++) {
428
+ pages.push(
429
+ /* @__PURE__ */ React.createElement(
430
+ "button",
431
+ {
432
+ key: i,
433
+ onClick: () => setCurrentPage(i),
434
+ className: `px-3 py-1 rounded-pill border ${i === currentPage ? "bg-dark text-white" : "bg-white text-dark"}`
435
+ },
436
+ i
437
+ )
438
+ );
439
+ }
440
+ return /* @__PURE__ */ React.createElement("div", { className: "d-flex justify-content-center gap-2 mt-4 flex-wrap" }, currentPage > 1 && /* @__PURE__ */ React.createElement(
441
+ "button",
442
+ {
443
+ onClick: () => setCurrentPage(currentPage - 1),
444
+ className: "px-3 py-1 rounded-pill border bg-white text-dark"
445
+ },
446
+ "Anterior"
447
+ ), pages, currentPage < totalPages && /* @__PURE__ */ React.createElement(
448
+ "button",
449
+ {
450
+ onClick: () => setCurrentPage(currentPage + 1),
451
+ className: "px-3 py-1 rounded-pill border bg-white text-dark"
452
+ },
453
+ "Siguiente"
454
+ ));
455
+ };
456
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "row g-4" }, paginatedData.map(renderItem)), totalPages > 1 && renderPagination());
457
+ }
458
+
459
+ // src/components/skeletons/CardSkeleton.jsx
460
+ var import_react_pro9 = require("@coreui/react-pro");
461
+ function CardSkeleton() {
462
+ return /* @__PURE__ */ React.createElement(import_react_pro9.CCard, { className: "shadow-none p-0 m-0 bg-transparent border-0" }, /* @__PURE__ */ React.createElement(import_react_pro9.CPlaceholder, { component: "div", animation: "glow", className: "d-flex flex-column gap-2 bg-transparent" }, /* @__PURE__ */ React.createElement(import_react_pro9.CPlaceholder, { className: "p-4 mt-2 rounded-1", size: "lg", xs: 12, color: "skeleton" })));
463
+ }
464
+
465
+ // src/components/skeletons/TextSkeleton.jsx
466
+ var import_react_pro10 = require("@coreui/react-pro");
467
+ function TextSkeleton() {
468
+ return /* @__PURE__ */ React.createElement(import_react_pro10.CCard, { className: "shadow-none p-0 m-0 bg-transparent border-0" }, /* @__PURE__ */ React.createElement(import_react_pro10.CPlaceholder, { component: "div", animation: "glow", className: "d-flex flex-column gap-2 bg-transparent" }, /* @__PURE__ */ React.createElement(import_react_pro10.CPlaceholder, { className: "p-0 my-2 rounded-1", size: "lg", xs: 8, color: "skeleton" })));
469
+ }
470
+
471
+ // src/components/skeletons/MetricsSkeleton.jsx
472
+ var import_react_pro11 = require("@coreui/react-pro");
473
+ function MetricsSkeleton() {
474
+ return /* @__PURE__ */ React.createElement(import_react_pro11.CCard, { className: "shadow-none p-0 m-0 bg-transparent border-0" }, /* @__PURE__ */ React.createElement(import_react_pro11.CPlaceholder, { component: "div", animation: "glow", className: "d-flex flex-column gap-2 bg-transparent" }, /* @__PURE__ */ React.createElement(import_react_pro11.CPlaceholder, { className: "p-5 mt-2 rounded-1", size: "lg", xs: 12, color: "skeleton" }), /* @__PURE__ */ React.createElement(import_react_pro11.CPlaceholder, { className: "p-3 mt-2 rounded-1", size: "xs", xs: 12, color: "skeleton" })));
475
+ }
476
+
477
+ // src/components/back-button/BackButton.jsx
478
+ var import_navigation = require("next/navigation");
479
+ var import_react_pro12 = require("@coreui/react-pro");
480
+ var import_icons_react7 = __toESM(require("@coreui/icons-react"));
481
+ function BackButton({ title, color = "dark", className = "", path }) {
482
+ const { back, push } = (0, import_navigation.useRouter)();
483
+ const buttonClasses = `back-button d-flex align-items-center px-0 ${className}`;
484
+ function handleBack() {
485
+ if (path) push(path);
486
+ else back();
487
+ }
488
+ return /* @__PURE__ */ React.createElement(CustomTooltip, { content: "Volver atr\xE1s", placement: "bottom" }, /* @__PURE__ */ React.createElement(import_react_pro12.CButton, { color, variant: "ghost", className: buttonClasses, onClick: handleBack }, /* @__PURE__ */ React.createElement(import_icons_react7.default, { icon: cilArrowLeft, size: "lg", className: "mx-1" }), title && /* @__PURE__ */ React.createElement("span", { className: "px-2" }, title)));
489
+ }
197
490
  // Annotate the CommonJS export names for ESM import in node:
198
491
  0 && (module.exports = {
492
+ BackButton,
493
+ CardSkeleton,
199
494
  CustomTooltip,
200
495
  IconButton,
496
+ MetricCard,
497
+ MetricsSkeleton,
498
+ Modal,
201
499
  OutlineButton,
500
+ PaginatedGrid,
501
+ PaginatedTable,
202
502
  SolidButton,
203
- TextButton
503
+ TextButton,
504
+ TextSkeleton,
505
+ formatDateRange,
506
+ formatValue,
507
+ getBadgeStyles
204
508
  });
205
509
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.js","../src/components/buttons/SolidButton.jsx","../src/components/buttons/OutlineButton.jsx","../src/components/buttons/TextButton.jsx","../src/components/buttons/IconButton.jsx","../src/components/custom-tooltip/CustomTooltip.jsx"],"sourcesContent":["// Buttons\nexport { default as SolidButton } from './components/buttons/SolidButton'\nexport { default as OutlineButton } from './components/buttons/OutlineButton'\nexport { default as TextButton } from './components/buttons/TextButton'\nexport { default as IconButton } from './components/buttons/IconButton'\n\n// Utilities\nexport { default as CustomTooltip } from './components/custom-tooltip/CustomTooltip'\n","'use client'\nimport { CLoadingButton } from '@coreui/react-pro'\nimport CIcon from '@coreui/icons-react'\nimport './SolidButton.scss'\n\nexport default function SolidButton({\n title = 'Button',\n onClick,\n color = 'custom-primary',\n textColor = 'custom-white',\n className = '',\n loading = false,\n icon,\n svgComponent: SvgComponent,\n type = 'submit',\n badge,\n disabled,\n}) {\n return (\n <CLoadingButton\n type={type}\n onClick={onClick}\n className={`solid-button rounded-4 px-4 py-2 fw-semibold text-${textColor} bg-${color} ${className}`}\n loading={loading}\n disabledOnLoading\n disabled={disabled}\n style={{\n minHeight: '44px',\n minWidth: 'fit-content',\n fontSize: '0.95rem',\n letterSpacing: '0.3px',\n }}\n >\n {icon && <CIcon icon={icon} className=\"btn-icon\" />}\n {SvgComponent && !icon && <SvgComponent />}\n <span className=\"btn-title\">{title}</span>\n {badge && badge}\n </CLoadingButton>\n )\n}\n","'use client'\nimport { CLoadingButton } from '@coreui/react-pro'\nimport CIcon from '@coreui/icons-react'\nimport './OutlineButton.scss'\n\nexport default function OutlineButton({\n title = 'Button',\n onClick,\n color = 'custom-primary',\n className = '',\n loading = false,\n icon,\n type = 'submit',\n disabled,\n}) {\n return (\n <CLoadingButton\n type={type}\n onClick={onClick}\n className={`outline-button rounded-3 fw-medium text-${color} border-${color} ${className}`}\n loading={loading}\n disabledOnLoading\n disabled={disabled}\n variant=\"outline\"\n style={{\n maxHeight: '40px',\n minWidth: 'fit-content',\n }}\n >\n {icon && <CIcon icon={icon} />}\n <span>{title}</span>\n </CLoadingButton>\n )\n}\n","'use client'\nimport { CLoadingButton } from '@coreui/react-pro'\nimport CIcon from '@coreui/icons-react'\n\nexport default function TextButton({\n disabled,\n title,\n onClick,\n color = 'dark',\n className = '',\n loading = false,\n icon,\n children,\n}) {\n const buttonClasses = `rounded-3 px-2 d-flex justify-content-center gap-2 fw-medium ${className}`\n\n return (\n <span className=\"d-inline-block\" tabIndex={0}>\n <CLoadingButton\n disabled={disabled}\n onClick={onClick}\n variant=\"ghost\"\n type=\"button\"\n color={color}\n className={buttonClasses}\n loading={loading}\n >\n {icon && <CIcon size=\"xl\" icon={icon} />}\n {children ? children : title}\n </CLoadingButton>\n </span>\n )\n}\n","'use client'\nimport { CLoadingButton } from '@coreui/react-pro'\nimport CIcon from '@coreui/icons-react'\nimport CustomTooltip from '../custom-tooltip/CustomTooltip'\n\nexport default function IconButton({\n title,\n onClick,\n color = 'dark',\n className = '',\n loading = false,\n icon,\n tooltip = '',\n disabled,\n}) {\n const buttonClasses = `d-flex justify-content-center align-items-center gap-1 m-0 p-1 ${className}`\n\n return (\n <CustomTooltip content={tooltip} placement=\"bottom\">\n <CLoadingButton\n onClick={onClick}\n variant=\"ghost\"\n type=\"button\"\n color={color}\n className={buttonClasses}\n loading={loading}\n disabled={disabled}\n >\n <CIcon size=\"xl\" icon={icon} />\n {title && <span className=\"ml-2 d-none d-md-block\">{title}</span>}\n </CLoadingButton>\n </CustomTooltip>\n )\n}\n","'use client'\nimport Tippy from '@tippyjs/react'\nimport 'tippy.js/dist/tippy.css'\n\nexport default function CustomTooltip({\n content,\n placement = 'bottom',\n delay = 0,\n className = '',\n children,\n}) {\n return (\n <Tippy\n content={content}\n placement={placement}\n className={className}\n delay={delay}\n >\n {children}\n </Tippy>\n )\n}\n"],"mappings":"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","names":["CIcon","import_react_pro","import_icons_react","CIcon","import_react_pro","import_icons_react","CIcon","import_react_pro","import_icons_react","Tippy","CIcon"]}
1
+ {"version":3,"sources":["../src/index.js","../src/components/buttons/SolidButton.jsx","../src/components/buttons/OutlineButton.jsx","../src/components/buttons/TextButton.jsx","../src/components/buttons/IconButton.jsx","../src/components/custom-tooltip/CustomTooltip.jsx","../src/components/modal/Modal.jsx","../../../node_modules/@coreui/icons/src/free/cil-arrow-bottom.ts","../../../node_modules/@coreui/icons/src/free/cil-arrow-left.ts","../../../node_modules/@coreui/icons/src/free/cil-arrow-top.ts","../../../node_modules/@coreui/icons/src/free/cil-info.ts","../../../node_modules/@coreui/icons/src/free/cil-x.ts","../src/components/card/MetricCard.jsx","../src/components/card/card-utils.js","../src/components/pagination/PaginatedTable.jsx","../src/components/pagination/PaginatedGrid.jsx","../src/components/skeletons/CardSkeleton.jsx","../src/components/skeletons/TextSkeleton.jsx","../src/components/skeletons/MetricsSkeleton.jsx","../src/components/back-button/BackButton.jsx"],"sourcesContent":["// ── Buttons ───────────────────────────────────────────────────────────────────\nexport { default as SolidButton } from './components/buttons/SolidButton'\nexport { default as OutlineButton } from './components/buttons/OutlineButton'\nexport { default as TextButton } from './components/buttons/TextButton'\nexport { default as IconButton } from './components/buttons/IconButton'\n\n// ── Modal ─────────────────────────────────────────────────────────────────────\nexport { default as Modal } from './components/modal/Modal'\n\n// ── Cards ─────────────────────────────────────────────────────────────────────\nexport { default as MetricCard } from './components/card/MetricCard'\nexport { formatValue, getBadgeStyles, formatDateRange } from './components/card/card-utils'\n\n// ── Pagination ────────────────────────────────────────────────────────────────\nexport { default as PaginatedTable } from './components/pagination/PaginatedTable'\nexport { default as PaginatedGrid } from './components/pagination/PaginatedGrid'\n\n// ── Skeletons ─────────────────────────────────────────────────────────────────\nexport { default as CardSkeleton } from './components/skeletons/CardSkeleton'\nexport { default as TextSkeleton } from './components/skeletons/TextSkeleton'\nexport { default as MetricsSkeleton } from './components/skeletons/MetricsSkeleton'\n\n// ── Navigation ────────────────────────────────────────────────────────────────\nexport { default as BackButton } from './components/back-button/BackButton'\n\n// ── Utilities ─────────────────────────────────────────────────────────────────\nexport { default as CustomTooltip } from './components/custom-tooltip/CustomTooltip'\n","'use client'\nimport { CLoadingButton } from '@coreui/react-pro'\nimport CIcon from '@coreui/icons-react'\nimport './SolidButton.scss'\n\nexport default function SolidButton({\n title = 'Button',\n onClick,\n color = 'custom-primary',\n textColor = 'custom-white',\n className = '',\n loading = false,\n icon,\n svgComponent: SvgComponent,\n type = 'submit',\n badge,\n disabled,\n}) {\n return (\n <CLoadingButton\n type={type}\n onClick={onClick}\n className={`solid-button rounded-4 px-4 py-2 fw-semibold text-${textColor} bg-${color} ${className}`}\n loading={loading}\n disabledOnLoading\n disabled={disabled}\n style={{\n minHeight: '44px',\n minWidth: 'fit-content',\n fontSize: '0.95rem',\n letterSpacing: '0.3px',\n }}\n >\n {icon && <CIcon icon={icon} className=\"btn-icon\" />}\n {SvgComponent && !icon && <SvgComponent />}\n <span className=\"btn-title\">{title}</span>\n {badge && badge}\n </CLoadingButton>\n )\n}\n","'use client'\nimport { CLoadingButton } from '@coreui/react-pro'\nimport CIcon from '@coreui/icons-react'\nimport './OutlineButton.scss'\n\nexport default function OutlineButton({\n title = 'Button',\n onClick,\n color = 'custom-primary',\n className = '',\n loading = false,\n icon,\n type = 'submit',\n disabled,\n}) {\n return (\n <CLoadingButton\n type={type}\n onClick={onClick}\n className={`outline-button rounded-3 fw-medium text-${color} border-${color} ${className}`}\n loading={loading}\n disabledOnLoading\n disabled={disabled}\n variant=\"outline\"\n style={{\n maxHeight: '40px',\n minWidth: 'fit-content',\n }}\n >\n {icon && <CIcon icon={icon} />}\n <span>{title}</span>\n </CLoadingButton>\n )\n}\n","'use client'\nimport { CLoadingButton } from '@coreui/react-pro'\nimport CIcon from '@coreui/icons-react'\n\nexport default function TextButton({\n disabled,\n title,\n onClick,\n color = 'dark',\n className = '',\n loading = false,\n icon,\n children,\n}) {\n const buttonClasses = `rounded-3 px-2 d-flex justify-content-center gap-2 fw-medium ${className}`\n\n return (\n <span className=\"d-inline-block\" tabIndex={0}>\n <CLoadingButton\n disabled={disabled}\n onClick={onClick}\n variant=\"ghost\"\n type=\"button\"\n color={color}\n className={buttonClasses}\n loading={loading}\n >\n {icon && <CIcon size=\"xl\" icon={icon} />}\n {children ? children : title}\n </CLoadingButton>\n </span>\n )\n}\n","'use client'\nimport { CLoadingButton } from '@coreui/react-pro'\nimport CIcon from '@coreui/icons-react'\nimport CustomTooltip from '../custom-tooltip/CustomTooltip'\n\nexport default function IconButton({\n title,\n onClick,\n color = 'dark',\n className = '',\n loading = false,\n icon,\n tooltip = '',\n disabled,\n}) {\n const buttonClasses = `d-flex justify-content-center align-items-center gap-1 m-0 p-1 ${className}`\n\n return (\n <CustomTooltip content={tooltip} placement=\"bottom\">\n <CLoadingButton\n onClick={onClick}\n variant=\"ghost\"\n type=\"button\"\n color={color}\n className={buttonClasses}\n loading={loading}\n disabled={disabled}\n >\n <CIcon size=\"xl\" icon={icon} />\n {title && <span className=\"ml-2 d-none d-md-block\">{title}</span>}\n </CLoadingButton>\n </CustomTooltip>\n )\n}\n","'use client'\nimport Tippy from '@tippyjs/react'\nimport 'tippy.js/dist/tippy.css'\n\nexport default function CustomTooltip({\n content,\n placement = 'bottom',\n delay = 0,\n className = '',\n children,\n}) {\n return (\n <Tippy\n content={content}\n placement={placement}\n className={className}\n delay={delay}\n >\n {children}\n </Tippy>\n )\n}\n","'use client'\nimport CIcon from '@coreui/icons-react'\nimport { CModal, CModalBody, CModalHeader, CModalTitle } from '@coreui/react-pro'\nimport { cilX } from '@coreui/icons'\n\n/**\n * Modal reutilizable construido sobre CoreUI.\n *\n * @param {string} props.title - Título del modal\n * @param {Array} [props.titleIcon] - Ícono CoreUI opcional junto al título\n * @param {boolean} props.visible - Controla visibilidad\n * @param {Function} props.setVisible - Setter para abrir/cerrar\n * @param {'top'|'center'|'bottom'} [props.alignment='center'] - Alineación vertical\n * @param {'sm'|'lg'|'xl'} [props.size] - Tamaño del modal\n * @param {React.ReactNode} props.children - Contenido del body\n */\nexport default function Modal({\n title,\n titleIcon,\n visible,\n setVisible,\n alignment = 'center',\n size,\n children,\n}) {\n return (\n <CModal\n alignment={alignment}\n visible={visible}\n onClose={() => setVisible(false)}\n size={size}\n focus\n keyboard\n aria-labelledby=\"roax-modal-title\"\n >\n <CModalHeader className=\"position-relative\">\n <CModalTitle id=\"roax-modal-title\" className=\"d-flex align-items-center gap-2\">\n {titleIcon && <CIcon icon={titleIcon} size=\"lg\" className=\"text-muted\" />}\n {title}\n </CModalTitle>\n\n <button\n onClick={() => setVisible(false)}\n type=\"button\"\n className=\"position-absolute end-0 top-0 mt-3 me-3 p-0 bg-transparent border-0\"\n style={{ fontSize: '1.25rem', color: 'var(--cui-body-color)', zIndex: 10 }}\n aria-label=\"Cerrar\"\n >\n <CIcon icon={cilX} size=\"lg\" />\n </button>\n </CModalHeader>\n\n <CModalBody>{children}</CModalBody>\n </CModal>\n )\n}\n","export var cilArrowBottom = [\"512 512\", \"<polygon fill='var(--ci-primary-color, currentColor)' points='367.997 338.75 271.999 434.747 271.999 17.503 239.999 17.503 239.999 434.745 144.003 338.75 121.376 361.377 256 496 390.624 361.377 367.997 338.75' class='ci-primary'/>\"];\n","export var cilArrowLeft = [\"512 512\", \"<polygon fill='var(--ci-primary-color, currentColor)' points='497.333 239.999 80.092 239.999 176.087 144.004 153.46 121.377 18.837 256 153.46 390.623 176.087 367.996 80.09 271.999 497.333 271.999 497.333 239.999' class='ci-primary'/>\"];\n","export var cilArrowTop = [\"512 512\", \"<polygon fill='var(--ci-primary-color, currentColor)' points='390.624 150.625 256 16 121.376 150.625 144.004 173.252 240.001 77.254 240.001 495.236 272.001 495.236 272.001 77.257 367.996 173.252 390.624 150.625' class='ci-primary'/>\"];\n","export var cilInfo = [\"512 512\", \"<rect width='34.924' height='34.924' x='256' y='95.998' fill='var(--ci-primary-color, currentColor)' class='ci-primary'/><path fill='var(--ci-primary-color, currentColor)' d='M16,496H496V16H16ZM48,48H464V464H48Z' class='ci-primary'/><path fill='var(--ci-primary-color, currentColor)' d='M285.313,359.032a18.123,18.123,0,0,1-15.6,8.966,18.061,18.061,0,0,1-17.327-23.157l35.67-121.277A49.577,49.577,0,0,0,194.7,190.572l-11.718,28.234,29.557,12.266,11.718-28.235a17.577,17.577,0,0,1,33.1,11.7l-35.67,121.277A50.061,50.061,0,0,0,269.709,400a50.227,50.227,0,0,0,43.25-24.853l15.1-25.913-27.646-16.115Z' class='ci-primary'/>\"];\n","export var cilX = [\"512 512\", \"<polygon fill='var(--ci-primary-color, currentColor)' points='427.314 107.313 404.686 84.687 256 233.373 107.314 84.687 84.686 107.313 233.373 256 84.686 404.687 107.314 427.313 256 278.627 404.686 427.313 427.314 404.687 278.627 256 427.314 107.313' class='ci-primary'/>\"];\n","'use client'\nimport { CCard, CCardBody } from '@coreui/react-pro'\nimport CIcon from '@coreui/icons-react'\nimport { cilArrowTop, cilArrowBottom, cilInfo } from '@coreui/icons'\nimport CustomTooltip from '../custom-tooltip/CustomTooltip'\nimport { formatValue, getBadgeStyles, formatDateRange } from './card-utils'\nimport './MetricCard.scss'\n\n/**\n * Tarjeta de métrica con glassmorphism, tendencia y rango de fechas previo.\n *\n * @param {string} props.title - Nombre de la métrica\n * @param {number} props.current - Valor actual\n * @param {number} props.previous - Valor anterior (periodo previo)\n * @param {number} props.change - Variación porcentual\n * @param {boolean} props.isPositive - Si la tendencia es positiva\n * @param {string} [props.unit=''] - Unidad: '$', '%', 'COP', 'x'\n * @param {string} [props.previousDateRange=''] - Rango de fechas previo (yyyy-MM-dd - yyyy-MM-dd)\n * @param {string} [props.tooltipText=''] - Texto del tooltip de información\n * @param {string} [props.backgroundColor] - Color de fondo custom (glassmorphism tintado)\n */\nexport default function MetricCard({\n title,\n current,\n previous,\n change,\n isPositive,\n unit = '',\n previousDateRange = '',\n tooltipText = '',\n backgroundColor,\n}) {\n const isColored = !!backgroundColor\n const cardClass = `metric-card w-100 h-100 d-flex flex-column border-0${isColored ? ' metric-card--colored' : ''}`\n\n return (\n <CCard\n className={cardClass}\n style={isColored ? { background: backgroundColor } : undefined}\n >\n <CCardBody className=\"d-flex flex-column justify-content-between h-100 p-4 position-relative\">\n\n {tooltipText && (\n <div className=\"position-absolute top-0 end-0 m-2\">\n <CustomTooltip content={tooltipText} placement=\"top\">\n <CIcon\n icon={cilInfo}\n style={{ cursor: 'pointer', opacity: 0.5, width: 16, height: 16 }}\n />\n </CustomTooltip>\n </div>\n )}\n\n <p className=\"metric-card__title m-0\">{title}</p>\n\n <div className=\"d-flex align-items-center gap-2 mt-1\">\n <span className=\"metric-card__value\">\n {formatValue(current, unit, title)}\n </span>\n {typeof change === 'number' && isFinite(change) && current > 0 && (\n <div style={getBadgeStyles(isPositive)}>\n <CIcon icon={isPositive ? cilArrowTop : cilArrowBottom} size=\"sm\" />\n {Math.abs(change)}%\n </div>\n )}\n </div>\n\n <hr className=\"metric-card__divider\" />\n\n {(() => {\n const { formattedRange } = formatDateRange(previousDateRange)\n return (\n <div className=\"d-flex justify-content-between align-items-center metric-card__footer\">\n <strong>{formatValue(previous, unit, title)}</strong>\n <span>{formattedRange}</span>\n </div>\n )\n })()}\n\n </CCardBody>\n </CCard>\n )\n}\n","/**\n * Formatea un valor numérico según su unidad o contexto del título.\n * @param {number} val\n * @param {string} [unit='']\n * @param {string} [title='']\n * @returns {string}\n */\nexport const formatValue = (val, unit = '', title = '') => {\n if (val == null || typeof val !== 'number' || val === 0) return '0'\n if (title.includes('ROAS')) return `x ${val.toFixed(2)}`\n if (title.includes('CAC %')) return `${val.toFixed(2)}%`\n if (unit === '%' || title.includes('%')) return `${val.toFixed(2)}%`\n if (unit === 'x') return `x ${val.toFixed(2)}`\n if (unit === 'COP') return `COP ${Math.round(val).toLocaleString('es-CO')}`\n return val.toLocaleString(undefined, { minimumFractionDigits: 0, maximumFractionDigits: 2 })\n}\n\n/**\n * Retorna estilos de badge según si la tendencia es positiva o negativa.\n * @param {boolean} isPositive\n * @returns {Object}\n */\nexport const getBadgeStyles = (isPositive) => ({\n backgroundColor: isPositive ? '#55ed7b' : '#f74a4a',\n color: isPositive ? '#0b3e26' : '#842029',\n borderRadius: '9999px',\n padding: '4px 10px',\n fontSize: '0.75rem',\n fontWeight: 700,\n display: 'inline-flex',\n alignItems: 'center',\n gap: '4px',\n})\n\n/**\n * Formatea un rango de fechas 'yyyy-MM-dd - yyyy-MM-dd' a formato legible.\n * @param {string} previousDateRange\n * @returns {{ formattedRange: string }}\n */\nexport function formatDateRange(previousDateRange) {\n if (!previousDateRange) return { formattedRange: '' }\n const parts = previousDateRange.split(' - ')\n const parseDate = (str) => {\n const [year, month, day] = str.split('-').map(Number)\n return new Date(year, month - 1, day)\n }\n const format = (date) => {\n const day = String(date.getDate()).padStart(2, '0')\n const month = date.toLocaleString('es-CO', { month: 'short' }).replace('.', '')\n const year = String(date.getFullYear()).slice(-2)\n return `${month} ${day},${year}`\n }\n const since = parseDate(parts[0])\n const until = parts[1] ? parseDate(parts[1]) : null\n const formattedRange = until ? `${format(since)} - ${format(until)}` : format(since)\n return { formattedRange }\n}\n","'use client'\nimport {\n CTable,\n CTableHead,\n CTableBody,\n CTableRow,\n CTableHeaderCell,\n CSpinner,\n} from '@coreui/react-pro'\n\n/**\n * Tabla paginada reutilizable construida sobre CoreUI.\n *\n * @param {Array} [props.data=[]] - Dataset completo\n * @param {number} [props.itemsPerPage=10] - Items por página\n * @param {number} [props.currentPage=1] - Página actual\n * @param {Function} [props.setCurrentPage] - Setter de página\n * @param {string[]} [props.columns=[]] - Cabeceras de columna\n * @param {Function} [props.renderRow] - Función que renderiza cada fila\n * @param {boolean} [props.loading=false] - Estado de carga\n * @param {string} [props.emptyMessage] - Mensaje sin datos\n */\nexport default function PaginatedTable({\n data = [],\n itemsPerPage = 10,\n currentPage = 1,\n setCurrentPage = () => {},\n columns = [],\n renderRow = () => null,\n loading = false,\n emptyMessage = 'No hay datos disponibles.',\n}) {\n const totalPages = Math.ceil(data.length / itemsPerPage)\n const paginatedData = data.slice(\n (currentPage - 1) * itemsPerPage,\n currentPage * itemsPerPage\n )\n\n if (loading) {\n return (\n <div className=\"text-center py-5\">\n <CSpinner color=\"secondary\" />\n </div>\n )\n }\n\n if (!data.length) {\n return <div className=\"text-center py-5 text-muted\">{emptyMessage}</div>\n }\n\n const renderPagination = () => {\n const pages = []\n for (let i = 1; i <= totalPages; i++) {\n pages.push(\n <button\n key={i}\n onClick={() => setCurrentPage(i)}\n className={`px-3 py-1 rounded-pill border ${\n i === currentPage ? 'bg-dark text-white' : 'bg-white text-dark'\n }`}\n >\n {i}\n </button>\n )\n }\n\n return (\n <div className=\"d-flex justify-content-center align-items-center gap-2 mt-3 flex-wrap\">\n {currentPage > 1 && (\n <button\n onClick={() => setCurrentPage(currentPage - 1)}\n className=\"px-3 py-1 rounded-pill border bg-white text-dark\"\n style={{ minWidth: '80px', fontWeight: 500 }}\n >\n Anterior\n </button>\n )}\n {pages}\n {currentPage < totalPages && (\n <button\n onClick={() => setCurrentPage(currentPage + 1)}\n className=\"px-3 py-1 rounded-pill border bg-white text-dark\"\n style={{ minWidth: '80px', fontWeight: 500 }}\n >\n Siguiente\n </button>\n )}\n </div>\n )\n }\n\n return (\n <>\n <CTable hover responsive>\n <CTableHead className=\"bg-dark text-white\">\n <CTableRow>\n {columns.map((col, idx) => (\n <CTableHeaderCell key={idx}>{col}</CTableHeaderCell>\n ))}\n </CTableRow>\n </CTableHead>\n <CTableBody>{paginatedData.map(renderRow)}</CTableBody>\n </CTable>\n {totalPages > 1 && renderPagination()}\n </>\n )\n}\n","'use client'\nimport { CSpinner } from '@coreui/react-pro'\n\n/**\n * Grid paginado para renderizar ítems tipo card.\n *\n * @param {Array} [props.data=[]] - Dataset completo\n * @param {number} [props.itemsPerPage=6] - Items por página\n * @param {number} [props.currentPage=1] - Página actual\n * @param {Function} [props.setCurrentPage] - Setter de página\n * @param {Function} [props.renderItem] - Función que renderiza cada ítem\n * @param {boolean} [props.loading=false] - Estado de carga\n * @param {string} [props.emptyMessage] - Mensaje sin datos\n */\nexport default function PaginatedGrid({\n data = [],\n itemsPerPage = 6,\n currentPage = 1,\n setCurrentPage = () => {},\n renderItem = () => null,\n loading = false,\n emptyMessage = 'No hay elementos.',\n}) {\n const totalPages = Math.ceil(data.length / itemsPerPage)\n const paginatedData = data.slice(\n (currentPage - 1) * itemsPerPage,\n currentPage * itemsPerPage\n )\n\n if (loading) {\n return (\n <div className=\"text-center py-5\">\n <CSpinner color=\"secondary\" />\n </div>\n )\n }\n\n if (!data.length) {\n return <div className=\"text-center py-5 text-muted\">{emptyMessage}</div>\n }\n\n const renderPagination = () => {\n const pages = []\n for (let i = 1; i <= totalPages; i++) {\n pages.push(\n <button\n key={i}\n onClick={() => setCurrentPage(i)}\n className={`px-3 py-1 rounded-pill border ${\n i === currentPage ? 'bg-dark text-white' : 'bg-white text-dark'\n }`}\n >\n {i}\n </button>\n )\n }\n return (\n <div className=\"d-flex justify-content-center gap-2 mt-4 flex-wrap\">\n {currentPage > 1 && (\n <button\n onClick={() => setCurrentPage(currentPage - 1)}\n className=\"px-3 py-1 rounded-pill border bg-white text-dark\"\n >\n Anterior\n </button>\n )}\n {pages}\n {currentPage < totalPages && (\n <button\n onClick={() => setCurrentPage(currentPage + 1)}\n className=\"px-3 py-1 rounded-pill border bg-white text-dark\"\n >\n Siguiente\n </button>\n )}\n </div>\n )\n }\n\n return (\n <>\n <div className=\"row g-4\">{paginatedData.map(renderItem)}</div>\n {totalPages > 1 && renderPagination()}\n </>\n )\n}\n","import { CCard, CPlaceholder } from '@coreui/react-pro'\n\n/** Skeleton de tarjeta — reemplaza un card mientras carga su contenido. */\nexport default function CardSkeleton() {\n return (\n <CCard className=\"shadow-none p-0 m-0 bg-transparent border-0\">\n <CPlaceholder component=\"div\" animation=\"glow\" className=\"d-flex flex-column gap-2 bg-transparent\">\n <CPlaceholder className=\"p-4 mt-2 rounded-1\" size=\"lg\" xs={12} color=\"skeleton\" />\n </CPlaceholder>\n </CCard>\n )\n}\n","import { CCard, CPlaceholder } from '@coreui/react-pro'\n\n/** Skeleton de texto — reemplaza una línea de texto mientras carga. */\nexport default function TextSkeleton() {\n return (\n <CCard className=\"shadow-none p-0 m-0 bg-transparent border-0\">\n <CPlaceholder component=\"div\" animation=\"glow\" className=\"d-flex flex-column gap-2 bg-transparent\">\n <CPlaceholder className=\"p-0 my-2 rounded-1\" size=\"lg\" xs={8} color=\"skeleton\" />\n </CPlaceholder>\n </CCard>\n )\n}\n","import { CCard, CPlaceholder } from '@coreui/react-pro'\n\n/** Skeleton de métrica — reemplaza un MetricCard mientras carga. */\nexport default function MetricsSkeleton() {\n return (\n <CCard className=\"shadow-none p-0 m-0 bg-transparent border-0\">\n <CPlaceholder component=\"div\" animation=\"glow\" className=\"d-flex flex-column gap-2 bg-transparent\">\n <CPlaceholder className=\"p-5 mt-2 rounded-1\" size=\"lg\" xs={12} color=\"skeleton\" />\n <CPlaceholder className=\"p-3 mt-2 rounded-1\" size=\"xs\" xs={12} color=\"skeleton\" />\n </CPlaceholder>\n </CCard>\n )\n}\n","'use client'\nimport { useRouter } from 'next/navigation'\nimport { CButton } from '@coreui/react-pro'\nimport { cilArrowLeft } from '@coreui/icons'\nimport CIcon from '@coreui/icons-react'\nimport CustomTooltip from '../custom-tooltip/CustomTooltip'\n\n/**\n * Botón de navegación hacia atrás.\n * Usa router.push(path) si se pasa path, o router.back() si no.\n *\n * @param {string} [props.title] - Texto opcional junto al ícono\n * @param {string} [props.color='dark'] - Color CoreUI del botón\n * @param {string} [props.path] - Ruta destino (si no, usa history.back())\n * @param {string} [props.className] - Clases CSS adicionales\n */\nexport default function BackButton({ title, color = 'dark', className = '', path }) {\n const { back, push } = useRouter()\n const buttonClasses = `back-button d-flex align-items-center px-0 ${className}`\n\n function handleBack() {\n if (path) push(path)\n else back()\n }\n\n return (\n <CustomTooltip content=\"Volver atrás\" placement=\"bottom\">\n <CButton color={color} variant=\"ghost\" className={buttonClasses} onClick={handleBack}>\n <CIcon icon={cilArrowLeft} size=\"lg\" className=\"mx-1\" />\n {title && <span className=\"px-2\">{title}</span>}\n </CButton>\n </CustomTooltip>\n )\n}\n"],"mappings":"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","names":["CIcon","import_react_pro","import_icons_react","CIcon","import_react_pro","import_icons_react","CIcon","import_react_pro","import_icons_react","Tippy","CIcon","import_icons_react","import_react_pro","CIcon","import_react_pro","import_icons_react","CIcon","import_react_pro","import_react_pro","import_react_pro","import_react_pro","import_react_pro","import_react_pro","import_icons_react","CIcon"]}
package/dist/index.mjs CHANGED
@@ -155,11 +155,311 @@ function IconButton({
155
155
  title && /* @__PURE__ */ React.createElement("span", { className: "ml-2 d-none d-md-block" }, title)
156
156
  ));
157
157
  }
158
+
159
+ // src/components/modal/Modal.jsx
160
+ import CIcon5 from "@coreui/icons-react";
161
+ import { CModal, CModalBody, CModalHeader, CModalTitle } from "@coreui/react-pro";
162
+
163
+ // ../../node_modules/@coreui/icons/dist/esm/free/cil-arrow-bottom.js
164
+ var cilArrowBottom = ["512 512", "<polygon fill='var(--ci-primary-color, currentColor)' points='367.997 338.75 271.999 434.747 271.999 17.503 239.999 17.503 239.999 434.745 144.003 338.75 121.376 361.377 256 496 390.624 361.377 367.997 338.75' class='ci-primary'/>"];
165
+
166
+ // ../../node_modules/@coreui/icons/dist/esm/free/cil-arrow-left.js
167
+ var cilArrowLeft = ["512 512", "<polygon fill='var(--ci-primary-color, currentColor)' points='497.333 239.999 80.092 239.999 176.087 144.004 153.46 121.377 18.837 256 153.46 390.623 176.087 367.996 80.09 271.999 497.333 271.999 497.333 239.999' class='ci-primary'/>"];
168
+
169
+ // ../../node_modules/@coreui/icons/dist/esm/free/cil-arrow-top.js
170
+ var cilArrowTop = ["512 512", "<polygon fill='var(--ci-primary-color, currentColor)' points='390.624 150.625 256 16 121.376 150.625 144.004 173.252 240.001 77.254 240.001 495.236 272.001 495.236 272.001 77.257 367.996 173.252 390.624 150.625' class='ci-primary'/>"];
171
+
172
+ // ../../node_modules/@coreui/icons/dist/esm/free/cil-info.js
173
+ var cilInfo = ["512 512", "<rect width='34.924' height='34.924' x='256' y='95.998' fill='var(--ci-primary-color, currentColor)' class='ci-primary'/><path fill='var(--ci-primary-color, currentColor)' d='M16,496H496V16H16ZM48,48H464V464H48Z' class='ci-primary'/><path fill='var(--ci-primary-color, currentColor)' d='M285.313,359.032a18.123,18.123,0,0,1-15.6,8.966,18.061,18.061,0,0,1-17.327-23.157l35.67-121.277A49.577,49.577,0,0,0,194.7,190.572l-11.718,28.234,29.557,12.266,11.718-28.235a17.577,17.577,0,0,1,33.1,11.7l-35.67,121.277A50.061,50.061,0,0,0,269.709,400a50.227,50.227,0,0,0,43.25-24.853l15.1-25.913-27.646-16.115Z' class='ci-primary'/>"];
174
+
175
+ // ../../node_modules/@coreui/icons/dist/esm/free/cil-x.js
176
+ var cilX = ["512 512", "<polygon fill='var(--ci-primary-color, currentColor)' points='427.314 107.313 404.686 84.687 256 233.373 107.314 84.687 84.686 107.313 233.373 256 84.686 404.687 107.314 427.313 256 278.627 404.686 427.313 427.314 404.687 278.627 256 427.314 107.313' class='ci-primary'/>"];
177
+
178
+ // src/components/modal/Modal.jsx
179
+ function Modal({
180
+ title,
181
+ titleIcon,
182
+ visible,
183
+ setVisible,
184
+ alignment = "center",
185
+ size,
186
+ children
187
+ }) {
188
+ return /* @__PURE__ */ React.createElement(
189
+ CModal,
190
+ {
191
+ alignment,
192
+ visible,
193
+ onClose: () => setVisible(false),
194
+ size,
195
+ focus: true,
196
+ keyboard: true,
197
+ "aria-labelledby": "roax-modal-title"
198
+ },
199
+ /* @__PURE__ */ React.createElement(CModalHeader, { className: "position-relative" }, /* @__PURE__ */ React.createElement(CModalTitle, { id: "roax-modal-title", className: "d-flex align-items-center gap-2" }, titleIcon && /* @__PURE__ */ React.createElement(CIcon5, { icon: titleIcon, size: "lg", className: "text-muted" }), title), /* @__PURE__ */ React.createElement(
200
+ "button",
201
+ {
202
+ onClick: () => setVisible(false),
203
+ type: "button",
204
+ className: "position-absolute end-0 top-0 mt-3 me-3 p-0 bg-transparent border-0",
205
+ style: { fontSize: "1.25rem", color: "var(--cui-body-color)", zIndex: 10 },
206
+ "aria-label": "Cerrar"
207
+ },
208
+ /* @__PURE__ */ React.createElement(CIcon5, { icon: cilX, size: "lg" })
209
+ )),
210
+ /* @__PURE__ */ React.createElement(CModalBody, null, children)
211
+ );
212
+ }
213
+
214
+ // src/components/card/MetricCard.jsx
215
+ import { CCard, CCardBody } from "@coreui/react-pro";
216
+ import CIcon6 from "@coreui/icons-react";
217
+
218
+ // src/components/card/card-utils.js
219
+ var formatValue = (val, unit = "", title = "") => {
220
+ if (val == null || typeof val !== "number" || val === 0) return "0";
221
+ if (title.includes("ROAS")) return `x ${val.toFixed(2)}`;
222
+ if (title.includes("CAC %")) return `${val.toFixed(2)}%`;
223
+ if (unit === "%" || title.includes("%")) return `${val.toFixed(2)}%`;
224
+ if (unit === "x") return `x ${val.toFixed(2)}`;
225
+ if (unit === "COP") return `COP ${Math.round(val).toLocaleString("es-CO")}`;
226
+ return val.toLocaleString(void 0, { minimumFractionDigits: 0, maximumFractionDigits: 2 });
227
+ };
228
+ var getBadgeStyles = (isPositive) => ({
229
+ backgroundColor: isPositive ? "#55ed7b" : "#f74a4a",
230
+ color: isPositive ? "#0b3e26" : "#842029",
231
+ borderRadius: "9999px",
232
+ padding: "4px 10px",
233
+ fontSize: "0.75rem",
234
+ fontWeight: 700,
235
+ display: "inline-flex",
236
+ alignItems: "center",
237
+ gap: "4px"
238
+ });
239
+ function formatDateRange(previousDateRange) {
240
+ if (!previousDateRange) return { formattedRange: "" };
241
+ const parts = previousDateRange.split(" - ");
242
+ const parseDate = (str) => {
243
+ const [year, month, day] = str.split("-").map(Number);
244
+ return new Date(year, month - 1, day);
245
+ };
246
+ const format = (date) => {
247
+ const day = String(date.getDate()).padStart(2, "0");
248
+ const month = date.toLocaleString("es-CO", { month: "short" }).replace(".", "");
249
+ const year = String(date.getFullYear()).slice(-2);
250
+ return `${month} ${day},${year}`;
251
+ };
252
+ const since = parseDate(parts[0]);
253
+ const until = parts[1] ? parseDate(parts[1]) : null;
254
+ const formattedRange = until ? `${format(since)} - ${format(until)}` : format(since);
255
+ return { formattedRange };
256
+ }
257
+
258
+ // src/components/card/MetricCard.jsx
259
+ import "./MetricCard.scss";
260
+ function MetricCard({
261
+ title,
262
+ current,
263
+ previous,
264
+ change,
265
+ isPositive,
266
+ unit = "",
267
+ previousDateRange = "",
268
+ tooltipText = "",
269
+ backgroundColor
270
+ }) {
271
+ const isColored = !!backgroundColor;
272
+ const cardClass = `metric-card w-100 h-100 d-flex flex-column border-0${isColored ? " metric-card--colored" : ""}`;
273
+ return /* @__PURE__ */ React.createElement(
274
+ CCard,
275
+ {
276
+ className: cardClass,
277
+ style: isColored ? { background: backgroundColor } : void 0
278
+ },
279
+ /* @__PURE__ */ React.createElement(CCardBody, { className: "d-flex flex-column justify-content-between h-100 p-4 position-relative" }, tooltipText && /* @__PURE__ */ React.createElement("div", { className: "position-absolute top-0 end-0 m-2" }, /* @__PURE__ */ React.createElement(CustomTooltip, { content: tooltipText, placement: "top" }, /* @__PURE__ */ React.createElement(
280
+ CIcon6,
281
+ {
282
+ icon: cilInfo,
283
+ style: { cursor: "pointer", opacity: 0.5, width: 16, height: 16 }
284
+ }
285
+ ))), /* @__PURE__ */ React.createElement("p", { className: "metric-card__title m-0" }, title), /* @__PURE__ */ React.createElement("div", { className: "d-flex align-items-center gap-2 mt-1" }, /* @__PURE__ */ React.createElement("span", { className: "metric-card__value" }, formatValue(current, unit, title)), typeof change === "number" && isFinite(change) && current > 0 && /* @__PURE__ */ React.createElement("div", { style: getBadgeStyles(isPositive) }, /* @__PURE__ */ React.createElement(CIcon6, { icon: isPositive ? cilArrowTop : cilArrowBottom, size: "sm" }), Math.abs(change), "%")), /* @__PURE__ */ React.createElement("hr", { className: "metric-card__divider" }), (() => {
286
+ const { formattedRange } = formatDateRange(previousDateRange);
287
+ return /* @__PURE__ */ React.createElement("div", { className: "d-flex justify-content-between align-items-center metric-card__footer" }, /* @__PURE__ */ React.createElement("strong", null, formatValue(previous, unit, title)), /* @__PURE__ */ React.createElement("span", null, formattedRange));
288
+ })())
289
+ );
290
+ }
291
+
292
+ // src/components/pagination/PaginatedTable.jsx
293
+ import {
294
+ CTable,
295
+ CTableHead,
296
+ CTableBody,
297
+ CTableRow,
298
+ CTableHeaderCell,
299
+ CSpinner
300
+ } from "@coreui/react-pro";
301
+ function PaginatedTable({
302
+ data = [],
303
+ itemsPerPage = 10,
304
+ currentPage = 1,
305
+ setCurrentPage = () => {
306
+ },
307
+ columns = [],
308
+ renderRow = () => null,
309
+ loading = false,
310
+ emptyMessage = "No hay datos disponibles."
311
+ }) {
312
+ const totalPages = Math.ceil(data.length / itemsPerPage);
313
+ const paginatedData = data.slice(
314
+ (currentPage - 1) * itemsPerPage,
315
+ currentPage * itemsPerPage
316
+ );
317
+ if (loading) {
318
+ return /* @__PURE__ */ React.createElement("div", { className: "text-center py-5" }, /* @__PURE__ */ React.createElement(CSpinner, { color: "secondary" }));
319
+ }
320
+ if (!data.length) {
321
+ return /* @__PURE__ */ React.createElement("div", { className: "text-center py-5 text-muted" }, emptyMessage);
322
+ }
323
+ const renderPagination = () => {
324
+ const pages = [];
325
+ for (let i = 1; i <= totalPages; i++) {
326
+ pages.push(
327
+ /* @__PURE__ */ React.createElement(
328
+ "button",
329
+ {
330
+ key: i,
331
+ onClick: () => setCurrentPage(i),
332
+ className: `px-3 py-1 rounded-pill border ${i === currentPage ? "bg-dark text-white" : "bg-white text-dark"}`
333
+ },
334
+ i
335
+ )
336
+ );
337
+ }
338
+ return /* @__PURE__ */ React.createElement("div", { className: "d-flex justify-content-center align-items-center gap-2 mt-3 flex-wrap" }, currentPage > 1 && /* @__PURE__ */ React.createElement(
339
+ "button",
340
+ {
341
+ onClick: () => setCurrentPage(currentPage - 1),
342
+ className: "px-3 py-1 rounded-pill border bg-white text-dark",
343
+ style: { minWidth: "80px", fontWeight: 500 }
344
+ },
345
+ "Anterior"
346
+ ), pages, currentPage < totalPages && /* @__PURE__ */ React.createElement(
347
+ "button",
348
+ {
349
+ onClick: () => setCurrentPage(currentPage + 1),
350
+ className: "px-3 py-1 rounded-pill border bg-white text-dark",
351
+ style: { minWidth: "80px", fontWeight: 500 }
352
+ },
353
+ "Siguiente"
354
+ ));
355
+ };
356
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(CTable, { hover: true, responsive: true }, /* @__PURE__ */ React.createElement(CTableHead, { className: "bg-dark text-white" }, /* @__PURE__ */ React.createElement(CTableRow, null, columns.map((col, idx) => /* @__PURE__ */ React.createElement(CTableHeaderCell, { key: idx }, col)))), /* @__PURE__ */ React.createElement(CTableBody, null, paginatedData.map(renderRow))), totalPages > 1 && renderPagination());
357
+ }
358
+
359
+ // src/components/pagination/PaginatedGrid.jsx
360
+ import { CSpinner as CSpinner2 } from "@coreui/react-pro";
361
+ function PaginatedGrid({
362
+ data = [],
363
+ itemsPerPage = 6,
364
+ currentPage = 1,
365
+ setCurrentPage = () => {
366
+ },
367
+ renderItem = () => null,
368
+ loading = false,
369
+ emptyMessage = "No hay elementos."
370
+ }) {
371
+ const totalPages = Math.ceil(data.length / itemsPerPage);
372
+ const paginatedData = data.slice(
373
+ (currentPage - 1) * itemsPerPage,
374
+ currentPage * itemsPerPage
375
+ );
376
+ if (loading) {
377
+ return /* @__PURE__ */ React.createElement("div", { className: "text-center py-5" }, /* @__PURE__ */ React.createElement(CSpinner2, { color: "secondary" }));
378
+ }
379
+ if (!data.length) {
380
+ return /* @__PURE__ */ React.createElement("div", { className: "text-center py-5 text-muted" }, emptyMessage);
381
+ }
382
+ const renderPagination = () => {
383
+ const pages = [];
384
+ for (let i = 1; i <= totalPages; i++) {
385
+ pages.push(
386
+ /* @__PURE__ */ React.createElement(
387
+ "button",
388
+ {
389
+ key: i,
390
+ onClick: () => setCurrentPage(i),
391
+ className: `px-3 py-1 rounded-pill border ${i === currentPage ? "bg-dark text-white" : "bg-white text-dark"}`
392
+ },
393
+ i
394
+ )
395
+ );
396
+ }
397
+ return /* @__PURE__ */ React.createElement("div", { className: "d-flex justify-content-center gap-2 mt-4 flex-wrap" }, currentPage > 1 && /* @__PURE__ */ React.createElement(
398
+ "button",
399
+ {
400
+ onClick: () => setCurrentPage(currentPage - 1),
401
+ className: "px-3 py-1 rounded-pill border bg-white text-dark"
402
+ },
403
+ "Anterior"
404
+ ), pages, currentPage < totalPages && /* @__PURE__ */ React.createElement(
405
+ "button",
406
+ {
407
+ onClick: () => setCurrentPage(currentPage + 1),
408
+ className: "px-3 py-1 rounded-pill border bg-white text-dark"
409
+ },
410
+ "Siguiente"
411
+ ));
412
+ };
413
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "row g-4" }, paginatedData.map(renderItem)), totalPages > 1 && renderPagination());
414
+ }
415
+
416
+ // src/components/skeletons/CardSkeleton.jsx
417
+ import { CCard as CCard2, CPlaceholder } from "@coreui/react-pro";
418
+ function CardSkeleton() {
419
+ return /* @__PURE__ */ React.createElement(CCard2, { className: "shadow-none p-0 m-0 bg-transparent border-0" }, /* @__PURE__ */ React.createElement(CPlaceholder, { component: "div", animation: "glow", className: "d-flex flex-column gap-2 bg-transparent" }, /* @__PURE__ */ React.createElement(CPlaceholder, { className: "p-4 mt-2 rounded-1", size: "lg", xs: 12, color: "skeleton" })));
420
+ }
421
+
422
+ // src/components/skeletons/TextSkeleton.jsx
423
+ import { CCard as CCard3, CPlaceholder as CPlaceholder2 } from "@coreui/react-pro";
424
+ function TextSkeleton() {
425
+ return /* @__PURE__ */ React.createElement(CCard3, { className: "shadow-none p-0 m-0 bg-transparent border-0" }, /* @__PURE__ */ React.createElement(CPlaceholder2, { component: "div", animation: "glow", className: "d-flex flex-column gap-2 bg-transparent" }, /* @__PURE__ */ React.createElement(CPlaceholder2, { className: "p-0 my-2 rounded-1", size: "lg", xs: 8, color: "skeleton" })));
426
+ }
427
+
428
+ // src/components/skeletons/MetricsSkeleton.jsx
429
+ import { CCard as CCard4, CPlaceholder as CPlaceholder3 } from "@coreui/react-pro";
430
+ function MetricsSkeleton() {
431
+ return /* @__PURE__ */ React.createElement(CCard4, { className: "shadow-none p-0 m-0 bg-transparent border-0" }, /* @__PURE__ */ React.createElement(CPlaceholder3, { component: "div", animation: "glow", className: "d-flex flex-column gap-2 bg-transparent" }, /* @__PURE__ */ React.createElement(CPlaceholder3, { className: "p-5 mt-2 rounded-1", size: "lg", xs: 12, color: "skeleton" }), /* @__PURE__ */ React.createElement(CPlaceholder3, { className: "p-3 mt-2 rounded-1", size: "xs", xs: 12, color: "skeleton" })));
432
+ }
433
+
434
+ // src/components/back-button/BackButton.jsx
435
+ import { useRouter } from "next/navigation";
436
+ import { CButton } from "@coreui/react-pro";
437
+ import CIcon7 from "@coreui/icons-react";
438
+ function BackButton({ title, color = "dark", className = "", path }) {
439
+ const { back, push } = useRouter();
440
+ const buttonClasses = `back-button d-flex align-items-center px-0 ${className}`;
441
+ function handleBack() {
442
+ if (path) push(path);
443
+ else back();
444
+ }
445
+ return /* @__PURE__ */ React.createElement(CustomTooltip, { content: "Volver atr\xE1s", placement: "bottom" }, /* @__PURE__ */ React.createElement(CButton, { color, variant: "ghost", className: buttonClasses, onClick: handleBack }, /* @__PURE__ */ React.createElement(CIcon7, { icon: cilArrowLeft, size: "lg", className: "mx-1" }), title && /* @__PURE__ */ React.createElement("span", { className: "px-2" }, title)));
446
+ }
158
447
  export {
448
+ BackButton,
449
+ CardSkeleton,
159
450
  CustomTooltip,
160
451
  IconButton,
452
+ MetricCard,
453
+ MetricsSkeleton,
454
+ Modal,
161
455
  OutlineButton,
456
+ PaginatedGrid,
457
+ PaginatedTable,
162
458
  SolidButton,
163
- TextButton
459
+ TextButton,
460
+ TextSkeleton,
461
+ formatDateRange,
462
+ formatValue,
463
+ getBadgeStyles
164
464
  };
165
465
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/buttons/SolidButton.jsx","../src/components/buttons/OutlineButton.jsx","../src/components/buttons/TextButton.jsx","../src/components/buttons/IconButton.jsx","../src/components/custom-tooltip/CustomTooltip.jsx"],"sourcesContent":["'use client'\nimport { CLoadingButton } from '@coreui/react-pro'\nimport CIcon from '@coreui/icons-react'\nimport './SolidButton.scss'\n\nexport default function SolidButton({\n title = 'Button',\n onClick,\n color = 'custom-primary',\n textColor = 'custom-white',\n className = '',\n loading = false,\n icon,\n svgComponent: SvgComponent,\n type = 'submit',\n badge,\n disabled,\n}) {\n return (\n <CLoadingButton\n type={type}\n onClick={onClick}\n className={`solid-button rounded-4 px-4 py-2 fw-semibold text-${textColor} bg-${color} ${className}`}\n loading={loading}\n disabledOnLoading\n disabled={disabled}\n style={{\n minHeight: '44px',\n minWidth: 'fit-content',\n fontSize: '0.95rem',\n letterSpacing: '0.3px',\n }}\n >\n {icon && <CIcon icon={icon} className=\"btn-icon\" />}\n {SvgComponent && !icon && <SvgComponent />}\n <span className=\"btn-title\">{title}</span>\n {badge && badge}\n </CLoadingButton>\n )\n}\n","'use client'\nimport { CLoadingButton } from '@coreui/react-pro'\nimport CIcon from '@coreui/icons-react'\nimport './OutlineButton.scss'\n\nexport default function OutlineButton({\n title = 'Button',\n onClick,\n color = 'custom-primary',\n className = '',\n loading = false,\n icon,\n type = 'submit',\n disabled,\n}) {\n return (\n <CLoadingButton\n type={type}\n onClick={onClick}\n className={`outline-button rounded-3 fw-medium text-${color} border-${color} ${className}`}\n loading={loading}\n disabledOnLoading\n disabled={disabled}\n variant=\"outline\"\n style={{\n maxHeight: '40px',\n minWidth: 'fit-content',\n }}\n >\n {icon && <CIcon icon={icon} />}\n <span>{title}</span>\n </CLoadingButton>\n )\n}\n","'use client'\nimport { CLoadingButton } from '@coreui/react-pro'\nimport CIcon from '@coreui/icons-react'\n\nexport default function TextButton({\n disabled,\n title,\n onClick,\n color = 'dark',\n className = '',\n loading = false,\n icon,\n children,\n}) {\n const buttonClasses = `rounded-3 px-2 d-flex justify-content-center gap-2 fw-medium ${className}`\n\n return (\n <span className=\"d-inline-block\" tabIndex={0}>\n <CLoadingButton\n disabled={disabled}\n onClick={onClick}\n variant=\"ghost\"\n type=\"button\"\n color={color}\n className={buttonClasses}\n loading={loading}\n >\n {icon && <CIcon size=\"xl\" icon={icon} />}\n {children ? children : title}\n </CLoadingButton>\n </span>\n )\n}\n","'use client'\nimport { CLoadingButton } from '@coreui/react-pro'\nimport CIcon from '@coreui/icons-react'\nimport CustomTooltip from '../custom-tooltip/CustomTooltip'\n\nexport default function IconButton({\n title,\n onClick,\n color = 'dark',\n className = '',\n loading = false,\n icon,\n tooltip = '',\n disabled,\n}) {\n const buttonClasses = `d-flex justify-content-center align-items-center gap-1 m-0 p-1 ${className}`\n\n return (\n <CustomTooltip content={tooltip} placement=\"bottom\">\n <CLoadingButton\n onClick={onClick}\n variant=\"ghost\"\n type=\"button\"\n color={color}\n className={buttonClasses}\n loading={loading}\n disabled={disabled}\n >\n <CIcon size=\"xl\" icon={icon} />\n {title && <span className=\"ml-2 d-none d-md-block\">{title}</span>}\n </CLoadingButton>\n </CustomTooltip>\n )\n}\n","'use client'\nimport Tippy from '@tippyjs/react'\nimport 'tippy.js/dist/tippy.css'\n\nexport default function CustomTooltip({\n content,\n placement = 'bottom',\n delay = 0,\n className = '',\n children,\n}) {\n return (\n <Tippy\n content={content}\n placement={placement}\n className={className}\n delay={delay}\n >\n {children}\n </Tippy>\n )\n}\n"],"mappings":"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","names":["CLoadingButton","CIcon","CLoadingButton","CIcon","CLoadingButton","CIcon","CLoadingButton","CIcon"]}
1
+ {"version":3,"sources":["../src/components/buttons/SolidButton.jsx","../src/components/buttons/OutlineButton.jsx","../src/components/buttons/TextButton.jsx","../src/components/buttons/IconButton.jsx","../src/components/custom-tooltip/CustomTooltip.jsx","../src/components/modal/Modal.jsx","../../../node_modules/@coreui/icons/src/free/cil-arrow-bottom.ts","../../../node_modules/@coreui/icons/src/free/cil-arrow-left.ts","../../../node_modules/@coreui/icons/src/free/cil-arrow-top.ts","../../../node_modules/@coreui/icons/src/free/cil-info.ts","../../../node_modules/@coreui/icons/src/free/cil-x.ts","../src/components/card/MetricCard.jsx","../src/components/card/card-utils.js","../src/components/pagination/PaginatedTable.jsx","../src/components/pagination/PaginatedGrid.jsx","../src/components/skeletons/CardSkeleton.jsx","../src/components/skeletons/TextSkeleton.jsx","../src/components/skeletons/MetricsSkeleton.jsx","../src/components/back-button/BackButton.jsx"],"sourcesContent":["'use client'\nimport { CLoadingButton } from '@coreui/react-pro'\nimport CIcon from '@coreui/icons-react'\nimport './SolidButton.scss'\n\nexport default function SolidButton({\n title = 'Button',\n onClick,\n color = 'custom-primary',\n textColor = 'custom-white',\n className = '',\n loading = false,\n icon,\n svgComponent: SvgComponent,\n type = 'submit',\n badge,\n disabled,\n}) {\n return (\n <CLoadingButton\n type={type}\n onClick={onClick}\n className={`solid-button rounded-4 px-4 py-2 fw-semibold text-${textColor} bg-${color} ${className}`}\n loading={loading}\n disabledOnLoading\n disabled={disabled}\n style={{\n minHeight: '44px',\n minWidth: 'fit-content',\n fontSize: '0.95rem',\n letterSpacing: '0.3px',\n }}\n >\n {icon && <CIcon icon={icon} className=\"btn-icon\" />}\n {SvgComponent && !icon && <SvgComponent />}\n <span className=\"btn-title\">{title}</span>\n {badge && badge}\n </CLoadingButton>\n )\n}\n","'use client'\nimport { CLoadingButton } from '@coreui/react-pro'\nimport CIcon from '@coreui/icons-react'\nimport './OutlineButton.scss'\n\nexport default function OutlineButton({\n title = 'Button',\n onClick,\n color = 'custom-primary',\n className = '',\n loading = false,\n icon,\n type = 'submit',\n disabled,\n}) {\n return (\n <CLoadingButton\n type={type}\n onClick={onClick}\n className={`outline-button rounded-3 fw-medium text-${color} border-${color} ${className}`}\n loading={loading}\n disabledOnLoading\n disabled={disabled}\n variant=\"outline\"\n style={{\n maxHeight: '40px',\n minWidth: 'fit-content',\n }}\n >\n {icon && <CIcon icon={icon} />}\n <span>{title}</span>\n </CLoadingButton>\n )\n}\n","'use client'\nimport { CLoadingButton } from '@coreui/react-pro'\nimport CIcon from '@coreui/icons-react'\n\nexport default function TextButton({\n disabled,\n title,\n onClick,\n color = 'dark',\n className = '',\n loading = false,\n icon,\n children,\n}) {\n const buttonClasses = `rounded-3 px-2 d-flex justify-content-center gap-2 fw-medium ${className}`\n\n return (\n <span className=\"d-inline-block\" tabIndex={0}>\n <CLoadingButton\n disabled={disabled}\n onClick={onClick}\n variant=\"ghost\"\n type=\"button\"\n color={color}\n className={buttonClasses}\n loading={loading}\n >\n {icon && <CIcon size=\"xl\" icon={icon} />}\n {children ? children : title}\n </CLoadingButton>\n </span>\n )\n}\n","'use client'\nimport { CLoadingButton } from '@coreui/react-pro'\nimport CIcon from '@coreui/icons-react'\nimport CustomTooltip from '../custom-tooltip/CustomTooltip'\n\nexport default function IconButton({\n title,\n onClick,\n color = 'dark',\n className = '',\n loading = false,\n icon,\n tooltip = '',\n disabled,\n}) {\n const buttonClasses = `d-flex justify-content-center align-items-center gap-1 m-0 p-1 ${className}`\n\n return (\n <CustomTooltip content={tooltip} placement=\"bottom\">\n <CLoadingButton\n onClick={onClick}\n variant=\"ghost\"\n type=\"button\"\n color={color}\n className={buttonClasses}\n loading={loading}\n disabled={disabled}\n >\n <CIcon size=\"xl\" icon={icon} />\n {title && <span className=\"ml-2 d-none d-md-block\">{title}</span>}\n </CLoadingButton>\n </CustomTooltip>\n )\n}\n","'use client'\nimport Tippy from '@tippyjs/react'\nimport 'tippy.js/dist/tippy.css'\n\nexport default function CustomTooltip({\n content,\n placement = 'bottom',\n delay = 0,\n className = '',\n children,\n}) {\n return (\n <Tippy\n content={content}\n placement={placement}\n className={className}\n delay={delay}\n >\n {children}\n </Tippy>\n )\n}\n","'use client'\nimport CIcon from '@coreui/icons-react'\nimport { CModal, CModalBody, CModalHeader, CModalTitle } from '@coreui/react-pro'\nimport { cilX } from '@coreui/icons'\n\n/**\n * Modal reutilizable construido sobre CoreUI.\n *\n * @param {string} props.title - Título del modal\n * @param {Array} [props.titleIcon] - Ícono CoreUI opcional junto al título\n * @param {boolean} props.visible - Controla visibilidad\n * @param {Function} props.setVisible - Setter para abrir/cerrar\n * @param {'top'|'center'|'bottom'} [props.alignment='center'] - Alineación vertical\n * @param {'sm'|'lg'|'xl'} [props.size] - Tamaño del modal\n * @param {React.ReactNode} props.children - Contenido del body\n */\nexport default function Modal({\n title,\n titleIcon,\n visible,\n setVisible,\n alignment = 'center',\n size,\n children,\n}) {\n return (\n <CModal\n alignment={alignment}\n visible={visible}\n onClose={() => setVisible(false)}\n size={size}\n focus\n keyboard\n aria-labelledby=\"roax-modal-title\"\n >\n <CModalHeader className=\"position-relative\">\n <CModalTitle id=\"roax-modal-title\" className=\"d-flex align-items-center gap-2\">\n {titleIcon && <CIcon icon={titleIcon} size=\"lg\" className=\"text-muted\" />}\n {title}\n </CModalTitle>\n\n <button\n onClick={() => setVisible(false)}\n type=\"button\"\n className=\"position-absolute end-0 top-0 mt-3 me-3 p-0 bg-transparent border-0\"\n style={{ fontSize: '1.25rem', color: 'var(--cui-body-color)', zIndex: 10 }}\n aria-label=\"Cerrar\"\n >\n <CIcon icon={cilX} size=\"lg\" />\n </button>\n </CModalHeader>\n\n <CModalBody>{children}</CModalBody>\n </CModal>\n )\n}\n","export var cilArrowBottom = [\"512 512\", \"<polygon fill='var(--ci-primary-color, currentColor)' points='367.997 338.75 271.999 434.747 271.999 17.503 239.999 17.503 239.999 434.745 144.003 338.75 121.376 361.377 256 496 390.624 361.377 367.997 338.75' class='ci-primary'/>\"];\n","export var cilArrowLeft = [\"512 512\", \"<polygon fill='var(--ci-primary-color, currentColor)' points='497.333 239.999 80.092 239.999 176.087 144.004 153.46 121.377 18.837 256 153.46 390.623 176.087 367.996 80.09 271.999 497.333 271.999 497.333 239.999' class='ci-primary'/>\"];\n","export var cilArrowTop = [\"512 512\", \"<polygon fill='var(--ci-primary-color, currentColor)' points='390.624 150.625 256 16 121.376 150.625 144.004 173.252 240.001 77.254 240.001 495.236 272.001 495.236 272.001 77.257 367.996 173.252 390.624 150.625' class='ci-primary'/>\"];\n","export var cilInfo = [\"512 512\", \"<rect width='34.924' height='34.924' x='256' y='95.998' fill='var(--ci-primary-color, currentColor)' class='ci-primary'/><path fill='var(--ci-primary-color, currentColor)' d='M16,496H496V16H16ZM48,48H464V464H48Z' class='ci-primary'/><path fill='var(--ci-primary-color, currentColor)' d='M285.313,359.032a18.123,18.123,0,0,1-15.6,8.966,18.061,18.061,0,0,1-17.327-23.157l35.67-121.277A49.577,49.577,0,0,0,194.7,190.572l-11.718,28.234,29.557,12.266,11.718-28.235a17.577,17.577,0,0,1,33.1,11.7l-35.67,121.277A50.061,50.061,0,0,0,269.709,400a50.227,50.227,0,0,0,43.25-24.853l15.1-25.913-27.646-16.115Z' class='ci-primary'/>\"];\n","export var cilX = [\"512 512\", \"<polygon fill='var(--ci-primary-color, currentColor)' points='427.314 107.313 404.686 84.687 256 233.373 107.314 84.687 84.686 107.313 233.373 256 84.686 404.687 107.314 427.313 256 278.627 404.686 427.313 427.314 404.687 278.627 256 427.314 107.313' class='ci-primary'/>\"];\n","'use client'\nimport { CCard, CCardBody } from '@coreui/react-pro'\nimport CIcon from '@coreui/icons-react'\nimport { cilArrowTop, cilArrowBottom, cilInfo } from '@coreui/icons'\nimport CustomTooltip from '../custom-tooltip/CustomTooltip'\nimport { formatValue, getBadgeStyles, formatDateRange } from './card-utils'\nimport './MetricCard.scss'\n\n/**\n * Tarjeta de métrica con glassmorphism, tendencia y rango de fechas previo.\n *\n * @param {string} props.title - Nombre de la métrica\n * @param {number} props.current - Valor actual\n * @param {number} props.previous - Valor anterior (periodo previo)\n * @param {number} props.change - Variación porcentual\n * @param {boolean} props.isPositive - Si la tendencia es positiva\n * @param {string} [props.unit=''] - Unidad: '$', '%', 'COP', 'x'\n * @param {string} [props.previousDateRange=''] - Rango de fechas previo (yyyy-MM-dd - yyyy-MM-dd)\n * @param {string} [props.tooltipText=''] - Texto del tooltip de información\n * @param {string} [props.backgroundColor] - Color de fondo custom (glassmorphism tintado)\n */\nexport default function MetricCard({\n title,\n current,\n previous,\n change,\n isPositive,\n unit = '',\n previousDateRange = '',\n tooltipText = '',\n backgroundColor,\n}) {\n const isColored = !!backgroundColor\n const cardClass = `metric-card w-100 h-100 d-flex flex-column border-0${isColored ? ' metric-card--colored' : ''}`\n\n return (\n <CCard\n className={cardClass}\n style={isColored ? { background: backgroundColor } : undefined}\n >\n <CCardBody className=\"d-flex flex-column justify-content-between h-100 p-4 position-relative\">\n\n {tooltipText && (\n <div className=\"position-absolute top-0 end-0 m-2\">\n <CustomTooltip content={tooltipText} placement=\"top\">\n <CIcon\n icon={cilInfo}\n style={{ cursor: 'pointer', opacity: 0.5, width: 16, height: 16 }}\n />\n </CustomTooltip>\n </div>\n )}\n\n <p className=\"metric-card__title m-0\">{title}</p>\n\n <div className=\"d-flex align-items-center gap-2 mt-1\">\n <span className=\"metric-card__value\">\n {formatValue(current, unit, title)}\n </span>\n {typeof change === 'number' && isFinite(change) && current > 0 && (\n <div style={getBadgeStyles(isPositive)}>\n <CIcon icon={isPositive ? cilArrowTop : cilArrowBottom} size=\"sm\" />\n {Math.abs(change)}%\n </div>\n )}\n </div>\n\n <hr className=\"metric-card__divider\" />\n\n {(() => {\n const { formattedRange } = formatDateRange(previousDateRange)\n return (\n <div className=\"d-flex justify-content-between align-items-center metric-card__footer\">\n <strong>{formatValue(previous, unit, title)}</strong>\n <span>{formattedRange}</span>\n </div>\n )\n })()}\n\n </CCardBody>\n </CCard>\n )\n}\n","/**\n * Formatea un valor numérico según su unidad o contexto del título.\n * @param {number} val\n * @param {string} [unit='']\n * @param {string} [title='']\n * @returns {string}\n */\nexport const formatValue = (val, unit = '', title = '') => {\n if (val == null || typeof val !== 'number' || val === 0) return '0'\n if (title.includes('ROAS')) return `x ${val.toFixed(2)}`\n if (title.includes('CAC %')) return `${val.toFixed(2)}%`\n if (unit === '%' || title.includes('%')) return `${val.toFixed(2)}%`\n if (unit === 'x') return `x ${val.toFixed(2)}`\n if (unit === 'COP') return `COP ${Math.round(val).toLocaleString('es-CO')}`\n return val.toLocaleString(undefined, { minimumFractionDigits: 0, maximumFractionDigits: 2 })\n}\n\n/**\n * Retorna estilos de badge según si la tendencia es positiva o negativa.\n * @param {boolean} isPositive\n * @returns {Object}\n */\nexport const getBadgeStyles = (isPositive) => ({\n backgroundColor: isPositive ? '#55ed7b' : '#f74a4a',\n color: isPositive ? '#0b3e26' : '#842029',\n borderRadius: '9999px',\n padding: '4px 10px',\n fontSize: '0.75rem',\n fontWeight: 700,\n display: 'inline-flex',\n alignItems: 'center',\n gap: '4px',\n})\n\n/**\n * Formatea un rango de fechas 'yyyy-MM-dd - yyyy-MM-dd' a formato legible.\n * @param {string} previousDateRange\n * @returns {{ formattedRange: string }}\n */\nexport function formatDateRange(previousDateRange) {\n if (!previousDateRange) return { formattedRange: '' }\n const parts = previousDateRange.split(' - ')\n const parseDate = (str) => {\n const [year, month, day] = str.split('-').map(Number)\n return new Date(year, month - 1, day)\n }\n const format = (date) => {\n const day = String(date.getDate()).padStart(2, '0')\n const month = date.toLocaleString('es-CO', { month: 'short' }).replace('.', '')\n const year = String(date.getFullYear()).slice(-2)\n return `${month} ${day},${year}`\n }\n const since = parseDate(parts[0])\n const until = parts[1] ? parseDate(parts[1]) : null\n const formattedRange = until ? `${format(since)} - ${format(until)}` : format(since)\n return { formattedRange }\n}\n","'use client'\nimport {\n CTable,\n CTableHead,\n CTableBody,\n CTableRow,\n CTableHeaderCell,\n CSpinner,\n} from '@coreui/react-pro'\n\n/**\n * Tabla paginada reutilizable construida sobre CoreUI.\n *\n * @param {Array} [props.data=[]] - Dataset completo\n * @param {number} [props.itemsPerPage=10] - Items por página\n * @param {number} [props.currentPage=1] - Página actual\n * @param {Function} [props.setCurrentPage] - Setter de página\n * @param {string[]} [props.columns=[]] - Cabeceras de columna\n * @param {Function} [props.renderRow] - Función que renderiza cada fila\n * @param {boolean} [props.loading=false] - Estado de carga\n * @param {string} [props.emptyMessage] - Mensaje sin datos\n */\nexport default function PaginatedTable({\n data = [],\n itemsPerPage = 10,\n currentPage = 1,\n setCurrentPage = () => {},\n columns = [],\n renderRow = () => null,\n loading = false,\n emptyMessage = 'No hay datos disponibles.',\n}) {\n const totalPages = Math.ceil(data.length / itemsPerPage)\n const paginatedData = data.slice(\n (currentPage - 1) * itemsPerPage,\n currentPage * itemsPerPage\n )\n\n if (loading) {\n return (\n <div className=\"text-center py-5\">\n <CSpinner color=\"secondary\" />\n </div>\n )\n }\n\n if (!data.length) {\n return <div className=\"text-center py-5 text-muted\">{emptyMessage}</div>\n }\n\n const renderPagination = () => {\n const pages = []\n for (let i = 1; i <= totalPages; i++) {\n pages.push(\n <button\n key={i}\n onClick={() => setCurrentPage(i)}\n className={`px-3 py-1 rounded-pill border ${\n i === currentPage ? 'bg-dark text-white' : 'bg-white text-dark'\n }`}\n >\n {i}\n </button>\n )\n }\n\n return (\n <div className=\"d-flex justify-content-center align-items-center gap-2 mt-3 flex-wrap\">\n {currentPage > 1 && (\n <button\n onClick={() => setCurrentPage(currentPage - 1)}\n className=\"px-3 py-1 rounded-pill border bg-white text-dark\"\n style={{ minWidth: '80px', fontWeight: 500 }}\n >\n Anterior\n </button>\n )}\n {pages}\n {currentPage < totalPages && (\n <button\n onClick={() => setCurrentPage(currentPage + 1)}\n className=\"px-3 py-1 rounded-pill border bg-white text-dark\"\n style={{ minWidth: '80px', fontWeight: 500 }}\n >\n Siguiente\n </button>\n )}\n </div>\n )\n }\n\n return (\n <>\n <CTable hover responsive>\n <CTableHead className=\"bg-dark text-white\">\n <CTableRow>\n {columns.map((col, idx) => (\n <CTableHeaderCell key={idx}>{col}</CTableHeaderCell>\n ))}\n </CTableRow>\n </CTableHead>\n <CTableBody>{paginatedData.map(renderRow)}</CTableBody>\n </CTable>\n {totalPages > 1 && renderPagination()}\n </>\n )\n}\n","'use client'\nimport { CSpinner } from '@coreui/react-pro'\n\n/**\n * Grid paginado para renderizar ítems tipo card.\n *\n * @param {Array} [props.data=[]] - Dataset completo\n * @param {number} [props.itemsPerPage=6] - Items por página\n * @param {number} [props.currentPage=1] - Página actual\n * @param {Function} [props.setCurrentPage] - Setter de página\n * @param {Function} [props.renderItem] - Función que renderiza cada ítem\n * @param {boolean} [props.loading=false] - Estado de carga\n * @param {string} [props.emptyMessage] - Mensaje sin datos\n */\nexport default function PaginatedGrid({\n data = [],\n itemsPerPage = 6,\n currentPage = 1,\n setCurrentPage = () => {},\n renderItem = () => null,\n loading = false,\n emptyMessage = 'No hay elementos.',\n}) {\n const totalPages = Math.ceil(data.length / itemsPerPage)\n const paginatedData = data.slice(\n (currentPage - 1) * itemsPerPage,\n currentPage * itemsPerPage\n )\n\n if (loading) {\n return (\n <div className=\"text-center py-5\">\n <CSpinner color=\"secondary\" />\n </div>\n )\n }\n\n if (!data.length) {\n return <div className=\"text-center py-5 text-muted\">{emptyMessage}</div>\n }\n\n const renderPagination = () => {\n const pages = []\n for (let i = 1; i <= totalPages; i++) {\n pages.push(\n <button\n key={i}\n onClick={() => setCurrentPage(i)}\n className={`px-3 py-1 rounded-pill border ${\n i === currentPage ? 'bg-dark text-white' : 'bg-white text-dark'\n }`}\n >\n {i}\n </button>\n )\n }\n return (\n <div className=\"d-flex justify-content-center gap-2 mt-4 flex-wrap\">\n {currentPage > 1 && (\n <button\n onClick={() => setCurrentPage(currentPage - 1)}\n className=\"px-3 py-1 rounded-pill border bg-white text-dark\"\n >\n Anterior\n </button>\n )}\n {pages}\n {currentPage < totalPages && (\n <button\n onClick={() => setCurrentPage(currentPage + 1)}\n className=\"px-3 py-1 rounded-pill border bg-white text-dark\"\n >\n Siguiente\n </button>\n )}\n </div>\n )\n }\n\n return (\n <>\n <div className=\"row g-4\">{paginatedData.map(renderItem)}</div>\n {totalPages > 1 && renderPagination()}\n </>\n )\n}\n","import { CCard, CPlaceholder } from '@coreui/react-pro'\n\n/** Skeleton de tarjeta — reemplaza un card mientras carga su contenido. */\nexport default function CardSkeleton() {\n return (\n <CCard className=\"shadow-none p-0 m-0 bg-transparent border-0\">\n <CPlaceholder component=\"div\" animation=\"glow\" className=\"d-flex flex-column gap-2 bg-transparent\">\n <CPlaceholder className=\"p-4 mt-2 rounded-1\" size=\"lg\" xs={12} color=\"skeleton\" />\n </CPlaceholder>\n </CCard>\n )\n}\n","import { CCard, CPlaceholder } from '@coreui/react-pro'\n\n/** Skeleton de texto — reemplaza una línea de texto mientras carga. */\nexport default function TextSkeleton() {\n return (\n <CCard className=\"shadow-none p-0 m-0 bg-transparent border-0\">\n <CPlaceholder component=\"div\" animation=\"glow\" className=\"d-flex flex-column gap-2 bg-transparent\">\n <CPlaceholder className=\"p-0 my-2 rounded-1\" size=\"lg\" xs={8} color=\"skeleton\" />\n </CPlaceholder>\n </CCard>\n )\n}\n","import { CCard, CPlaceholder } from '@coreui/react-pro'\n\n/** Skeleton de métrica — reemplaza un MetricCard mientras carga. */\nexport default function MetricsSkeleton() {\n return (\n <CCard className=\"shadow-none p-0 m-0 bg-transparent border-0\">\n <CPlaceholder component=\"div\" animation=\"glow\" className=\"d-flex flex-column gap-2 bg-transparent\">\n <CPlaceholder className=\"p-5 mt-2 rounded-1\" size=\"lg\" xs={12} color=\"skeleton\" />\n <CPlaceholder className=\"p-3 mt-2 rounded-1\" size=\"xs\" xs={12} color=\"skeleton\" />\n </CPlaceholder>\n </CCard>\n )\n}\n","'use client'\nimport { useRouter } from 'next/navigation'\nimport { CButton } from '@coreui/react-pro'\nimport { cilArrowLeft } from '@coreui/icons'\nimport CIcon from '@coreui/icons-react'\nimport CustomTooltip from '../custom-tooltip/CustomTooltip'\n\n/**\n * Botón de navegación hacia atrás.\n * Usa router.push(path) si se pasa path, o router.back() si no.\n *\n * @param {string} [props.title] - Texto opcional junto al ícono\n * @param {string} [props.color='dark'] - Color CoreUI del botón\n * @param {string} [props.path] - Ruta destino (si no, usa history.back())\n * @param {string} [props.className] - Clases CSS adicionales\n */\nexport default function BackButton({ title, color = 'dark', className = '', path }) {\n const { back, push } = useRouter()\n const buttonClasses = `back-button d-flex align-items-center px-0 ${className}`\n\n function handleBack() {\n if (path) push(path)\n else back()\n }\n\n return (\n <CustomTooltip content=\"Volver atrás\" placement=\"bottom\">\n <CButton color={color} variant=\"ghost\" className={buttonClasses} onClick={handleBack}>\n <CIcon icon={cilArrowLeft} size=\"lg\" className=\"mx-1\" />\n {title && <span className=\"px-2\">{title}</span>}\n </CButton>\n </CustomTooltip>\n )\n}\n"],"mappings":"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","names":["CLoadingButton","CIcon","CLoadingButton","CIcon","CLoadingButton","CIcon","CLoadingButton","CIcon","CIcon","CIcon","CIcon","CIcon","CSpinner","CCard","CCard","CPlaceholder","CCard","CPlaceholder","CIcon","CIcon"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@roax/ui",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Roax UI Component Library — componentes reutilizables para proyectos Roax",
5
5
  "keywords": ["react", "ui", "components", "roax", "coreui"],
6
6
  "main": "./dist/index.js",