@opencorestack/opengridx 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.
Files changed (130) hide show
  1. package/CHANGELOG.md +30 -1
  2. package/README.md +9 -0
  3. package/dist/index.d.ts +12 -1
  4. package/dist/opengridx.css +1 -1
  5. package/dist/opengridx.es.js +2505 -2450
  6. package/dist/opengridx.es.js.map +1 -1
  7. package/dist/opengridx.umd.js +12 -12
  8. package/dist/opengridx.umd.js.map +1 -1
  9. package/docs/API_REFERENCE.md +177 -0
  10. package/docs/README.md +60 -0
  11. package/docs/components/cell.md +44 -0
  12. package/docs/components/column-group-header.md +57 -0
  13. package/docs/components/column-resize.md +63 -0
  14. package/docs/components/column-visibility.md +61 -0
  15. package/docs/components/datagrid.md +70 -0
  16. package/docs/components/filter-panel.md +26 -0
  17. package/docs/components/header.md +39 -0
  18. package/docs/components/pagination.md +34 -0
  19. package/docs/components/row.md +31 -0
  20. package/docs/components/toolbar.md +40 -0
  21. package/docs/components/tooltip.md +68 -0
  22. package/docs/customization/slots-api.md +227 -0
  23. package/docs/customization/theming.md +293 -0
  24. package/docs/features/aggregation-pivot.md +79 -0
  25. package/docs/features/cell-spanning.md +520 -0
  26. package/docs/features/clipboard.md +76 -0
  27. package/docs/features/custom-pagination.md +143 -0
  28. package/docs/features/data-source.md +72 -0
  29. package/docs/features/editing-reordering.md +99 -0
  30. package/docs/features/export-guide.md +434 -0
  31. package/docs/features/filtering.md +83 -0
  32. package/docs/features/infinite-scroll.md +87 -0
  33. package/docs/features/list-view.md +65 -0
  34. package/docs/features/loading-states.md +68 -0
  35. package/docs/features/master-detail.md +46 -0
  36. package/docs/features/pinning.md +67 -0
  37. package/docs/features/selection.md +70 -0
  38. package/docs/features/sorting-pagination.md +66 -0
  39. package/docs/features/state-persistence.md +67 -0
  40. package/docs/features/tree-data-grouping.md +67 -0
  41. package/docs/features/virtualization.md +188 -0
  42. package/docs/roadmap.md +71 -0
  43. package/lib/components/Cell/Cell.css +119 -0
  44. package/lib/components/Cell/Cell.tsx +264 -0
  45. package/lib/components/Cell/GridEditInputCell.css +62 -0
  46. package/lib/components/Cell/GridEditInputCell.tsx +152 -0
  47. package/lib/components/ColumnGroupHeader/ColumnGroupHeader.css +67 -0
  48. package/lib/components/ColumnGroupHeader/ColumnGroupHeader.tsx +220 -0
  49. package/lib/components/ColumnResizeHandle/ColumnResizeHandle.css +31 -0
  50. package/lib/components/ColumnResizeHandle/ColumnResizeHandle.tsx +85 -0
  51. package/lib/components/ColumnVisibilityPanel/ColumnVisibilityPanel.css +137 -0
  52. package/lib/components/ColumnVisibilityPanel/ColumnVisibilityPanel.tsx +190 -0
  53. package/lib/components/DataGrid/DataGrid.css +224 -0
  54. package/lib/components/DataGrid/DataGrid.tsx +2269 -0
  55. package/lib/components/DetailPanel/DetailPanel.css +36 -0
  56. package/lib/components/DetailPanel/DetailPanel.tsx +34 -0
  57. package/lib/components/FilterPanel/FilterPanel.css +196 -0
  58. package/lib/components/FilterPanel/FilterPanel.tsx +214 -0
  59. package/lib/components/FilterPanel/index.ts +1 -0
  60. package/lib/components/Header/ColumnMenu.css +68 -0
  61. package/lib/components/Header/ColumnMenu.tsx +249 -0
  62. package/lib/components/Header/Header.css +224 -0
  63. package/lib/components/Header/Header.tsx +516 -0
  64. package/lib/components/ListView/ListView.css +112 -0
  65. package/lib/components/ListView/ListViewRow.tsx +63 -0
  66. package/lib/components/Pagination/Pagination.css +91 -0
  67. package/lib/components/Pagination/Pagination.tsx +151 -0
  68. package/lib/components/QuickFilter/QuickFilter.css +23 -0
  69. package/lib/components/QuickFilter/QuickFilter.tsx +79 -0
  70. package/lib/components/Row/Row.css +126 -0
  71. package/lib/components/Row/Row.tsx +377 -0
  72. package/lib/components/Skeleton/Skeleton.css +55 -0
  73. package/lib/components/Skeleton/Skeleton.tsx +22 -0
  74. package/lib/components/SkeletonRow/SkeletonRow.css +32 -0
  75. package/lib/components/SkeletonRow/SkeletonRow.tsx +89 -0
  76. package/lib/components/SkeletonRow/index.ts +1 -0
  77. package/lib/components/Toolbar/GlobalSearch.css +110 -0
  78. package/lib/components/Toolbar/GlobalSearch.tsx +167 -0
  79. package/lib/components/Toolbar/GridToolbar.css +221 -0
  80. package/lib/components/Toolbar/GridToolbar.tsx +658 -0
  81. package/lib/components/Toolbar/PivotPanel.css +212 -0
  82. package/lib/components/Toolbar/PivotPanel.tsx +239 -0
  83. package/lib/components/Tooltip/Tooltip.css +59 -0
  84. package/lib/components/Tooltip/Tooltip.tsx +106 -0
  85. package/lib/components/ui/Button.css +89 -0
  86. package/lib/components/ui/Button.tsx +39 -0
  87. package/lib/components/ui/Checkbox.css +71 -0
  88. package/lib/components/ui/Checkbox.tsx +66 -0
  89. package/lib/components/ui/DragHandleIcon.css +19 -0
  90. package/lib/components/ui/DragHandleIcon.tsx +18 -0
  91. package/lib/components/ui/ExpandIcon.css +38 -0
  92. package/lib/components/ui/ExpandIcon.tsx +75 -0
  93. package/lib/components/ui/Input.css +59 -0
  94. package/lib/components/ui/Input.tsx +45 -0
  95. package/lib/components/ui/index.ts +15 -0
  96. package/lib/hooks/core/useDataGrid.ts +392 -0
  97. package/lib/hooks/core/useGridApiRef.ts +10 -0
  98. package/lib/hooks/features/useAggregation.ts +143 -0
  99. package/lib/hooks/features/useGridClipboard.ts +133 -0
  100. package/lib/hooks/features/useGridDataSource.ts +190 -0
  101. package/lib/hooks/features/useGridEditing.ts +100 -0
  102. package/lib/hooks/features/useGridSpanning.ts +349 -0
  103. package/lib/hooks/features/usePivot.ts +174 -0
  104. package/lib/hooks/useColumnReorder.ts +114 -0
  105. package/lib/hooks/useRowGrouping.ts +302 -0
  106. package/lib/hooks/useRowReorder.ts +83 -0
  107. package/lib/hooks/useTreeData.ts +323 -0
  108. package/lib/index.ts +106 -0
  109. package/lib/state/index.ts +17 -0
  110. package/lib/state/types.ts +48 -0
  111. package/lib/state/useGridStateStorage.ts +113 -0
  112. package/lib/styles/base/reset.css +21 -0
  113. package/lib/styles/base/variables.css +161 -0
  114. package/lib/styles/opengridx.css +27 -0
  115. package/lib/styles/opengridx.css.d.ts +4 -0
  116. package/lib/theme/DataGridThemeProvider.tsx +276 -0
  117. package/lib/theme/defaultStyles.ts +0 -0
  118. package/lib/theme/index.ts +21 -0
  119. package/lib/theme/presets.ts +148 -0
  120. package/lib/theme/types.ts +155 -0
  121. package/lib/types/index.ts +764 -0
  122. package/lib/utils/export/exportToExcelAdvanced.ts +516 -0
  123. package/lib/utils/export/index.ts +550 -0
  124. package/lib/utils/filtering/index.ts +240 -0
  125. package/lib/utils/pinning/index.ts +282 -0
  126. package/lib/utils/sorting/index.ts +55 -0
  127. package/lib/utils/virtualization/index.ts +106 -0
  128. package/lib/vite-env.d.ts +1 -0
  129. package/llms.txt +2 -1
  130. package/package.json +12 -4
@@ -0,0 +1,167 @@
1
+ import React, { useState, useEffect, useRef, useCallback, useLayoutEffect } from 'react';
2
+
3
+
4
+ interface GlobalSearchProps {
5
+ value?: string;
6
+ onChange: (value: string) => void;
7
+ placeholder?: string;
8
+ debounceMs?: number;
9
+ }
10
+
11
+ function SearchIcon() {
12
+ return (
13
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
14
+ <circle cx="11" cy="11" r="8" />
15
+ <line x1="21" y1="21" x2="16.65" y2="16.65" />
16
+ </svg>
17
+ );
18
+ }
19
+
20
+ function CloseIcon() {
21
+ return (
22
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
23
+ <line x1="18" y1="6" x2="6" y2="18" />
24
+ <line x1="6" y1="6" x2="18" y2="18" />
25
+ </svg>
26
+ );
27
+ }
28
+
29
+ export function GlobalSearch({ value = '', onChange, placeholder = 'Search...', debounceMs = 250 }: GlobalSearchProps) {
30
+ const [isExpanded, setIsExpanded] = useState(() => value.length > 0);
31
+ // Fully uncontrolled: localValue is the single source of truth.
32
+ const [localValue, setLocalValue] = useState(value);
33
+ const inputRef = useRef<HTMLInputElement>(null);
34
+ const containerRef = useRef<HTMLDivElement>(null);
35
+ // Keep onChange always current without adding it to effect deps
36
+ const onChangeRef = useRef(onChange);
37
+ onChangeRef.current = onChange;
38
+ // Track the last value we emitted upward
39
+ const lastEmittedRef = useRef(value);
40
+ // Track the last incoming prop value to detect external resets
41
+ const lastIncomingValueRef = useRef(value);
42
+ // Track whether input was focused BEFORE a re-render so we can restore it
43
+ const wasFocusedRef = useRef(false);
44
+
45
+ // ── Focus preservation across re-renders ─────────────────────────────────
46
+ // When the parent updates filterModel (triggered by our debounce), React
47
+ // re-renders the entire tree. Even though the input element stays mounted,
48
+ // the browser can lose focus during heavy reconciliation. We detect this
49
+ // via useLayoutEffect (runs synchronously after DOM mutations, before paint)
50
+ // and immediately restore focus without any visual flicker.
51
+ useLayoutEffect(() => {
52
+ if (wasFocusedRef.current && document.activeElement !== inputRef.current) {
53
+ inputRef.current?.focus();
54
+ }
55
+ });
56
+
57
+ // ── External reset detection ──────────────────────────────────────────────
58
+ // Only responds when the PARENT programmatically changes the value
59
+ // (e.g. "Clear all filters" button) — not from our own typing.
60
+ useEffect(() => {
61
+ if (value === lastIncomingValueRef.current) return;
62
+ lastIncomingValueRef.current = value;
63
+
64
+ if (value !== lastEmittedRef.current) {
65
+ setLocalValue(value);
66
+ lastEmittedRef.current = value;
67
+ if (!value) {
68
+ wasFocusedRef.current = false;
69
+ setIsExpanded(false);
70
+ } else {
71
+ setIsExpanded(true);
72
+ }
73
+ }
74
+ }, [value]);
75
+
76
+ // ── Debounced upward notification ─────────────────────────────────────────
77
+ useEffect(() => {
78
+ const handler = setTimeout(() => {
79
+ if (localValue !== lastEmittedRef.current) {
80
+ lastEmittedRef.current = localValue;
81
+ onChangeRef.current(localValue);
82
+ }
83
+ }, debounceMs);
84
+ return () => clearTimeout(handler);
85
+ }, [localValue, debounceMs]);
86
+
87
+ const handleExpand = useCallback(() => {
88
+ setIsExpanded(true);
89
+ requestAnimationFrame(() => inputRef.current?.focus());
90
+ }, []);
91
+
92
+ const handleClear = useCallback((e: React.MouseEvent) => {
93
+ e.stopPropagation();
94
+ setLocalValue('');
95
+ lastEmittedRef.current = '';
96
+ onChangeRef.current('');
97
+ inputRef.current?.focus();
98
+ }, []);
99
+
100
+ const handleFocus = useCallback(() => {
101
+ wasFocusedRef.current = true;
102
+ setIsExpanded(true);
103
+ }, []);
104
+
105
+ // Blur: defer 150ms to allow focus to move within the container first
106
+ // (e.g. clicking the clear button) before deciding to collapse.
107
+ const handleBlur = useCallback(() => {
108
+ wasFocusedRef.current = false;
109
+ setTimeout(() => {
110
+ if (
111
+ containerRef.current &&
112
+ document.activeElement &&
113
+ containerRef.current.contains(document.activeElement)
114
+ ) {
115
+ // Focus is still inside — mark as focused again and abort
116
+ wasFocusedRef.current = true;
117
+ return;
118
+ }
119
+ if (!localValue) {
120
+ setIsExpanded(false);
121
+ }
122
+ }, 150);
123
+ }, [localValue]);
124
+
125
+ // ── Click outside ─────────────────────────────────────────────────────────
126
+ useEffect(() => {
127
+ const handleClickOutside = (event: MouseEvent) => {
128
+ if (containerRef.current && !containerRef.current.contains(event.target as Node)) {
129
+ if (!localValue) {
130
+ setIsExpanded(false);
131
+ }
132
+ }
133
+ };
134
+ document.addEventListener('mousedown', handleClickOutside);
135
+ return () => document.removeEventListener('mousedown', handleClickOutside);
136
+ }, [localValue]);
137
+
138
+ return (
139
+ <div
140
+ ref={containerRef}
141
+ className={`ogx-global-search${isExpanded ? ' ogx-global-search--expanded' : ''}`}
142
+ onClick={!isExpanded ? handleExpand : undefined}
143
+ >
144
+ <div className="ogx-global-search__icon-wrapper">
145
+ <SearchIcon />
146
+ </div>
147
+ <input
148
+ ref={inputRef}
149
+ id="ogx-global-search-input"
150
+ name="ogx-global-search"
151
+ className="ogx-global-search__input"
152
+ value={localValue}
153
+ onChange={(e) => setLocalValue(e.target.value)}
154
+ onFocus={handleFocus}
155
+ onBlur={handleBlur}
156
+ placeholder={placeholder}
157
+ aria-label="Global Search"
158
+ autoComplete="off"
159
+ />
160
+ {localValue && (
161
+ <button className="ogx-global-search__clear" onClick={handleClear} aria-label="Clear search">
162
+ <CloseIcon />
163
+ </button>
164
+ )}
165
+ </div>
166
+ );
167
+ }
@@ -0,0 +1,221 @@
1
+ .ogx-toolbar {
2
+ display: flex;
3
+ align-items: center;
4
+ gap: var(--ogx-spacing-sm);
5
+ padding: var(--ogx-spacing-sm) var(--ogx-spacing-sm);
6
+ border-bottom: var(--ogx-border-width-thin) solid var(--ogx-grid-border-color);
7
+ background: var(--ogx-grid-header-background);
8
+ min-height: 44px;
9
+ position: relative;
10
+ z-index: 100;
11
+ }
12
+ .ogx-toolbar__left {
13
+ display: flex;
14
+ align-items: center;
15
+ gap: var(--ogx-spacing-sm);
16
+ }
17
+ .ogx-toolbar__spacer {
18
+ flex: 1;
19
+ }
20
+ .ogx-toolbar__actions {
21
+ display: flex;
22
+ align-items: center;
23
+ gap: var(--ogx-spacing-xs);
24
+ flex-wrap: nowrap;
25
+ flex-shrink: 0;
26
+ padding-right: 5px;
27
+ }
28
+ .ogx-toolbar__dropdown-wrapper {
29
+ position: relative;
30
+ }
31
+ .ogx-toolbar__icon-btn {
32
+ display: inline-flex;
33
+ align-items: center;
34
+ justify-content: center;
35
+ width: 34px;
36
+ height: 34px;
37
+ padding: 0;
38
+ border: none;
39
+ border-radius: 8px;
40
+ background: transparent;
41
+ color: var(--ogx-grid-header-text);
42
+ cursor: pointer;
43
+ transition: background 0.15s, color 0.15s;
44
+ position: relative;
45
+ }
46
+ .ogx-toolbar__icon-btn:hover {
47
+ background: var(--ogx-grid-header-hover-background);
48
+ }
49
+ .ogx-toolbar__icon-btn--active {
50
+ background: var(--ogx-grid-header-hover-background);
51
+ outline: none;
52
+ }
53
+ .ogx-toolbar__icon-btn:focus {
54
+ outline: none;
55
+ }
56
+ .ogx-toolbar__icon-btn:focus-visible {
57
+ outline: 2px solid var(--ogx-color-primary);
58
+ outline-offset: 1px;
59
+ }
60
+ .ogx-toolbar__dot {
61
+ position: absolute;
62
+ top: 4px;
63
+ right: 4px;
64
+ width: 8px;
65
+ height: 8px;
66
+ border-radius: 50%;
67
+ background: var(--ogx-color-success, #10b981);
68
+ border: 1.5px solid var(--ogx-grid-header-background, #fff);
69
+ pointer-events: none;
70
+ }
71
+ .ogx-toolbar__panel {
72
+ position: fixed;
73
+ width: 380px;
74
+ max-width: calc(100vw - 24px);
75
+ background: var(--ogx-overlay-background, var(--ogx-grid-background));
76
+ border: var(--ogx-border-width-thin) solid var(--ogx-overlay-border, var(--ogx-grid-border-color));
77
+ border-radius: var(--ogx-border-radius-lg);
78
+ box-shadow: var(--ogx-overlay-shadow, var(--ogx-shadow-lg));
79
+ z-index: 9999;
80
+ overflow: hidden;
81
+ animation: ogx-panel-in 0.15s ease-out;
82
+ }
83
+ @keyframes ogx-panel-in {
84
+ from { opacity: 0; transform: translateY(-6px) scale(0.98); }
85
+ to { opacity: 1; transform: translateY(0) scale(1); }
86
+ }
87
+ .ogx-toolbar__panel-header {
88
+ display: flex;
89
+ align-items: center;
90
+ justify-content: space-between;
91
+ padding: var(--ogx-spacing-sm) var(--ogx-spacing-md);
92
+ border-bottom: var(--ogx-border-width-thin) solid var(--ogx-overlay-border, var(--ogx-grid-border-color));
93
+ background: var(--ogx-grid-header-background);
94
+ }
95
+ .ogx-toolbar__panel-title {
96
+ display: flex;
97
+ align-items: center;
98
+ gap: var(--ogx-spacing-xs);
99
+ font-family: var(--ogx-font-family);
100
+ font-size: var(--ogx-font-size-sm);
101
+ font-weight: 600;
102
+ color: var(--ogx-grid-header-text);
103
+ }
104
+ .ogx-toolbar__clear-btn {
105
+ padding: 2px 8px;
106
+ border: var(--ogx-border-width-thin) solid var(--ogx-border-color);
107
+ border-radius: var(--ogx-border-radius-sm);
108
+ background: transparent;
109
+ color: var(--ogx-color-error, #ef4444);
110
+ font-family: var(--ogx-font-family);
111
+ font-size: var(--ogx-font-size-xs);
112
+ font-weight: 500;
113
+ cursor: pointer;
114
+ transition: background 0.15s, border-color 0.15s;
115
+ }
116
+ .ogx-toolbar__clear-btn:hover {
117
+ background: var(--ogx-toolbar-btn-danger-bg, rgba(239, 68, 68, 0.08));
118
+ border-color: var(--ogx-color-error, #ef4444);
119
+ }
120
+ .ogx-toolbar__close-btn {
121
+ padding: 2px 10px;
122
+ border: var(--ogx-border-width-thin) solid var(--ogx-border-color);
123
+ border-radius: var(--ogx-border-radius-sm);
124
+ background: transparent;
125
+ color: var(--ogx-grid-header-text);
126
+ font-family: var(--ogx-font-family);
127
+ font-size: var(--ogx-font-size-xs);
128
+ font-weight: 500;
129
+ cursor: pointer;
130
+ transition: background 0.15s, border-color 0.15s;
131
+ }
132
+ .ogx-toolbar__close-btn:hover {
133
+ background: var(--ogx-grid-header-hover-background);
134
+ border-color: var(--ogx-color-primary);
135
+ color: var(--ogx-color-primary);
136
+ }
137
+ .ogx-toolbar__panel-body {
138
+ padding: var(--ogx-spacing-xs) 0;
139
+ max-height: 360px;
140
+ overflow-y: auto;
141
+ }
142
+ .ogx-toolbar__empty {
143
+ padding: var(--ogx-spacing-md) var(--ogx-spacing-md);
144
+ font-family: var(--ogx-font-family);
145
+ font-size: var(--ogx-font-size-sm);
146
+ color: var(--ogx-grid-header-text);
147
+ line-height: 1.5;
148
+ text-align: center;
149
+ }
150
+ .ogx-toolbar__empty code {
151
+ font-family: var(--ogx-font-family-mono);
152
+ font-size: 0.9em;
153
+ background: var(--ogx-grid-header-background);
154
+ padding: 1px 4px;
155
+ border-radius: 3px;
156
+ }
157
+ .ogx-toolbar__agg-row {
158
+ display: flex;
159
+ align-items: center;
160
+ gap: var(--ogx-spacing-md);
161
+ padding: 8px var(--ogx-spacing-md);
162
+ border-bottom: var(--ogx-border-width-thin) solid var(--ogx-overlay-border, var(--ogx-grid-border-color));
163
+ transition: background 0.1s;
164
+ }
165
+ .ogx-toolbar__agg-row:last-child {
166
+ border-bottom: none;
167
+ }
168
+ .ogx-toolbar__agg-row:hover {
169
+ background: var(--ogx-overlay-item-hover-bg, var(--ogx-grid-row-hover-background));
170
+ }
171
+ .ogx-toolbar__agg-label {
172
+ flex: 0 0 100px;
173
+ font-family: var(--ogx-font-family);
174
+ font-size: var(--ogx-font-size-xs);
175
+ font-weight: 500;
176
+ color: var(--ogx-grid-row-text);
177
+ overflow: hidden;
178
+ text-overflow: ellipsis;
179
+ white-space: nowrap;
180
+ }
181
+ .ogx-toolbar__agg-pills {
182
+ display: flex;
183
+ gap: 4px;
184
+ flex-wrap: wrap;
185
+ }
186
+ .ogx-toolbar__pill {
187
+ display: inline-flex;
188
+ align-items: center;
189
+ padding: 3px 6px;
190
+ border: var(--ogx-border-width-thin) solid var(--ogx-overlay-border, var(--ogx-border-color));
191
+ border-radius: 999px;
192
+ background: transparent;
193
+ color: var(--ogx-grid-row-text);
194
+ font-family: var(--ogx-font-family-mono, monospace);
195
+ font-size: 10px;
196
+ font-weight: 500;
197
+ cursor: pointer;
198
+ text-transform: uppercase;
199
+ letter-spacing: 0.03em;
200
+ transition: background 0.15s, border-color 0.15s, color 0.15s;
201
+ line-height: 1;
202
+ white-space: nowrap;
203
+ }
204
+ .ogx-toolbar__pill:hover {
205
+ background: var(--ogx-grid-header-hover-background);
206
+ border-color: var(--ogx-color-primary);
207
+ color: var(--ogx-color-primary);
208
+ }
209
+ .ogx-toolbar__pill--active {
210
+ background: var(--ogx-toolbar-chip-active-bg, var(--ogx-color-primary));
211
+ border-color: var(--ogx-toolbar-chip-active-bg, var(--ogx-color-primary));
212
+ color: var(--ogx-toolbar-chip-active-text, #fff);
213
+ font-weight: 700;
214
+ }
215
+ .ogx-toolbar__pill--active:hover {
216
+ background: var(--ogx-toolbar-btn-primary-hover, var(--ogx-color-primary-dark));
217
+ border-color: var(--ogx-toolbar-btn-primary-hover, var(--ogx-color-primary-dark));
218
+ color: var(--ogx-toolbar-btn-primary-text, #fff);
219
+ }
220
+
221
+ /* Tooltip classes removed - migrated to Tooltip component */