indas-ui 0.1.6 → 0.1.8
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/cjs/components/datagrid/cells/CellRenderer.js +4 -4
- package/dist/cjs/components/datagrid/cells/SelectionCell.js +10 -10
- package/dist/cjs/components/datagrid/controls/PaginationControls.js +3 -3
- package/dist/cjs/components/datagrid/rows/DraggableRow.js +6 -6
- package/dist/cjs/components/datagrid/search/InlineSearchCell.js +4 -4
- package/dist/cjs/components/draft/AutoSaveIndicator.js +9 -9
- package/dist/cjs/components/draft/DraftModal.js +6 -6
- package/dist/cjs/components/modals/Modal.js +23 -4
- package/dist/cjs/hooks/useIntelligentColumnSizing.js +10 -5
- package/dist/cjs/styles/index.css +5 -5
- package/dist/components/datagrid/cells/CellRenderer.js +4 -4
- package/dist/components/datagrid/cells/SelectionCell.js +10 -10
- package/dist/components/datagrid/controls/PaginationControls.js +3 -3
- package/dist/components/datagrid/rows/DraggableRow.js +6 -6
- package/dist/components/datagrid/search/InlineSearchCell.js +4 -4
- package/dist/components/draft/AutoSaveIndicator.js +9 -9
- package/dist/components/draft/DraftModal.js +6 -6
- package/dist/components/modals/Modal.js +23 -4
- package/dist/hooks/useIntelligentColumnSizing.d.ts +0 -5
- package/dist/hooks/useIntelligentColumnSizing.js +10 -5
- package/dist/styles/index.css +5 -5
- package/package.json +195 -195
|
@@ -94,10 +94,10 @@ function CellRenderer({ cell, cellIndex, row, enableBacchaSearch = false, mainCo
|
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
96
|
const rowId = row.original.id || row.id;
|
|
97
|
-
return ((0, jsx_runtime_1.jsx)("td", { className: `
|
|
98
|
-
px-1 py-1 text-xs text-fg-default align-middle
|
|
99
|
-
${isBadgeColumn || isPlaceholderValue ? 'text-center' : isNumericContent ? 'text-right' : 'text-left'}
|
|
100
|
-
${isCellFrozen || isPinnedRight ? 'sticky z-[5]' : ''}
|
|
97
|
+
return ((0, jsx_runtime_1.jsx)("td", { className: `
|
|
98
|
+
px-1 py-1 text-xs text-fg-default align-middle
|
|
99
|
+
${isBadgeColumn || isPlaceholderValue ? 'text-center' : isNumericContent ? 'text-right' : 'text-left'}
|
|
100
|
+
${isCellFrozen || isPinnedRight ? 'sticky z-[5]' : ''}
|
|
101
101
|
`, style: {
|
|
102
102
|
width: `${cell.column.getSize()}px`,
|
|
103
103
|
minWidth: `${cell.column.getSize()}px`,
|
|
@@ -15,13 +15,13 @@ function SelectionCell({ checked, indeterminate = false, onChange, disabled = fa
|
|
|
15
15
|
};
|
|
16
16
|
// Radio button mode (single selection) - always circular regardless of circularCheckboxes prop
|
|
17
17
|
if (mode === 'radio') {
|
|
18
|
-
return ((0, jsx_runtime_1.jsx)("div", { onClick: handleClick, className: `
|
|
19
|
-
relative rounded-full border-2 cursor-pointer transition-all duration-150
|
|
20
|
-
flex items-center justify-center flex-shrink-0
|
|
21
|
-
${disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}
|
|
18
|
+
return ((0, jsx_runtime_1.jsx)("div", { onClick: handleClick, className: `
|
|
19
|
+
relative rounded-full border-2 cursor-pointer transition-all duration-150
|
|
20
|
+
flex items-center justify-center flex-shrink-0
|
|
21
|
+
${disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}
|
|
22
22
|
${checked
|
|
23
23
|
? 'border-primary bg-white'
|
|
24
|
-
: 'border-gray-300 bg-white hover:border-gray-400'}
|
|
24
|
+
: 'border-gray-300 bg-white hover:border-gray-400'}
|
|
25
25
|
`, style: {
|
|
26
26
|
boxShadow: checked ? '0 0 0 2px rgba(59, 130, 246, 0.1)' : 'none',
|
|
27
27
|
width: '14px',
|
|
@@ -43,13 +43,13 @@ function SelectionCell({ checked, indeterminate = false, onChange, disabled = fa
|
|
|
43
43
|
: "border-[rgb(var(--bd-default))] bg-[rgb(var(--bg-surface))] hover:border-[rgb(var(--color-primary))]", disabled && "opacity-50 cursor-not-allowed"), children: [checked && !indeterminate && ((0, jsx_runtime_1.jsx)(lucide_react_1.Check, { className: "w-3 h-3 text-white", strokeWidth: 3 })), indeterminate && ((0, jsx_runtime_1.jsx)("div", { className: "w-2 h-0.5 bg-white rounded" }))] })] }));
|
|
44
44
|
}
|
|
45
45
|
// Circular checkbox (AG Grid style, multi-select with circular prop)
|
|
46
|
-
return ((0, jsx_runtime_1.jsxs)("div", { onClick: handleClick, className: `
|
|
47
|
-
relative rounded-full border-2 cursor-pointer transition-all duration-150
|
|
48
|
-
flex items-center justify-center flex-shrink-0
|
|
49
|
-
${disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}
|
|
46
|
+
return ((0, jsx_runtime_1.jsxs)("div", { onClick: handleClick, className: `
|
|
47
|
+
relative rounded-full border-2 cursor-pointer transition-all duration-150
|
|
48
|
+
flex items-center justify-center flex-shrink-0
|
|
49
|
+
${disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}
|
|
50
50
|
${checked || indeterminate
|
|
51
51
|
? 'border-primary bg-primary'
|
|
52
|
-
: 'border-gray-300 bg-white hover:border-gray-400'}
|
|
52
|
+
: 'border-gray-300 bg-white hover:border-gray-400'}
|
|
53
53
|
`, style: {
|
|
54
54
|
boxShadow: checked || indeterminate ? '0 0 0 2px rgba(59, 130, 246, 0.1)' : 'none',
|
|
55
55
|
width: '14px',
|
|
@@ -25,11 +25,11 @@ function PaginationControls({ pageIndex, pageSize, totalRows, pageSizeOptions =
|
|
|
25
25
|
return ((0, jsx_runtime_1.jsx)("span", { className: "px-2 text-[rgb(var(--fg-muted))]", children: "..." }, `ellipsis-${index}`));
|
|
26
26
|
}
|
|
27
27
|
const isCurrentPage = page === pageIndex;
|
|
28
|
-
return ((0, jsx_runtime_1.jsx)("button", { onClick: () => onPageChange(page), className: `
|
|
29
|
-
min-w-[32px] h-8 px-2 rounded text-sm font-medium transition-colors
|
|
28
|
+
return ((0, jsx_runtime_1.jsx)("button", { onClick: () => onPageChange(page), className: `
|
|
29
|
+
min-w-[32px] h-8 px-2 rounded text-sm font-medium transition-colors
|
|
30
30
|
${isCurrentPage
|
|
31
31
|
? 'border border-[rgb(var(--color-primary))] text-[rgb(var(--color-primary))] bg-[rgb(var(--color-primary)/0.08)]'
|
|
32
|
-
: 'text-[rgb(var(--fg-default))] hover:bg-[rgb(var(--bd-default))]'}
|
|
32
|
+
: 'text-[rgb(var(--fg-default))] hover:bg-[rgb(var(--bd-default))]'}
|
|
33
33
|
`, children: page + 1 }, page));
|
|
34
34
|
}) }), (0, jsx_runtime_1.jsx)("button", { onClick: () => onPageChange(pageIndex + 1), disabled: !hasNextPage, className: "p-1.5 rounded hover:bg-[rgb(var(--bd-default))] disabled:opacity-40 disabled:cursor-not-allowed transition-colors", "aria-label": "Next Page", children: (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronRight, { className: "h-4 w-4 text-[rgb(var(--fg-muted))]" }) }), (0, jsx_runtime_1.jsx)("button", { onClick: () => onPageChange(totalPages - 1), disabled: !hasNextPage, className: "p-1.5 rounded hover:bg-[rgb(var(--bd-default))] disabled:opacity-40 disabled:cursor-not-allowed transition-colors", "aria-label": "Last Page", children: (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronsRight, { className: "h-4 w-4 text-[rgb(var(--fg-muted))]" }) })] }), !isMobile && ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 text-sm text-[rgb(var(--fg-default))] flex-shrink-0 order-2 sm:order-3", children: [(0, jsx_runtime_1.jsx)("span", { className: "hidden sm:inline", children: "Show:" }), (0, jsx_runtime_1.jsx)(components_1.Dropdown, { value: String(pageSize), onValueChange: (value) => onPageSizeChange(Number(value)), options: pageSizeOptions.map((size) => ({
|
|
35
35
|
value: String(size),
|
|
@@ -20,15 +20,15 @@ navigationState = {}, columnSearches = {}, isColumnSearchActive = {}, onColumnSe
|
|
|
20
20
|
transition,
|
|
21
21
|
opacity: isDragging ? 0.5 : 1,
|
|
22
22
|
};
|
|
23
|
-
return ((0, jsx_runtime_1.jsxs)("tr", { ref: setNodeRef, style: style, className: `
|
|
24
|
-
cursor-pointer group
|
|
25
|
-
transition-colors duration-150 ease-out
|
|
26
|
-
${isDragging ? 'shadow-lg z-50' : ''}
|
|
23
|
+
return ((0, jsx_runtime_1.jsxs)("tr", { ref: setNodeRef, style: style, className: `
|
|
24
|
+
cursor-pointer group
|
|
25
|
+
transition-colors duration-150 ease-out
|
|
26
|
+
${isDragging ? 'shadow-lg z-50' : ''}
|
|
27
27
|
${isHighlighted
|
|
28
28
|
? 'border-2 border-[rgb(var(--color-primary))] bg-gradient-to-r from-[rgb(var(--color-primary))]/10 to-[rgb(var(--color-primary))]/20 shadow-lg relative'
|
|
29
29
|
: isSelected
|
|
30
30
|
? 'bg-[color-mix(in_srgb,rgb(var(--color-primary))_8%,rgb(var(--bg-surface)))] shadow-sm hover:bg-[color-mix(in_srgb,rgb(var(--color-primary))_15%,rgb(var(--bg-surface)))]'
|
|
31
|
-
: 'hover:bg-[color-mix(in_srgb,rgb(var(--color-primary))_5%,rgb(var(--bg-surface)))]'}
|
|
32
|
-
${className ?? ''}
|
|
31
|
+
: 'hover:bg-[color-mix(in_srgb,rgb(var(--color-primary))_5%,rgb(var(--bg-surface)))]'}
|
|
32
|
+
${className ?? ''}
|
|
33
33
|
`, onClick: onRowClick, onDoubleClick: onRowDoubleClick, onContextMenu: onRowContextMenu, children: [showDragHandle && ((0, jsx_runtime_1.jsx)("td", { className: "text-center align-middle cursor-grab active:cursor-grabbing", style: { width: '1.875rem', minWidth: '1.875rem', maxWidth: '1.875rem' }, ...attributes, ...listeners, children: (0, jsx_runtime_1.jsx)("div", { className: "w-full h-full flex items-center justify-center", children: (0, jsx_runtime_1.jsx)(lucide_react_1.GripVertical, { className: "h-4 w-4 text-gray-400" }) }) })), row.getVisibleCells().map((cell, cellIndex) => ((0, jsx_runtime_1.jsx)(CellRenderer_1.CellRenderer, { cell: cell, cellIndex: cellIndex, row: row, enableBacchaSearch: enableBacchaSearch, mainColumnsArray: mainColumnsArray, frozenColumnsState: frozenColumnsState, navigationState: navigationState, columnSearches: columnSearches, isColumnSearchActive: isColumnSearchActive, onColumnSearch: onColumnSearch, onClearColumnSearch: onClearColumnSearch, SearchHighlighter: SearchHighlighter, InlineSearchCell: InlineSearchCell, isSelected: isSelected }, cell.id)))] }));
|
|
34
34
|
}
|
|
@@ -89,10 +89,10 @@ function InlineSearchCell({ value, columnId, rowId, onSearch, onClearSearch, isS
|
|
|
89
89
|
return ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: parts.map((part, index) => part.toLowerCase() === highlight.toLowerCase() ? ((0, jsx_runtime_1.jsx)("mark", { className: "bg-yellow-200 text-yellow-900 px-0.5 rounded", children: part }, index)) : ((0, jsx_runtime_1.jsx)("span", { children: part }, index))) }));
|
|
90
90
|
};
|
|
91
91
|
const displayValue = value?.toString() || '';
|
|
92
|
-
return ((0, jsx_runtime_1.jsxs)("div", { ref: cellRef, tabIndex: 0, className: `bacchasearch relative group cursor-pointer outline-none inline-flex items-center w-full ${className}`, onClick: handleCellClick, children: [(0, jsx_runtime_1.jsx)("span", { className: `
|
|
93
|
-
text-xs flex-1 rounded transition-colors
|
|
94
|
-
${isSearchActive ? 'bg-[rgb(var(--color-primary)/0.1)]' : 'hover:bg-[rgb(var(--color-primary)/0.05)]'}
|
|
95
|
-
${isTyping ? 'ring-1 ring-[rgb(var(--color-primary)/0.3)] bg-[rgb(var(--color-primary)/0.15)]' : ''}
|
|
92
|
+
return ((0, jsx_runtime_1.jsxs)("div", { ref: cellRef, tabIndex: 0, className: `bacchasearch relative group cursor-pointer outline-none inline-flex items-center w-full ${className}`, onClick: handleCellClick, children: [(0, jsx_runtime_1.jsx)("span", { className: `
|
|
93
|
+
text-xs flex-1 rounded transition-colors
|
|
94
|
+
${isSearchActive ? 'bg-[rgb(var(--color-primary)/0.1)]' : 'hover:bg-[rgb(var(--color-primary)/0.05)]'}
|
|
95
|
+
${isTyping ? 'ring-1 ring-[rgb(var(--color-primary)/0.3)] bg-[rgb(var(--color-primary)/0.15)]' : ''}
|
|
96
96
|
`, children: isSearchActive && searchTerm ?
|
|
97
97
|
renderHighlightedText(displayValue, searchTerm) :
|
|
98
98
|
displayValue }), (0, jsx_runtime_1.jsx)(lucide_react_1.Search, { className: `h-3 w-3 text-[rgb(var(--fg-muted))] ml-0.5 flex-shrink-0 transition-opacity ${isTyping ? 'opacity-100' : 'opacity-0 group-hover:opacity-100'}` }), (isTyping || isSearchActive) && ((0, jsx_runtime_1.jsx)("div", { className: "absolute -top-0.5 -right-0.5", children: (0, jsx_runtime_1.jsx)("div", { className: `h-1.5 w-1.5 rounded-full ${isTyping ? 'bg-[rgb(var(--color-success))]' : 'bg-[rgb(var(--color-primary))]'}` }) })), isTyping && localSearchTerm && ((0, jsx_runtime_1.jsxs)("div", { className: "absolute -bottom-5 left-0 bg-[rgb(var(--bg-surface))] text-[rgb(var(--fg-default))] text-xs px-1.5 py-0.5 rounded shadow-lg border border-[rgb(var(--bd-default))] z-10 whitespace-nowrap", children: ["\"", localSearchTerm, "\""] }))] }));
|
|
@@ -57,14 +57,14 @@ function AutoSaveIndicator({ enabled, lastSaved, isDirty, isSaving, onOpenDraftM
|
|
|
57
57
|
};
|
|
58
58
|
};
|
|
59
59
|
const status = getStatus();
|
|
60
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-xs text-[rgb(var(--fg-muted))]", children: "Auto-save:" }), (0, jsx_runtime_1.jsx)("button", { onClick: () => onToggleAutoSave?.(!enabled), className: `
|
|
61
|
-
relative inline-flex h-5 w-9 items-center rounded-full transition-colors
|
|
62
|
-
${enabled ? 'bg-[rgb(var(--color-primary))]' : 'bg-[rgb(var(--bg-muted))]'}
|
|
63
|
-
`, title: enabled ? 'Disable auto-save' : 'Enable auto-save', children: (0, jsx_runtime_1.jsx)("span", { className: `
|
|
64
|
-
inline-block h-3.5 w-3.5 transform rounded-full bg-white transition-transform
|
|
65
|
-
${enabled ? 'translate-x-5' : 'translate-x-1'}
|
|
66
|
-
` }) }), (0, jsx_runtime_1.jsx)("span", { className: "text-xs font-medium text-[rgb(var(--fg-default))]", children: enabled ? 'ON' : 'OFF' })] }), (0, jsx_runtime_1.jsx)("div", { className: "h-4 w-px bg-[rgb(var(--bd-default))]" }), (0, jsx_runtime_1.jsxs)("button", { onClick: onOpenDraftManager, className: `
|
|
67
|
-
flex items-center gap-2 px-3 py-1.5 rounded-md transition-colors
|
|
68
|
-
${status.bg} ${status.color} hover:opacity-80
|
|
60
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-xs text-[rgb(var(--fg-muted))]", children: "Auto-save:" }), (0, jsx_runtime_1.jsx)("button", { onClick: () => onToggleAutoSave?.(!enabled), className: `
|
|
61
|
+
relative inline-flex h-5 w-9 items-center rounded-full transition-colors
|
|
62
|
+
${enabled ? 'bg-[rgb(var(--color-primary))]' : 'bg-[rgb(var(--bg-muted))]'}
|
|
63
|
+
`, title: enabled ? 'Disable auto-save' : 'Enable auto-save', children: (0, jsx_runtime_1.jsx)("span", { className: `
|
|
64
|
+
inline-block h-3.5 w-3.5 transform rounded-full bg-white transition-transform
|
|
65
|
+
${enabled ? 'translate-x-5' : 'translate-x-1'}
|
|
66
|
+
` }) }), (0, jsx_runtime_1.jsx)("span", { className: "text-xs font-medium text-[rgb(var(--fg-default))]", children: enabled ? 'ON' : 'OFF' })] }), (0, jsx_runtime_1.jsx)("div", { className: "h-4 w-px bg-[rgb(var(--bd-default))]" }), (0, jsx_runtime_1.jsxs)("button", { onClick: onOpenDraftManager, className: `
|
|
67
|
+
flex items-center gap-2 px-3 py-1.5 rounded-md transition-colors
|
|
68
|
+
${status.bg} ${status.color} hover:opacity-80
|
|
69
69
|
`, title: "Click to manage drafts", children: [status.icon, (0, jsx_runtime_1.jsx)("span", { className: "text-xs font-medium", children: status.text })] })] }));
|
|
70
70
|
}
|
|
@@ -192,10 +192,10 @@ function DraftModal({ open, onClose, drafts, onLoad, onDelete, isLoading = false
|
|
|
192
192
|
// Early return after all hooks to comply with Rules of Hooks
|
|
193
193
|
if (!open)
|
|
194
194
|
return null;
|
|
195
|
-
return ((0, jsx_runtime_1.jsx)("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm", children: (0, jsx_runtime_1.jsxs)("div", { className: "bg-[rgb(var(--bg-surface))] rounded-lg shadow-2xl w-full max-w-4xl max-h-[85vh] flex flex-col", children: [(0, jsx_runtime_1.jsxs)("div", { className: "px-6 py-3 border-b border-[rgb(var(--bd-default))] flex items-center gap-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 flex-shrink-0", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.FileText, { className: "w-5 h-5 text-[rgb(var(--color-primary))]" }), (0, jsx_runtime_1.jsx)("h2", { className: "text-base font-semibold text-[rgb(var(--fg-default))]", children: "Saved Drafts" }), (0, jsx_runtime_1.jsxs)("span", { className: "text-xs text-[rgb(var(--fg-muted))]", children: ["(", drafts.length, ")"] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "relative flex-1", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Search, { className: "absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 text-[rgb(var(--fg-muted))]" }), (0, jsx_runtime_1.jsx)("input", { type: "text", placeholder: "Search...", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), className: "\
|
|
195
|
+
return ((0, jsx_runtime_1.jsx)("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm", children: (0, jsx_runtime_1.jsxs)("div", { className: "bg-[rgb(var(--bg-surface))] rounded-lg shadow-2xl w-full max-w-4xl max-h-[85vh] flex flex-col", children: [(0, jsx_runtime_1.jsxs)("div", { className: "px-6 py-3 border-b border-[rgb(var(--bd-default))] flex items-center gap-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 flex-shrink-0", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.FileText, { className: "w-5 h-5 text-[rgb(var(--color-primary))]" }), (0, jsx_runtime_1.jsx)("h2", { className: "text-base font-semibold text-[rgb(var(--fg-default))]", children: "Saved Drafts" }), (0, jsx_runtime_1.jsxs)("span", { className: "text-xs text-[rgb(var(--fg-muted))]", children: ["(", drafts.length, ")"] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "relative flex-1", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Search, { className: "absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 text-[rgb(var(--fg-muted))]" }), (0, jsx_runtime_1.jsx)("input", { type: "text", placeholder: "Search...", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), className: "\n w-full pl-9 pr-3 py-1.5 rounded-lg text-sm\n bg-[rgb(var(--bg-default))]\n border border-[rgb(var(--bd-default))]\n text-[rgb(var(--fg-default))]\n placeholder:text-[rgb(var(--fg-muted))]\n focus:outline-none focus:ring-2 focus:ring-[rgb(var(--color-primary))]\n " })] }), (0, jsx_runtime_1.jsx)("div", { className: "flex-shrink-0 w-36", children: (0, jsx_runtime_1.jsx)(dropdown_1.Dropdown, { options: SORT_OPTIONS, value: sortBy, onValueChange: (val) => setSortBy(val), size: "sm", autoWidth: true }) }), (0, jsx_runtime_1.jsx)("button", { onClick: onClose, className: "p-1.5 rounded-lg hover:bg-[rgb(var(--bg-muted))] text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))] transition-colors flex-shrink-0", children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { className: "w-5 h-5" }) })] }), (0, jsx_runtime_1.jsx)("div", { className: "flex-1 overflow-y-auto px-6 py-4", children: isLoading ? ((0, jsx_runtime_1.jsx)("div", { className: "flex items-center justify-center py-16", children: (0, jsx_runtime_1.jsxs)("div", { className: "text-center", children: [(0, jsx_runtime_1.jsx)("div", { className: "w-12 h-12 rounded-full border-4 border-[rgb(var(--color-primary)_/_0.2)] border-t-[rgb(var(--color-primary))] animate-spin mx-auto mb-3" }), (0, jsx_runtime_1.jsx)("p", { className: "text-[rgb(var(--fg-muted))]", children: "Loading drafts..." })] }) })) : filteredAndSortedDrafts.length === 0 ? ((0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col items-center justify-center py-16 text-center", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.FileText, { className: "w-16 h-16 text-[rgb(var(--fg-muted))] mb-4 opacity-50" }), (0, jsx_runtime_1.jsx)("p", { className: "text-lg font-medium text-[rgb(var(--fg-default))] mb-1", children: searchQuery ? 'No matching drafts' : 'No drafts saved yet' }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-[rgb(var(--fg-muted))]", children: searchQuery ? 'Try a different search term' : 'Start by clicking "Save Draft" button' })] })) : ((0, jsx_runtime_1.jsx)("div", { className: "space-y-3", children: paginatedDrafts.map((draft) => {
|
|
196
196
|
const progress = calculateProgress(draft);
|
|
197
197
|
const preview = draft.previewData || {};
|
|
198
|
-
return ((0, jsx_runtime_1.jsx)("div", { className: "\
|
|
198
|
+
return ((0, jsx_runtime_1.jsx)("div", { className: "\n group relative p-3 rounded-lg\n bg-[rgb(var(--bg-default))]\n border border-[rgb(var(--bd-default))]\n hover:border-[rgb(var(--color-primary))]\n hover:shadow-lg\n transition-all duration-200\n ", children: (0, jsx_runtime_1.jsx)("div", { className: "flex items-start gap-4", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex-1 min-w-0", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-start justify-between gap-3", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex-1 min-w-0", children: [(0, jsx_runtime_1.jsx)("h3", { className: "font-semibold text-[rgb(var(--fg-default))] truncate text-base", children: draft.draftName || 'Untitled Draft' }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 mt-1 text-xs text-[rgb(var(--fg-muted))]", children: [(0, jsx_runtime_1.jsx)("span", { children: formatRelativeTime(draft.lastSaved) }), (0, jsx_runtime_1.jsxs)("span", { className: "hidden group-hover:inline", children: ["\u2022 ", formatFullDate(draft.lastSaved)] }), draft.isAutoSave && ((0, jsx_runtime_1.jsx)("span", { className: "text-[10px] px-2 py-0.5 rounded-full bg-[rgb(var(--color-primary)_/_0.1)] text-[rgb(var(--color-primary))] font-medium", children: "AUTO-SAVE" }))] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 opacity-0 group-hover:opacity-100 transition-opacity", children: [(0, jsx_runtime_1.jsxs)("button", { onClick: () => handleLoad(draft.draftId), className: "\n px-4 py-2 rounded-lg text-sm font-medium\n bg-[rgb(var(--color-primary))]\n text-white\n hover:opacity-90\n transition-opacity\n flex items-center gap-2\n ", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Download, { className: "w-4 h-4" }), "Load"] }), (0, jsx_runtime_1.jsx)("button", { onClick: () => handleDelete(draft.draftId), disabled: deletingId === draft.draftId, className: "\n p-2 rounded-lg\n text-[rgb(var(--fg-muted))]\n hover:text-red-600\n hover:bg-red-50\n transition-colors\n disabled:opacity-50\n ", title: "Delete draft", children: deletingId === draft.draftId ? ((0, jsx_runtime_1.jsx)("div", { className: "w-4 h-4 rounded-full border-2 border-red-200 border-t-red-600 animate-spin" })) : ((0, jsx_runtime_1.jsx)(lucide_react_1.Trash2, { className: "w-4 h-4" })) })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "grid grid-cols-2 gap-x-6 gap-y-1 mt-2 text-sm", children: [preview.jobName && ((0, jsx_runtime_1.jsx)("div", { className: "text-[rgb(var(--fg-muted))] truncate", children: preview.jobName }, "job")), preview.clientName && ((0, jsx_runtime_1.jsx)("div", { className: "text-[rgb(var(--fg-muted))] truncate", children: preview.clientName }, "client")), preview.category && ((0, jsx_runtime_1.jsx)("div", { className: "text-[rgb(var(--fg-muted))] truncate", children: preview.category }, "category")), preview.totalCost !== undefined && preview.totalCost > 0 && ((0, jsx_runtime_1.jsxs)("div", { className: "font-medium text-[rgb(var(--color-primary))]", children: [currencySymbol, preview.totalCost.toLocaleString('en-IN')] }, "cost"))] }), progress > 0 && ((0, jsx_runtime_1.jsxs)("div", { className: "mt-2", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between text-xs text-[rgb(var(--fg-muted))] mb-1", children: [(0, jsx_runtime_1.jsx)("span", { children: "Progress" }), (0, jsx_runtime_1.jsxs)("span", { className: "font-medium", children: [progress, "%"] })] }), (0, jsx_runtime_1.jsx)("div", { className: "h-1.5 bg-[rgb(var(--bg-muted))] rounded-full overflow-hidden", children: (0, jsx_runtime_1.jsx)("div", { className: "h-full bg-[rgb(var(--color-primary))] transition-all duration-500 rounded-full", style: { width: `${progress}%` } }) })] }))] }) }) }, draft.draftId));
|
|
199
199
|
}) })) }), (0, jsx_runtime_1.jsxs)("div", { className: "px-6 py-4 border-t border-[rgb(var(--bd-default))] flex justify-between items-center bg-[rgb(var(--bg-muted)_/_0.3)]", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-sm text-[rgb(var(--fg-muted))]", children: filteredAndSortedDrafts.length > 0 ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: ["Showing ", ((currentPage - 1) * PAGE_SIZE) + 1, "-", Math.min(currentPage * PAGE_SIZE, filteredAndSortedDrafts.length), " of ", filteredAndSortedDrafts.length, filteredAndSortedDrafts.length !== drafts.length && ` (filtered from ${drafts.length})`] })) : (`0 of ${drafts.length} drafts`) }), totalPages > 1 && ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("button", { onClick: () => setCurrentPage(p => Math.max(1, p - 1)), disabled: currentPage === 1, className: "p-1.5 rounded text-[rgb(var(--fg-muted))] hover:bg-[rgb(var(--bg-default))] disabled:opacity-30 disabled:cursor-not-allowed transition-colors", children: (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronLeft, { className: "w-4 h-4" }) }), (0, jsx_runtime_1.jsx)("div", { className: "flex items-center gap-1", children: Array.from({ length: Math.min(5, totalPages) }, (_, i) => {
|
|
200
200
|
let pageNum;
|
|
201
201
|
if (totalPages <= 5) {
|
|
@@ -210,11 +210,11 @@ function DraftModal({ open, onClose, drafts, onLoad, onDelete, isLoading = false
|
|
|
210
210
|
else {
|
|
211
211
|
pageNum = currentPage - 2 + i;
|
|
212
212
|
}
|
|
213
|
-
return ((0, jsx_runtime_1.jsx)("button", { onClick: () => setCurrentPage(pageNum), className: `
|
|
214
|
-
w-8 h-8 rounded text-sm font-medium transition-colors
|
|
213
|
+
return ((0, jsx_runtime_1.jsx)("button", { onClick: () => setCurrentPage(pageNum), className: `
|
|
214
|
+
w-8 h-8 rounded text-sm font-medium transition-colors
|
|
215
215
|
${currentPage === pageNum
|
|
216
216
|
? 'bg-[rgb(var(--color-primary))] text-white'
|
|
217
|
-
: 'text-[rgb(var(--fg-muted))] hover:bg-[rgb(var(--bg-default))]'}
|
|
217
|
+
: 'text-[rgb(var(--fg-muted))] hover:bg-[rgb(var(--bg-default))]'}
|
|
218
218
|
`, children: pageNum }, pageNum));
|
|
219
|
-
}) }), (0, jsx_runtime_1.jsx)("button", { onClick: () => setCurrentPage(p => Math.min(totalPages, p + 1)), disabled: currentPage === totalPages, className: "p-1.5 rounded text-[rgb(var(--fg-muted))] hover:bg-[rgb(var(--bg-default))] disabled:opacity-30 disabled:cursor-not-allowed transition-colors", children: (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronRight, { className: "w-4 h-4" }) })] })), (0, jsx_runtime_1.jsx)("button", { onClick: onClose, className: "\
|
|
219
|
+
}) }), (0, jsx_runtime_1.jsx)("button", { onClick: () => setCurrentPage(p => Math.min(totalPages, p + 1)), disabled: currentPage === totalPages, className: "p-1.5 rounded text-[rgb(var(--fg-muted))] hover:bg-[rgb(var(--bg-default))] disabled:opacity-30 disabled:cursor-not-allowed transition-colors", children: (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronRight, { className: "w-4 h-4" }) })] })), (0, jsx_runtime_1.jsx)("button", { onClick: onClose, className: "\n px-5 py-2 rounded-lg text-sm font-medium\n bg-[rgb(var(--bg-default))]\n text-[rgb(var(--fg-default))]\n border border-[rgb(var(--bd-default))]\n hover:bg-[rgb(var(--bg-muted))]\n transition-colors\n ", children: "Close" })] })] }) }));
|
|
220
220
|
}
|
|
@@ -64,7 +64,11 @@ const modalSizes = {
|
|
|
64
64
|
* @param breakpoint - Pixel width threshold (default 768)
|
|
65
65
|
*/
|
|
66
66
|
function useIsMobile(breakpoint = 768) {
|
|
67
|
-
|
|
67
|
+
return useMobileQuery(breakpoint) ?? false;
|
|
68
|
+
}
|
|
69
|
+
/** As useIsMobile, but null until the width has been read (the first render, and on the server). */
|
|
70
|
+
function useMobileQuery(breakpoint) {
|
|
71
|
+
const [isMobile, setIsMobile] = React.useState(null);
|
|
68
72
|
React.useEffect(() => {
|
|
69
73
|
const mq = window.matchMedia(`(max-width: ${breakpoint}px)`);
|
|
70
74
|
setIsMobile(mq.matches);
|
|
@@ -241,7 +245,22 @@ ModalOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
|
|
241
245
|
*/
|
|
242
246
|
const ModalContent = React.forwardRef(({ className, children, hideCloseButton, disableOutsideClick, size, style, 'aria-describedby': ariaDescribedBy, ...props }, ref) => {
|
|
243
247
|
const stableRef = useStableRef(ref);
|
|
244
|
-
|
|
248
|
+
// The page and the dialog are different trees, so switching between them remounts everything
|
|
249
|
+
// inside: a form half filled in was wiped when a tablet turned, or a window was dragged, across
|
|
250
|
+
// the breakpoint. So the layout follows the screen only while closed; open, it keeps the one it
|
|
251
|
+
// opened with, and catches up once closed. The content exists only while open, so its ref says.
|
|
252
|
+
const live = useMobileQuery(768);
|
|
253
|
+
const [open, setOpen] = React.useState(false);
|
|
254
|
+
const [held, setHeld] = React.useState(null);
|
|
255
|
+
// The first reading always counts: before it the width is unknown, and a modal open at page load
|
|
256
|
+
// on a phone must still become the page.
|
|
257
|
+
if (live !== null && held !== live && (held === null || !open))
|
|
258
|
+
setHeld(live);
|
|
259
|
+
const isMobile = held ?? false;
|
|
260
|
+
const contentRef = React.useCallback((node) => {
|
|
261
|
+
stableRef(node);
|
|
262
|
+
setOpen(node !== null);
|
|
263
|
+
}, [stableRef]);
|
|
245
264
|
// Nested modals must paint above their parent. Radix portals every modal to
|
|
246
265
|
// <body>, so equal z-index makes stacking fall back to DOM order and the
|
|
247
266
|
// child renders behind / overlapping the parent.
|
|
@@ -256,12 +275,12 @@ const ModalContent = React.forwardRef(({ className, children, hideCloseButton, d
|
|
|
256
275
|
}, [hasOpenChild]);
|
|
257
276
|
// On mobile: render as a full-screen page
|
|
258
277
|
if (isMobile) {
|
|
259
|
-
return ((0, jsx_runtime_1.jsx)(DialogPrimitive.Portal, { children: (0, jsx_runtime_1.jsx)(DialogPrimitive.Content, { ref:
|
|
278
|
+
return ((0, jsx_runtime_1.jsx)(DialogPrimitive.Portal, { children: (0, jsx_runtime_1.jsx)(DialogPrimitive.Content, { ref: contentRef, "aria-describedby": ariaDescribedBy, style: { zIndex, ...style }, className: (0, utils_1.cn)("fixed inset-0 flex flex-col", "bg-[rgb(var(--bg-surface))]", className),
|
|
260
279
|
// Always block outside click on mobile — there's nothing "outside"
|
|
261
280
|
onInteractOutside: (e) => e.preventDefault(), onEscapeKeyDown: handleEscapeKeyDown, ...props, children: (0, jsx_runtime_1.jsx)(ModalMobileContext.Provider, { value: { isMobilePage: true, onClose: undefined }, children: children }) }) }));
|
|
262
281
|
}
|
|
263
282
|
// Desktop: unchanged Radix dialog
|
|
264
|
-
return ((0, jsx_runtime_1.jsxs)(ModalPortal, { children: [(0, jsx_runtime_1.jsx)(ModalOverlay, { style: { zIndex: zIndex - 1 } }), (0, jsx_runtime_1.jsxs)(DialogPrimitive.Content, { ref:
|
|
283
|
+
return ((0, jsx_runtime_1.jsxs)(ModalPortal, { children: [(0, jsx_runtime_1.jsx)(ModalOverlay, { style: { zIndex: zIndex - 1 } }), (0, jsx_runtime_1.jsxs)(DialogPrimitive.Content, { ref: contentRef, "aria-describedby": ariaDescribedBy, style: { zIndex, ...style }, className: (0, utils_1.cn)("fixed left-[50%] top-[50%] grid translate-x-[-50%] translate-y-[-50%]", "border border-[rgb(var(--bd-default))] bg-[rgb(var(--bg-surface))] shadow-lg", "rounded-lg sm:rounded-lg", size ? modalSizes[size] : "max-w-lg w-full mx-4 h-auto max-h-[85vh]",
|
|
265
284
|
// Gap + padding only for standard modals — fullscreen/master/p-0 modals
|
|
266
285
|
// run their own flush header/body/footer layout, so the gap shows as bands.
|
|
267
286
|
size !== 'master' && size !== 'fullscreen' && !className?.includes('p-0') && "gap-3 sm:gap-4 p-4 sm:p-6", className), onInteractOutside: (e) => {
|
|
@@ -23,11 +23,17 @@ const CALCULATION_DEFAULTS = {
|
|
|
23
23
|
* Automatically calculates optimal column widths based on content
|
|
24
24
|
* MERGED: Best features from useAutoIntelligentSizing + useIntelligentColumnSizing
|
|
25
25
|
*/
|
|
26
|
+
/** What the cell renderer shows for an empty cell; not content to size a column by. */
|
|
27
|
+
const PLACEHOLDERS = new Set(['', '-', '–', '—', 'N/A', 'n/a']);
|
|
26
28
|
function useIntelligentColumnSizing(data, columns, config = {}) {
|
|
27
29
|
const finalConfig = { ...DEFAULT_CONFIG, ...config };
|
|
28
30
|
// Smart content analyzer - detects data type and calculates optimal width
|
|
29
31
|
const analyzeContent = (0, react_1.useCallback)((columnId, sampleData) => {
|
|
30
|
-
|
|
32
|
+
// Blanks are not entries: the cell renderer centres a placeholder, and counted as zero-width
|
|
33
|
+
// text they dragged a mostly-empty column (a purpose, a payment mode) down to the average.
|
|
34
|
+
const values = sampleData
|
|
35
|
+
.map(row => row[columnId])
|
|
36
|
+
.filter(v => v !== null && v !== undefined && !(typeof v === 'string' && PLACEHOLDERS.has(v.trim())));
|
|
31
37
|
if (values.length === 0) {
|
|
32
38
|
return {
|
|
33
39
|
dataType: 'text',
|
|
@@ -149,10 +155,9 @@ function useIntelligentColumnSizing(data, columns, config = {}) {
|
|
|
149
155
|
}
|
|
150
156
|
// Optimal width calculation with intelligent rules
|
|
151
157
|
let optimalWidth;
|
|
152
|
-
//
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
: maxContentWidth + contentBuffer;
|
|
158
|
+
// Size to the longest entry, not the average: a column mixing "Cash" with "Bank / RTGS / NEFT"
|
|
159
|
+
// was sized to the middle and cut the long ones short. finalMaxWidth still caps outliers.
|
|
160
|
+
const baseContentWidth = maxContentWidth + contentBuffer;
|
|
156
161
|
// Rule 1: If header is much wider than content (ratio > 1.8), use compromise
|
|
157
162
|
if (headerToContentRatio > 1.8) {
|
|
158
163
|
// Use 60% content + 40% header (let header wrap significantly)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
@tailwind base;
|
|
2
|
-
@tailwind components;
|
|
3
|
-
@tailwind utilities;
|
|
4
|
-
|
|
5
|
-
@import './tokens.css';
|
|
1
|
+
@tailwind base;
|
|
2
|
+
@tailwind components;
|
|
3
|
+
@tailwind utilities;
|
|
4
|
+
|
|
5
|
+
@import './tokens.css';
|
|
@@ -91,10 +91,10 @@ export function CellRenderer({ cell, cellIndex, row, enableBacchaSearch = false,
|
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
93
|
const rowId = row.original.id || row.id;
|
|
94
|
-
return (_jsx("td", { className: `
|
|
95
|
-
px-1 py-1 text-xs text-fg-default align-middle
|
|
96
|
-
${isBadgeColumn || isPlaceholderValue ? 'text-center' : isNumericContent ? 'text-right' : 'text-left'}
|
|
97
|
-
${isCellFrozen || isPinnedRight ? 'sticky z-[5]' : ''}
|
|
94
|
+
return (_jsx("td", { className: `
|
|
95
|
+
px-1 py-1 text-xs text-fg-default align-middle
|
|
96
|
+
${isBadgeColumn || isPlaceholderValue ? 'text-center' : isNumericContent ? 'text-right' : 'text-left'}
|
|
97
|
+
${isCellFrozen || isPinnedRight ? 'sticky z-[5]' : ''}
|
|
98
98
|
`, style: {
|
|
99
99
|
width: `${cell.column.getSize()}px`,
|
|
100
100
|
minWidth: `${cell.column.getSize()}px`,
|
|
@@ -11,13 +11,13 @@ export function SelectionCell({ checked, indeterminate = false, onChange, disabl
|
|
|
11
11
|
};
|
|
12
12
|
// Radio button mode (single selection) - always circular regardless of circularCheckboxes prop
|
|
13
13
|
if (mode === 'radio') {
|
|
14
|
-
return (_jsx("div", { onClick: handleClick, className: `
|
|
15
|
-
relative rounded-full border-2 cursor-pointer transition-all duration-150
|
|
16
|
-
flex items-center justify-center flex-shrink-0
|
|
17
|
-
${disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}
|
|
14
|
+
return (_jsx("div", { onClick: handleClick, className: `
|
|
15
|
+
relative rounded-full border-2 cursor-pointer transition-all duration-150
|
|
16
|
+
flex items-center justify-center flex-shrink-0
|
|
17
|
+
${disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}
|
|
18
18
|
${checked
|
|
19
19
|
? 'border-primary bg-white'
|
|
20
|
-
: 'border-gray-300 bg-white hover:border-gray-400'}
|
|
20
|
+
: 'border-gray-300 bg-white hover:border-gray-400'}
|
|
21
21
|
`, style: {
|
|
22
22
|
boxShadow: checked ? '0 0 0 2px rgba(59, 130, 246, 0.1)' : 'none',
|
|
23
23
|
width: '14px',
|
|
@@ -39,13 +39,13 @@ export function SelectionCell({ checked, indeterminate = false, onChange, disabl
|
|
|
39
39
|
: "border-[rgb(var(--bd-default))] bg-[rgb(var(--bg-surface))] hover:border-[rgb(var(--color-primary))]", disabled && "opacity-50 cursor-not-allowed"), children: [checked && !indeterminate && (_jsx(Check, { className: "w-3 h-3 text-white", strokeWidth: 3 })), indeterminate && (_jsx("div", { className: "w-2 h-0.5 bg-white rounded" }))] })] }));
|
|
40
40
|
}
|
|
41
41
|
// Circular checkbox (AG Grid style, multi-select with circular prop)
|
|
42
|
-
return (_jsxs("div", { onClick: handleClick, className: `
|
|
43
|
-
relative rounded-full border-2 cursor-pointer transition-all duration-150
|
|
44
|
-
flex items-center justify-center flex-shrink-0
|
|
45
|
-
${disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}
|
|
42
|
+
return (_jsxs("div", { onClick: handleClick, className: `
|
|
43
|
+
relative rounded-full border-2 cursor-pointer transition-all duration-150
|
|
44
|
+
flex items-center justify-center flex-shrink-0
|
|
45
|
+
${disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}
|
|
46
46
|
${checked || indeterminate
|
|
47
47
|
? 'border-primary bg-primary'
|
|
48
|
-
: 'border-gray-300 bg-white hover:border-gray-400'}
|
|
48
|
+
: 'border-gray-300 bg-white hover:border-gray-400'}
|
|
49
49
|
`, style: {
|
|
50
50
|
boxShadow: checked || indeterminate ? '0 0 0 2px rgba(59, 130, 246, 0.1)' : 'none',
|
|
51
51
|
width: '14px',
|
|
@@ -21,11 +21,11 @@ export function PaginationControls({ pageIndex, pageSize, totalRows, pageSizeOpt
|
|
|
21
21
|
return (_jsx("span", { className: "px-2 text-[rgb(var(--fg-muted))]", children: "..." }, `ellipsis-${index}`));
|
|
22
22
|
}
|
|
23
23
|
const isCurrentPage = page === pageIndex;
|
|
24
|
-
return (_jsx("button", { onClick: () => onPageChange(page), className: `
|
|
25
|
-
min-w-[32px] h-8 px-2 rounded text-sm font-medium transition-colors
|
|
24
|
+
return (_jsx("button", { onClick: () => onPageChange(page), className: `
|
|
25
|
+
min-w-[32px] h-8 px-2 rounded text-sm font-medium transition-colors
|
|
26
26
|
${isCurrentPage
|
|
27
27
|
? 'border border-[rgb(var(--color-primary))] text-[rgb(var(--color-primary))] bg-[rgb(var(--color-primary)/0.08)]'
|
|
28
|
-
: 'text-[rgb(var(--fg-default))] hover:bg-[rgb(var(--bd-default))]'}
|
|
28
|
+
: 'text-[rgb(var(--fg-default))] hover:bg-[rgb(var(--bd-default))]'}
|
|
29
29
|
`, children: page + 1 }, page));
|
|
30
30
|
}) }), _jsx("button", { onClick: () => onPageChange(pageIndex + 1), disabled: !hasNextPage, className: "p-1.5 rounded hover:bg-[rgb(var(--bd-default))] disabled:opacity-40 disabled:cursor-not-allowed transition-colors", "aria-label": "Next Page", children: _jsx(ChevronRight, { className: "h-4 w-4 text-[rgb(var(--fg-muted))]" }) }), _jsx("button", { onClick: () => onPageChange(totalPages - 1), disabled: !hasNextPage, className: "p-1.5 rounded hover:bg-[rgb(var(--bd-default))] disabled:opacity-40 disabled:cursor-not-allowed transition-colors", "aria-label": "Last Page", children: _jsx(ChevronsRight, { className: "h-4 w-4 text-[rgb(var(--fg-muted))]" }) })] }), !isMobile && (_jsxs("div", { className: "flex items-center gap-2 text-sm text-[rgb(var(--fg-default))] flex-shrink-0 order-2 sm:order-3", children: [_jsx("span", { className: "hidden sm:inline", children: "Show:" }), _jsx(Dropdown, { value: String(pageSize), onValueChange: (value) => onPageSizeChange(Number(value)), options: pageSizeOptions.map((size) => ({
|
|
31
31
|
value: String(size),
|
|
@@ -17,15 +17,15 @@ navigationState = {}, columnSearches = {}, isColumnSearchActive = {}, onColumnSe
|
|
|
17
17
|
transition,
|
|
18
18
|
opacity: isDragging ? 0.5 : 1,
|
|
19
19
|
};
|
|
20
|
-
return (_jsxs("tr", { ref: setNodeRef, style: style, className: `
|
|
21
|
-
cursor-pointer group
|
|
22
|
-
transition-colors duration-150 ease-out
|
|
23
|
-
${isDragging ? 'shadow-lg z-50' : ''}
|
|
20
|
+
return (_jsxs("tr", { ref: setNodeRef, style: style, className: `
|
|
21
|
+
cursor-pointer group
|
|
22
|
+
transition-colors duration-150 ease-out
|
|
23
|
+
${isDragging ? 'shadow-lg z-50' : ''}
|
|
24
24
|
${isHighlighted
|
|
25
25
|
? 'border-2 border-[rgb(var(--color-primary))] bg-gradient-to-r from-[rgb(var(--color-primary))]/10 to-[rgb(var(--color-primary))]/20 shadow-lg relative'
|
|
26
26
|
: isSelected
|
|
27
27
|
? 'bg-[color-mix(in_srgb,rgb(var(--color-primary))_8%,rgb(var(--bg-surface)))] shadow-sm hover:bg-[color-mix(in_srgb,rgb(var(--color-primary))_15%,rgb(var(--bg-surface)))]'
|
|
28
|
-
: 'hover:bg-[color-mix(in_srgb,rgb(var(--color-primary))_5%,rgb(var(--bg-surface)))]'}
|
|
29
|
-
${className ?? ''}
|
|
28
|
+
: 'hover:bg-[color-mix(in_srgb,rgb(var(--color-primary))_5%,rgb(var(--bg-surface)))]'}
|
|
29
|
+
${className ?? ''}
|
|
30
30
|
`, onClick: onRowClick, onDoubleClick: onRowDoubleClick, onContextMenu: onRowContextMenu, children: [showDragHandle && (_jsx("td", { className: "text-center align-middle cursor-grab active:cursor-grabbing", style: { width: '1.875rem', minWidth: '1.875rem', maxWidth: '1.875rem' }, ...attributes, ...listeners, children: _jsx("div", { className: "w-full h-full flex items-center justify-center", children: _jsx(GripVertical, { className: "h-4 w-4 text-gray-400" }) }) })), row.getVisibleCells().map((cell, cellIndex) => (_jsx(CellRenderer, { cell: cell, cellIndex: cellIndex, row: row, enableBacchaSearch: enableBacchaSearch, mainColumnsArray: mainColumnsArray, frozenColumnsState: frozenColumnsState, navigationState: navigationState, columnSearches: columnSearches, isColumnSearchActive: isColumnSearchActive, onColumnSearch: onColumnSearch, onClearColumnSearch: onClearColumnSearch, SearchHighlighter: SearchHighlighter, InlineSearchCell: InlineSearchCell, isSelected: isSelected }, cell.id)))] }));
|
|
31
31
|
}
|
|
@@ -86,10 +86,10 @@ export function InlineSearchCell({ value, columnId, rowId, onSearch, onClearSear
|
|
|
86
86
|
return (_jsx(_Fragment, { children: parts.map((part, index) => part.toLowerCase() === highlight.toLowerCase() ? (_jsx("mark", { className: "bg-yellow-200 text-yellow-900 px-0.5 rounded", children: part }, index)) : (_jsx("span", { children: part }, index))) }));
|
|
87
87
|
};
|
|
88
88
|
const displayValue = value?.toString() || '';
|
|
89
|
-
return (_jsxs("div", { ref: cellRef, tabIndex: 0, className: `bacchasearch relative group cursor-pointer outline-none inline-flex items-center w-full ${className}`, onClick: handleCellClick, children: [_jsx("span", { className: `
|
|
90
|
-
text-xs flex-1 rounded transition-colors
|
|
91
|
-
${isSearchActive ? 'bg-[rgb(var(--color-primary)/0.1)]' : 'hover:bg-[rgb(var(--color-primary)/0.05)]'}
|
|
92
|
-
${isTyping ? 'ring-1 ring-[rgb(var(--color-primary)/0.3)] bg-[rgb(var(--color-primary)/0.15)]' : ''}
|
|
89
|
+
return (_jsxs("div", { ref: cellRef, tabIndex: 0, className: `bacchasearch relative group cursor-pointer outline-none inline-flex items-center w-full ${className}`, onClick: handleCellClick, children: [_jsx("span", { className: `
|
|
90
|
+
text-xs flex-1 rounded transition-colors
|
|
91
|
+
${isSearchActive ? 'bg-[rgb(var(--color-primary)/0.1)]' : 'hover:bg-[rgb(var(--color-primary)/0.05)]'}
|
|
92
|
+
${isTyping ? 'ring-1 ring-[rgb(var(--color-primary)/0.3)] bg-[rgb(var(--color-primary)/0.15)]' : ''}
|
|
93
93
|
`, children: isSearchActive && searchTerm ?
|
|
94
94
|
renderHighlightedText(displayValue, searchTerm) :
|
|
95
95
|
displayValue }), _jsx(Search, { className: `h-3 w-3 text-[rgb(var(--fg-muted))] ml-0.5 flex-shrink-0 transition-opacity ${isTyping ? 'opacity-100' : 'opacity-0 group-hover:opacity-100'}` }), (isTyping || isSearchActive) && (_jsx("div", { className: "absolute -top-0.5 -right-0.5", children: _jsx("div", { className: `h-1.5 w-1.5 rounded-full ${isTyping ? 'bg-[rgb(var(--color-success))]' : 'bg-[rgb(var(--color-primary))]'}` }) })), isTyping && localSearchTerm && (_jsxs("div", { className: "absolute -bottom-5 left-0 bg-[rgb(var(--bg-surface))] text-[rgb(var(--fg-default))] text-xs px-1.5 py-0.5 rounded shadow-lg border border-[rgb(var(--bd-default))] z-10 whitespace-nowrap", children: ["\"", localSearchTerm, "\""] }))] }));
|
|
@@ -54,14 +54,14 @@ export function AutoSaveIndicator({ enabled, lastSaved, isDirty, isSaving, onOpe
|
|
|
54
54
|
};
|
|
55
55
|
};
|
|
56
56
|
const status = getStatus();
|
|
57
|
-
return (_jsxs("div", { className: "flex items-center gap-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "text-xs text-[rgb(var(--fg-muted))]", children: "Auto-save:" }), _jsx("button", { onClick: () => onToggleAutoSave?.(!enabled), className: `
|
|
58
|
-
relative inline-flex h-5 w-9 items-center rounded-full transition-colors
|
|
59
|
-
${enabled ? 'bg-[rgb(var(--color-primary))]' : 'bg-[rgb(var(--bg-muted))]'}
|
|
60
|
-
`, title: enabled ? 'Disable auto-save' : 'Enable auto-save', children: _jsx("span", { className: `
|
|
61
|
-
inline-block h-3.5 w-3.5 transform rounded-full bg-white transition-transform
|
|
62
|
-
${enabled ? 'translate-x-5' : 'translate-x-1'}
|
|
63
|
-
` }) }), _jsx("span", { className: "text-xs font-medium text-[rgb(var(--fg-default))]", children: enabled ? 'ON' : 'OFF' })] }), _jsx("div", { className: "h-4 w-px bg-[rgb(var(--bd-default))]" }), _jsxs("button", { onClick: onOpenDraftManager, className: `
|
|
64
|
-
flex items-center gap-2 px-3 py-1.5 rounded-md transition-colors
|
|
65
|
-
${status.bg} ${status.color} hover:opacity-80
|
|
57
|
+
return (_jsxs("div", { className: "flex items-center gap-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "text-xs text-[rgb(var(--fg-muted))]", children: "Auto-save:" }), _jsx("button", { onClick: () => onToggleAutoSave?.(!enabled), className: `
|
|
58
|
+
relative inline-flex h-5 w-9 items-center rounded-full transition-colors
|
|
59
|
+
${enabled ? 'bg-[rgb(var(--color-primary))]' : 'bg-[rgb(var(--bg-muted))]'}
|
|
60
|
+
`, title: enabled ? 'Disable auto-save' : 'Enable auto-save', children: _jsx("span", { className: `
|
|
61
|
+
inline-block h-3.5 w-3.5 transform rounded-full bg-white transition-transform
|
|
62
|
+
${enabled ? 'translate-x-5' : 'translate-x-1'}
|
|
63
|
+
` }) }), _jsx("span", { className: "text-xs font-medium text-[rgb(var(--fg-default))]", children: enabled ? 'ON' : 'OFF' })] }), _jsx("div", { className: "h-4 w-px bg-[rgb(var(--bd-default))]" }), _jsxs("button", { onClick: onOpenDraftManager, className: `
|
|
64
|
+
flex items-center gap-2 px-3 py-1.5 rounded-md transition-colors
|
|
65
|
+
${status.bg} ${status.color} hover:opacity-80
|
|
66
66
|
`, title: "Click to manage drafts", children: [status.icon, _jsx("span", { className: "text-xs font-medium", children: status.text })] })] }));
|
|
67
67
|
}
|
|
@@ -156,10 +156,10 @@ export function DraftModal({ open, onClose, drafts, onLoad, onDelete, isLoading
|
|
|
156
156
|
// Early return after all hooks to comply with Rules of Hooks
|
|
157
157
|
if (!open)
|
|
158
158
|
return null;
|
|
159
|
-
return (_jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm", children: _jsxs("div", { className: "bg-[rgb(var(--bg-surface))] rounded-lg shadow-2xl w-full max-w-4xl max-h-[85vh] flex flex-col", children: [_jsxs("div", { className: "px-6 py-3 border-b border-[rgb(var(--bd-default))] flex items-center gap-4", children: [_jsxs("div", { className: "flex items-center gap-2 flex-shrink-0", children: [_jsx(FileText, { className: "w-5 h-5 text-[rgb(var(--color-primary))]" }), _jsx("h2", { className: "text-base font-semibold text-[rgb(var(--fg-default))]", children: "Saved Drafts" }), _jsxs("span", { className: "text-xs text-[rgb(var(--fg-muted))]", children: ["(", drafts.length, ")"] })] }), _jsxs("div", { className: "relative flex-1", children: [_jsx(Search, { className: "absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 text-[rgb(var(--fg-muted))]" }), _jsx("input", { type: "text", placeholder: "Search...", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), className: "\
|
|
159
|
+
return (_jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm", children: _jsxs("div", { className: "bg-[rgb(var(--bg-surface))] rounded-lg shadow-2xl w-full max-w-4xl max-h-[85vh] flex flex-col", children: [_jsxs("div", { className: "px-6 py-3 border-b border-[rgb(var(--bd-default))] flex items-center gap-4", children: [_jsxs("div", { className: "flex items-center gap-2 flex-shrink-0", children: [_jsx(FileText, { className: "w-5 h-5 text-[rgb(var(--color-primary))]" }), _jsx("h2", { className: "text-base font-semibold text-[rgb(var(--fg-default))]", children: "Saved Drafts" }), _jsxs("span", { className: "text-xs text-[rgb(var(--fg-muted))]", children: ["(", drafts.length, ")"] })] }), _jsxs("div", { className: "relative flex-1", children: [_jsx(Search, { className: "absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 text-[rgb(var(--fg-muted))]" }), _jsx("input", { type: "text", placeholder: "Search...", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), className: "\n w-full pl-9 pr-3 py-1.5 rounded-lg text-sm\n bg-[rgb(var(--bg-default))]\n border border-[rgb(var(--bd-default))]\n text-[rgb(var(--fg-default))]\n placeholder:text-[rgb(var(--fg-muted))]\n focus:outline-none focus:ring-2 focus:ring-[rgb(var(--color-primary))]\n " })] }), _jsx("div", { className: "flex-shrink-0 w-36", children: _jsx(Dropdown, { options: SORT_OPTIONS, value: sortBy, onValueChange: (val) => setSortBy(val), size: "sm", autoWidth: true }) }), _jsx("button", { onClick: onClose, className: "p-1.5 rounded-lg hover:bg-[rgb(var(--bg-muted))] text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))] transition-colors flex-shrink-0", children: _jsx(X, { className: "w-5 h-5" }) })] }), _jsx("div", { className: "flex-1 overflow-y-auto px-6 py-4", children: isLoading ? (_jsx("div", { className: "flex items-center justify-center py-16", children: _jsxs("div", { className: "text-center", children: [_jsx("div", { className: "w-12 h-12 rounded-full border-4 border-[rgb(var(--color-primary)_/_0.2)] border-t-[rgb(var(--color-primary))] animate-spin mx-auto mb-3" }), _jsx("p", { className: "text-[rgb(var(--fg-muted))]", children: "Loading drafts..." })] }) })) : filteredAndSortedDrafts.length === 0 ? (_jsxs("div", { className: "flex flex-col items-center justify-center py-16 text-center", children: [_jsx(FileText, { className: "w-16 h-16 text-[rgb(var(--fg-muted))] mb-4 opacity-50" }), _jsx("p", { className: "text-lg font-medium text-[rgb(var(--fg-default))] mb-1", children: searchQuery ? 'No matching drafts' : 'No drafts saved yet' }), _jsx("p", { className: "text-sm text-[rgb(var(--fg-muted))]", children: searchQuery ? 'Try a different search term' : 'Start by clicking "Save Draft" button' })] })) : (_jsx("div", { className: "space-y-3", children: paginatedDrafts.map((draft) => {
|
|
160
160
|
const progress = calculateProgress(draft);
|
|
161
161
|
const preview = draft.previewData || {};
|
|
162
|
-
return (_jsx("div", { className: "\
|
|
162
|
+
return (_jsx("div", { className: "\n group relative p-3 rounded-lg\n bg-[rgb(var(--bg-default))]\n border border-[rgb(var(--bd-default))]\n hover:border-[rgb(var(--color-primary))]\n hover:shadow-lg\n transition-all duration-200\n ", children: _jsx("div", { className: "flex items-start gap-4", children: _jsxs("div", { className: "flex-1 min-w-0", children: [_jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("h3", { className: "font-semibold text-[rgb(var(--fg-default))] truncate text-base", children: draft.draftName || 'Untitled Draft' }), _jsxs("div", { className: "flex items-center gap-2 mt-1 text-xs text-[rgb(var(--fg-muted))]", children: [_jsx("span", { children: formatRelativeTime(draft.lastSaved) }), _jsxs("span", { className: "hidden group-hover:inline", children: ["\u2022 ", formatFullDate(draft.lastSaved)] }), draft.isAutoSave && (_jsx("span", { className: "text-[10px] px-2 py-0.5 rounded-full bg-[rgb(var(--color-primary)_/_0.1)] text-[rgb(var(--color-primary))] font-medium", children: "AUTO-SAVE" }))] })] }), _jsxs("div", { className: "flex items-center gap-2 opacity-0 group-hover:opacity-100 transition-opacity", children: [_jsxs("button", { onClick: () => handleLoad(draft.draftId), className: "\n px-4 py-2 rounded-lg text-sm font-medium\n bg-[rgb(var(--color-primary))]\n text-white\n hover:opacity-90\n transition-opacity\n flex items-center gap-2\n ", children: [_jsx(Download, { className: "w-4 h-4" }), "Load"] }), _jsx("button", { onClick: () => handleDelete(draft.draftId), disabled: deletingId === draft.draftId, className: "\n p-2 rounded-lg\n text-[rgb(var(--fg-muted))]\n hover:text-red-600\n hover:bg-red-50\n transition-colors\n disabled:opacity-50\n ", title: "Delete draft", children: deletingId === draft.draftId ? (_jsx("div", { className: "w-4 h-4 rounded-full border-2 border-red-200 border-t-red-600 animate-spin" })) : (_jsx(Trash2, { className: "w-4 h-4" })) })] })] }), _jsxs("div", { className: "grid grid-cols-2 gap-x-6 gap-y-1 mt-2 text-sm", children: [preview.jobName && (_jsx("div", { className: "text-[rgb(var(--fg-muted))] truncate", children: preview.jobName }, "job")), preview.clientName && (_jsx("div", { className: "text-[rgb(var(--fg-muted))] truncate", children: preview.clientName }, "client")), preview.category && (_jsx("div", { className: "text-[rgb(var(--fg-muted))] truncate", children: preview.category }, "category")), preview.totalCost !== undefined && preview.totalCost > 0 && (_jsxs("div", { className: "font-medium text-[rgb(var(--color-primary))]", children: [currencySymbol, preview.totalCost.toLocaleString('en-IN')] }, "cost"))] }), progress > 0 && (_jsxs("div", { className: "mt-2", children: [_jsxs("div", { className: "flex items-center justify-between text-xs text-[rgb(var(--fg-muted))] mb-1", children: [_jsx("span", { children: "Progress" }), _jsxs("span", { className: "font-medium", children: [progress, "%"] })] }), _jsx("div", { className: "h-1.5 bg-[rgb(var(--bg-muted))] rounded-full overflow-hidden", children: _jsx("div", { className: "h-full bg-[rgb(var(--color-primary))] transition-all duration-500 rounded-full", style: { width: `${progress}%` } }) })] }))] }) }) }, draft.draftId));
|
|
163
163
|
}) })) }), _jsxs("div", { className: "px-6 py-4 border-t border-[rgb(var(--bd-default))] flex justify-between items-center bg-[rgb(var(--bg-muted)_/_0.3)]", children: [_jsx("div", { className: "text-sm text-[rgb(var(--fg-muted))]", children: filteredAndSortedDrafts.length > 0 ? (_jsxs(_Fragment, { children: ["Showing ", ((currentPage - 1) * PAGE_SIZE) + 1, "-", Math.min(currentPage * PAGE_SIZE, filteredAndSortedDrafts.length), " of ", filteredAndSortedDrafts.length, filteredAndSortedDrafts.length !== drafts.length && ` (filtered from ${drafts.length})`] })) : (`0 of ${drafts.length} drafts`) }), totalPages > 1 && (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("button", { onClick: () => setCurrentPage(p => Math.max(1, p - 1)), disabled: currentPage === 1, className: "p-1.5 rounded text-[rgb(var(--fg-muted))] hover:bg-[rgb(var(--bg-default))] disabled:opacity-30 disabled:cursor-not-allowed transition-colors", children: _jsx(ChevronLeft, { className: "w-4 h-4" }) }), _jsx("div", { className: "flex items-center gap-1", children: Array.from({ length: Math.min(5, totalPages) }, (_, i) => {
|
|
164
164
|
let pageNum;
|
|
165
165
|
if (totalPages <= 5) {
|
|
@@ -174,11 +174,11 @@ export function DraftModal({ open, onClose, drafts, onLoad, onDelete, isLoading
|
|
|
174
174
|
else {
|
|
175
175
|
pageNum = currentPage - 2 + i;
|
|
176
176
|
}
|
|
177
|
-
return (_jsx("button", { onClick: () => setCurrentPage(pageNum), className: `
|
|
178
|
-
w-8 h-8 rounded text-sm font-medium transition-colors
|
|
177
|
+
return (_jsx("button", { onClick: () => setCurrentPage(pageNum), className: `
|
|
178
|
+
w-8 h-8 rounded text-sm font-medium transition-colors
|
|
179
179
|
${currentPage === pageNum
|
|
180
180
|
? 'bg-[rgb(var(--color-primary))] text-white'
|
|
181
|
-
: 'text-[rgb(var(--fg-muted))] hover:bg-[rgb(var(--bg-default))]'}
|
|
181
|
+
: 'text-[rgb(var(--fg-muted))] hover:bg-[rgb(var(--bg-default))]'}
|
|
182
182
|
`, children: pageNum }, pageNum));
|
|
183
|
-
}) }), _jsx("button", { onClick: () => setCurrentPage(p => Math.min(totalPages, p + 1)), disabled: currentPage === totalPages, className: "p-1.5 rounded text-[rgb(var(--fg-muted))] hover:bg-[rgb(var(--bg-default))] disabled:opacity-30 disabled:cursor-not-allowed transition-colors", children: _jsx(ChevronRight, { className: "w-4 h-4" }) })] })), _jsx("button", { onClick: onClose, className: "\
|
|
183
|
+
}) }), _jsx("button", { onClick: () => setCurrentPage(p => Math.min(totalPages, p + 1)), disabled: currentPage === totalPages, className: "p-1.5 rounded text-[rgb(var(--fg-muted))] hover:bg-[rgb(var(--bg-default))] disabled:opacity-30 disabled:cursor-not-allowed transition-colors", children: _jsx(ChevronRight, { className: "w-4 h-4" }) })] })), _jsx("button", { onClick: onClose, className: "\n px-5 py-2 rounded-lg text-sm font-medium\n bg-[rgb(var(--bg-default))]\n text-[rgb(var(--fg-default))]\n border border-[rgb(var(--bd-default))]\n hover:bg-[rgb(var(--bg-muted))]\n transition-colors\n ", children: "Close" })] })] }) }));
|
|
184
184
|
}
|
|
@@ -25,7 +25,11 @@ const modalSizes = {
|
|
|
25
25
|
* @param breakpoint - Pixel width threshold (default 768)
|
|
26
26
|
*/
|
|
27
27
|
export function useIsMobile(breakpoint = 768) {
|
|
28
|
-
|
|
28
|
+
return useMobileQuery(breakpoint) ?? false;
|
|
29
|
+
}
|
|
30
|
+
/** As useIsMobile, but null until the width has been read (the first render, and on the server). */
|
|
31
|
+
function useMobileQuery(breakpoint) {
|
|
32
|
+
const [isMobile, setIsMobile] = React.useState(null);
|
|
29
33
|
React.useEffect(() => {
|
|
30
34
|
const mq = window.matchMedia(`(max-width: ${breakpoint}px)`);
|
|
31
35
|
setIsMobile(mq.matches);
|
|
@@ -198,7 +202,22 @@ ModalOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
|
|
198
202
|
*/
|
|
199
203
|
const ModalContent = React.forwardRef(({ className, children, hideCloseButton, disableOutsideClick, size, style, 'aria-describedby': ariaDescribedBy, ...props }, ref) => {
|
|
200
204
|
const stableRef = useStableRef(ref);
|
|
201
|
-
|
|
205
|
+
// The page and the dialog are different trees, so switching between them remounts everything
|
|
206
|
+
// inside: a form half filled in was wiped when a tablet turned, or a window was dragged, across
|
|
207
|
+
// the breakpoint. So the layout follows the screen only while closed; open, it keeps the one it
|
|
208
|
+
// opened with, and catches up once closed. The content exists only while open, so its ref says.
|
|
209
|
+
const live = useMobileQuery(768);
|
|
210
|
+
const [open, setOpen] = React.useState(false);
|
|
211
|
+
const [held, setHeld] = React.useState(null);
|
|
212
|
+
// The first reading always counts: before it the width is unknown, and a modal open at page load
|
|
213
|
+
// on a phone must still become the page.
|
|
214
|
+
if (live !== null && held !== live && (held === null || !open))
|
|
215
|
+
setHeld(live);
|
|
216
|
+
const isMobile = held ?? false;
|
|
217
|
+
const contentRef = React.useCallback((node) => {
|
|
218
|
+
stableRef(node);
|
|
219
|
+
setOpen(node !== null);
|
|
220
|
+
}, [stableRef]);
|
|
202
221
|
// Nested modals must paint above their parent. Radix portals every modal to
|
|
203
222
|
// <body>, so equal z-index makes stacking fall back to DOM order and the
|
|
204
223
|
// child renders behind / overlapping the parent.
|
|
@@ -213,12 +232,12 @@ const ModalContent = React.forwardRef(({ className, children, hideCloseButton, d
|
|
|
213
232
|
}, [hasOpenChild]);
|
|
214
233
|
// On mobile: render as a full-screen page
|
|
215
234
|
if (isMobile) {
|
|
216
|
-
return (_jsx(DialogPrimitive.Portal, { children: _jsx(DialogPrimitive.Content, { ref:
|
|
235
|
+
return (_jsx(DialogPrimitive.Portal, { children: _jsx(DialogPrimitive.Content, { ref: contentRef, "aria-describedby": ariaDescribedBy, style: { zIndex, ...style }, className: cn("fixed inset-0 flex flex-col", "bg-[rgb(var(--bg-surface))]", className),
|
|
217
236
|
// Always block outside click on mobile — there's nothing "outside"
|
|
218
237
|
onInteractOutside: (e) => e.preventDefault(), onEscapeKeyDown: handleEscapeKeyDown, ...props, children: _jsx(ModalMobileContext.Provider, { value: { isMobilePage: true, onClose: undefined }, children: children }) }) }));
|
|
219
238
|
}
|
|
220
239
|
// Desktop: unchanged Radix dialog
|
|
221
|
-
return (_jsxs(ModalPortal, { children: [_jsx(ModalOverlay, { style: { zIndex: zIndex - 1 } }), _jsxs(DialogPrimitive.Content, { ref:
|
|
240
|
+
return (_jsxs(ModalPortal, { children: [_jsx(ModalOverlay, { style: { zIndex: zIndex - 1 } }), _jsxs(DialogPrimitive.Content, { ref: contentRef, "aria-describedby": ariaDescribedBy, style: { zIndex, ...style }, className: cn("fixed left-[50%] top-[50%] grid translate-x-[-50%] translate-y-[-50%]", "border border-[rgb(var(--bd-default))] bg-[rgb(var(--bg-surface))] shadow-lg", "rounded-lg sm:rounded-lg", size ? modalSizes[size] : "max-w-lg w-full mx-4 h-auto max-h-[85vh]",
|
|
222
241
|
// Gap + padding only for standard modals — fullscreen/master/p-0 modals
|
|
223
242
|
// run their own flush header/body/footer layout, so the gap shows as bands.
|
|
224
243
|
size !== 'master' && size !== 'fullscreen' && !className?.includes('p-0') && "gap-3 sm:gap-4 p-4 sm:p-6", className), onInteractOutside: (e) => {
|
|
@@ -14,11 +14,6 @@ export interface ColumnSizeConstraints {
|
|
|
14
14
|
dataType?: 'text' | 'number' | 'date' | 'boolean' | 'array' | 'badge' | 'action';
|
|
15
15
|
variance?: number;
|
|
16
16
|
}
|
|
17
|
-
/**
|
|
18
|
-
* Hook for intelligent column sizing based on content analysis
|
|
19
|
-
* Automatically calculates optimal column widths based on content
|
|
20
|
-
* MERGED: Best features from useAutoIntelligentSizing + useIntelligentColumnSizing
|
|
21
|
-
*/
|
|
22
17
|
export declare function useIntelligentColumnSizing<TData>(data: TData[], columns: ColumnDef<TData>[], config?: ColumnSizingConfig): {
|
|
23
18
|
enhancedColumns: ColumnDef<TData>[];
|
|
24
19
|
getColumnWidth: (columnId: string) => number;
|
|
@@ -18,11 +18,17 @@ const CALCULATION_DEFAULTS = {
|
|
|
18
18
|
* Automatically calculates optimal column widths based on content
|
|
19
19
|
* MERGED: Best features from useAutoIntelligentSizing + useIntelligentColumnSizing
|
|
20
20
|
*/
|
|
21
|
+
/** What the cell renderer shows for an empty cell; not content to size a column by. */
|
|
22
|
+
const PLACEHOLDERS = new Set(['', '-', '–', '—', 'N/A', 'n/a']);
|
|
21
23
|
export function useIntelligentColumnSizing(data, columns, config = {}) {
|
|
22
24
|
const finalConfig = { ...DEFAULT_CONFIG, ...config };
|
|
23
25
|
// Smart content analyzer - detects data type and calculates optimal width
|
|
24
26
|
const analyzeContent = useCallback((columnId, sampleData) => {
|
|
25
|
-
|
|
27
|
+
// Blanks are not entries: the cell renderer centres a placeholder, and counted as zero-width
|
|
28
|
+
// text they dragged a mostly-empty column (a purpose, a payment mode) down to the average.
|
|
29
|
+
const values = sampleData
|
|
30
|
+
.map(row => row[columnId])
|
|
31
|
+
.filter(v => v !== null && v !== undefined && !(typeof v === 'string' && PLACEHOLDERS.has(v.trim())));
|
|
26
32
|
if (values.length === 0) {
|
|
27
33
|
return {
|
|
28
34
|
dataType: 'text',
|
|
@@ -144,10 +150,9 @@ export function useIntelligentColumnSizing(data, columns, config = {}) {
|
|
|
144
150
|
}
|
|
145
151
|
// Optimal width calculation with intelligent rules
|
|
146
152
|
let optimalWidth;
|
|
147
|
-
//
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
: maxContentWidth + contentBuffer;
|
|
153
|
+
// Size to the longest entry, not the average: a column mixing "Cash" with "Bank / RTGS / NEFT"
|
|
154
|
+
// was sized to the middle and cut the long ones short. finalMaxWidth still caps outliers.
|
|
155
|
+
const baseContentWidth = maxContentWidth + contentBuffer;
|
|
151
156
|
// Rule 1: If header is much wider than content (ratio > 1.8), use compromise
|
|
152
157
|
if (headerToContentRatio > 1.8) {
|
|
153
158
|
// Use 60% content + 40% header (let header wrap significantly)
|
package/dist/styles/index.css
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
@tailwind base;
|
|
2
|
-
@tailwind components;
|
|
3
|
-
@tailwind utilities;
|
|
4
|
-
|
|
5
|
-
@import './tokens.css';
|
|
1
|
+
@tailwind base;
|
|
2
|
+
@tailwind components;
|
|
3
|
+
@tailwind utilities;
|
|
4
|
+
|
|
5
|
+
@import './tokens.css';
|
package/package.json
CHANGED
|
@@ -1,196 +1,196 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "indas-ui",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Indas UI — React component library for business apps: Tailwind design tokens, Radix primitives, Lucide icons, DataGrid, dashboards and charts.",
|
|
5
|
-
"license": "MIT",
|
|
6
|
-
"author": "Indas Analytics Pvt Ltd",
|
|
7
|
-
"contributors": [
|
|
8
|
-
"Shreyansh Patidar",
|
|
9
|
-
"Abhinav"
|
|
10
|
-
],
|
|
11
|
-
"repository": {
|
|
12
|
-
"type": "git",
|
|
13
|
-
"url": "git+https://github.com/ShreyanshPatidar/indas-ui.git",
|
|
14
|
-
"directory": "packages/indas-ui"
|
|
15
|
-
},
|
|
16
|
-
"homepage": "https://shreyanshpatidar.github.io/indas-ui",
|
|
17
|
-
"type": "module",
|
|
18
|
-
"main": "./dist/cjs/index.js",
|
|
19
|
-
"module": "./dist/index.js",
|
|
20
|
-
"types": "./dist/index.d.ts",
|
|
21
|
-
"exports": {
|
|
22
|
-
".": {
|
|
23
|
-
"types": "./dist/index.d.ts",
|
|
24
|
-
"import": "./dist/index.js",
|
|
25
|
-
"require": "./dist/cjs/index.js"
|
|
26
|
-
},
|
|
27
|
-
"./ui": {
|
|
28
|
-
"types": "./dist/components/ui/index.d.ts",
|
|
29
|
-
"import": "./dist/components/ui/index.js",
|
|
30
|
-
"require": "./dist/cjs/components/ui/index.js"
|
|
31
|
-
},
|
|
32
|
-
"./layout": {
|
|
33
|
-
"types": "./dist/components/layout/index.d.ts",
|
|
34
|
-
"import": "./dist/components/layout/index.js",
|
|
35
|
-
"require": "./dist/cjs/components/layout/index.js"
|
|
36
|
-
},
|
|
37
|
-
"./datagrid": {
|
|
38
|
-
"types": "./dist/components/datagrid/index.d.ts",
|
|
39
|
-
"import": "./dist/components/datagrid/index.js",
|
|
40
|
-
"require": "./dist/cjs/components/datagrid/index.js"
|
|
41
|
-
},
|
|
42
|
-
"./dashboard": {
|
|
43
|
-
"types": "./dist/components/dashboard/index.d.ts",
|
|
44
|
-
"import": "./dist/components/dashboard/index.js",
|
|
45
|
-
"require": "./dist/cjs/components/dashboard/index.js"
|
|
46
|
-
},
|
|
47
|
-
"./charts": {
|
|
48
|
-
"types": "./dist/components/dashboard/charts/index.d.ts",
|
|
49
|
-
"import": "./dist/components/dashboard/charts/index.js",
|
|
50
|
-
"require": "./dist/cjs/components/dashboard/charts/index.js"
|
|
51
|
-
},
|
|
52
|
-
"./kpi": {
|
|
53
|
-
"types": "./dist/components/dashboard/kpi/index.d.ts",
|
|
54
|
-
"import": "./dist/components/dashboard/kpi/index.js",
|
|
55
|
-
"require": "./dist/cjs/components/dashboard/kpi/index.js"
|
|
56
|
-
},
|
|
57
|
-
"./modals": {
|
|
58
|
-
"types": "./dist/components/modals/index.d.ts",
|
|
59
|
-
"import": "./dist/components/modals/index.js",
|
|
60
|
-
"require": "./dist/cjs/components/modals/index.js"
|
|
61
|
-
},
|
|
62
|
-
"./forms": {
|
|
63
|
-
"types": "./dist/components/forms/index.d.ts",
|
|
64
|
-
"import": "./dist/components/forms/index.js",
|
|
65
|
-
"require": "./dist/cjs/components/forms/index.js"
|
|
66
|
-
},
|
|
67
|
-
"./chat": {
|
|
68
|
-
"types": "./dist/components/chat/index.d.ts",
|
|
69
|
-
"import": "./dist/components/chat/index.js",
|
|
70
|
-
"require": "./dist/cjs/components/chat/index.js"
|
|
71
|
-
},
|
|
72
|
-
"./providers": {
|
|
73
|
-
"types": "./dist/providers.d.ts",
|
|
74
|
-
"import": "./dist/providers.js",
|
|
75
|
-
"require": "./dist/cjs/providers.js"
|
|
76
|
-
},
|
|
77
|
-
"./auth": {
|
|
78
|
-
"types": "./dist/auth.d.ts",
|
|
79
|
-
"import": "./dist/auth.js",
|
|
80
|
-
"require": "./dist/cjs/auth.js"
|
|
81
|
-
},
|
|
82
|
-
"./tokens.css": "./dist/styles/tokens.css",
|
|
83
|
-
"./styles/*": "./dist/styles/*",
|
|
84
|
-
"./package.json": "./package.json"
|
|
85
|
-
},
|
|
86
|
-
"files": [
|
|
87
|
-
"dist"
|
|
88
|
-
],
|
|
89
|
-
"sideEffects": [
|
|
90
|
-
"**/*.css"
|
|
91
|
-
],
|
|
92
|
-
"scripts": {
|
|
93
|
-
"build": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json --resolve-full-paths && tsc -p tsconfig.build.cjs.json && tsc-alias -p tsconfig.build.cjs.json --resolve-full-paths && node scripts/copy-assets.mjs",
|
|
94
|
-
"dev": "node scripts/dev.mjs",
|
|
95
|
-
"type-check": "tsc --noEmit",
|
|
96
|
-
"prepublishOnly": "npm run build"
|
|
97
|
-
},
|
|
98
|
-
"peerDependencies": {
|
|
99
|
-
"react": ">=18.0.0",
|
|
100
|
-
"react-dom": ">=18.0.0",
|
|
101
|
-
"lucide-react": ">=0.562.0 <2"
|
|
102
|
-
},
|
|
103
|
-
"dependencies": {
|
|
104
|
-
"@dnd-kit/core": "^6.3.1",
|
|
105
|
-
"@dnd-kit/modifiers": "^9.0.0",
|
|
106
|
-
"@dnd-kit/sortable": "^10.0.0",
|
|
107
|
-
"@dnd-kit/utilities": "^3.2.2",
|
|
108
|
-
"@microsoft/signalr": "^10.0.0",
|
|
109
|
-
"@radix-ui/react-collapsible": "^1.1.12",
|
|
110
|
-
"@radix-ui/react-dialog": "^1.1.15",
|
|
111
|
-
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
|
112
|
-
"@radix-ui/react-icons": "^1.3.2",
|
|
113
|
-
"@radix-ui/react-popover": "^1.1.15",
|
|
114
|
-
"@radix-ui/react-progress": "^1.1.7",
|
|
115
|
-
"@radix-ui/react-select": "^2.2.6",
|
|
116
|
-
"@radix-ui/react-separator": "^1.1.7",
|
|
117
|
-
"@radix-ui/react-tabs": "^1.1.13",
|
|
118
|
-
"@radix-ui/react-tooltip": "^1.2.8",
|
|
119
|
-
"@tanstack/react-query": "^5.90.10",
|
|
120
|
-
"@tanstack/react-query-devtools": "^5.90.2",
|
|
121
|
-
"@tanstack/react-table": "^8.21.3",
|
|
122
|
-
"@tanstack/react-virtual": "^3.13.12",
|
|
123
|
-
"class-variance-authority": "^0.7.1",
|
|
124
|
-
"clsx": "^2.1.1",
|
|
125
|
-
"echarts": "^6.0.0",
|
|
126
|
-
"echarts-for-react": "^3.0.5",
|
|
127
|
-
"exceljs": "^4.4.0",
|
|
128
|
-
"file-saver": "^2.0.5",
|
|
129
|
-
"framer-motion": "^12.23.12",
|
|
130
|
-
"jspdf": "^4.2.1",
|
|
131
|
-
"jspdf-autotable": "^5.0.8",
|
|
132
|
-
"ldrs": "^1.1.9",
|
|
133
|
-
"papaparse": "^5.5.3",
|
|
134
|
-
"react-hook-form": "^7.76.1",
|
|
135
|
-
"react-image-crop": "^11.0.10",
|
|
136
|
-
"react-markdown": "^10.1.0",
|
|
137
|
-
"rehype-highlight": "^7.0.2",
|
|
138
|
-
"rehype-raw": "^7.0.0",
|
|
139
|
-
"remark-gfm": "^4.0.1",
|
|
140
|
-
"svg2pdf.js": "^2.8.1",
|
|
141
|
-
"tailwind-merge": "^3.3.1"
|
|
142
|
-
},
|
|
143
|
-
"devDependencies": {
|
|
144
|
-
"@types/react": "^18.3.12",
|
|
145
|
-
"@types/react-dom": "^18.3.1",
|
|
146
|
-
"lucide-react": "^0.562.0",
|
|
147
|
-
"next": "^16.2.1",
|
|
148
|
-
"next-auth": "^4.24.7",
|
|
149
|
-
"tsc-alias": "^1.9.4",
|
|
150
|
-
"typescript": "^5.7.2"
|
|
151
|
-
},
|
|
152
|
-
"keywords": [
|
|
153
|
-
"react",
|
|
154
|
-
"components",
|
|
155
|
-
"ui",
|
|
156
|
-
"tailwind",
|
|
157
|
-
"design-system",
|
|
158
|
-
"datagrid",
|
|
159
|
-
"indas",
|
|
160
|
-
"erp"
|
|
161
|
-
],
|
|
162
|
-
"typesVersions": {
|
|
163
|
-
"*": {
|
|
164
|
-
"ui": [
|
|
165
|
-
"./dist/components/ui/index.d.ts"
|
|
166
|
-
],
|
|
167
|
-
"layout": [
|
|
168
|
-
"./dist/components/layout/index.d.ts"
|
|
169
|
-
],
|
|
170
|
-
"datagrid": [
|
|
171
|
-
"./dist/components/datagrid/index.d.ts"
|
|
172
|
-
],
|
|
173
|
-
"dashboard": [
|
|
174
|
-
"./dist/components/dashboard/index.d.ts"
|
|
175
|
-
],
|
|
176
|
-
"charts": [
|
|
177
|
-
"./dist/components/dashboard/charts/index.d.ts"
|
|
178
|
-
],
|
|
179
|
-
"kpi": [
|
|
180
|
-
"./dist/components/dashboard/kpi/index.d.ts"
|
|
181
|
-
],
|
|
182
|
-
"modals": [
|
|
183
|
-
"./dist/components/modals/index.d.ts"
|
|
184
|
-
],
|
|
185
|
-
"forms": [
|
|
186
|
-
"./dist/components/forms/index.d.ts"
|
|
187
|
-
],
|
|
188
|
-
"providers": [
|
|
189
|
-
"./dist/providers.d.ts"
|
|
190
|
-
],
|
|
191
|
-
"auth": [
|
|
192
|
-
"./dist/auth.d.ts"
|
|
193
|
-
]
|
|
194
|
-
}
|
|
195
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "indas-ui",
|
|
3
|
+
"version": "0.1.8",
|
|
4
|
+
"description": "Indas UI — React component library for business apps: Tailwind design tokens, Radix primitives, Lucide icons, DataGrid, dashboards and charts.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Indas Analytics Pvt Ltd",
|
|
7
|
+
"contributors": [
|
|
8
|
+
"Shreyansh Patidar",
|
|
9
|
+
"Abhinav"
|
|
10
|
+
],
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/ShreyanshPatidar/indas-ui.git",
|
|
14
|
+
"directory": "packages/indas-ui"
|
|
15
|
+
},
|
|
16
|
+
"homepage": "https://shreyanshpatidar.github.io/indas-ui",
|
|
17
|
+
"type": "module",
|
|
18
|
+
"main": "./dist/cjs/index.js",
|
|
19
|
+
"module": "./dist/index.js",
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"types": "./dist/index.d.ts",
|
|
24
|
+
"import": "./dist/index.js",
|
|
25
|
+
"require": "./dist/cjs/index.js"
|
|
26
|
+
},
|
|
27
|
+
"./ui": {
|
|
28
|
+
"types": "./dist/components/ui/index.d.ts",
|
|
29
|
+
"import": "./dist/components/ui/index.js",
|
|
30
|
+
"require": "./dist/cjs/components/ui/index.js"
|
|
31
|
+
},
|
|
32
|
+
"./layout": {
|
|
33
|
+
"types": "./dist/components/layout/index.d.ts",
|
|
34
|
+
"import": "./dist/components/layout/index.js",
|
|
35
|
+
"require": "./dist/cjs/components/layout/index.js"
|
|
36
|
+
},
|
|
37
|
+
"./datagrid": {
|
|
38
|
+
"types": "./dist/components/datagrid/index.d.ts",
|
|
39
|
+
"import": "./dist/components/datagrid/index.js",
|
|
40
|
+
"require": "./dist/cjs/components/datagrid/index.js"
|
|
41
|
+
},
|
|
42
|
+
"./dashboard": {
|
|
43
|
+
"types": "./dist/components/dashboard/index.d.ts",
|
|
44
|
+
"import": "./dist/components/dashboard/index.js",
|
|
45
|
+
"require": "./dist/cjs/components/dashboard/index.js"
|
|
46
|
+
},
|
|
47
|
+
"./charts": {
|
|
48
|
+
"types": "./dist/components/dashboard/charts/index.d.ts",
|
|
49
|
+
"import": "./dist/components/dashboard/charts/index.js",
|
|
50
|
+
"require": "./dist/cjs/components/dashboard/charts/index.js"
|
|
51
|
+
},
|
|
52
|
+
"./kpi": {
|
|
53
|
+
"types": "./dist/components/dashboard/kpi/index.d.ts",
|
|
54
|
+
"import": "./dist/components/dashboard/kpi/index.js",
|
|
55
|
+
"require": "./dist/cjs/components/dashboard/kpi/index.js"
|
|
56
|
+
},
|
|
57
|
+
"./modals": {
|
|
58
|
+
"types": "./dist/components/modals/index.d.ts",
|
|
59
|
+
"import": "./dist/components/modals/index.js",
|
|
60
|
+
"require": "./dist/cjs/components/modals/index.js"
|
|
61
|
+
},
|
|
62
|
+
"./forms": {
|
|
63
|
+
"types": "./dist/components/forms/index.d.ts",
|
|
64
|
+
"import": "./dist/components/forms/index.js",
|
|
65
|
+
"require": "./dist/cjs/components/forms/index.js"
|
|
66
|
+
},
|
|
67
|
+
"./chat": {
|
|
68
|
+
"types": "./dist/components/chat/index.d.ts",
|
|
69
|
+
"import": "./dist/components/chat/index.js",
|
|
70
|
+
"require": "./dist/cjs/components/chat/index.js"
|
|
71
|
+
},
|
|
72
|
+
"./providers": {
|
|
73
|
+
"types": "./dist/providers.d.ts",
|
|
74
|
+
"import": "./dist/providers.js",
|
|
75
|
+
"require": "./dist/cjs/providers.js"
|
|
76
|
+
},
|
|
77
|
+
"./auth": {
|
|
78
|
+
"types": "./dist/auth.d.ts",
|
|
79
|
+
"import": "./dist/auth.js",
|
|
80
|
+
"require": "./dist/cjs/auth.js"
|
|
81
|
+
},
|
|
82
|
+
"./tokens.css": "./dist/styles/tokens.css",
|
|
83
|
+
"./styles/*": "./dist/styles/*",
|
|
84
|
+
"./package.json": "./package.json"
|
|
85
|
+
},
|
|
86
|
+
"files": [
|
|
87
|
+
"dist"
|
|
88
|
+
],
|
|
89
|
+
"sideEffects": [
|
|
90
|
+
"**/*.css"
|
|
91
|
+
],
|
|
92
|
+
"scripts": {
|
|
93
|
+
"build": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json --resolve-full-paths && tsc -p tsconfig.build.cjs.json && tsc-alias -p tsconfig.build.cjs.json --resolve-full-paths && node scripts/copy-assets.mjs",
|
|
94
|
+
"dev": "node scripts/dev.mjs",
|
|
95
|
+
"type-check": "tsc --noEmit",
|
|
96
|
+
"prepublishOnly": "npm run build"
|
|
97
|
+
},
|
|
98
|
+
"peerDependencies": {
|
|
99
|
+
"react": ">=18.0.0",
|
|
100
|
+
"react-dom": ">=18.0.0",
|
|
101
|
+
"lucide-react": ">=0.562.0 <2"
|
|
102
|
+
},
|
|
103
|
+
"dependencies": {
|
|
104
|
+
"@dnd-kit/core": "^6.3.1",
|
|
105
|
+
"@dnd-kit/modifiers": "^9.0.0",
|
|
106
|
+
"@dnd-kit/sortable": "^10.0.0",
|
|
107
|
+
"@dnd-kit/utilities": "^3.2.2",
|
|
108
|
+
"@microsoft/signalr": "^10.0.0",
|
|
109
|
+
"@radix-ui/react-collapsible": "^1.1.12",
|
|
110
|
+
"@radix-ui/react-dialog": "^1.1.15",
|
|
111
|
+
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
|
112
|
+
"@radix-ui/react-icons": "^1.3.2",
|
|
113
|
+
"@radix-ui/react-popover": "^1.1.15",
|
|
114
|
+
"@radix-ui/react-progress": "^1.1.7",
|
|
115
|
+
"@radix-ui/react-select": "^2.2.6",
|
|
116
|
+
"@radix-ui/react-separator": "^1.1.7",
|
|
117
|
+
"@radix-ui/react-tabs": "^1.1.13",
|
|
118
|
+
"@radix-ui/react-tooltip": "^1.2.8",
|
|
119
|
+
"@tanstack/react-query": "^5.90.10",
|
|
120
|
+
"@tanstack/react-query-devtools": "^5.90.2",
|
|
121
|
+
"@tanstack/react-table": "^8.21.3",
|
|
122
|
+
"@tanstack/react-virtual": "^3.13.12",
|
|
123
|
+
"class-variance-authority": "^0.7.1",
|
|
124
|
+
"clsx": "^2.1.1",
|
|
125
|
+
"echarts": "^6.0.0",
|
|
126
|
+
"echarts-for-react": "^3.0.5",
|
|
127
|
+
"exceljs": "^4.4.0",
|
|
128
|
+
"file-saver": "^2.0.5",
|
|
129
|
+
"framer-motion": "^12.23.12",
|
|
130
|
+
"jspdf": "^4.2.1",
|
|
131
|
+
"jspdf-autotable": "^5.0.8",
|
|
132
|
+
"ldrs": "^1.1.9",
|
|
133
|
+
"papaparse": "^5.5.3",
|
|
134
|
+
"react-hook-form": "^7.76.1",
|
|
135
|
+
"react-image-crop": "^11.0.10",
|
|
136
|
+
"react-markdown": "^10.1.0",
|
|
137
|
+
"rehype-highlight": "^7.0.2",
|
|
138
|
+
"rehype-raw": "^7.0.0",
|
|
139
|
+
"remark-gfm": "^4.0.1",
|
|
140
|
+
"svg2pdf.js": "^2.8.1",
|
|
141
|
+
"tailwind-merge": "^3.3.1"
|
|
142
|
+
},
|
|
143
|
+
"devDependencies": {
|
|
144
|
+
"@types/react": "^18.3.12",
|
|
145
|
+
"@types/react-dom": "^18.3.1",
|
|
146
|
+
"lucide-react": "^0.562.0",
|
|
147
|
+
"next": "^16.2.1",
|
|
148
|
+
"next-auth": "^4.24.7",
|
|
149
|
+
"tsc-alias": "^1.9.4",
|
|
150
|
+
"typescript": "^5.7.2"
|
|
151
|
+
},
|
|
152
|
+
"keywords": [
|
|
153
|
+
"react",
|
|
154
|
+
"components",
|
|
155
|
+
"ui",
|
|
156
|
+
"tailwind",
|
|
157
|
+
"design-system",
|
|
158
|
+
"datagrid",
|
|
159
|
+
"indas",
|
|
160
|
+
"erp"
|
|
161
|
+
],
|
|
162
|
+
"typesVersions": {
|
|
163
|
+
"*": {
|
|
164
|
+
"ui": [
|
|
165
|
+
"./dist/components/ui/index.d.ts"
|
|
166
|
+
],
|
|
167
|
+
"layout": [
|
|
168
|
+
"./dist/components/layout/index.d.ts"
|
|
169
|
+
],
|
|
170
|
+
"datagrid": [
|
|
171
|
+
"./dist/components/datagrid/index.d.ts"
|
|
172
|
+
],
|
|
173
|
+
"dashboard": [
|
|
174
|
+
"./dist/components/dashboard/index.d.ts"
|
|
175
|
+
],
|
|
176
|
+
"charts": [
|
|
177
|
+
"./dist/components/dashboard/charts/index.d.ts"
|
|
178
|
+
],
|
|
179
|
+
"kpi": [
|
|
180
|
+
"./dist/components/dashboard/kpi/index.d.ts"
|
|
181
|
+
],
|
|
182
|
+
"modals": [
|
|
183
|
+
"./dist/components/modals/index.d.ts"
|
|
184
|
+
],
|
|
185
|
+
"forms": [
|
|
186
|
+
"./dist/components/forms/index.d.ts"
|
|
187
|
+
],
|
|
188
|
+
"providers": [
|
|
189
|
+
"./dist/providers.d.ts"
|
|
190
|
+
],
|
|
191
|
+
"auth": [
|
|
192
|
+
"./dist/auth.d.ts"
|
|
193
|
+
]
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
196
|
}
|