@rakeyshgidwani/roger-ui-bank-theme-stan-design 0.1.4 → 0.1.6

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 (164) hide show
  1. package/CHANGELOG.md +1 -1
  2. package/dist/index.d.ts +131 -131
  3. package/dist/index.esm.js +148 -148
  4. package/dist/index.js +148 -148
  5. package/dist/styles.css +1 -1
  6. package/package.json +1 -1
  7. package/src/components/ui/accessibility-demo.tsx +271 -0
  8. package/src/components/ui/advanced-component-architecture-demo.tsx +916 -0
  9. package/src/components/ui/advanced-transition-system-demo.tsx +670 -0
  10. package/src/components/ui/advanced-transition-system.tsx +395 -0
  11. package/src/components/ui/animation/animated-container.tsx +166 -0
  12. package/src/components/ui/animation/index.ts +19 -0
  13. package/src/components/ui/animation/staggered-container.tsx +68 -0
  14. package/src/components/ui/animation-demo.tsx +250 -0
  15. package/src/components/ui/badge.tsx +33 -0
  16. package/src/components/ui/battery-conscious-animation-demo.tsx +568 -0
  17. package/src/components/ui/border-radius-shadow-demo.tsx +187 -0
  18. package/src/components/ui/button.tsx +36 -0
  19. package/src/components/ui/card.tsx +207 -0
  20. package/src/components/ui/checkbox.tsx +30 -0
  21. package/src/components/ui/color-preview.tsx +411 -0
  22. package/src/components/ui/data-display/chart.tsx +653 -0
  23. package/src/components/ui/data-display/data-grid-simple.tsx +76 -0
  24. package/src/components/ui/data-display/data-grid.tsx +680 -0
  25. package/src/components/ui/data-display/list.tsx +456 -0
  26. package/src/components/ui/data-display/table.tsx +482 -0
  27. package/src/components/ui/data-display/timeline.tsx +441 -0
  28. package/src/components/ui/data-display/tree.tsx +602 -0
  29. package/src/components/ui/data-display/types.ts +536 -0
  30. package/src/components/ui/enterprise-mobile-experience-demo.tsx +749 -0
  31. package/src/components/ui/enterprise-mobile-experience.tsx +464 -0
  32. package/src/components/ui/feedback/alert.tsx +157 -0
  33. package/src/components/ui/feedback/progress.tsx +292 -0
  34. package/src/components/ui/feedback/skeleton.tsx +185 -0
  35. package/src/components/ui/feedback/toast.tsx +280 -0
  36. package/src/components/ui/feedback/types.ts +125 -0
  37. package/src/components/ui/font-preview.tsx +288 -0
  38. package/src/components/ui/form-demo.tsx +553 -0
  39. package/src/components/ui/hardware-acceleration-demo.tsx +547 -0
  40. package/src/components/ui/input.tsx +35 -0
  41. package/src/components/ui/label.tsx +16 -0
  42. package/src/components/ui/layout-demo.tsx +367 -0
  43. package/src/components/ui/layouts/adaptive-layout.tsx +139 -0
  44. package/src/components/ui/layouts/desktop-layout.tsx +224 -0
  45. package/src/components/ui/layouts/index.ts +10 -0
  46. package/src/components/ui/layouts/mobile-layout.tsx +162 -0
  47. package/src/components/ui/layouts/tablet-layout.tsx +197 -0
  48. package/src/components/ui/mobile-form-validation.tsx +451 -0
  49. package/src/components/ui/mobile-input-demo.tsx +201 -0
  50. package/src/components/ui/mobile-input.tsx +281 -0
  51. package/src/components/ui/mobile-skeleton-loading-demo.tsx +638 -0
  52. package/src/components/ui/navigation/breadcrumb.tsx +158 -0
  53. package/src/components/ui/navigation/index.ts +36 -0
  54. package/src/components/ui/navigation/menu.tsx +374 -0
  55. package/src/components/ui/navigation/navigation-demo.tsx +324 -0
  56. package/src/components/ui/navigation/pagination.tsx +272 -0
  57. package/src/components/ui/navigation/sidebar.tsx +383 -0
  58. package/src/components/ui/navigation/stepper.tsx +303 -0
  59. package/src/components/ui/navigation/tabs.tsx +205 -0
  60. package/src/components/ui/navigation/types.ts +299 -0
  61. package/src/components/ui/overlay/backdrop.tsx +81 -0
  62. package/src/components/ui/overlay/focus-manager.tsx +143 -0
  63. package/src/components/ui/overlay/index.ts +36 -0
  64. package/src/components/ui/overlay/modal.tsx +270 -0
  65. package/src/components/ui/overlay/overlay-manager.tsx +110 -0
  66. package/src/components/ui/overlay/popover.tsx +462 -0
  67. package/src/components/ui/overlay/portal.tsx +79 -0
  68. package/src/components/ui/overlay/tooltip.tsx +303 -0
  69. package/src/components/ui/overlay/types.ts +196 -0
  70. package/src/components/ui/performance-demo.tsx +596 -0
  71. package/src/components/ui/semantic-input-system-demo.tsx +502 -0
  72. package/src/components/ui/semantic-input-system-demo.tsx.disabled +873 -0
  73. package/src/components/ui/tablet-layout.tsx +192 -0
  74. package/src/components/ui/theme-customizer.tsx +386 -0
  75. package/src/components/ui/theme-preview.tsx +310 -0
  76. package/src/components/ui/theme-switcher.tsx +264 -0
  77. package/src/components/ui/theme-toggle.tsx +38 -0
  78. package/src/components/ui/token-demo.tsx +195 -0
  79. package/src/components/ui/touch-demo.tsx +462 -0
  80. package/src/components/ui/touch-friendly-interface-demo.tsx +519 -0
  81. package/src/components/ui/touch-friendly-interface.tsx +296 -0
  82. package/src/hooks/index.ts +190 -0
  83. package/src/hooks/use-accessibility-support.ts +518 -0
  84. package/src/hooks/use-adaptive-layout.ts +289 -0
  85. package/src/hooks/use-advanced-patterns.ts +294 -0
  86. package/src/hooks/use-advanced-transition-system.ts +393 -0
  87. package/src/hooks/use-animation-profile.ts +288 -0
  88. package/src/hooks/use-battery-animations.ts +384 -0
  89. package/src/hooks/use-battery-conscious-loading.ts +475 -0
  90. package/src/hooks/use-battery-optimization.ts +330 -0
  91. package/src/hooks/use-battery-status.ts +299 -0
  92. package/src/hooks/use-component-performance.ts +344 -0
  93. package/src/hooks/use-device-loading-states.ts +459 -0
  94. package/src/hooks/use-device.tsx +110 -0
  95. package/src/hooks/use-enterprise-mobile-experience.ts +488 -0
  96. package/src/hooks/use-form-feedback.ts +403 -0
  97. package/src/hooks/use-form-performance.ts +513 -0
  98. package/src/hooks/use-frame-rate.ts +251 -0
  99. package/src/hooks/use-gestures.ts +338 -0
  100. package/src/hooks/use-hardware-acceleration.ts +341 -0
  101. package/src/hooks/use-input-accessibility.ts +455 -0
  102. package/src/hooks/use-input-performance.ts +506 -0
  103. package/src/hooks/use-layout-performance.ts +319 -0
  104. package/src/hooks/use-loading-accessibility.ts +535 -0
  105. package/src/hooks/use-loading-performance.ts +473 -0
  106. package/src/hooks/use-memory-usage.ts +287 -0
  107. package/src/hooks/use-mobile-form-layout.ts +464 -0
  108. package/src/hooks/use-mobile-form-validation.ts +518 -0
  109. package/src/hooks/use-mobile-keyboard-optimization.ts +472 -0
  110. package/src/hooks/use-mobile-layout.ts +302 -0
  111. package/src/hooks/use-mobile-optimization.ts +406 -0
  112. package/src/hooks/use-mobile-skeleton.ts +402 -0
  113. package/src/hooks/use-mobile-touch.ts +414 -0
  114. package/src/hooks/use-performance-throttling.ts +348 -0
  115. package/src/hooks/use-performance.ts +316 -0
  116. package/src/hooks/use-reusable-architecture.ts +414 -0
  117. package/src/hooks/use-semantic-input-types.ts +357 -0
  118. package/src/hooks/use-semantic-input.ts +565 -0
  119. package/src/hooks/use-tablet-layout.ts +384 -0
  120. package/src/hooks/use-touch-friendly-input.ts +524 -0
  121. package/src/hooks/use-touch-friendly-interface.ts +331 -0
  122. package/src/hooks/use-touch-optimization.ts +375 -0
  123. package/src/index.ts +279 -279
  124. package/src/lib/utils.ts +6 -0
  125. package/src/themes/README.md +272 -0
  126. package/src/themes/ThemeContext.tsx +31 -0
  127. package/src/themes/ThemeProvider.tsx +232 -0
  128. package/src/themes/accessibility/index.ts +27 -0
  129. package/src/themes/accessibility.ts +259 -0
  130. package/src/themes/aria-patterns.ts +420 -0
  131. package/src/themes/base-themes.ts +55 -0
  132. package/src/themes/colorManager.ts +380 -0
  133. package/src/themes/examples/dark-theme.ts +154 -0
  134. package/src/themes/examples/minimal-theme.ts +108 -0
  135. package/src/themes/focus-management.ts +701 -0
  136. package/src/themes/fontLoader.ts +201 -0
  137. package/src/themes/high-contrast.ts +621 -0
  138. package/src/themes/index.ts +19 -0
  139. package/src/themes/inheritance.ts +227 -0
  140. package/src/themes/keyboard-navigation.ts +550 -0
  141. package/src/themes/motion-reduction.ts +662 -0
  142. package/src/themes/navigation.ts +238 -0
  143. package/src/themes/screen-reader.ts +645 -0
  144. package/src/themes/systemThemeDetector.ts +182 -0
  145. package/src/themes/themeCSSUpdater.ts +262 -0
  146. package/src/themes/themePersistence.ts +238 -0
  147. package/src/themes/themes/default.ts +586 -0
  148. package/src/themes/themes/harvey.ts +554 -0
  149. package/src/themes/themes/stan-design.ts +683 -0
  150. package/src/themes/types.ts +460 -0
  151. package/src/themes/useSystemTheme.ts +48 -0
  152. package/src/themes/useTheme.ts +87 -0
  153. package/src/themes/validation.ts +462 -0
  154. package/src/tokens/index.ts +34 -0
  155. package/src/tokens/tokenExporter.ts +397 -0
  156. package/src/tokens/tokenGenerator.ts +276 -0
  157. package/src/tokens/tokenManager.ts +248 -0
  158. package/src/tokens/tokenValidator.ts +543 -0
  159. package/src/tokens/types.ts +78 -0
  160. package/src/utils/bundle-analyzer.ts +260 -0
  161. package/src/utils/bundle-splitting.ts +483 -0
  162. package/src/utils/lazy-loading.ts +441 -0
  163. package/src/utils/performance-monitor.ts +513 -0
  164. package/src/utils/tree-shaking.ts +274 -0
@@ -0,0 +1,602 @@
1
+ import React, { useCallback, useMemo } from 'react';
2
+ import { useTheme } from '../../../themes/useTheme';
3
+ import {
4
+ TreeProps,
5
+ TreeNode,
6
+ TreeItemProps
7
+ } from './types';
8
+
9
+ // Simple icon components (inline SVG)
10
+ const ChevronRightIcon: React.FC<{ className?: string }> = ({ className = '' }) => (
11
+ <svg
12
+ className={`tree__icon ${className}`}
13
+ fill="none"
14
+ stroke="currentColor"
15
+ viewBox="0 0 24 24"
16
+ >
17
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
18
+ </svg>
19
+ );
20
+
21
+ const ChevronDownIcon: React.FC<{ className?: string }> = ({ className = '' }) => (
22
+ <svg
23
+ className={`tree__icon ${className}`}
24
+ fill="none"
25
+ stroke="currentColor"
26
+ viewBox="0 0 24 24"
27
+ >
28
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
29
+ </svg>
30
+ );
31
+
32
+ const SearchIcon: React.FC<{ className?: string }> = ({ className = '' }) => (
33
+ <svg
34
+ className={`tree__icon ${className}`}
35
+ fill="none"
36
+ stroke="currentColor"
37
+ viewBox="0 0 24 24"
38
+ >
39
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
40
+ </svg>
41
+ );
42
+
43
+ const FilterIcon: React.FC<{ className?: string }> = ({ className = '' }) => (
44
+ <svg
45
+ className={`tree__icon ${className}`}
46
+ fill="none"
47
+ stroke="currentColor"
48
+ viewBox="0 0 24 24"
49
+ >
50
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.414A1 1 0 013 6.707V4z" />
51
+ </svg>
52
+ );
53
+
54
+ const FolderIcon: React.FC<{ className?: string }> = ({ className = '' }) => (
55
+ <svg
56
+ className={`tree__icon ${className}`}
57
+ fill="none"
58
+ stroke="currentColor"
59
+ viewBox="0 0 24 24"
60
+ >
61
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z" />
62
+ </svg>
63
+ );
64
+
65
+ const DocumentIcon: React.FC<{ className?: string }> = ({ className = '' }) => (
66
+ <svg
67
+ className={`tree__icon ${className}`}
68
+ fill="none"
69
+ stroke="currentColor"
70
+ viewBox="0 0 24 24"
71
+ >
72
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
73
+ </svg>
74
+ );
75
+
76
+ const CheckIcon: React.FC<{ className?: string }> = ({ className = '' }) => (
77
+ <svg
78
+ className={`tree__icon ${className}`}
79
+ fill="none"
80
+ stroke="currentColor"
81
+ viewBox="0 0 24 24"
82
+ >
83
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
84
+ </svg>
85
+ );
86
+
87
+ const MinusIcon: React.FC<{ className?: string }> = ({ className = '' }) => (
88
+ <svg
89
+ className={`tree__icon ${className}`}
90
+ fill="none"
91
+ stroke="currentColor"
92
+ viewBox="0 0 24 24"
93
+ >
94
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M20 12H4" />
95
+ </svg>
96
+ );
97
+
98
+ // Default color fallbacks for when theme is not available
99
+ const getDefaultColors = () => ({
100
+ surface: {
101
+ background: '#ffffff',
102
+ surface: '#f3f4f6',
103
+ border: '#d1d5db',
104
+ divider: '#e5e7eb'
105
+ },
106
+ text: {
107
+ primary: '#111827',
108
+ secondary: '#6b7280',
109
+ muted: '#9ca3af',
110
+ inverse: '#ffffff',
111
+ onPrimary: '#ffffff',
112
+ onSecondary: '#ffffff',
113
+ onSurface: '#111827'
114
+ },
115
+ interactive: {
116
+ hover: '#f3f4f6',
117
+ active: '#e5e7eb',
118
+ focus: '#3b82f6',
119
+ disabled: '#d1d5db'
120
+ },
121
+ primary: { 500: '#3b82f6' },
122
+ semantic: {
123
+ success: '#10b981',
124
+ warning: '#f59e0b',
125
+ error: '#ef4444',
126
+ info: '#3b82f6'
127
+ }
128
+ });
129
+
130
+ // Tree Search Bar
131
+ const TreeSearchBar: React.FC<{
132
+ searchable: boolean;
133
+ searchValue: string;
134
+ onSearchChange: (value: string) => void;
135
+ filterable: boolean;
136
+ theme: string;
137
+ size: 'sm' | 'md' | 'lg';
138
+ }> = ({
139
+ searchable,
140
+ searchValue,
141
+ onSearchChange,
142
+ filterable,
143
+ theme,
144
+ size
145
+ }) => {
146
+ const { getTheme } = useTheme();
147
+ const themeConfig = getTheme(theme);
148
+ const colors = themeConfig?.colors || getDefaultColors();
149
+
150
+ const sizeClasses = {
151
+ sm: 'h-8 text-sm px-3',
152
+ md: 'h-10 text-base px-4',
153
+ lg: 'h-12 text-lg px-5'
154
+ };
155
+
156
+ if (!searchable && !filterable) return null;
157
+
158
+ return (
159
+ <div className="tree__search-filter">
160
+ {searchable && (
161
+ <div className="tree__search">
162
+ <div className="tree__search-icon">
163
+ <SearchIcon className="tree__icon" />
164
+ </div>
165
+ <input
166
+ type="text"
167
+ value={searchValue}
168
+ onChange={(e) => onSearchChange(e.target.value)}
169
+ placeholder="Search nodes..."
170
+ className={`w-full ${sizeClasses[size]} pl-10 pr-4 rounded-lg border outline-none`}
171
+ style={{
172
+ backgroundColor: colors.surface.background,
173
+ border: `1px solid ${colors.surface.border}`,
174
+ color: colors.text.primary
175
+ }}
176
+ onFocus={(e) => {
177
+ e.target.style.borderColor = colors.primary[500];
178
+ e.target.style.boxShadow = `0 0 0 3px ${colors.primary[500]}20`;
179
+ }}
180
+ onBlur={(e) => {
181
+ e.target.style.borderColor = colors.surface.border;
182
+ e.target.style.boxShadow = 'none';
183
+ }}
184
+ />
185
+ </div>
186
+ )}
187
+
188
+ {filterable && (
189
+ <button className="tree__filter-button">
190
+ <FilterIcon className="tree__icon" />
191
+ <span>Filter</span>
192
+ </button>
193
+ )}
194
+ </div>
195
+ );
196
+ };
197
+
198
+ // Individual Tree Item Component
199
+ const TreeItem: React.FC<TreeItemProps> = ({
200
+ node,
201
+ level = 0,
202
+ expandedKeys,
203
+ selectedKeys,
204
+ selectable,
205
+ expandable,
206
+ onToggleExpand,
207
+ onSelectionChange,
208
+ onClick,
209
+ theme,
210
+ size,
211
+ variant,
212
+ // draggable = false, // TODO: Implement drag and drop
213
+ // onDragStart, // TODO: Implement drag and drop
214
+ // onDragEnd, // TODO: Implement drag and drop
215
+ // onDrop, // TODO: Implement drag and drop
216
+ showLines = true,
217
+ showIcons = true
218
+ }) => {
219
+ // const { getTheme } = useTheme();
220
+ // const themeConfig = getTheme(theme);
221
+ // const colors = themeConfig?.colors || getDefaultColors();
222
+
223
+ const isExpanded = expandedKeys.includes(node.id);
224
+ const isSelected = selectedKeys.includes(node.id);
225
+ const hasChildren = node.children && node.children.length > 0;
226
+ const isClickable = !!onClick;
227
+
228
+ const iconSizes = {
229
+ sm: 'w-3 h-3',
230
+ md: 'w-4 h-4',
231
+ lg: 'w-5 h-5'
232
+ };
233
+
234
+ const indentWidth = {
235
+ sm: 16,
236
+ md: 20,
237
+ lg: 24
238
+ };
239
+
240
+ const handleToggleExpand = (e: React.MouseEvent) => {
241
+ e.stopPropagation();
242
+ if (hasChildren && expandable) {
243
+ onToggleExpand?.(node.id, !isExpanded);
244
+ }
245
+ };
246
+
247
+ const handleSelectionChange = (e: React.MouseEvent) => {
248
+ e.stopPropagation();
249
+ if (selectable) {
250
+ onSelectionChange?.(node.id, !isSelected);
251
+ }
252
+ };
253
+
254
+ const handleClick = (e: React.MouseEvent) => {
255
+ if (isClickable) {
256
+ onClick?.(node, e);
257
+ }
258
+ };
259
+
260
+ const getNodeIcon = () => {
261
+ if (node.icon) {
262
+ return node.icon;
263
+ }
264
+ if (hasChildren) {
265
+ return <FolderIcon className={iconSizes[size]} />;
266
+ }
267
+ return <DocumentIcon className={iconSizes[size]} />;
268
+ };
269
+
270
+ const getCheckboxState = () => {
271
+ if (!hasChildren) return isSelected;
272
+
273
+ // For parent nodes, check if all children are selected
274
+ const selectedChildrenCount = node.children?.filter(child =>
275
+ selectedKeys.includes(child.id)
276
+ ).length || 0;
277
+
278
+ const totalChildren = node.children?.length || 0;
279
+
280
+ if (selectedChildrenCount === 0) return false;
281
+ if (selectedChildrenCount === totalChildren) return true;
282
+ return 'indeterminate'; // Some children selected
283
+ };
284
+
285
+ const checkboxState = getCheckboxState();
286
+
287
+ return (
288
+ <>
289
+ <div
290
+ className={`tree__node tree__node--${size} ${variant !== 'default' ? `tree__node--${variant}` : ''} ${
291
+ isSelected ? 'tree__node--selected' : ''
292
+ } ${isClickable ? 'tree__node--clickable' : ''}`}
293
+ style={{
294
+ paddingLeft: `${level * indentWidth[size] + 12}px`
295
+ }}
296
+ onClick={handleClick}
297
+ >
298
+ {/* Tree Lines */}
299
+ {showLines && level > 0 && (
300
+ <div
301
+ className="tree__line"
302
+ style={{
303
+ left: `${(level - 1) * indentWidth[size] + 12 + indentWidth[size] / 2 - 1}px`
304
+ }}
305
+ />
306
+ )}
307
+
308
+ {/* Expand/Collapse Button */}
309
+ <div className="tree__node-toggle-container">
310
+ {hasChildren && expandable ? (
311
+ <button
312
+ onClick={handleToggleExpand}
313
+ className={`tree__node-toggle tree__node-toggle--${size}`}
314
+ >
315
+ <div className={`tree__expand-icon ${isExpanded ? 'tree__expand-icon--expanded' : ''}`}>
316
+ {isExpanded ? (
317
+ <ChevronDownIcon className={`tree__icon tree__icon--${size}`} />
318
+ ) : (
319
+ <ChevronRightIcon className={`tree__icon tree__icon--${size}`} />
320
+ )}
321
+ </div>
322
+ </button>
323
+ ) : (
324
+ <div className={`tree__node-spacer tree__node-spacer--${size}`} />
325
+ )}
326
+ </div>
327
+
328
+ {/* Selection Checkbox */}
329
+ {selectable && (
330
+ <div className={`tree__checkbox tree__checkbox--${size}`}>
331
+ <button
332
+ onClick={handleSelectionChange}
333
+ className={`tree__checkbox-input ${
334
+ checkboxState ? 'tree__checkbox-input--checked' : ''
335
+ } ${
336
+ checkboxState === 'indeterminate' ? 'tree__checkbox-input--indeterminate' : ''
337
+ }`}
338
+ >
339
+ {checkboxState === true && <CheckIcon className="tree__checkbox-icon" />}
340
+ {checkboxState === 'indeterminate' && <MinusIcon className="tree__checkbox-icon" />}
341
+ </button>
342
+ </div>
343
+ )}
344
+
345
+ {/* Node Icon */}
346
+ {showIcons && (
347
+ <div className={`tree__node-icon tree__node-icon--${size}`}>
348
+ {getNodeIcon()}
349
+ </div>
350
+ )}
351
+
352
+ {/* Node Content */}
353
+ <div className={`tree__node-content tree__node-content--${size}`}>
354
+ <div className="tree__node-main">
355
+ <div className="tree__node-text">
356
+ <span className={`tree__node-label ${
357
+ isSelected ? 'tree__node-label--selected' : ''
358
+ }`}>
359
+ {node.label}
360
+ </span>
361
+ {node.description && (
362
+ <div className="tree__node-description">
363
+ {node.description}
364
+ </div>
365
+ )}
366
+ </div>
367
+
368
+ {/* Node Metadata */}
369
+ {node.metadata && (
370
+ <div className="tree__node-metadata">
371
+ {node.metadata.count !== undefined && (
372
+ <span className="tree__node-badge tree__node-badge--count">
373
+ {node.metadata.count}
374
+ </span>
375
+ )}
376
+ {node.metadata.status && (
377
+ <span className={`tree__node-badge tree__node-badge--status tree__node-badge--${node.metadata.status}`}>
378
+ {node.metadata.status}
379
+ </span>
380
+ )}
381
+ </div>
382
+ )}
383
+ </div>
384
+ </div>
385
+ </div>
386
+
387
+ {/* Child Nodes */}
388
+ {hasChildren && isExpanded && (
389
+ <>
390
+ {node.children!.map((childNode) => (
391
+ <TreeItem
392
+ key={childNode.id}
393
+ node={childNode}
394
+ level={level + 1}
395
+ expandedKeys={expandedKeys}
396
+ selectedKeys={selectedKeys}
397
+ selectable={selectable}
398
+ expandable={expandable}
399
+ onToggleExpand={onToggleExpand}
400
+ onSelectionChange={onSelectionChange}
401
+ onClick={onClick}
402
+ theme={theme}
403
+ size={size}
404
+ variant={variant}
405
+ showLines={showLines}
406
+ showIcons={showIcons}
407
+ />
408
+ ))}
409
+ </>
410
+ )}
411
+ </>
412
+ );
413
+ };
414
+
415
+ // Main Tree Component
416
+ export const Tree: React.FC<TreeProps> = ({
417
+ data,
418
+ expandedKeys = [],
419
+ selectedKeys = [],
420
+ onExpandedKeysChange,
421
+ onSelectedKeysChange,
422
+ onNodeClick,
423
+ selectable = false,
424
+ expandable = true,
425
+ // draggable = false, // TODO: Implement drag and drop
426
+ // onDragStart, // TODO: Implement drag and drop
427
+ // onDragEnd, // TODO: Implement drag and drop
428
+ // onDrop, // TODO: Implement drag and drop
429
+ searchable = false,
430
+ searchValue = '',
431
+ onSearchChange,
432
+ filterable = false,
433
+ // filters = [], // TODO: Implement filter functionality
434
+ // onFiltersChange, // TODO: Implement filter functionality
435
+ showLines = true,
436
+ showIcons = true,
437
+ expandAll = false,
438
+ collapseAll = false,
439
+ loading = false,
440
+ error = null,
441
+ emptyMessage = 'No data available',
442
+ className = '',
443
+ theme = 'stan-design',
444
+ size = 'md',
445
+ variant = 'default'
446
+ }) => {
447
+ const { getTheme } = useTheme();
448
+ const themeConfig = getTheme(theme);
449
+ const colors = themeConfig?.colors || getDefaultColors();
450
+
451
+ // Filter nodes based on search
452
+ const filteredData = useMemo(() => {
453
+ if (!searchable || !searchValue.trim()) return data;
454
+
455
+ const searchLower = searchValue.toLowerCase();
456
+
457
+ const filterNode = (node: TreeNode): TreeNode | null => {
458
+ const matchesSearch = node.label.toLowerCase().includes(searchLower) ||
459
+ node.description?.toLowerCase().includes(searchLower);
460
+
461
+ let filteredChildren: TreeNode[] = [];
462
+ if (node.children) {
463
+ filteredChildren = node.children
464
+ .map(child => filterNode(child))
465
+ .filter((child): child is TreeNode => child !== null);
466
+ }
467
+
468
+ // Include node if it matches search OR has matching children
469
+ if (matchesSearch || filteredChildren.length > 0) {
470
+ return {
471
+ ...node,
472
+ children: filteredChildren.length > 0 ? filteredChildren : node.children
473
+ };
474
+ }
475
+
476
+ return null;
477
+ };
478
+
479
+ return data
480
+ .map(node => filterNode(node))
481
+ .filter((node): node is TreeNode => node !== null);
482
+ }, [data, searchable, searchValue]);
483
+
484
+ // Auto-expand all nodes when expandAll changes
485
+ React.useEffect(() => {
486
+ if (expandAll) {
487
+ const getAllNodeIds = (nodes: TreeNode[]): string[] => {
488
+ const ids: string[] = [];
489
+ const traverse = (nodeList: TreeNode[]) => {
490
+ nodeList.forEach(node => {
491
+ if (node.children && node.children.length > 0) {
492
+ ids.push(node.id);
493
+ traverse(node.children);
494
+ }
495
+ });
496
+ };
497
+ traverse(nodes);
498
+ return ids;
499
+ };
500
+
501
+ const allIds = getAllNodeIds(data);
502
+ onExpandedKeysChange?.(allIds);
503
+ }
504
+ }, [expandAll, data, onExpandedKeysChange]);
505
+
506
+ // Auto-collapse all nodes when collapseAll changes
507
+ React.useEffect(() => {
508
+ if (collapseAll) {
509
+ onExpandedKeysChange?.([]);
510
+ }
511
+ }, [collapseAll, onExpandedKeysChange]);
512
+
513
+ const handleToggleExpand = useCallback((nodeId: string, expanded: boolean) => {
514
+ const newExpandedKeys = expanded
515
+ ? [...expandedKeys, nodeId]
516
+ : expandedKeys.filter(key => key !== nodeId);
517
+
518
+ onExpandedKeysChange?.(newExpandedKeys);
519
+ }, [expandedKeys, onExpandedKeysChange]);
520
+
521
+ const handleSelectionChange = useCallback((nodeId: string, selected: boolean) => {
522
+ const newSelectedKeys = selected
523
+ ? [...selectedKeys, nodeId]
524
+ : selectedKeys.filter(key => key !== nodeId);
525
+
526
+ onSelectedKeysChange?.(newSelectedKeys);
527
+ }, [selectedKeys, onSelectedKeysChange]);
528
+
529
+ if (loading) {
530
+ return (
531
+ <div
532
+ className={`p-8 text-center ${className}`}
533
+ style={{ color: colors.text.muted }}
534
+ >
535
+ Loading...
536
+ </div>
537
+ );
538
+ }
539
+
540
+ if (error) {
541
+ return (
542
+ <div
543
+ className={`p-8 text-center ${className}`}
544
+ style={{
545
+ color: colors.semantic.error,
546
+ backgroundColor: colors.semantic.error + '10',
547
+ border: `1px solid ${colors.semantic.error}30`,
548
+ borderRadius: '8px'
549
+ }}
550
+ >
551
+ {error}
552
+ </div>
553
+ );
554
+ }
555
+
556
+ return (
557
+ <div className={`tree__container tree__container--${size} ${variant !== 'default' ? `tree__container--${variant}` : ''} ${className}`}>
558
+ {/* Search Bar */}
559
+ <TreeSearchBar
560
+ searchable={searchable}
561
+ searchValue={searchValue}
562
+ onSearchChange={onSearchChange || (() => {})}
563
+ filterable={filterable}
564
+ theme={theme}
565
+ size={size}
566
+ />
567
+
568
+ {/* Tree */}
569
+ <div className={`tree__tree tree__tree--${size} ${variant !== 'default' ? `tree__tree--${variant}` : ''}`}>
570
+ {filteredData.length === 0 ? (
571
+ <div className="tree__empty">
572
+ {emptyMessage}
573
+ </div>
574
+ ) : (
575
+ <div className="tree__nodes">
576
+ {filteredData.map((node) => (
577
+ <TreeItem
578
+ key={node.id}
579
+ node={node}
580
+ level={0}
581
+ expandedKeys={expandedKeys}
582
+ selectedKeys={selectedKeys}
583
+ selectable={selectable}
584
+ expandable={expandable}
585
+ onToggleExpand={handleToggleExpand}
586
+ onSelectionChange={handleSelectionChange}
587
+ onClick={onNodeClick}
588
+ theme={theme}
589
+ size={size}
590
+ variant={variant}
591
+ showLines={showLines}
592
+ showIcons={showIcons}
593
+ />
594
+ ))}
595
+ </div>
596
+ )}
597
+ </div>
598
+ </div>
599
+ );
600
+ };
601
+
602
+ export default Tree;