@anymux/ui-kit 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (244) hide show
  1. package/dist/ExplorerLayout-CSIJd7N4.js +105 -0
  2. package/dist/ExplorerLayout-CSIJd7N4.js.map +1 -0
  3. package/dist/FileBrowserContext-B6jixa2j.js +11 -0
  4. package/dist/FileBrowserContext-B6jixa2j.js.map +1 -0
  5. package/dist/calendar-DSlrbHoj.js +761 -0
  6. package/dist/calendar-DSlrbHoj.js.map +1 -0
  7. package/dist/calendar.d.ts +3 -0
  8. package/dist/calendar.js +3 -0
  9. package/dist/contacts-DQXTZzHc.js +539 -0
  10. package/dist/contacts-DQXTZzHc.js.map +1 -0
  11. package/dist/contacts.d.ts +3 -0
  12. package/dist/contacts.js +3 -0
  13. package/dist/file-browser-m5atC3kF.js +6755 -0
  14. package/dist/file-browser-m5atC3kF.js.map +1 -0
  15. package/dist/file-browser.d.ts +11 -0
  16. package/dist/file-browser.js +9 -0
  17. package/dist/git-B55e6LL-.js +561 -0
  18. package/dist/git-B55e6LL-.js.map +1 -0
  19. package/dist/git.d.ts +2 -0
  20. package/dist/git.js +3 -0
  21. package/dist/iconMap-V4B8P-Uh.js +206 -0
  22. package/dist/iconMap-V4B8P-Uh.js.map +1 -0
  23. package/dist/icons-CIsIOZXR.js +0 -0
  24. package/dist/icons.d.ts +2 -0
  25. package/dist/icons.js +4 -0
  26. package/dist/index-BNmNIWBL.d.ts +71 -0
  27. package/dist/index-BNmNIWBL.d.ts.map +1 -0
  28. package/dist/index-Bryv_GCG.d.ts +1481 -0
  29. package/dist/index-Bryv_GCG.d.ts.map +1 -0
  30. package/dist/index-CuQIjSXs.d.ts +134 -0
  31. package/dist/index-CuQIjSXs.d.ts.map +1 -0
  32. package/dist/index-DSu19mq0.d.ts +153 -0
  33. package/dist/index-DSu19mq0.d.ts.map +1 -0
  34. package/dist/index-DmsyeHFr.d.ts +149 -0
  35. package/dist/index-DmsyeHFr.d.ts.map +1 -0
  36. package/dist/index-DxnJ8FYM.d.ts +17 -0
  37. package/dist/index-DxnJ8FYM.d.ts.map +1 -0
  38. package/dist/index-DzfY1Tok.d.ts +32 -0
  39. package/dist/index-DzfY1Tok.d.ts.map +1 -0
  40. package/dist/index-Ml_SgiKa.d.ts +1847 -0
  41. package/dist/index-Ml_SgiKa.d.ts.map +1 -0
  42. package/dist/index-kHr9udZD.d.ts +1025 -0
  43. package/dist/index-kHr9udZD.d.ts.map +1 -0
  44. package/dist/index.d.ts +11 -0
  45. package/dist/index.js +15 -0
  46. package/dist/layout-Ca_4r8ka.js +89 -0
  47. package/dist/layout-Ca_4r8ka.js.map +1 -0
  48. package/dist/layout.d.ts +2 -0
  49. package/dist/layout.js +5 -0
  50. package/dist/list-CxfT6hix.js +6831 -0
  51. package/dist/list-CxfT6hix.js.map +1 -0
  52. package/dist/list.d.ts +2 -0
  53. package/dist/list.js +5 -0
  54. package/dist/media-DZ292aKK.js +557 -0
  55. package/dist/media-DZ292aKK.js.map +1 -0
  56. package/dist/media.d.ts +3 -0
  57. package/dist/media.js +3 -0
  58. package/dist/tree-Dd9Z0Aso.js +3351 -0
  59. package/dist/tree-Dd9Z0Aso.js.map +1 -0
  60. package/dist/tree.d.ts +2 -0
  61. package/dist/tree.js +6 -0
  62. package/dist/types-common-CB3kRek8.d.ts +26 -0
  63. package/dist/types-common-CB3kRek8.d.ts.map +1 -0
  64. package/dist/utils-B4fdKKsy.js +3 -0
  65. package/package.json +109 -0
  66. package/src/calendar/AgendaView.tsx +37 -0
  67. package/src/calendar/CalendarBrowser.tsx +90 -0
  68. package/src/calendar/CalendarModel.ts +142 -0
  69. package/src/calendar/CalendarSidebar.tsx +81 -0
  70. package/src/calendar/DayView.tsx +76 -0
  71. package/src/calendar/EventCard.tsx +51 -0
  72. package/src/calendar/MockCalendarProvider.ts +98 -0
  73. package/src/calendar/MonthView.tsx +77 -0
  74. package/src/calendar/WeekView.tsx +129 -0
  75. package/src/calendar/index.ts +18 -0
  76. package/src/calendar/types.ts +25 -0
  77. package/src/contacts/ContactAvatar.tsx +35 -0
  78. package/src/contacts/ContactBrowser.tsx +56 -0
  79. package/src/contacts/ContactCard.tsx +37 -0
  80. package/src/contacts/ContactDetail.tsx +63 -0
  81. package/src/contacts/ContactGroupSidebar.tsx +40 -0
  82. package/src/contacts/ContactList.tsx +32 -0
  83. package/src/contacts/ContactListModel.ts +120 -0
  84. package/src/contacts/MockContactProvider.ts +77 -0
  85. package/src/contacts/index.ts +17 -0
  86. package/src/contacts/types.ts +26 -0
  87. package/src/demos/CalendarBrowserDemo.tsx +15 -0
  88. package/src/demos/ContactBrowserDemo.tsx +15 -0
  89. package/src/demos/MediaBrowserDemo.tsx +15 -0
  90. package/src/file-browser/adapters/DocumentViewerAdapter.ts +371 -0
  91. package/src/file-browser/adapters/FileSystemBridge.ts +168 -0
  92. package/src/file-browser/adapters/GitBrowserAdapter.ts +546 -0
  93. package/src/file-browser/adapters/README.md +504 -0
  94. package/src/file-browser/adapters/index.ts +27 -0
  95. package/src/file-browser/adapters/types.ts +70 -0
  96. package/src/file-browser/architecture.md +645 -0
  97. package/src/file-browser/components/CreateItemDialog.tsx +71 -0
  98. package/src/file-browser/components/DeleteConfirmDialog.tsx +58 -0
  99. package/src/file-browser/components/FileBrowser.tsx +473 -0
  100. package/src/file-browser/components/FileBrowserContent.tsx +209 -0
  101. package/src/file-browser/components/FileBrowserHeader.tsx +151 -0
  102. package/src/file-browser/components/FileBrowserToolbar.tsx +145 -0
  103. package/src/file-browser/components/LeftPanel/LeftPanel.tsx +103 -0
  104. package/src/file-browser/components/LeftPanel/LeftPanelTabs.tsx +70 -0
  105. package/src/file-browser/components/LeftPanel/TreeNavigationView.tsx +256 -0
  106. package/src/file-browser/components/PreviewPane.tsx +146 -0
  107. package/src/file-browser/components/RightPanel/FilePreview.tsx +219 -0
  108. package/src/file-browser/components/RightPanel/RightPanel.tsx +186 -0
  109. package/src/file-browser/components/RightPanel/RightPanelToolbar.tsx +113 -0
  110. package/src/file-browser/components/UploadProgress.tsx +123 -0
  111. package/src/file-browser/components/ViewerHost.tsx +208 -0
  112. package/src/file-browser/components/mobile/MobileNavigation.tsx +227 -0
  113. package/src/file-browser/components/navigation/NavigationButtons.tsx +171 -0
  114. package/src/file-browser/components/shared/ErrorBoundary.tsx +116 -0
  115. package/src/file-browser/components/shared/FileBrowserItem.tsx +195 -0
  116. package/src/file-browser/components/shared/FileIcon.tsx +169 -0
  117. package/src/file-browser/components/toolbar/ViewModeToggle.tsx +200 -0
  118. package/src/file-browser/components/views/ListView/ListView.tsx +484 -0
  119. package/src/file-browser/components/views/ThumbnailView/ThumbnailView.tsx +323 -0
  120. package/src/file-browser/components/views/TreeView/TreeNode.tsx +186 -0
  121. package/src/file-browser/components/views/TreeView/TreeNodeList.tsx +191 -0
  122. package/src/file-browser/components/views/TreeView/TreeView.tsx +200 -0
  123. package/src/file-browser/components/views/TreemapView/TreemapView.tsx +339 -0
  124. package/src/file-browser/context/FileBrowserContext.tsx +13 -0
  125. package/src/file-browser/examples/BasicUsage.tsx +20 -0
  126. package/src/file-browser/index.ts +98 -0
  127. package/src/file-browser/models/FileBrowserModel.ts +623 -0
  128. package/src/file-browser/models/LeftPanelManagerModel.ts +105 -0
  129. package/src/file-browser/models/NavigationManagerModel.ts +312 -0
  130. package/src/file-browser/models/ResponsiveLayoutManagerModel.ts +437 -0
  131. package/src/file-browser/models/RightPanelManagerModel.ts +190 -0
  132. package/src/file-browser/models/SelectionManagerModel.ts +252 -0
  133. package/src/file-browser/models/ToolbarManagerModel.ts +144 -0
  134. package/src/file-browser/models/UploadModel.ts +147 -0
  135. package/src/file-browser/models/ViewModeManagerModel.ts +185 -0
  136. package/src/file-browser/models/ViewerHostModel.ts +44 -0
  137. package/src/file-browser/models/ui/ListViewUIModel.ts +265 -0
  138. package/src/file-browser/models/ui/PreviewUIModel.ts +297 -0
  139. package/src/file-browser/models/ui/ThumbnailViewUIModel.ts +254 -0
  140. package/src/file-browser/models/ui/TreeViewUIModel.ts +128 -0
  141. package/src/file-browser/models/ui/TreemapViewUIModel.ts +350 -0
  142. package/src/file-browser/providers/FileSystemListProvider.ts +552 -0
  143. package/src/file-browser/providers/FileSystemProvider.ts +401 -0
  144. package/src/file-browser/providers/FileSystemTreeProvider.ts +231 -0
  145. package/src/file-browser/providers/GitProvider.ts +337 -0
  146. package/src/file-browser/providers/GitRepositoryProvider.ts +376 -0
  147. package/src/file-browser/providers/IFileBrowserProvider.ts +56 -0
  148. package/src/file-browser/providers/MemoryProvider.ts +303 -0
  149. package/src/file-browser/providers/index.ts +4 -0
  150. package/src/file-browser/registry/ViewerRegistry.ts +551 -0
  151. package/src/file-browser/registry/types.ts +144 -0
  152. package/src/file-browser/scripts/performanceBenchmark.ts +553 -0
  153. package/src/file-browser/services/ThumbnailCacheService.ts +128 -0
  154. package/src/file-browser/tasks.md +537 -0
  155. package/src/file-browser/types/FileBrowserTypes.ts +126 -0
  156. package/src/file-browser/types/ProviderTypes.ts +155 -0
  157. package/src/file-browser/types/UITypes.ts +235 -0
  158. package/src/file-browser/types/ViewModeTypes.ts +150 -0
  159. package/src/file-browser/utils/gestures.ts +327 -0
  160. package/src/file-browser/utils/performance.ts +563 -0
  161. package/src/file-browser/viewers/ImageViewer.tsx +163 -0
  162. package/src/file-browser/viewers/ImageViewerModel.ts +79 -0
  163. package/src/file-browser/viewers/TextViewer.tsx +95 -0
  164. package/src/file-browser/viewers/UnsupportedFileViewer.tsx +57 -0
  165. package/src/file-browser/viewers/index.ts +61 -0
  166. package/src/git/BranchList.tsx +128 -0
  167. package/src/git/CommitGraph.tsx +239 -0
  168. package/src/git/CommitList.tsx +258 -0
  169. package/src/git/DiffViewer.tsx +219 -0
  170. package/src/git/index.ts +4 -0
  171. package/src/icons/iconMap.ts +146 -0
  172. package/src/icons/index.ts +9 -0
  173. package/src/index.ts +13 -0
  174. package/src/layout/README.md +307 -0
  175. package/src/layout/components/ExplorerLayout/ExplorerLayout.tsx +178 -0
  176. package/src/layout/examples/SimpleExample.tsx +60 -0
  177. package/src/layout/index.ts +6 -0
  178. package/src/lib/utils.ts +1 -0
  179. package/src/list/README.md +303 -0
  180. package/src/list/architecture.md +807 -0
  181. package/src/list/components/CalculatedGridView.tsx +252 -0
  182. package/src/list/components/DragPreview.tsx +102 -0
  183. package/src/list/components/ListContextMenu.tsx +274 -0
  184. package/src/list/components/ListItem.tsx +761 -0
  185. package/src/list/components/ListItems.tsx +919 -0
  186. package/src/list/components/MasonryView.tsx +241 -0
  187. package/src/list/components/SearchFilter.tsx +44 -0
  188. package/src/list/components/TreemapView.tsx +709 -0
  189. package/src/list/components/ViewSizeControls.tsx +205 -0
  190. package/src/list/components/ViewTypeSelector.tsx +312 -0
  191. package/src/list/components/VirtualizedDetailsView.tsx +231 -0
  192. package/src/list/components/VirtualizedGrid.tsx +164 -0
  193. package/src/list/components/VirtualizedList.tsx +154 -0
  194. package/src/list/components/VirtualizedMasonryView.tsx +344 -0
  195. package/src/list/components/shared/EmptyState.tsx +103 -0
  196. package/src/list/components/shared/ErrorBoundary.tsx +123 -0
  197. package/src/list/components/shared/ErrorDisplay.tsx +100 -0
  198. package/src/list/components/shared/ListLoader.tsx +146 -0
  199. package/src/list/components/shared/LoadingIndicator.tsx +80 -0
  200. package/src/list/index.ts +92 -0
  201. package/src/list/models/ListItemsModel.ts +1301 -0
  202. package/src/list/models/TreemapModel.ts +204 -0
  203. package/src/list/providers/ListItemsProvider.ts +313 -0
  204. package/src/list/providers/TestListProvider.ts +604 -0
  205. package/src/list/tasks.md +937 -0
  206. package/src/list/types/ListTypes.ts +178 -0
  207. package/src/list/utils/BenchmarkLogger.ts +243 -0
  208. package/src/list/utils/DragDropManager.ts +320 -0
  209. package/src/list/utils/GridLayoutCalculator.ts +290 -0
  210. package/src/list/utils/ListAccessibility.ts +367 -0
  211. package/src/list/utils/ListKeyboard.ts +414 -0
  212. package/src/list/utils/MasonryLayoutCalculator.ts +302 -0
  213. package/src/list/utils/MasonryLayoutEngine.ts +401 -0
  214. package/src/list/utils/__tests__/MasonryLayoutEngine.test.ts +157 -0
  215. package/src/list/utils/__tests__/VirtualizedMasonryView.test.tsx +251 -0
  216. package/src/media/AlbumSidebar.tsx +48 -0
  217. package/src/media/MediaBrowser.tsx +92 -0
  218. package/src/media/MediaBrowserModel.ts +138 -0
  219. package/src/media/MediaGrid.tsx +50 -0
  220. package/src/media/MediaList.tsx +49 -0
  221. package/src/media/MediaPreview.tsx +63 -0
  222. package/src/media/MediaTimeline.tsx +38 -0
  223. package/src/media/MockMediaProvider.ts +70 -0
  224. package/src/media/index.ts +18 -0
  225. package/src/media/types.ts +21 -0
  226. package/src/styles/variables.css +60 -0
  227. package/src/tree/DEVELOPMENT_SUMMARY.md +170 -0
  228. package/src/tree/__tests__/TreeModel.test.ts +16 -0
  229. package/src/tree/architecture.md +530 -0
  230. package/src/tree/components/Tree.tsx +283 -0
  231. package/src/tree/components/TreeCheckbox.tsx +147 -0
  232. package/src/tree/components/TreeContextMenu.tsx +139 -0
  233. package/src/tree/components/TreeNodeList.tsx +329 -0
  234. package/src/tree/components/TreeTable.tsx +382 -0
  235. package/src/tree/index.ts +58 -0
  236. package/src/tree/models/TreeModel.ts +839 -0
  237. package/src/tree/providers/SimpleTreeProvider.ts +463 -0
  238. package/src/tree/providers/TestTreeProvider.ts +946 -0
  239. package/src/tree/providers/TreeProvider.ts +308 -0
  240. package/src/tree/tasks.md +2046 -0
  241. package/src/tree/types/TreeTypes.ts +279 -0
  242. package/src/tree/utils/SelectionTheme.ts +150 -0
  243. package/src/tree/utils/logger.ts +203 -0
  244. package/src/types-common.ts +21 -0
@@ -0,0 +1,382 @@
1
+ /**
2
+ * TreeTable - Table component for displaying tree data in tabular format
3
+ *
4
+ * Provides a table view of tree data with:
5
+ * - Hierarchical indentation in tree column
6
+ * - Sortable columns
7
+ * - Filterable columns
8
+ * - Export functionality
9
+ * - Expand/collapse support
10
+ * - Selection support
11
+ */
12
+
13
+ import React, { useMemo, useCallback, useState } from 'react';
14
+ import { observer } from 'mobx-react-lite';
15
+ import { ChevronRight, ChevronDown, ArrowUp, ArrowDown, ArrowUpDown, Download, Search } from 'lucide-react';
16
+ import { cn } from '../../lib/utils';
17
+ import { getSelectionClasses, getCustomColorVariables, DEFAULT_SELECTION_THEME } from '../utils/SelectionTheme';
18
+ import type { TreeModel } from '../models/TreeModel';
19
+ import type { TreeTableColumn, TreeNodeData } from '../types/TreeTypes';
20
+
21
+ export interface TreeTableProps {
22
+ /** The tree model managing state */
23
+ treeModel: TreeModel;
24
+
25
+ /** Table columns configuration */
26
+ columns?: TreeTableColumn[];
27
+
28
+ /** Enable animations for expand/collapse transitions */
29
+ enableAnimations?: boolean;
30
+
31
+ /** Additional CSS classes */
32
+ className?: string;
33
+
34
+ /** Whether to show export functionality */
35
+ enableExport?: boolean;
36
+
37
+ /** Whether to enable filtering */
38
+ enableFiltering?: boolean;
39
+
40
+ /** Whether to enable sorting */
41
+ enableSorting?: boolean;
42
+ }
43
+
44
+ /**
45
+ * TreeTable Component - Table view of tree data
46
+ */
47
+ export const TreeTable = observer<TreeTableProps>(({
48
+ treeModel,
49
+ columns: propColumns,
50
+ enableAnimations = true,
51
+ className,
52
+ enableExport = true,
53
+ enableFiltering = false,
54
+ enableSorting = true
55
+ }) => {
56
+ const [sortColumn, setSortColumn] = useState<string | null>(null);
57
+ const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>('asc');
58
+ const [filters, setFilters] = useState<Record<string, string>>({});
59
+
60
+ // Default columns if none provided
61
+ const defaultColumns: TreeTableColumn[] = useMemo(() => [
62
+ {
63
+ id: 'name',
64
+ label: 'Name',
65
+ dataKey: 'name',
66
+ width: '100%',
67
+ sortable: true,
68
+ filterable: true,
69
+ isTreeColumn: true
70
+ }
71
+ ], []);
72
+
73
+ const columns = propColumns || defaultColumns;
74
+ const isHeaderVisible = columns.length > 1 || enableFiltering || enableExport;
75
+
76
+ // Flatten the tree into a list for table rendering
77
+ const tableData = useMemo(() => {
78
+ const flattenNode = (node: TreeNodeData, level: number = 0): Array<{ node: TreeNodeData; level: number }> => {
79
+ const result = [{ node, level }];
80
+
81
+ if (treeModel.isNodeExpanded(node.id) && node.children) {
82
+ for (const child of node.children) {
83
+ result.push(...flattenNode(child, level + 1));
84
+ }
85
+ }
86
+
87
+ return result;
88
+ };
89
+
90
+ let data: Array<{ node: TreeNodeData; level: number }> = [];
91
+ const rootNodes = treeModel.nodes;
92
+
93
+ for (const node of rootNodes) {
94
+ data.push(...flattenNode(node));
95
+ }
96
+
97
+ // Apply filters
98
+ if (Object.values(filters).some(f => f.trim())) {
99
+ data = data.filter(({ node }) => {
100
+ return Object.entries(filters).every(([columnKey, filterValue]) => {
101
+ if (!filterValue.trim()) return true;
102
+
103
+ const column = columns.find(c => c.id === columnKey);
104
+ if (!column) return true;
105
+
106
+ let cellValue = '';
107
+ if (column.renderCell) {
108
+ // If custom renderer, use it to get the text value
109
+ const rendered = column.renderCell((node as any)[column.dataKey], node);
110
+ cellValue = typeof rendered === 'string' ? rendered : String(rendered || '');
111
+ } else if (column.formatValue) {
112
+ cellValue = column.formatValue((node as any)[column.dataKey], node);
113
+ } else {
114
+ cellValue = (node as any)[column.dataKey]?.toString() || '';
115
+ }
116
+
117
+ return cellValue.toLowerCase().includes(filterValue.toLowerCase());
118
+ });
119
+ });
120
+ }
121
+
122
+ // Apply sorting
123
+ if (sortColumn) {
124
+ const column = columns.find(c => c.id === sortColumn);
125
+ if (column) {
126
+ data.sort((a, b) => {
127
+ let aValue = '';
128
+ let bValue = '';
129
+
130
+ if (column.formatValue) {
131
+ aValue = column.formatValue((a.node as any)[column.dataKey], a.node);
132
+ bValue = column.formatValue((b.node as any)[column.dataKey], b.node);
133
+ } else {
134
+ aValue = (a.node as any)[column.dataKey]?.toString() || '';
135
+ bValue = (b.node as any)[column.dataKey]?.toString() || '';
136
+ }
137
+
138
+ const compareResult = aValue.localeCompare(bValue);
139
+ return sortDirection === 'asc' ? compareResult : -compareResult;
140
+ });
141
+ }
142
+ }
143
+
144
+ return data;
145
+ }, [treeModel.nodes, sortColumn, sortDirection, filters, columns, treeModel]);
146
+
147
+ const handleSort = useCallback((columnKey: string) => {
148
+ if (sortColumn === columnKey) {
149
+ setSortDirection(prev => prev === 'asc' ? 'desc' : 'asc');
150
+ } else {
151
+ setSortColumn(columnKey);
152
+ setSortDirection('asc');
153
+ }
154
+ }, [sortColumn]);
155
+
156
+ const handleExport = useCallback(() => {
157
+ const csvContent = [
158
+ // Header
159
+ columns.map(col => col.label).join(','),
160
+ // Rows
161
+ ...tableData.map(({ node }) =>
162
+ columns.map(col => {
163
+ let value = '';
164
+ if (col.formatValue) {
165
+ value = col.formatValue((node as any)[col.dataKey], node);
166
+ } else {
167
+ value = (node as any)[col.dataKey]?.toString() || '';
168
+ }
169
+ return `"${value.replace(/"/g, '""')}"`;
170
+ }).join(',')
171
+ )
172
+ ].join('\n');
173
+
174
+ const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
175
+ const link = document.createElement('a');
176
+ link.href = URL.createObjectURL(blob);
177
+ link.download = 'tree-data.csv';
178
+ link.click();
179
+ }, [tableData, columns]);
180
+
181
+ const selectionTheme = treeModel.provider.getSelectionTheme?.() || DEFAULT_SELECTION_THEME;
182
+
183
+ return (
184
+ <div className={cn('flex flex-col h-full', className)}>
185
+ {/* Header with controls */}
186
+ {isHeaderVisible && (
187
+ <div className="flex-shrink-0 p-3 border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
188
+ <div className="flex items-center justify-between gap-4">
189
+ <div className="flex items-center gap-2">
190
+ {enableFiltering && (
191
+ <div className="flex items-center gap-2">
192
+ <Search className="w-4 h-4 text-muted-foreground" />
193
+ <span className="text-sm text-muted-foreground">Filter:</span>
194
+ {columns.filter(c => c.filterable).map(column => (
195
+ <input
196
+ key={column.id}
197
+ type="text"
198
+ placeholder={`Filter ${column.label}`}
199
+ value={filters[column.id] || ''}
200
+ onChange={(e) => setFilters(prev => ({ ...prev, [column.id]: e.target.value }))}
201
+ className="px-2 py-1 text-sm border rounded-md w-32"
202
+ />
203
+ ))}
204
+ </div>
205
+ )}
206
+ </div>
207
+
208
+ {enableExport && (
209
+ <button
210
+ onClick={handleExport}
211
+ className="flex items-center gap-2 px-3 py-1 text-sm bg-primary text-primary-foreground rounded-md hover:bg-primary/90"
212
+ >
213
+ <Download className="w-4 h-4" />
214
+ Export CSV
215
+ </button>
216
+ )}
217
+ </div>
218
+ </div>
219
+ )}
220
+
221
+ {/* Table content */}
222
+ <div className="flex-1 overflow-auto">
223
+ <div className="min-w-full">
224
+ {/* Column headers - only show if more than one column */}
225
+ {columns.length > 1 && (
226
+ <div className="sticky top-0 bg-background border-b z-10">
227
+ <div className="flex">
228
+ {columns.map((column) => (
229
+ <div
230
+ key={column.id}
231
+ className={cn(
232
+ 'px-2 py-2 text-sm font-medium text-muted-foreground',
233
+ column.sortable && enableSorting && 'cursor-pointer hover:text-foreground',
234
+ 'flex items-center gap-1'
235
+ )}
236
+ style={{ width: column.width }}
237
+ onClick={() => column.sortable && enableSorting && handleSort(column.id)}
238
+ >
239
+ <span>{column.label}</span>
240
+ {column.sortable && enableSorting && (
241
+ <div className="ml-auto">
242
+ {sortColumn === column.id ? (
243
+ sortDirection === 'asc' ? (
244
+ <ArrowUp className="w-3 h-3" />
245
+ ) : (
246
+ <ArrowDown className="w-3 h-3" />
247
+ )
248
+ ) : (
249
+ <ArrowUpDown className="w-3 h-3 opacity-50" />
250
+ )}
251
+ </div>
252
+ )}
253
+ </div>
254
+ ))}
255
+ </div>
256
+ </div>
257
+ )}
258
+
259
+ {/* Rows */}
260
+ <div>
261
+ {tableData.length === 0 ? (
262
+ <div className="p-8 text-center">
263
+ <p className="text-sm text-muted-foreground">
264
+ {Object.values(filters).some(f => f.trim()) ? 'No results found for current filters' : 'No data available'}
265
+ </p>
266
+ </div>
267
+ ) : (
268
+ tableData.map(({ node, level }) => {
269
+ const isSelected = treeModel.isNodeSelected(node.id);
270
+ const isFocused = treeModel.focusedNode === node.id;
271
+ const isExpanded = treeModel.isNodeExpanded(node.id);
272
+ const hasChildren = node.hasChildren || (node.children && node.children.length > 0);
273
+ const useCheckboxes = treeModel.provider.useCheckboxSelection;
274
+ const customColorVars = getCustomColorVariables(selectionTheme);
275
+
276
+ return (
277
+ <div
278
+ key={node.id}
279
+ className={cn(
280
+ 'flex w-full cursor-pointer group',
281
+ getSelectionClasses(selectionTheme, isSelected, isFocused, !!useCheckboxes),
282
+ useCheckboxes && 'select-none'
283
+ )}
284
+ style={customColorVars}
285
+ onClick={(event) => {
286
+ if (useCheckboxes) return;
287
+
288
+ const isMultiSelectKeyPressed = event.ctrlKey || event.metaKey;
289
+
290
+ if (treeModel.provider.isMultiSelectEnabled && isMultiSelectKeyPressed) {
291
+ // Toggle selection for multi-select mode with Ctrl/Cmd
292
+ if (isSelected) {
293
+ treeModel.deselectNode(node);
294
+ } else {
295
+ treeModel.selectNode(node);
296
+ }
297
+ } else {
298
+ // Single click without modifier
299
+ if (treeModel.provider.isMultiSelectEnabled) {
300
+ // In multi-select mode, single click replaces selection
301
+ treeModel.clearSelection();
302
+ treeModel.selectNode(node);
303
+ } else {
304
+ // In single-select mode, toggle selection
305
+ if (isSelected) {
306
+ treeModel.clearSelection();
307
+ } else {
308
+ treeModel.selectNode(node);
309
+ }
310
+ }
311
+ }
312
+ }}
313
+ onDoubleClick={() => hasChildren && treeModel.toggleExpansion(node)}
314
+ >
315
+ {columns.map((column, columnIndex) => {
316
+ let cellContent: React.ReactNode = '';
317
+
318
+ if (column.renderCell) {
319
+ cellContent = column.renderCell((node as any)[column.dataKey], node);
320
+ } else if (column.formatValue) {
321
+ cellContent = column.formatValue((node as any)[column.dataKey], node);
322
+ } else {
323
+ cellContent = (node as any)[column.dataKey]?.toString() || '';
324
+ }
325
+
326
+ // For tree column, add indentation and controls
327
+ if (column.isTreeColumn) {
328
+ return (
329
+ <div
330
+ key={column.id}
331
+ className="flex items-center px-2 py-1 text-sm"
332
+ style={{ width: column.width }}
333
+ >
334
+ {/* Indentation */}
335
+ <div style={{ width: level * 16 }} className="flex-shrink-0" />
336
+
337
+ {/* Expand/Collapse Icon */}
338
+ <div className="flex-shrink-0 w-4 h-4 mr-1">
339
+ {hasChildren && (
340
+ <button
341
+ onClick={(e) => {
342
+ e.stopPropagation();
343
+ treeModel.toggleExpansion(node);
344
+ }}
345
+ className="w-4 h-4 flex items-center justify-center transition-transform duration-200 hover:bg-accent/20"
346
+ >
347
+ {isExpanded ? (
348
+ <ChevronDown className="w-3 h-3" />
349
+ ) : (
350
+ <ChevronRight className="w-3 h-3" />
351
+ )}
352
+ </button>
353
+ )}
354
+ </div>
355
+
356
+ {/* Content */}
357
+ <span className="flex-1 truncate">{cellContent}</span>
358
+ </div>
359
+ );
360
+ }
361
+
362
+ // Regular column
363
+ return (
364
+ <div
365
+ key={column.id}
366
+ className="px-2 py-1 text-sm truncate"
367
+ style={{ width: column.width }}
368
+ >
369
+ {cellContent}
370
+ </div>
371
+ );
372
+ })}
373
+ </div>
374
+ );
375
+ })
376
+ )}
377
+ </div>
378
+ </div>
379
+ </div>
380
+ </div>
381
+ );
382
+ });
@@ -0,0 +1,58 @@
1
+ /**
2
+ * TreeComponent - Reusable tree component with MobX state management
3
+ *
4
+ * A high-performance, accessible tree component that supports:
5
+ * - Multi-selection
6
+ * - Keyboard navigation
7
+ * - Context menus
8
+ * - Lazy loading
9
+ * - Custom node rendering
10
+ * - Drag and drop (future)
11
+ * - Virtualization (future)
12
+ */
13
+
14
+ /**
15
+ * TreeComponent Module Exports
16
+ *
17
+ * This file exports all public APIs for the TreeComponent system,
18
+ * including types, providers, models, and React components.
19
+ */
20
+
21
+ // Core type definitions
22
+ export * from './types/TreeTypes';
23
+
24
+ // Provider interfaces
25
+ export * from './providers/TreeProvider';
26
+ export { TestTreeProvider } from './providers/TestTreeProvider';
27
+ export { SimpleTreeProvider } from './providers/SimpleTreeProvider';
28
+
29
+ // Models
30
+ export * from './models/TreeModel';
31
+
32
+ // Components
33
+ export * from './components/Tree';
34
+ export * from './components/TreeNodeList';
35
+ export * from './components/TreeContextMenu';
36
+ export * from './components/TreeTable';
37
+ export { TreeCheckbox } from './components/TreeCheckbox';
38
+ export type { CheckboxState } from './components/TreeCheckbox';
39
+ // export * from './components/TreeNode';
40
+
41
+ // Core Types
42
+ export type { TreeNodeData, TreeLoadResult, TreeLoadOptions, TreeTableColumn, TreeTableSort, TreeTableExportOptions } from './types/TreeTypes';
43
+
44
+ // Provider System
45
+ export type { TreeProvider } from './providers/TreeProvider';
46
+
47
+ // MobX Models
48
+ export { TreeModel } from './models/TreeModel';
49
+
50
+ // React Components
51
+ export { Tree } from './components/Tree';
52
+ export type { TreeProps } from './components/Tree';
53
+ export { TreeNodeList } from './components/TreeNodeList';
54
+ export type { TreeNodeListProps } from './components/TreeNodeList';
55
+
56
+ // Utilities
57
+ export { getCustomColorVariables, getSelectionClasses, DEFAULT_SELECTION_THEME } from './utils/SelectionTheme';
58
+ export { logger } from './utils/logger';