@beweco/aurora-ui 0.1.34 → 0.1.41
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/assets/css/styles.css +1 -1
- package/dist/index.cjs.js +186 -0
- package/dist/index.esm.js +186 -3
- package/dist/types/components/kanban/Kanban.d.ts +27 -0
- package/dist/types/components/kanban/Kanban.d.ts.map +1 -0
- package/dist/types/components/kanban/Kanban.types.d.ts +163 -0
- package/dist/types/components/kanban/Kanban.types.d.ts.map +1 -0
- package/dist/types/components/kanban/_internal/KanbanCard.d.ts +11 -0
- package/dist/types/components/kanban/_internal/KanbanCard.d.ts.map +1 -0
- package/dist/types/components/kanban/_internal/KanbanColumn.d.ts +12 -0
- package/dist/types/components/kanban/_internal/KanbanColumn.d.ts.map +1 -0
- package/dist/types/components/kanban/_internal/index.d.ts +3 -0
- package/dist/types/components/kanban/_internal/index.d.ts.map +1 -0
- package/dist/types/components/kanban/index.d.ts +4 -0
- package/dist/types/components/kanban/index.d.ts.map +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs.js
CHANGED
|
@@ -1699,6 +1699,189 @@ var HeaderComponent = function (_a) {
|
|
|
1699
1699
|
};
|
|
1700
1700
|
HeaderComponent.displayName = "Header";
|
|
1701
1701
|
|
|
1702
|
+
/**
|
|
1703
|
+
* KanbanCard - Contenedor de tarjeta genérico del Kanban con soporte drag and drop
|
|
1704
|
+
*
|
|
1705
|
+
* El contenido es 100% definido por el padre mediante renderContent.
|
|
1706
|
+
* Este componente solo provee el contenedor con estilos, eventos y drag.
|
|
1707
|
+
*/
|
|
1708
|
+
var KanbanCardComponent = function (_a) {
|
|
1709
|
+
var item = _a.item, columnId = _a.columnId, index = _a.index, renderContent = _a.renderContent, onCardClick = _a.onCardClick, className = _a.className, _b = _a.isClickable, isClickable = _b === void 0 ? true : _b, _c = _a.isDraggable, isDraggable = _c === void 0 ? false : _c, onDragStart = _a.onDragStart, onDragEnd = _a.onDragEnd;
|
|
1710
|
+
var _d = React.useState(false), isDragging = _d[0], setIsDragging = _d[1];
|
|
1711
|
+
var handleClick = React.useCallback(function () {
|
|
1712
|
+
if (!isDragging) {
|
|
1713
|
+
onCardClick === null || onCardClick === void 0 ? void 0 : onCardClick(item);
|
|
1714
|
+
}
|
|
1715
|
+
}, [item, onCardClick, isDragging]);
|
|
1716
|
+
var handleKeyDown = React.useCallback(function (e) {
|
|
1717
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
1718
|
+
e.preventDefault();
|
|
1719
|
+
onCardClick === null || onCardClick === void 0 ? void 0 : onCardClick(item);
|
|
1720
|
+
}
|
|
1721
|
+
}, [item, onCardClick]);
|
|
1722
|
+
var handleDragStart = React.useCallback(function (e) {
|
|
1723
|
+
if (!isDraggable)
|
|
1724
|
+
return;
|
|
1725
|
+
setIsDragging(true);
|
|
1726
|
+
// Datos para el drop
|
|
1727
|
+
e.dataTransfer.setData("application/json", JSON.stringify({ itemId: item.id, fromColumnId: columnId, fromIndex: index }));
|
|
1728
|
+
e.dataTransfer.effectAllowed = "move";
|
|
1729
|
+
// Notificar al padre
|
|
1730
|
+
onDragStart === null || onDragStart === void 0 ? void 0 : onDragStart(item, columnId, index);
|
|
1731
|
+
}, [item, columnId, index, isDraggable, onDragStart]);
|
|
1732
|
+
var handleDragEnd = React.useCallback(function () {
|
|
1733
|
+
setIsDragging(false);
|
|
1734
|
+
onDragEnd === null || onDragEnd === void 0 ? void 0 : onDragEnd();
|
|
1735
|
+
}, [onDragEnd]);
|
|
1736
|
+
var isInteractive = isClickable && onCardClick;
|
|
1737
|
+
return (jsxRuntime.jsx("div", { className: react.cn("bg-content1 border border-default-200 rounded-lg p-4 transition-all", isInteractive && "cursor-pointer hover:border-default-400", isDraggable && "cursor-grab active:cursor-grabbing", isDragging && "opacity-50 scale-95 shadow-lg", className), onClick: isInteractive ? handleClick : undefined, onKeyDown: isInteractive ? handleKeyDown : undefined, role: isInteractive ? "button" : undefined, tabIndex: isInteractive ? 0 : undefined, draggable: isDraggable, onDragStart: handleDragStart, onDragEnd: handleDragEnd, children: renderContent(item) }));
|
|
1738
|
+
};
|
|
1739
|
+
var KanbanCard = React.memo(KanbanCardComponent);
|
|
1740
|
+
KanbanCard.displayName = "KanbanCard";
|
|
1741
|
+
|
|
1742
|
+
/**
|
|
1743
|
+
* KanbanColumn - Columna individual del Kanban con soporte de drop
|
|
1744
|
+
*
|
|
1745
|
+
* Muestra un header con título y badge de conteo,
|
|
1746
|
+
* una lista scrolleable de tarjetas, y estado vacío.
|
|
1747
|
+
* Acepta drops de tarjetas de otras columnas.
|
|
1748
|
+
*/
|
|
1749
|
+
var KanbanColumnComponent = function (_a) {
|
|
1750
|
+
var _b, _c;
|
|
1751
|
+
var column = _a.column, renderItem = _a.renderItem, onCardClick = _a.onCardClick, cardClassName = _a.cardClassName, isCardClickable = _a.isCardClickable, className = _a.className, _d = _a.maxHeight, maxHeight = _d === void 0 ? "calc(100vh - 280px)" : _d, renderColumnHeader = _a.renderColumnHeader, renderEmptyState = _a.renderEmptyState, _e = _a.isDraggable, isDraggable = _e === void 0 ? false : _e, onDragStart = _a.onDragStart, onDragEnd = _a.onDragEnd, onDrop = _a.onDrop, _f = _a.isDragging, isDragging = _f === void 0 ? false : _f, _g = _a.translations, translations = _g === void 0 ? {} : _g;
|
|
1752
|
+
// Traducciones con fallbacks
|
|
1753
|
+
var t = {
|
|
1754
|
+
dropHere: (_b = translations.dropHere) !== null && _b !== void 0 ? _b : "Soltar aquí",
|
|
1755
|
+
emptyMessage: (_c = translations.emptyMessage) !== null && _c !== void 0 ? _c : "No hay elementos",
|
|
1756
|
+
};
|
|
1757
|
+
var _h = React.useState(false), isDragOver = _h[0], setIsDragOver = _h[1];
|
|
1758
|
+
var _j = React.useState(null), dropIndex = _j[0], setDropIndex = _j[1];
|
|
1759
|
+
var itemCount = column.items.length;
|
|
1760
|
+
var isEmpty = itemCount === 0;
|
|
1761
|
+
var handleDragOver = React.useCallback(function (e) {
|
|
1762
|
+
if (!isDraggable)
|
|
1763
|
+
return;
|
|
1764
|
+
e.preventDefault();
|
|
1765
|
+
e.dataTransfer.dropEffect = "move";
|
|
1766
|
+
setIsDragOver(true);
|
|
1767
|
+
}, [isDraggable]);
|
|
1768
|
+
var handleDragLeave = React.useCallback(function (e) {
|
|
1769
|
+
// Solo salir si realmente salimos de la columna (no de un hijo)
|
|
1770
|
+
if (!e.currentTarget.contains(e.relatedTarget)) {
|
|
1771
|
+
setIsDragOver(false);
|
|
1772
|
+
setDropIndex(null);
|
|
1773
|
+
}
|
|
1774
|
+
}, []);
|
|
1775
|
+
var handleDrop = React.useCallback(function (e) {
|
|
1776
|
+
e.preventDefault();
|
|
1777
|
+
setIsDragOver(false);
|
|
1778
|
+
setDropIndex(null);
|
|
1779
|
+
if (!isDraggable)
|
|
1780
|
+
return;
|
|
1781
|
+
// Calcular índice de drop basado en posición Y
|
|
1782
|
+
var finalDropIndex = dropIndex !== null && dropIndex !== void 0 ? dropIndex : column.items.length;
|
|
1783
|
+
onDrop === null || onDrop === void 0 ? void 0 : onDrop(column.id, finalDropIndex);
|
|
1784
|
+
}, [isDraggable, column.id, column.items.length, dropIndex, onDrop]);
|
|
1785
|
+
// Calcular índice de drop basado en la posición del mouse
|
|
1786
|
+
var handleDragOverItem = React.useCallback(function (e, itemIndex) {
|
|
1787
|
+
e.preventDefault();
|
|
1788
|
+
var rect = e.currentTarget.getBoundingClientRect();
|
|
1789
|
+
var midpoint = rect.top + rect.height / 2;
|
|
1790
|
+
var newDropIndex = e.clientY < midpoint ? itemIndex : itemIndex + 1;
|
|
1791
|
+
setDropIndex(newDropIndex);
|
|
1792
|
+
}, []);
|
|
1793
|
+
return (jsxRuntime.jsxs("div", { className: react.cn("flex flex-col bg-default-50 rounded-lg border border-default-200 transition-colors", isDragOver && isDragging && "border-primary-400 bg-primary-50/30", className), onDragOver: handleDragOver, onDragLeave: handleDragLeave, onDrop: handleDrop, children: [renderColumnHeader ? (renderColumnHeader(column)) : (jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-b border-default-200", children: [jsxRuntime.jsx("h3", { className: "font-semibold text-foreground", children: column.title }), jsxRuntime.jsx(react.Badge, { content: itemCount, color: column.countBadgeColor || "default", variant: "flat", size: "md", classNames: {
|
|
1794
|
+
badge: "text-xs font-medium min-w-6 h-6",
|
|
1795
|
+
}, children: jsxRuntime.jsxs("span", { className: "sr-only", children: [itemCount, " items"] }) })] })), jsxRuntime.jsx("div", { className: react.cn("flex-1 overflow-y-auto p-3 space-y-3", isDragOver && isEmpty && "min-h-24"), style: { maxHeight: maxHeight }, children: isEmpty ? (isDragOver && isDragging ? (jsxRuntime.jsx("div", { className: "h-24 border-2 border-dashed border-primary-300 rounded-lg bg-primary-50/50 flex items-center justify-center", children: jsxRuntime.jsx("span", { className: "text-primary-500 text-sm", children: t.dropHere }) })) : renderEmptyState ? (renderEmptyState(column)) : (jsxRuntime.jsx("div", { className: "flex items-center justify-center h-24 text-default-400 text-sm", children: column.emptyMessage || t.emptyMessage }))) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [column.items.map(function (item, index) { return (jsxRuntime.jsxs("div", { onDragOver: function (e) { return handleDragOverItem(e, index); }, children: [isDragOver && dropIndex === index && (jsxRuntime.jsx("div", { className: "h-1 bg-primary-400 rounded-full mb-3 animate-pulse" })), jsxRuntime.jsx(KanbanCard, { item: item, columnId: column.id, index: index, renderContent: renderItem, onCardClick: onCardClick, className: cardClassName, isClickable: isCardClickable, isDraggable: isDraggable, onDragStart: onDragStart, onDragEnd: onDragEnd })] }, item.id)); }), isDragOver && dropIndex === column.items.length && (jsxRuntime.jsx("div", { className: "h-1 bg-primary-400 rounded-full mt-3 animate-pulse" }))] })) })] }));
|
|
1796
|
+
};
|
|
1797
|
+
var KanbanColumn = React.memo(KanbanColumnComponent);
|
|
1798
|
+
KanbanColumn.displayName = "KanbanColumn";
|
|
1799
|
+
|
|
1800
|
+
/**
|
|
1801
|
+
* Traducciones por defecto en español.
|
|
1802
|
+
* Se mezclan con las traducciones proporcionadas por el usuario.
|
|
1803
|
+
*/
|
|
1804
|
+
var DEFAULT_TRANSLATIONS = {
|
|
1805
|
+
dropHere: "Soltar aquí",
|
|
1806
|
+
emptyMessage: "No hay elementos",
|
|
1807
|
+
};
|
|
1808
|
+
var columnGapClasses = {
|
|
1809
|
+
sm: "gap-3",
|
|
1810
|
+
md: "gap-4",
|
|
1811
|
+
lg: "gap-6",
|
|
1812
|
+
};
|
|
1813
|
+
/**
|
|
1814
|
+
* Kanban - Tablero Kanban genérico con columnas, tarjetas y drag and drop
|
|
1815
|
+
*
|
|
1816
|
+
* El contenido de cada tarjeta es 100% definido por el consumidor
|
|
1817
|
+
* mediante la prop `renderItem`. Esto permite usar el Kanban para
|
|
1818
|
+
* cualquier caso de uso: contactos, tareas, proyectos, etc.
|
|
1819
|
+
*
|
|
1820
|
+
* Soporta drag and drop entre columnas con el callback `onItemMove`.
|
|
1821
|
+
*
|
|
1822
|
+
* @example
|
|
1823
|
+
* ```tsx
|
|
1824
|
+
* // Kanban de tareas con drag and drop
|
|
1825
|
+
* <Kanban<Task>
|
|
1826
|
+
* columns={columns}
|
|
1827
|
+
* renderItem={(item) => <TaskCard task={item.data} />}
|
|
1828
|
+
* onItemMove={(event) => {
|
|
1829
|
+
* console.log(`Moved ${event.item.id} from ${event.fromColumnId} to ${event.toColumnId}`);
|
|
1830
|
+
* // Actualizar estado...
|
|
1831
|
+
* }}
|
|
1832
|
+
* />
|
|
1833
|
+
* ```
|
|
1834
|
+
*/
|
|
1835
|
+
var KanbanComponent = function (_a) {
|
|
1836
|
+
var columns = _a.columns, renderItem = _a.renderItem, onCardClick = _a.onCardClick, onItemMove = _a.onItemMove, isDraggable = _a.isDraggable, cardClassName = _a.cardClassName, isCardClickable = _a.isCardClickable, className = _a.className, _b = _a.columnWidth, columnWidth = _b === void 0 ? "280px" : _b, _c = _a.columnGap, columnGap = _c === void 0 ? "md" : _c, _d = _a.horizontalScroll, horizontalScroll = _d === void 0 ? true : _d, columnMaxHeight = _a.columnMaxHeight, renderColumnHeader = _a.renderColumnHeader, renderEmptyState = _a.renderEmptyState, _e = _a.translations, translations = _e === void 0 ? {} : _e;
|
|
1837
|
+
// Mezclar traducciones del usuario con las por defecto
|
|
1838
|
+
var t = __assign(__assign({}, DEFAULT_TRANSLATIONS), translations);
|
|
1839
|
+
// Determinar si drag está habilitado
|
|
1840
|
+
var dragEnabled = isDraggable !== null && isDraggable !== void 0 ? isDraggable : !!onItemMove;
|
|
1841
|
+
// Estado del drag actual
|
|
1842
|
+
var _f = React.useState(false), isDragging = _f[0], setIsDragging = _f[1];
|
|
1843
|
+
var dragDataRef = React.useRef(null);
|
|
1844
|
+
// Cuando empieza el drag
|
|
1845
|
+
var handleDragStart = React.useCallback(function (item, columnId, index) {
|
|
1846
|
+
setIsDragging(true);
|
|
1847
|
+
dragDataRef.current = { item: item, fromColumnId: columnId, fromIndex: index };
|
|
1848
|
+
}, []);
|
|
1849
|
+
// Cuando termina el drag (sin drop válido)
|
|
1850
|
+
var handleDragEnd = React.useCallback(function () {
|
|
1851
|
+
setIsDragging(false);
|
|
1852
|
+
dragDataRef.current = null;
|
|
1853
|
+
}, []);
|
|
1854
|
+
// Cuando se suelta en una columna
|
|
1855
|
+
var handleDrop = React.useCallback(function (toColumnId, toIndex) {
|
|
1856
|
+
var dragData = dragDataRef.current;
|
|
1857
|
+
if (!dragData || !onItemMove)
|
|
1858
|
+
return;
|
|
1859
|
+
var item = dragData.item, fromColumnId = dragData.fromColumnId, fromIndex = dragData.fromIndex;
|
|
1860
|
+
// No hacer nada si se suelta en la misma posición
|
|
1861
|
+
if (fromColumnId === toColumnId && fromIndex === toIndex) {
|
|
1862
|
+
handleDragEnd();
|
|
1863
|
+
return;
|
|
1864
|
+
}
|
|
1865
|
+
// Ajustar índice si se mueve dentro de la misma columna hacia abajo
|
|
1866
|
+
var adjustedToIndex = toIndex;
|
|
1867
|
+
if (fromColumnId === toColumnId && fromIndex < toIndex) {
|
|
1868
|
+
adjustedToIndex = toIndex - 1;
|
|
1869
|
+
}
|
|
1870
|
+
// Notificar al padre
|
|
1871
|
+
onItemMove({
|
|
1872
|
+
item: item,
|
|
1873
|
+
fromColumnId: fromColumnId,
|
|
1874
|
+
toColumnId: toColumnId,
|
|
1875
|
+
fromIndex: fromIndex,
|
|
1876
|
+
toIndex: adjustedToIndex,
|
|
1877
|
+
});
|
|
1878
|
+
handleDragEnd();
|
|
1879
|
+
}, [onItemMove, handleDragEnd]);
|
|
1880
|
+
return (jsxRuntime.jsx("div", { className: react.cn("flex", columnGapClasses[columnGap], horizontalScroll && "overflow-x-auto pb-4", className), children: columns.map(function (column) { return (jsxRuntime.jsx("div", { className: "flex-shrink-0", style: { width: columnWidth }, children: jsxRuntime.jsx(KanbanColumn, { column: column, renderItem: renderItem, onCardClick: onCardClick, cardClassName: cardClassName, isCardClickable: isCardClickable, maxHeight: columnMaxHeight, renderColumnHeader: renderColumnHeader, renderEmptyState: renderEmptyState, isDraggable: dragEnabled, onDragStart: handleDragStart, onDragEnd: handleDragEnd, onDrop: handleDrop, isDragging: isDragging, translations: t }) }, column.id)); }) }));
|
|
1881
|
+
};
|
|
1882
|
+
var Kanban = React.memo(KanbanComponent);
|
|
1883
|
+
Kanban.displayName = "Kanban";
|
|
1884
|
+
|
|
1702
1885
|
var defaultTranslations$8 = {
|
|
1703
1886
|
previewAlt: "Vista previa de imagen",
|
|
1704
1887
|
removeButtonAriaLabel: "Eliminar imagen",
|
|
@@ -4986,6 +5169,9 @@ exports.HeaderComponent = HeaderComponent;
|
|
|
4986
5169
|
exports.IconComponent = IconComponent;
|
|
4987
5170
|
exports.ImagePreview = ImagePreview;
|
|
4988
5171
|
exports.Input = Input;
|
|
5172
|
+
exports.Kanban = Kanban;
|
|
5173
|
+
exports.KanbanCard = KanbanCard;
|
|
5174
|
+
exports.KanbanColumn = KanbanColumn;
|
|
4989
5175
|
exports.MenuComponent = MenuComponent;
|
|
4990
5176
|
exports.Modal = Modal;
|
|
4991
5177
|
exports.ModalBody = ModalBody;
|
package/dist/index.esm.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { Skeleton, Button as Button$1, Chip as Chip$1, Accordion, AccordionItem, Pagination as Pagination$1, DatePicker as DatePicker$1, DateRangePicker as DateRangePicker$1, Input as Input$1, RadioGroup, Radio, cn, Card as Card$1, Spacer, Tabs, Tab, Dropdown, DropdownTrigger, DropdownMenu, DropdownItem, Autocomplete, Breadcrumbs, BreadcrumbItem, DropdownSection, ListboxItem, Popover, PopoverTrigger, Tooltip as Tooltip$1, PopoverContent, Listbox, ListboxSection, Avatar, CardBody, CardFooter, Link, Switch as Switch$1, TimeInput as TimeInput$1, Select as Select$1, Image as Image$1, Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, Textarea as Textarea$1, Alert, Modal as Modal$1, ModalContent as ModalContent$1, ModalHeader as ModalHeader$1, ModalBody as ModalBody$1, Slider, ModalFooter as ModalFooter$1, Spinner, SelectItem, Drawer, DrawerContent, DrawerBody } from '@heroui/react';
|
|
1
|
+
import { Skeleton, Button as Button$1, Chip as Chip$1, Accordion, AccordionItem, Pagination as Pagination$1, DatePicker as DatePicker$1, DateRangePicker as DateRangePicker$1, Input as Input$1, RadioGroup, Radio, cn, Card as Card$1, Spacer, Tabs, Tab, Dropdown, DropdownTrigger, DropdownMenu, DropdownItem, Autocomplete, Breadcrumbs, BreadcrumbItem, DropdownSection, Badge, ListboxItem, Popover, PopoverTrigger, Tooltip as Tooltip$1, PopoverContent, Listbox, ListboxSection, Avatar, CardBody, CardFooter, Link, Switch as Switch$1, TimeInput as TimeInput$1, Select as Select$1, Image as Image$1, Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, Textarea as Textarea$1, Alert, Modal as Modal$1, ModalContent as ModalContent$1, ModalHeader as ModalHeader$1, ModalBody as ModalBody$1, Slider, ModalFooter as ModalFooter$1, Spinner, SelectItem, Drawer, DrawerContent, DrawerBody } from '@heroui/react';
|
|
2
2
|
export * from '@heroui/react';
|
|
3
3
|
export { Slider } from '@heroui/react';
|
|
4
4
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
5
5
|
import { Icon } from '@iconify/react';
|
|
6
6
|
export { loadIcons } from '@iconify/react';
|
|
7
|
-
import React, { useId, useState, useCallback, useMemo, useEffect, createContext, useContext,
|
|
7
|
+
import React, { useId, useState, useCallback, useMemo, useEffect, createContext, useContext, memo, useRef, createElement, useLayoutEffect } from 'react';
|
|
8
8
|
import { ResponsiveContainer, AreaChart, CartesianGrid, XAxis, Tooltip, Area } from 'recharts';
|
|
9
9
|
import { LazyMotion, domAnimation, m } from 'framer-motion';
|
|
10
10
|
import { createPortal } from 'react-dom';
|
|
@@ -1700,6 +1700,189 @@ var HeaderComponent = function (_a) {
|
|
|
1700
1700
|
};
|
|
1701
1701
|
HeaderComponent.displayName = "Header";
|
|
1702
1702
|
|
|
1703
|
+
/**
|
|
1704
|
+
* KanbanCard - Contenedor de tarjeta genérico del Kanban con soporte drag and drop
|
|
1705
|
+
*
|
|
1706
|
+
* El contenido es 100% definido por el padre mediante renderContent.
|
|
1707
|
+
* Este componente solo provee el contenedor con estilos, eventos y drag.
|
|
1708
|
+
*/
|
|
1709
|
+
var KanbanCardComponent = function (_a) {
|
|
1710
|
+
var item = _a.item, columnId = _a.columnId, index = _a.index, renderContent = _a.renderContent, onCardClick = _a.onCardClick, className = _a.className, _b = _a.isClickable, isClickable = _b === void 0 ? true : _b, _c = _a.isDraggable, isDraggable = _c === void 0 ? false : _c, onDragStart = _a.onDragStart, onDragEnd = _a.onDragEnd;
|
|
1711
|
+
var _d = useState(false), isDragging = _d[0], setIsDragging = _d[1];
|
|
1712
|
+
var handleClick = useCallback(function () {
|
|
1713
|
+
if (!isDragging) {
|
|
1714
|
+
onCardClick === null || onCardClick === void 0 ? void 0 : onCardClick(item);
|
|
1715
|
+
}
|
|
1716
|
+
}, [item, onCardClick, isDragging]);
|
|
1717
|
+
var handleKeyDown = useCallback(function (e) {
|
|
1718
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
1719
|
+
e.preventDefault();
|
|
1720
|
+
onCardClick === null || onCardClick === void 0 ? void 0 : onCardClick(item);
|
|
1721
|
+
}
|
|
1722
|
+
}, [item, onCardClick]);
|
|
1723
|
+
var handleDragStart = useCallback(function (e) {
|
|
1724
|
+
if (!isDraggable)
|
|
1725
|
+
return;
|
|
1726
|
+
setIsDragging(true);
|
|
1727
|
+
// Datos para el drop
|
|
1728
|
+
e.dataTransfer.setData("application/json", JSON.stringify({ itemId: item.id, fromColumnId: columnId, fromIndex: index }));
|
|
1729
|
+
e.dataTransfer.effectAllowed = "move";
|
|
1730
|
+
// Notificar al padre
|
|
1731
|
+
onDragStart === null || onDragStart === void 0 ? void 0 : onDragStart(item, columnId, index);
|
|
1732
|
+
}, [item, columnId, index, isDraggable, onDragStart]);
|
|
1733
|
+
var handleDragEnd = useCallback(function () {
|
|
1734
|
+
setIsDragging(false);
|
|
1735
|
+
onDragEnd === null || onDragEnd === void 0 ? void 0 : onDragEnd();
|
|
1736
|
+
}, [onDragEnd]);
|
|
1737
|
+
var isInteractive = isClickable && onCardClick;
|
|
1738
|
+
return (jsx("div", { className: cn("bg-content1 border border-default-200 rounded-lg p-4 transition-all", isInteractive && "cursor-pointer hover:border-default-400", isDraggable && "cursor-grab active:cursor-grabbing", isDragging && "opacity-50 scale-95 shadow-lg", className), onClick: isInteractive ? handleClick : undefined, onKeyDown: isInteractive ? handleKeyDown : undefined, role: isInteractive ? "button" : undefined, tabIndex: isInteractive ? 0 : undefined, draggable: isDraggable, onDragStart: handleDragStart, onDragEnd: handleDragEnd, children: renderContent(item) }));
|
|
1739
|
+
};
|
|
1740
|
+
var KanbanCard = memo(KanbanCardComponent);
|
|
1741
|
+
KanbanCard.displayName = "KanbanCard";
|
|
1742
|
+
|
|
1743
|
+
/**
|
|
1744
|
+
* KanbanColumn - Columna individual del Kanban con soporte de drop
|
|
1745
|
+
*
|
|
1746
|
+
* Muestra un header con título y badge de conteo,
|
|
1747
|
+
* una lista scrolleable de tarjetas, y estado vacío.
|
|
1748
|
+
* Acepta drops de tarjetas de otras columnas.
|
|
1749
|
+
*/
|
|
1750
|
+
var KanbanColumnComponent = function (_a) {
|
|
1751
|
+
var _b, _c;
|
|
1752
|
+
var column = _a.column, renderItem = _a.renderItem, onCardClick = _a.onCardClick, cardClassName = _a.cardClassName, isCardClickable = _a.isCardClickable, className = _a.className, _d = _a.maxHeight, maxHeight = _d === void 0 ? "calc(100vh - 280px)" : _d, renderColumnHeader = _a.renderColumnHeader, renderEmptyState = _a.renderEmptyState, _e = _a.isDraggable, isDraggable = _e === void 0 ? false : _e, onDragStart = _a.onDragStart, onDragEnd = _a.onDragEnd, onDrop = _a.onDrop, _f = _a.isDragging, isDragging = _f === void 0 ? false : _f, _g = _a.translations, translations = _g === void 0 ? {} : _g;
|
|
1753
|
+
// Traducciones con fallbacks
|
|
1754
|
+
var t = {
|
|
1755
|
+
dropHere: (_b = translations.dropHere) !== null && _b !== void 0 ? _b : "Soltar aquí",
|
|
1756
|
+
emptyMessage: (_c = translations.emptyMessage) !== null && _c !== void 0 ? _c : "No hay elementos",
|
|
1757
|
+
};
|
|
1758
|
+
var _h = useState(false), isDragOver = _h[0], setIsDragOver = _h[1];
|
|
1759
|
+
var _j = useState(null), dropIndex = _j[0], setDropIndex = _j[1];
|
|
1760
|
+
var itemCount = column.items.length;
|
|
1761
|
+
var isEmpty = itemCount === 0;
|
|
1762
|
+
var handleDragOver = useCallback(function (e) {
|
|
1763
|
+
if (!isDraggable)
|
|
1764
|
+
return;
|
|
1765
|
+
e.preventDefault();
|
|
1766
|
+
e.dataTransfer.dropEffect = "move";
|
|
1767
|
+
setIsDragOver(true);
|
|
1768
|
+
}, [isDraggable]);
|
|
1769
|
+
var handleDragLeave = useCallback(function (e) {
|
|
1770
|
+
// Solo salir si realmente salimos de la columna (no de un hijo)
|
|
1771
|
+
if (!e.currentTarget.contains(e.relatedTarget)) {
|
|
1772
|
+
setIsDragOver(false);
|
|
1773
|
+
setDropIndex(null);
|
|
1774
|
+
}
|
|
1775
|
+
}, []);
|
|
1776
|
+
var handleDrop = useCallback(function (e) {
|
|
1777
|
+
e.preventDefault();
|
|
1778
|
+
setIsDragOver(false);
|
|
1779
|
+
setDropIndex(null);
|
|
1780
|
+
if (!isDraggable)
|
|
1781
|
+
return;
|
|
1782
|
+
// Calcular índice de drop basado en posición Y
|
|
1783
|
+
var finalDropIndex = dropIndex !== null && dropIndex !== void 0 ? dropIndex : column.items.length;
|
|
1784
|
+
onDrop === null || onDrop === void 0 ? void 0 : onDrop(column.id, finalDropIndex);
|
|
1785
|
+
}, [isDraggable, column.id, column.items.length, dropIndex, onDrop]);
|
|
1786
|
+
// Calcular índice de drop basado en la posición del mouse
|
|
1787
|
+
var handleDragOverItem = useCallback(function (e, itemIndex) {
|
|
1788
|
+
e.preventDefault();
|
|
1789
|
+
var rect = e.currentTarget.getBoundingClientRect();
|
|
1790
|
+
var midpoint = rect.top + rect.height / 2;
|
|
1791
|
+
var newDropIndex = e.clientY < midpoint ? itemIndex : itemIndex + 1;
|
|
1792
|
+
setDropIndex(newDropIndex);
|
|
1793
|
+
}, []);
|
|
1794
|
+
return (jsxs("div", { className: cn("flex flex-col bg-default-50 rounded-lg border border-default-200 transition-colors", isDragOver && isDragging && "border-primary-400 bg-primary-50/30", className), onDragOver: handleDragOver, onDragLeave: handleDragLeave, onDrop: handleDrop, children: [renderColumnHeader ? (renderColumnHeader(column)) : (jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-b border-default-200", children: [jsx("h3", { className: "font-semibold text-foreground", children: column.title }), jsx(Badge, { content: itemCount, color: column.countBadgeColor || "default", variant: "flat", size: "md", classNames: {
|
|
1795
|
+
badge: "text-xs font-medium min-w-6 h-6",
|
|
1796
|
+
}, children: jsxs("span", { className: "sr-only", children: [itemCount, " items"] }) })] })), jsx("div", { className: cn("flex-1 overflow-y-auto p-3 space-y-3", isDragOver && isEmpty && "min-h-24"), style: { maxHeight: maxHeight }, children: isEmpty ? (isDragOver && isDragging ? (jsx("div", { className: "h-24 border-2 border-dashed border-primary-300 rounded-lg bg-primary-50/50 flex items-center justify-center", children: jsx("span", { className: "text-primary-500 text-sm", children: t.dropHere }) })) : renderEmptyState ? (renderEmptyState(column)) : (jsx("div", { className: "flex items-center justify-center h-24 text-default-400 text-sm", children: column.emptyMessage || t.emptyMessage }))) : (jsxs(Fragment, { children: [column.items.map(function (item, index) { return (jsxs("div", { onDragOver: function (e) { return handleDragOverItem(e, index); }, children: [isDragOver && dropIndex === index && (jsx("div", { className: "h-1 bg-primary-400 rounded-full mb-3 animate-pulse" })), jsx(KanbanCard, { item: item, columnId: column.id, index: index, renderContent: renderItem, onCardClick: onCardClick, className: cardClassName, isClickable: isCardClickable, isDraggable: isDraggable, onDragStart: onDragStart, onDragEnd: onDragEnd })] }, item.id)); }), isDragOver && dropIndex === column.items.length && (jsx("div", { className: "h-1 bg-primary-400 rounded-full mt-3 animate-pulse" }))] })) })] }));
|
|
1797
|
+
};
|
|
1798
|
+
var KanbanColumn = memo(KanbanColumnComponent);
|
|
1799
|
+
KanbanColumn.displayName = "KanbanColumn";
|
|
1800
|
+
|
|
1801
|
+
/**
|
|
1802
|
+
* Traducciones por defecto en español.
|
|
1803
|
+
* Se mezclan con las traducciones proporcionadas por el usuario.
|
|
1804
|
+
*/
|
|
1805
|
+
var DEFAULT_TRANSLATIONS = {
|
|
1806
|
+
dropHere: "Soltar aquí",
|
|
1807
|
+
emptyMessage: "No hay elementos",
|
|
1808
|
+
};
|
|
1809
|
+
var columnGapClasses = {
|
|
1810
|
+
sm: "gap-3",
|
|
1811
|
+
md: "gap-4",
|
|
1812
|
+
lg: "gap-6",
|
|
1813
|
+
};
|
|
1814
|
+
/**
|
|
1815
|
+
* Kanban - Tablero Kanban genérico con columnas, tarjetas y drag and drop
|
|
1816
|
+
*
|
|
1817
|
+
* El contenido de cada tarjeta es 100% definido por el consumidor
|
|
1818
|
+
* mediante la prop `renderItem`. Esto permite usar el Kanban para
|
|
1819
|
+
* cualquier caso de uso: contactos, tareas, proyectos, etc.
|
|
1820
|
+
*
|
|
1821
|
+
* Soporta drag and drop entre columnas con el callback `onItemMove`.
|
|
1822
|
+
*
|
|
1823
|
+
* @example
|
|
1824
|
+
* ```tsx
|
|
1825
|
+
* // Kanban de tareas con drag and drop
|
|
1826
|
+
* <Kanban<Task>
|
|
1827
|
+
* columns={columns}
|
|
1828
|
+
* renderItem={(item) => <TaskCard task={item.data} />}
|
|
1829
|
+
* onItemMove={(event) => {
|
|
1830
|
+
* console.log(`Moved ${event.item.id} from ${event.fromColumnId} to ${event.toColumnId}`);
|
|
1831
|
+
* // Actualizar estado...
|
|
1832
|
+
* }}
|
|
1833
|
+
* />
|
|
1834
|
+
* ```
|
|
1835
|
+
*/
|
|
1836
|
+
var KanbanComponent = function (_a) {
|
|
1837
|
+
var columns = _a.columns, renderItem = _a.renderItem, onCardClick = _a.onCardClick, onItemMove = _a.onItemMove, isDraggable = _a.isDraggable, cardClassName = _a.cardClassName, isCardClickable = _a.isCardClickable, className = _a.className, _b = _a.columnWidth, columnWidth = _b === void 0 ? "280px" : _b, _c = _a.columnGap, columnGap = _c === void 0 ? "md" : _c, _d = _a.horizontalScroll, horizontalScroll = _d === void 0 ? true : _d, columnMaxHeight = _a.columnMaxHeight, renderColumnHeader = _a.renderColumnHeader, renderEmptyState = _a.renderEmptyState, _e = _a.translations, translations = _e === void 0 ? {} : _e;
|
|
1838
|
+
// Mezclar traducciones del usuario con las por defecto
|
|
1839
|
+
var t = __assign(__assign({}, DEFAULT_TRANSLATIONS), translations);
|
|
1840
|
+
// Determinar si drag está habilitado
|
|
1841
|
+
var dragEnabled = isDraggable !== null && isDraggable !== void 0 ? isDraggable : !!onItemMove;
|
|
1842
|
+
// Estado del drag actual
|
|
1843
|
+
var _f = useState(false), isDragging = _f[0], setIsDragging = _f[1];
|
|
1844
|
+
var dragDataRef = useRef(null);
|
|
1845
|
+
// Cuando empieza el drag
|
|
1846
|
+
var handleDragStart = useCallback(function (item, columnId, index) {
|
|
1847
|
+
setIsDragging(true);
|
|
1848
|
+
dragDataRef.current = { item: item, fromColumnId: columnId, fromIndex: index };
|
|
1849
|
+
}, []);
|
|
1850
|
+
// Cuando termina el drag (sin drop válido)
|
|
1851
|
+
var handleDragEnd = useCallback(function () {
|
|
1852
|
+
setIsDragging(false);
|
|
1853
|
+
dragDataRef.current = null;
|
|
1854
|
+
}, []);
|
|
1855
|
+
// Cuando se suelta en una columna
|
|
1856
|
+
var handleDrop = useCallback(function (toColumnId, toIndex) {
|
|
1857
|
+
var dragData = dragDataRef.current;
|
|
1858
|
+
if (!dragData || !onItemMove)
|
|
1859
|
+
return;
|
|
1860
|
+
var item = dragData.item, fromColumnId = dragData.fromColumnId, fromIndex = dragData.fromIndex;
|
|
1861
|
+
// No hacer nada si se suelta en la misma posición
|
|
1862
|
+
if (fromColumnId === toColumnId && fromIndex === toIndex) {
|
|
1863
|
+
handleDragEnd();
|
|
1864
|
+
return;
|
|
1865
|
+
}
|
|
1866
|
+
// Ajustar índice si se mueve dentro de la misma columna hacia abajo
|
|
1867
|
+
var adjustedToIndex = toIndex;
|
|
1868
|
+
if (fromColumnId === toColumnId && fromIndex < toIndex) {
|
|
1869
|
+
adjustedToIndex = toIndex - 1;
|
|
1870
|
+
}
|
|
1871
|
+
// Notificar al padre
|
|
1872
|
+
onItemMove({
|
|
1873
|
+
item: item,
|
|
1874
|
+
fromColumnId: fromColumnId,
|
|
1875
|
+
toColumnId: toColumnId,
|
|
1876
|
+
fromIndex: fromIndex,
|
|
1877
|
+
toIndex: adjustedToIndex,
|
|
1878
|
+
});
|
|
1879
|
+
handleDragEnd();
|
|
1880
|
+
}, [onItemMove, handleDragEnd]);
|
|
1881
|
+
return (jsx("div", { className: cn("flex", columnGapClasses[columnGap], horizontalScroll && "overflow-x-auto pb-4", className), children: columns.map(function (column) { return (jsx("div", { className: "flex-shrink-0", style: { width: columnWidth }, children: jsx(KanbanColumn, { column: column, renderItem: renderItem, onCardClick: onCardClick, cardClassName: cardClassName, isCardClickable: isCardClickable, maxHeight: columnMaxHeight, renderColumnHeader: renderColumnHeader, renderEmptyState: renderEmptyState, isDraggable: dragEnabled, onDragStart: handleDragStart, onDragEnd: handleDragEnd, onDrop: handleDrop, isDragging: isDragging, translations: t }) }, column.id)); }) }));
|
|
1882
|
+
};
|
|
1883
|
+
var Kanban = memo(KanbanComponent);
|
|
1884
|
+
Kanban.displayName = "Kanban";
|
|
1885
|
+
|
|
1703
1886
|
var defaultTranslations$8 = {
|
|
1704
1887
|
previewAlt: "Vista previa de imagen",
|
|
1705
1888
|
removeButtonAriaLabel: "Eliminar imagen",
|
|
@@ -4952,4 +5135,4 @@ var NavigationLoadingProvider = function (_a) {
|
|
|
4952
5135
|
return (jsxs(NavigationLoadingContext.Provider, { value: value, children: [children, jsx(NavigationLoadingOverlay, { isVisible: isVisible })] }));
|
|
4953
5136
|
};
|
|
4954
5137
|
|
|
4955
|
-
export { AccordionList, AddHolidayForm, AnalyticsCard, AuraAutocomplete, AuraTable, AuraToastProvider, BreadcrumbsComponent, Button, Card, Chip, ColorPicker, ColorSelector, ContentCarousel, DEFAULT_PREDEFINED_COLORS, DatePicker, DateRangePicker, DateSelector, DrawerFilters, GlobalToast, H1, H2, H3, H4, HeaderComponent, HolidayType, IconComponent, ImagePreview, Input, MenuComponent, Modal, ModalBody, ModalContent, ModalFooter, ModalHeader, MultiStepWizard, NavigationLoadingContext, NavigationLoadingOverlay, NavigationLoadingProvider, P, Pagination, Phone, PromotionalBanner, RangeFilter, RowSteps, ScheduleRow, SearchInput, Select, SocialMediaBar, SocialMediaCarousel, SocialMediaPreview, StepIndicator, Switch as SwitchComponent, Textarea, ThemeContext, ThemePicker, ThemeProvider, TimeInput as TimeInputComponent, ToastContext, UploadFile, VerticalSteps, Wizard, WizardNavigation, WizardSidebar, defaultTranslations$4 as defaultTranslations, sizeMap, themeColors, useAuraToast, useNavigationLoading, useThemeContext };
|
|
5138
|
+
export { AccordionList, AddHolidayForm, AnalyticsCard, AuraAutocomplete, AuraTable, AuraToastProvider, BreadcrumbsComponent, Button, Card, Chip, ColorPicker, ColorSelector, ContentCarousel, DEFAULT_PREDEFINED_COLORS, DatePicker, DateRangePicker, DateSelector, DrawerFilters, GlobalToast, H1, H2, H3, H4, HeaderComponent, HolidayType, IconComponent, ImagePreview, Input, Kanban, KanbanCard, KanbanColumn, MenuComponent, Modal, ModalBody, ModalContent, ModalFooter, ModalHeader, MultiStepWizard, NavigationLoadingContext, NavigationLoadingOverlay, NavigationLoadingProvider, P, Pagination, Phone, PromotionalBanner, RangeFilter, RowSteps, ScheduleRow, SearchInput, Select, SocialMediaBar, SocialMediaCarousel, SocialMediaPreview, StepIndicator, Switch as SwitchComponent, Textarea, ThemeContext, ThemePicker, ThemeProvider, TimeInput as TimeInputComponent, ToastContext, UploadFile, VerticalSteps, Wizard, WizardNavigation, WizardSidebar, defaultTranslations$4 as defaultTranslations, sizeMap, themeColors, useAuraToast, useNavigationLoading, useThemeContext };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { KanbanProps } from "./Kanban.types";
|
|
2
|
+
/**
|
|
3
|
+
* Kanban - Tablero Kanban genérico con columnas, tarjetas y drag and drop
|
|
4
|
+
*
|
|
5
|
+
* El contenido de cada tarjeta es 100% definido por el consumidor
|
|
6
|
+
* mediante la prop `renderItem`. Esto permite usar el Kanban para
|
|
7
|
+
* cualquier caso de uso: contactos, tareas, proyectos, etc.
|
|
8
|
+
*
|
|
9
|
+
* Soporta drag and drop entre columnas con el callback `onItemMove`.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```tsx
|
|
13
|
+
* // Kanban de tareas con drag and drop
|
|
14
|
+
* <Kanban<Task>
|
|
15
|
+
* columns={columns}
|
|
16
|
+
* renderItem={(item) => <TaskCard task={item.data} />}
|
|
17
|
+
* onItemMove={(event) => {
|
|
18
|
+
* console.log(`Moved ${event.item.id} from ${event.fromColumnId} to ${event.toColumnId}`);
|
|
19
|
+
* // Actualizar estado...
|
|
20
|
+
* }}
|
|
21
|
+
* />
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
declare const KanbanComponent: <T>({ columns, renderItem, onCardClick, onItemMove, isDraggable, cardClassName, isCardClickable, className, columnWidth, columnGap, horizontalScroll, columnMaxHeight, renderColumnHeader, renderEmptyState, translations, }: KanbanProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
25
|
+
export declare const Kanban: typeof KanbanComponent;
|
|
26
|
+
export {};
|
|
27
|
+
//# sourceMappingURL=Kanban.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Kanban.d.ts","sourceRoot":"","sources":["../../../../src/components/kanban/Kanban.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAc,WAAW,EAAsB,MAAM,gBAAgB,CAAC;AAkBlF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,QAAA,MAAM,eAAe,GAAI,CAAC,EAAG,0NAgB1B,WAAW,CAAC,CAAC,CAAC,4CAmGhB,CAAC;AAEF,eAAO,MAAM,MAAM,EAA4B,OAAO,eAAe,CAAC"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Traducciones disponibles para el componente Kanban.
|
|
4
|
+
* Todas las propiedades son opcionales para permitir traducciones parciales.
|
|
5
|
+
*/
|
|
6
|
+
export type KanbanTranslations = {
|
|
7
|
+
/** Texto al arrastrar sobre zona de drop vacía */
|
|
8
|
+
dropHere?: string;
|
|
9
|
+
/** Mensaje por defecto cuando una columna está vacía */
|
|
10
|
+
emptyMessage?: string;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Representa un item genérico en el Kanban.
|
|
14
|
+
* El contenido visual lo define el consumidor con renderItem.
|
|
15
|
+
*/
|
|
16
|
+
export interface KanbanItem<T = unknown> {
|
|
17
|
+
/** Identificador único del item (requerido para keys) */
|
|
18
|
+
id: string;
|
|
19
|
+
/** Datos del item - el tipo lo define el consumidor */
|
|
20
|
+
data: T;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Representa una columna del Kanban
|
|
24
|
+
*/
|
|
25
|
+
export interface KanbanColumn<T = unknown> {
|
|
26
|
+
/** Identificador único de la columna */
|
|
27
|
+
id: string;
|
|
28
|
+
/** Título de la columna */
|
|
29
|
+
title: string;
|
|
30
|
+
/** Items en esta columna */
|
|
31
|
+
items: KanbanItem<T>[];
|
|
32
|
+
/** Mensaje cuando no hay items */
|
|
33
|
+
emptyMessage?: string;
|
|
34
|
+
/** Color del badge de conteo */
|
|
35
|
+
countBadgeColor?: "default" | "primary" | "secondary" | "success" | "warning" | "danger";
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Información del movimiento de un item entre columnas
|
|
39
|
+
*/
|
|
40
|
+
export interface KanbanMoveEvent<T = unknown> {
|
|
41
|
+
/** El item que fue movido */
|
|
42
|
+
item: KanbanItem<T>;
|
|
43
|
+
/** ID de la columna origen */
|
|
44
|
+
fromColumnId: string;
|
|
45
|
+
/** ID de la columna destino */
|
|
46
|
+
toColumnId: string;
|
|
47
|
+
/** Índice del item en la columna origen */
|
|
48
|
+
fromIndex: number;
|
|
49
|
+
/** Índice donde se soltó en la columna destino */
|
|
50
|
+
toIndex: number;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Props para el componente KanbanCard interno
|
|
54
|
+
*/
|
|
55
|
+
export interface KanbanCardProps<T = unknown> {
|
|
56
|
+
/** Item a renderizar */
|
|
57
|
+
item: KanbanItem<T>;
|
|
58
|
+
/** ID de la columna donde está el item */
|
|
59
|
+
columnId: string;
|
|
60
|
+
/** Índice del item en la columna */
|
|
61
|
+
index: number;
|
|
62
|
+
/** Función para renderizar el contenido (REQUERIDO) */
|
|
63
|
+
renderContent: (item: KanbanItem<T>) => ReactNode;
|
|
64
|
+
/** Callback al hacer clic en la tarjeta */
|
|
65
|
+
onCardClick?: (item: KanbanItem<T>) => void;
|
|
66
|
+
/** Clases CSS adicionales para la tarjeta */
|
|
67
|
+
className?: string;
|
|
68
|
+
/** Si la tarjeta es clickeable (muestra hover effects) */
|
|
69
|
+
isClickable?: boolean;
|
|
70
|
+
/** Si el drag and drop está habilitado */
|
|
71
|
+
isDraggable?: boolean;
|
|
72
|
+
/** Callback cuando empieza el drag */
|
|
73
|
+
onDragStart?: (item: KanbanItem<T>, columnId: string, index: number) => void;
|
|
74
|
+
/** Callback cuando termina el drag */
|
|
75
|
+
onDragEnd?: () => void;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Props para el componente KanbanColumnInternal
|
|
79
|
+
*/
|
|
80
|
+
export interface KanbanColumnInternalProps<T = unknown> {
|
|
81
|
+
/** Columna a renderizar */
|
|
82
|
+
column: KanbanColumn<T>;
|
|
83
|
+
/** Función para renderizar el contenido de cada item (REQUERIDO) */
|
|
84
|
+
renderItem: (item: KanbanItem<T>) => ReactNode;
|
|
85
|
+
/** Callback al hacer clic en una tarjeta */
|
|
86
|
+
onCardClick?: (item: KanbanItem<T>) => void;
|
|
87
|
+
/** Clases CSS adicionales para las tarjetas */
|
|
88
|
+
cardClassName?: string;
|
|
89
|
+
/** Si las tarjetas son clickeables */
|
|
90
|
+
isCardClickable?: boolean;
|
|
91
|
+
/** Clases CSS adicionales para la columna */
|
|
92
|
+
className?: string;
|
|
93
|
+
/** Altura máxima de la columna (con scroll) */
|
|
94
|
+
maxHeight?: string;
|
|
95
|
+
/** Render personalizado del header de la columna */
|
|
96
|
+
renderColumnHeader?: (column: KanbanColumn<T>) => ReactNode;
|
|
97
|
+
/** Render personalizado del estado vacío */
|
|
98
|
+
renderEmptyState?: (column: KanbanColumn<T>) => ReactNode;
|
|
99
|
+
/** Si el drag and drop está habilitado */
|
|
100
|
+
isDraggable?: boolean;
|
|
101
|
+
/** Callback cuando empieza el drag de un item */
|
|
102
|
+
onDragStart?: (item: KanbanItem<T>, columnId: string, index: number) => void;
|
|
103
|
+
/** Callback cuando termina el drag */
|
|
104
|
+
onDragEnd?: () => void;
|
|
105
|
+
/** Callback cuando se suelta un item en esta columna */
|
|
106
|
+
onDrop?: (columnId: string, dropIndex: number) => void;
|
|
107
|
+
/** Si hay un item siendo arrastrado actualmente */
|
|
108
|
+
isDragging?: boolean;
|
|
109
|
+
/**
|
|
110
|
+
* Traducciones i18n del componente.
|
|
111
|
+
* Si no se proporciona, usa traducciones por defecto en español.
|
|
112
|
+
*/
|
|
113
|
+
translations?: KanbanTranslations;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Props para el componente Kanban principal
|
|
117
|
+
*/
|
|
118
|
+
export interface KanbanProps<T = unknown> {
|
|
119
|
+
/** Columnas del Kanban */
|
|
120
|
+
columns: KanbanColumn<T>[];
|
|
121
|
+
/**
|
|
122
|
+
* Función para renderizar el contenido de cada item (REQUERIDO).
|
|
123
|
+
* El padre decide qué mostrar en cada tarjeta.
|
|
124
|
+
*/
|
|
125
|
+
renderItem: (item: KanbanItem<T>) => ReactNode;
|
|
126
|
+
/** Callback al hacer clic en una tarjeta */
|
|
127
|
+
onCardClick?: (item: KanbanItem<T>) => void;
|
|
128
|
+
/**
|
|
129
|
+
* Callback cuando un item se mueve entre columnas (drag and drop).
|
|
130
|
+
* Recibe información completa del movimiento.
|
|
131
|
+
*/
|
|
132
|
+
onItemMove?: (event: KanbanMoveEvent<T>) => void;
|
|
133
|
+
/** Si el drag and drop está habilitado (default: true si hay onItemMove) */
|
|
134
|
+
isDraggable?: boolean;
|
|
135
|
+
/** Clases CSS adicionales para las tarjetas */
|
|
136
|
+
cardClassName?: string;
|
|
137
|
+
/** Si las tarjetas son clickeables (default: true si hay onCardClick) */
|
|
138
|
+
isCardClickable?: boolean;
|
|
139
|
+
/** Clases CSS adicionales para el contenedor */
|
|
140
|
+
className?: string;
|
|
141
|
+
/** Ancho de cada columna */
|
|
142
|
+
columnWidth?: string;
|
|
143
|
+
/** Gap entre columnas */
|
|
144
|
+
columnGap?: "sm" | "md" | "lg";
|
|
145
|
+
/** Si el board tiene scroll horizontal */
|
|
146
|
+
horizontalScroll?: boolean;
|
|
147
|
+
/** Altura máxima de las columnas */
|
|
148
|
+
columnMaxHeight?: string;
|
|
149
|
+
/** Render personalizado del header de columna */
|
|
150
|
+
renderColumnHeader?: (column: KanbanColumn<T>) => ReactNode;
|
|
151
|
+
/** Render personalizado del estado vacío de columna */
|
|
152
|
+
renderEmptyState?: (column: KanbanColumn<T>) => ReactNode;
|
|
153
|
+
/**
|
|
154
|
+
* Traducciones i18n del componente.
|
|
155
|
+
* Si no se proporciona, usa traducciones por defecto en español.
|
|
156
|
+
* @example
|
|
157
|
+
* ```tsx
|
|
158
|
+
* <Kanban translations={{ dropHere: "Drop here", emptyMessage: "No items" }} />
|
|
159
|
+
* ```
|
|
160
|
+
*/
|
|
161
|
+
translations?: KanbanTranslations;
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=Kanban.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Kanban.types.d.ts","sourceRoot":"","sources":["../../../../src/components/kanban/Kanban.types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { KanbanCardProps } from "../Kanban.types";
|
|
2
|
+
/**
|
|
3
|
+
* KanbanCard - Contenedor de tarjeta genérico del Kanban con soporte drag and drop
|
|
4
|
+
*
|
|
5
|
+
* El contenido es 100% definido por el padre mediante renderContent.
|
|
6
|
+
* Este componente solo provee el contenedor con estilos, eventos y drag.
|
|
7
|
+
*/
|
|
8
|
+
declare const KanbanCardComponent: <T>({ item, columnId, index, renderContent, onCardClick, className, isClickable, isDraggable, onDragStart, onDragEnd, }: KanbanCardProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export declare const KanbanCard: typeof KanbanCardComponent;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=KanbanCard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"KanbanCard.d.ts","sourceRoot":"","sources":["../../../../../src/components/kanban/_internal/KanbanCard.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEvD;;;;;GAKG;AACH,QAAA,MAAM,mBAAmB,GAAI,CAAC,EAAG,qHAW9B,eAAe,CAAC,CAAC,CAAC,4CAiEpB,CAAC;AAEF,eAAO,MAAM,UAAU,EAAgC,OAAO,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { KanbanColumnInternalProps } from "../Kanban.types";
|
|
2
|
+
/**
|
|
3
|
+
* KanbanColumn - Columna individual del Kanban con soporte de drop
|
|
4
|
+
*
|
|
5
|
+
* Muestra un header con título y badge de conteo,
|
|
6
|
+
* una lista scrolleable de tarjetas, y estado vacío.
|
|
7
|
+
* Acepta drops de tarjetas de otras columnas.
|
|
8
|
+
*/
|
|
9
|
+
declare const KanbanColumnComponent: <T>({ column, renderItem, onCardClick, cardClassName, isCardClickable, className, maxHeight, renderColumnHeader, renderEmptyState, isDraggable, onDragStart, onDragEnd, onDrop, isDragging, translations, }: KanbanColumnInternalProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export declare const KanbanColumn: typeof KanbanColumnComponent;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=KanbanColumn.d.ts.map
|