ywana-core8 0.1.75 → 0.1.76

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 (122) hide show
  1. package/ACCORDION_EVALUATION.md +583 -0
  2. package/CHECKBOX_EVALUATION.md +273 -0
  3. package/CHIP_EVALUATION.md +542 -0
  4. package/COLOR_EVALUATION.md +524 -0
  5. package/COMPONENTS_EVALUATION.md +477 -0
  6. package/FORM_EVALUATION.md +459 -0
  7. package/HEADER_EVALUATION.md +436 -0
  8. package/ICON_EVALUATION.md +254 -0
  9. package/LIST_EVALUATION.md +574 -0
  10. package/PROGRESS_EVALUATION.md +450 -0
  11. package/RADIO_EVALUATION.md +439 -0
  12. package/RADIO_VISUAL_FIX.md +183 -0
  13. package/SECTION_IMPROVEMENTS.md +153 -0
  14. package/SWITCH_EVALUATION.md +335 -0
  15. package/SWITCH_VISUAL_FIX.md +232 -0
  16. package/TAB_EVALUATION.md +626 -0
  17. package/TEXTFIELD_EVALUATION.md +747 -0
  18. package/TOOLTIP_FIX.md +157 -0
  19. package/TREE_EVALUATION.md +708 -0
  20. package/dist/index.cjs +7900 -1615
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.css +6094 -1122
  23. package/dist/index.css.map +1 -1
  24. package/dist/index.modern.js +7929 -1645
  25. package/dist/index.modern.js.map +1 -1
  26. package/dist/index.umd.js +7900 -1615
  27. package/dist/index.umd.js.map +1 -1
  28. package/jest.config.js +24 -0
  29. package/package.json +10 -1
  30. package/src/html/accordion.css +208 -4
  31. package/src/html/accordion.example.js +390 -0
  32. package/src/html/accordion.js +284 -28
  33. package/src/html/accordion.unit.test.js +334 -0
  34. package/src/html/button.css +157 -16
  35. package/src/html/button.example.js +374 -0
  36. package/src/html/button.js +240 -60
  37. package/src/html/button.test.js +422 -0
  38. package/src/html/checkbox.css +74 -2
  39. package/src/html/checkbox.example.js +316 -0
  40. package/src/html/checkbox.js +113 -26
  41. package/src/html/checkbox.test.js +285 -0
  42. package/src/html/chip.css +230 -19
  43. package/src/html/chip.example.js +355 -0
  44. package/src/html/chip.js +321 -25
  45. package/src/html/chip.test.js +425 -0
  46. package/src/html/color.css +435 -6
  47. package/src/html/color.example.js +527 -0
  48. package/src/html/color.js +458 -9
  49. package/src/html/color.test.js +362 -4
  50. package/src/html/components.example.js +492 -0
  51. package/src/html/components_enhanced.test.js +581 -0
  52. package/src/html/form.css +70 -3
  53. package/src/html/form.example.js +385 -0
  54. package/src/html/form.js +232 -34
  55. package/src/html/form.test.js +369 -0
  56. package/src/html/header2.css +264 -0
  57. package/src/html/header2.example.js +411 -0
  58. package/src/html/header2.js +203 -0
  59. package/src/html/header2.test.js +377 -0
  60. package/src/html/icon.css +20 -2
  61. package/src/html/icon.example.js +268 -0
  62. package/src/html/icon.js +86 -16
  63. package/src/html/icon.test.js +231 -0
  64. package/src/html/index.js +1 -1
  65. package/src/html/list.css +393 -1
  66. package/src/html/list.example.js +404 -0
  67. package/src/html/list.js +583 -40
  68. package/src/html/list.test.js +383 -0
  69. package/src/html/progress.css +707 -17
  70. package/src/html/progress.example.js +424 -0
  71. package/src/html/progress.js +906 -9
  72. package/src/html/progress.test.js +313 -0
  73. package/src/html/property.css +399 -0
  74. package/src/html/property.example.js +553 -0
  75. package/src/html/property.js +393 -15
  76. package/src/html/property.test.js +351 -2
  77. package/src/html/radio-visual-test.js +289 -0
  78. package/src/html/radio.css +137 -11
  79. package/src/html/radio.example.js +389 -0
  80. package/src/html/radio.js +234 -10
  81. package/src/html/radio.test.js +318 -0
  82. package/src/html/section.example.js +99 -0
  83. package/src/html/section.js +40 -3
  84. package/src/html/section.test.js +131 -0
  85. package/src/html/selector.css +329 -3
  86. package/src/html/selector.js +369 -23
  87. package/src/html/switch-debug.js +197 -0
  88. package/src/html/switch-test-visual.js +294 -0
  89. package/src/html/switch.css +200 -0
  90. package/src/html/switch.example.js +461 -0
  91. package/src/html/switch.js +283 -23
  92. package/src/html/switch.test.js +355 -0
  93. package/src/html/tab.css +288 -0
  94. package/src/html/tab.example.js +446 -0
  95. package/src/html/tab.js +387 -22
  96. package/src/html/tab_enhanced.js +378 -0
  97. package/src/html/tab_enhanced.test.js +504 -0
  98. package/src/html/table2.css +576 -0
  99. package/src/html/table2.example.js +703 -0
  100. package/src/html/table2.js +1252 -0
  101. package/src/html/table2.migration.md +328 -0
  102. package/src/html/table2.test.js +582 -0
  103. package/src/html/text.css +375 -0
  104. package/src/html/text.js +311 -20
  105. package/src/html/textfield2.css +842 -0
  106. package/src/html/textfield2.example.js +499 -0
  107. package/src/html/textfield2.js +1130 -0
  108. package/src/html/textfield2.test.js +950 -0
  109. package/src/html/thumbnail.css +289 -2
  110. package/src/html/thumbnail.js +214 -9
  111. package/src/html/tokenfield.css +449 -1
  112. package/src/html/tokenfield.example.js +503 -0
  113. package/src/html/tokenfield.js +561 -56
  114. package/src/html/tokenfield.test.js +423 -0
  115. package/src/html/tooltip-positioning-demo.js +187 -0
  116. package/src/html/tooltip.css +25 -2
  117. package/src/html/tree.css +228 -0
  118. package/src/html/tree.example.js +475 -0
  119. package/src/html/tree.js +712 -28
  120. package/src/html/tree_enhanced.test.js +495 -0
  121. package/table2.test.js +454 -0
  122. package/src/html/button.tsx +0 -38
package/table2.test.js ADDED
@@ -0,0 +1,454 @@
1
+ import React from 'react'
2
+ import { DataTable2 } from './table2'
3
+
4
+ // Pruebas unitarias para el componente DataTable2 mejorado
5
+ describe('Enhanced DataTable2 Component', () => {
6
+ // Mock de los componentes dependientes
7
+ const mockIcon = jest.fn()
8
+ const mockText = jest.fn()
9
+ const mockCheckBox = jest.fn()
10
+ const mockTextField = jest.fn()
11
+ const mockDropDown = jest.fn()
12
+ const mockEmptyMessage = jest.fn()
13
+
14
+ beforeEach(() => {
15
+ jest.clearAllMocks()
16
+
17
+ // Mock de componentes
18
+ jest.doMock('./icon', () => ({ Icon: mockIcon }))
19
+ jest.doMock('./text', () => ({ Text: mockText }))
20
+ jest.doMock('./checkbox', () => ({ CheckBox: mockCheckBox }))
21
+ jest.doMock('./textfield', () => ({ TextField: mockTextField, DropDown: mockDropDown }))
22
+ jest.doMock('../widgets/empty/EmptyMessage', () => ({ EmptyMessage: mockEmptyMessage }))
23
+
24
+ // Mock de console.warn
25
+ jest.spyOn(console, 'warn').mockImplementation(() => {})
26
+
27
+ // Mock de navigator.clipboard
28
+ global.navigator = {
29
+ clipboard: {
30
+ writeText: jest.fn().mockResolvedValue(undefined)
31
+ },
32
+ userLanguage: 'en-US',
33
+ language: 'en-US'
34
+ }
35
+
36
+ // Mock de URL.createObjectURL
37
+ global.URL = {
38
+ createObjectURL: jest.fn().mockReturnValue('mock-url'),
39
+ revokeObjectURL: jest.fn()
40
+ }
41
+
42
+ // Mock de Blob
43
+ global.Blob = jest.fn().mockImplementation((content, options) => ({
44
+ content,
45
+ options
46
+ }))
47
+
48
+ // Mock de document.createElement
49
+ const mockAnchor = {
50
+ href: '',
51
+ download: '',
52
+ click: jest.fn()
53
+ }
54
+ jest.spyOn(document, 'createElement').mockReturnValue(mockAnchor)
55
+ })
56
+
57
+ afterEach(() => {
58
+ console.warn.mockRestore()
59
+ document.createElement.mockRestore()
60
+ })
61
+
62
+ // DataTable2 Component Tests
63
+ describe('DataTable2 Component', () => {
64
+ const mockColumns = [
65
+ { id: 'name', label: 'Name', type: 'String', sortable: true },
66
+ { id: 'age', label: 'Age', type: 'Number', sortable: true },
67
+ { id: 'email', label: 'Email', type: 'String', filterable: true }
68
+ ]
69
+
70
+ const mockRows = [
71
+ { id: 1, name: 'John Doe', age: 30, email: 'john@example.com' },
72
+ { id: 2, name: 'Jane Smith', age: 25, email: 'jane@example.com' },
73
+ { id: 3, name: 'Bob Johnson', age: 35, email: 'bob@example.com' }
74
+ ]
75
+
76
+ test('component exports correctly', () => {
77
+ expect(DataTable2).toBeDefined()
78
+ expect(typeof DataTable2).toBe('function')
79
+ })
80
+
81
+ test('component has correct PropTypes', () => {
82
+ expect(DataTable2.propTypes).toBeDefined()
83
+ expect(DataTable2.propTypes.columns).toBeDefined()
84
+ expect(DataTable2.propTypes.rows).toBeDefined()
85
+ expect(DataTable2.propTypes.onRowSelection).toBeDefined()
86
+ expect(DataTable2.propTypes.onSort).toBeDefined()
87
+ expect(DataTable2.propTypes.onCheckAll).toBeDefined()
88
+ expect(DataTable2.propTypes.editable).toBeDefined()
89
+ expect(DataTable2.propTypes.outlined).toBeDefined()
90
+ expect(DataTable2.propTypes.expanded).toBeDefined()
91
+ expect(DataTable2.propTypes.multisort).toBeDefined()
92
+ expect(DataTable2.propTypes.filterable).toBeDefined()
93
+ // New props
94
+ expect(DataTable2.propTypes.loading).toBeDefined()
95
+ expect(DataTable2.propTypes.skeleton).toBeDefined()
96
+ expect(DataTable2.propTypes.searchable).toBeDefined()
97
+ expect(DataTable2.propTypes.exportable).toBeDefined()
98
+ expect(DataTable2.propTypes.virtualScrolling).toBeDefined()
99
+ })
100
+
101
+ test('component has correct defaultProps', () => {
102
+ expect(DataTable2.defaultProps).toBeDefined()
103
+ expect(DataTable2.defaultProps.columns).toEqual([])
104
+ expect(DataTable2.defaultProps.rows).toEqual([])
105
+ expect(DataTable2.defaultProps.expanded).toBe(false)
106
+ expect(DataTable2.defaultProps.emptyMessage).toBe("No Results Found")
107
+ expect(DataTable2.defaultProps.emptyIcon).toBe("search_off")
108
+ expect(DataTable2.defaultProps.multisort).toBe(false)
109
+ expect(DataTable2.defaultProps.filterable).toBe(false)
110
+ // New defaults
111
+ expect(DataTable2.defaultProps.loading).toBe(false)
112
+ expect(DataTable2.defaultProps.skeleton).toBe(false)
113
+ expect(DataTable2.defaultProps.striped).toBe(false)
114
+ expect(DataTable2.defaultProps.hover).toBe(true)
115
+ expect(DataTable2.defaultProps.responsive).toBe(true)
116
+ expect(DataTable2.defaultProps.stickyHeader).toBe(true)
117
+ expect(DataTable2.defaultProps.selectionMode).toBe('single')
118
+ expect(DataTable2.defaultProps.sortMode).toBe('single')
119
+ })
120
+
121
+ test('validates props correctly', () => {
122
+ const validateProps = (columns, rows, virtualScrolling, pageSize) => {
123
+ if (!Array.isArray(columns)) {
124
+ console.warn('DataTable2: columns prop must be an array')
125
+ }
126
+ if (!Array.isArray(rows)) {
127
+ console.warn('DataTable2: rows prop must be an array')
128
+ }
129
+ if (virtualScrolling && !pageSize) {
130
+ console.warn('DataTable2: pageSize is required when virtualScrolling is enabled')
131
+ }
132
+ }
133
+
134
+ // Invalid columns prop
135
+ validateProps('not an array', [], false, null)
136
+ expect(console.warn).toHaveBeenCalledWith('DataTable2: columns prop must be an array')
137
+
138
+ console.warn.mockClear()
139
+
140
+ // Invalid rows prop
141
+ validateProps([], 'not an array', false, null)
142
+ expect(console.warn).toHaveBeenCalledWith('DataTable2: rows prop must be an array')
143
+
144
+ console.warn.mockClear()
145
+
146
+ // Virtual scrolling without pageSize
147
+ validateProps([], [], true, null)
148
+ expect(console.warn).toHaveBeenCalledWith('DataTable2: pageSize is required when virtualScrolling is enabled')
149
+
150
+ console.warn.mockClear()
151
+
152
+ // Valid props
153
+ validateProps(mockColumns, mockRows, false, null)
154
+ expect(console.warn).not.toHaveBeenCalled()
155
+ })
156
+
157
+ test('handles sort correctly (maintaining original behavior)', () => {
158
+ const changeSort = (id, sortDir, sortMode, multisort, setSortDir) => {
159
+ if (sortMode === 'none') return
160
+
161
+ if (sortMode === 'multiple' || multisort) {
162
+ const nextDir = sortDir[id] ? sortDir[id] * -1 : 1
163
+ const next = Object.assign({}, sortDir, { [id]: nextDir })
164
+ setSortDir(next)
165
+ } else {
166
+ const nextDir = sortDir[id] ? sortDir[id] * -1 : 1
167
+ setSortDir({ [id]: nextDir })
168
+ }
169
+ }
170
+
171
+ const mockSetSortDir = jest.fn()
172
+
173
+ // Single sort mode
174
+ changeSort('name', {}, 'single', false, mockSetSortDir)
175
+ expect(mockSetSortDir).toHaveBeenCalledWith({ name: 1 })
176
+
177
+ mockSetSortDir.mockClear()
178
+
179
+ // Multiple sort mode
180
+ changeSort('age', { name: 1 }, 'multiple', false, mockSetSortDir)
181
+ expect(mockSetSortDir).toHaveBeenCalledWith({ name: 1, age: 1 })
182
+
183
+ mockSetSortDir.mockClear()
184
+
185
+ // Reverse sort
186
+ changeSort('name', { name: 1 }, 'single', false, mockSetSortDir)
187
+ expect(mockSetSortDir).toHaveBeenCalledWith({ name: -1 })
188
+
189
+ mockSetSortDir.mockClear()
190
+
191
+ // No sort mode
192
+ changeSort('name', {}, 'none', false, mockSetSortDir)
193
+ expect(mockSetSortDir).not.toHaveBeenCalled()
194
+ })
195
+
196
+ test('handles multiSort correctly (maintaining original logic)', () => {
197
+ const multiSort = (array, sortObject = {}) => {
198
+ const sortKeys = Object.keys(sortObject);
199
+
200
+ if (!sortKeys.length) {
201
+ return array;
202
+ }
203
+
204
+ const keySort = (a, b, direction) => {
205
+ direction = direction !== null ? direction : 1;
206
+
207
+ // check if a and b are numbers and compare as numbers
208
+ if (!isNaN(a) && !isNaN(b)) {
209
+ a = Number(a);
210
+ b = Number(b);
211
+ }
212
+
213
+ // If b > a, multiply by -1 to get the reverse direction.
214
+ return a > b ? direction : -1 * direction;
215
+ };
216
+
217
+ return array.sort((a, b) => {
218
+ let sorted = 0;
219
+ let index = 0;
220
+
221
+ // Loop until sorted (-1 or 1) or until the sort keys have been processed.
222
+ while (sorted === 0 && index < sortKeys.length) {
223
+ const key = sortKeys[index];
224
+ if (key) {
225
+ const direction = sortObject[key];
226
+ sorted = keySort(a[key], b[key], direction);
227
+ index++;
228
+ }
229
+ }
230
+
231
+ return sorted;
232
+ });
233
+ };
234
+
235
+ const testData = [
236
+ { name: 'Charlie', age: 30 },
237
+ { name: 'Alice', age: 25 },
238
+ { name: 'Bob', age: 35 }
239
+ ]
240
+
241
+ // No sort
242
+ expect(multiSort([...testData], {})).toEqual(testData)
243
+
244
+ // Sort by name ascending
245
+ const sortedByName = multiSort([...testData], { name: 1 })
246
+ expect(sortedByName[0].name).toBe('Alice')
247
+ expect(sortedByName[1].name).toBe('Bob')
248
+ expect(sortedByName[2].name).toBe('Charlie')
249
+
250
+ // Sort by age descending
251
+ const sortedByAge = multiSort([...testData], { age: -1 })
252
+ expect(sortedByAge[0].age).toBe(35)
253
+ expect(sortedByAge[1].age).toBe(30)
254
+ expect(sortedByAge[2].age).toBe(25)
255
+
256
+ // Multi-sort: name asc, then age desc
257
+ const multiSorted = multiSort([...testData], { name: 1, age: -1 })
258
+ expect(multiSorted[0].name).toBe('Alice')
259
+ })
260
+
261
+ test('handles row selection correctly (maintaining original behavior)', () => {
262
+ const mockOnRowSelection = jest.fn()
263
+ const mockOnRowClick = jest.fn()
264
+
265
+ const select = (row, event, selectedRows, selectionMode, setSelectedRows, onRowSelection, onRowClick) => {
266
+ if (event.target.id !== "checked") {
267
+ // Enhanced selection logic
268
+ if (selectionMode === 'multiple') {
269
+ const newSelected = new Set(selectedRows)
270
+ if (newSelected.has(row.id)) {
271
+ newSelected.delete(row.id)
272
+ } else {
273
+ newSelected.add(row.id)
274
+ }
275
+ setSelectedRows(newSelected)
276
+ } else if (selectionMode === 'single') {
277
+ setSelectedRows(new Set([row.id]))
278
+ }
279
+
280
+ // Call original callback
281
+ if (onRowSelection) onRowSelection(row, event)
282
+ if (onRowClick) onRowClick(row, event)
283
+ }
284
+ }
285
+
286
+ const mockSetSelectedRows = jest.fn()
287
+ const mockEvent = { target: { id: 'not-checked' } }
288
+ const mockRow = { id: 1, name: 'Test' }
289
+
290
+ // Single selection
291
+ select(mockRow, mockEvent, new Set(), 'single', mockSetSelectedRows, mockOnRowSelection, mockOnRowClick)
292
+ expect(mockSetSelectedRows).toHaveBeenCalledWith(new Set([1]))
293
+ expect(mockOnRowSelection).toHaveBeenCalledWith(mockRow, mockEvent)
294
+ expect(mockOnRowClick).toHaveBeenCalledWith(mockRow, mockEvent)
295
+
296
+ mockSetSelectedRows.mockClear()
297
+ mockOnRowSelection.mockClear()
298
+ mockOnRowClick.mockClear()
299
+
300
+ // Multiple selection - add
301
+ select(mockRow, mockEvent, new Set(), 'multiple', mockSetSelectedRows, mockOnRowSelection, mockOnRowClick)
302
+ expect(mockSetSelectedRows).toHaveBeenCalledWith(new Set([1]))
303
+
304
+ // Multiple selection - remove
305
+ select(mockRow, mockEvent, new Set([1]), 'multiple', mockSetSelectedRows, mockOnRowSelection, mockOnRowClick)
306
+ expect(mockSetSelectedRows).toHaveBeenCalledWith(new Set())
307
+
308
+ // Checkbox click (should not trigger selection)
309
+ const checkboxEvent = { target: { id: 'checked' } }
310
+ select(mockRow, checkboxEvent, new Set(), 'single', mockSetSelectedRows, mockOnRowSelection, mockOnRowClick)
311
+ expect(mockOnRowSelection).not.toHaveBeenCalled()
312
+ })
313
+
314
+ test('handles check all correctly (maintaining original behavior)', () => {
315
+ const mockOnCheckAll = jest.fn()
316
+
317
+ const checkAll = (id, value, rows, selectionMode, setAllChecked, setSelectedRows, onCheckAll) => {
318
+ const ids = rows.map(row => row.id)
319
+ setAllChecked(value)
320
+
321
+ if (selectionMode === 'multiple') {
322
+ if (value) {
323
+ setSelectedRows(new Set(ids))
324
+ } else {
325
+ setSelectedRows(new Set())
326
+ }
327
+ }
328
+
329
+ if (onCheckAll) onCheckAll(ids, value)
330
+ }
331
+
332
+ const mockSetAllChecked = jest.fn()
333
+ const mockSetSelectedRows = jest.fn()
334
+
335
+ // Check all
336
+ checkAll('checked', true, mockRows, 'multiple', mockSetAllChecked, mockSetSelectedRows, mockOnCheckAll)
337
+ expect(mockSetAllChecked).toHaveBeenCalledWith(true)
338
+ expect(mockSetSelectedRows).toHaveBeenCalledWith(new Set([1, 2, 3]))
339
+ expect(mockOnCheckAll).toHaveBeenCalledWith([1, 2, 3], true)
340
+
341
+ mockSetAllChecked.mockClear()
342
+ mockSetSelectedRows.mockClear()
343
+ mockOnCheckAll.mockClear()
344
+
345
+ // Uncheck all
346
+ checkAll('checked', false, mockRows, 'multiple', mockSetAllChecked, mockSetSelectedRows, mockOnCheckAll)
347
+ expect(mockSetAllChecked).toHaveBeenCalledWith(false)
348
+ expect(mockSetSelectedRows).toHaveBeenCalledWith(new Set())
349
+ expect(mockOnCheckAll).toHaveBeenCalledWith([1, 2, 3], false)
350
+ })
351
+
352
+ test('handles search functionality', () => {
353
+ const searchRows = (rows, searchTerm, searchable, columns) => {
354
+ if (!searchTerm || !searchable) return rows
355
+
356
+ return rows.filter(row => {
357
+ return columns.some(column => {
358
+ const value = row[column.id]
359
+ if (value == null) return false
360
+ return String(value).toLowerCase().includes(searchTerm.toLowerCase())
361
+ })
362
+ })
363
+ }
364
+
365
+ // No search term
366
+ expect(searchRows(mockRows, '', true, mockColumns)).toEqual(mockRows)
367
+
368
+ // Search disabled
369
+ expect(searchRows(mockRows, 'john', false, mockColumns)).toEqual(mockRows)
370
+
371
+ // Search for 'john'
372
+ const johnResults = searchRows(mockRows, 'john', true, mockColumns)
373
+ expect(johnResults).toHaveLength(2) // John Doe and Bob Johnson
374
+ expect(johnResults.map(r => r.name)).toEqual(['John Doe', 'Bob Johnson'])
375
+
376
+ // Search for email
377
+ const emailResults = searchRows(mockRows, 'jane@', true, mockColumns)
378
+ expect(emailResults).toHaveLength(1)
379
+ expect(emailResults[0].name).toBe('Jane Smith')
380
+
381
+ // No results
382
+ const noResults = searchRows(mockRows, 'xyz', true, mockColumns)
383
+ expect(noResults).toHaveLength(0)
384
+ })
385
+
386
+ test('handles export functionality', () => {
387
+ const handleExport = (processedRows, columns, onExport) => {
388
+ if (onExport) {
389
+ onExport(processedRows, columns)
390
+ } else {
391
+ // Default CSV export
392
+ const csvContent = [
393
+ columns.map(col => col.label || col.id).join(','),
394
+ ...processedRows.map(row =>
395
+ columns.map(col => {
396
+ const value = row[col.id]
397
+ return typeof value === 'string' ? `"${value}"` : value
398
+ }).join(',')
399
+ )
400
+ ].join('\n')
401
+
402
+ const blob = new Blob([csvContent], { type: 'text/csv' })
403
+ const url = URL.createObjectURL(blob)
404
+ const a = document.createElement('a')
405
+ a.href = url
406
+ a.download = 'table-export.csv'
407
+ a.click()
408
+ URL.revokeObjectURL(url)
409
+ }
410
+ }
411
+
412
+ const mockOnExport = jest.fn()
413
+
414
+ // Custom export
415
+ handleExport(mockRows, mockColumns, mockOnExport)
416
+ expect(mockOnExport).toHaveBeenCalledWith(mockRows, mockColumns)
417
+
418
+ mockOnExport.mockClear()
419
+
420
+ // Default CSV export
421
+ handleExport(mockRows, mockColumns, null)
422
+ expect(Blob).toHaveBeenCalledWith([expect.stringContaining('Name,Age,Email')], { type: 'text/csv' })
423
+ expect(URL.createObjectURL).toHaveBeenCalled()
424
+ expect(document.createElement).toHaveBeenCalledWith('a')
425
+ })
426
+
427
+ test('generates CSS classes correctly', () => {
428
+ const generateClasses = (outlined, striped, compact, bordered, hover, rowHeight, density, theme, responsive, isLoading, skeleton, className) => {
429
+ return [
430
+ 'datatable8', // Maintain original class for compatibility
431
+ 'datatable2', // New class for v2 features
432
+ outlined && 'outlined',
433
+ striped && 'datatable2--striped',
434
+ compact && 'datatable2--compact',
435
+ bordered && 'datatable2--bordered',
436
+ !hover && 'datatable2--no-hover',
437
+ `datatable2--${rowHeight}`,
438
+ `datatable2--${density}`,
439
+ `datatable2--${theme}`,
440
+ responsive && 'datatable2--responsive',
441
+ isLoading && 'datatable2--loading',
442
+ skeleton && 'datatable2--skeleton',
443
+ className
444
+ ].filter(Boolean).join(' ')
445
+ }
446
+
447
+ expect(generateClasses(false, false, false, false, true, 'medium', 'normal', 'default', true, false, false, ''))
448
+ .toBe('datatable8 datatable2 datatable2--medium datatable2--normal datatable2--default datatable2--responsive')
449
+
450
+ expect(generateClasses(true, true, true, true, false, 'large', 'comfortable', 'dark', false, true, true, 'custom'))
451
+ .toBe('datatable8 datatable2 outlined datatable2--striped datatable2--compact datatable2--bordered datatable2--no-hover datatable2--large datatable2--comfortable datatable2--dark datatable2--loading datatable2--skeleton custom')
452
+ })
453
+ })
454
+ })
@@ -1,38 +0,0 @@
1
- import React from 'react'
2
- import './button.css'
3
- import { Icon } from './icon'
4
-
5
-
6
- interface Button2Props {
7
- label: String
8
- icon: String
9
- action: () => {},
10
- disabled: Boolean,
11
- outlined: Boolean,
12
- raised: Boolean
13
- }
14
-
15
- /**
16
- * HTML Button
17
- */
18
- export const Button2 = (props: Button2Props) => {
19
-
20
- const { label,icon, action, disabled, outlined, raised} = props
21
-
22
- function click(event) {
23
- if (!disabled) {
24
- event.stopPropagation();
25
- event.preventDefault();
26
- if (action) action()
27
- }
28
- }
29
-
30
- let style = raised ? 'raised' : outlined ? 'outlined' : 'normal'
31
- if (disabled) style = `${style} disabled`
32
- return (
33
- <button className={`btn ${style}`} onClick={click}>
34
- { icon ? <Icon icon={icon} size="small" clickable action={click} /> : null }
35
- <span>{ label }</span>
36
- </button>
37
- )
38
- }