ywana-core8 0.1.103 → 0.2.1

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 (172) hide show
  1. package/dist/index.css +4941 -324
  2. package/dist/index.js +42338 -0
  3. package/dist/index.js.map +1 -0
  4. package/dist/index.modern.js +37458 -31678
  5. package/dist/index.modern.js.map +1 -1
  6. package/dist/index.umd.js +39634 -34010
  7. package/dist/index.umd.js.map +1 -1
  8. package/package.json +26 -29
  9. package/src/Test.stories.jsx +28 -0
  10. package/src/desktop/Desktop.stories.jsx +110 -0
  11. package/src/desktop/WindowContext.js +135 -0
  12. package/src/desktop/WindowManager.js +355 -0
  13. package/src/desktop/desktop.css +55 -4
  14. package/src/desktop/desktop.js +312 -6
  15. package/src/desktop/index.js +7 -0
  16. package/src/desktop/window.css +229 -36
  17. package/src/desktop/window.js +254 -20
  18. package/src/desktop.backup/desktop.css +6 -0
  19. package/src/desktop.backup/desktop.js +13 -0
  20. package/src/desktop.backup/window.css +58 -0
  21. package/src/desktop.backup/window.js +27 -0
  22. package/src/html/Accordion.stories.jsx +178 -0
  23. package/src/html/Button.stories.jsx +175 -0
  24. package/src/html/Checkbox.stories.jsx +131 -0
  25. package/src/html/Chip.stories.jsx +189 -0
  26. package/src/html/Color.stories.jsx +234 -0
  27. package/src/html/Form.stories.jsx +271 -0
  28. package/src/html/Icon.stories.jsx +233 -0
  29. package/src/html/Progress.stories.jsx +247 -0
  30. package/src/html/Radio.stories.jsx +289 -0
  31. package/src/html/StyleTest.stories.jsx +81 -0
  32. package/src/html/Switch.stories.jsx +329 -0
  33. package/src/html/Tab.stories.jsx +239 -0
  34. package/src/html/Table.stories.jsx +188 -0
  35. package/src/html/Table2.stories.jsx +238 -0
  36. package/src/html/TextField2.stories.jsx +337 -0
  37. package/src/html/Tree.stories.jsx +285 -0
  38. package/src/html/accordion.example.js +0 -74
  39. package/src/html/accordion.js +1 -6
  40. package/src/html/button.js +2 -13
  41. package/src/html/checkbox.js +1 -9
  42. package/src/html/chip.js +2 -19
  43. package/src/html/color.js +1 -14
  44. package/src/html/form.js +4 -15
  45. package/src/html/header2.js +1 -12
  46. package/src/html/icon.js +1 -7
  47. package/src/html/index.js +1 -1
  48. package/src/html/list.js +1 -19
  49. package/src/html/menu.js +9 -5
  50. package/src/html/progress.js +5 -53
  51. package/src/html/property.js +9 -25
  52. package/src/html/radio.js +2 -16
  53. package/src/html/section.js +1 -6
  54. package/src/html/selector.js +2 -19
  55. package/src/html/switch.css +134 -100
  56. package/src/html/switch.example.js +46 -36
  57. package/src/html/switch.js +43 -192
  58. package/src/html/tab.js +3 -24
  59. package/src/html/text.js +1 -12
  60. package/src/html/textfield2.js +5 -42
  61. package/src/html/thumbnail.js +1 -12
  62. package/src/html/tokenfield.js +2 -21
  63. package/src/html/tree.js +3 -35
  64. package/src/index.js +1 -0
  65. package/__previewjs__/Wrapper.tsx +0 -14
  66. package/build-doc.sh +0 -10
  67. package/db/db.json +0 -89
  68. package/db/routes.json +0 -0
  69. package/dist/index.cjs +0 -36722
  70. package/dist/index.cjs.map +0 -1
  71. package/dist/index.css.map +0 -1
  72. package/doc/README.md +0 -196
  73. package/doc/evalulations/ACCORDION_EVALUATION.md +0 -583
  74. package/doc/evalulations/CHECKBOX_EVALUATION.md +0 -273
  75. package/doc/evalulations/CHIP_EVALUATION.md +0 -542
  76. package/doc/evalulations/COLOR_EVALUATION.md +0 -524
  77. package/doc/evalulations/COMPONENTS_EVALUATION.md +0 -477
  78. package/doc/evalulations/FORM_EVALUATION.md +0 -459
  79. package/doc/evalulations/HEADER_EVALUATION.md +0 -436
  80. package/doc/evalulations/ICON_EVALUATION.md +0 -254
  81. package/doc/evalulations/LIST_EVALUATION.md +0 -574
  82. package/doc/evalulations/PROGRESS_EVALUATION.md +0 -450
  83. package/doc/evalulations/RADIO_EVALUATION.md +0 -439
  84. package/doc/evalulations/RADIO_VISUAL_FIX.md +0 -183
  85. package/doc/evalulations/SECTION_IMPROVEMENTS.md +0 -153
  86. package/doc/evalulations/SWITCH_EVALUATION.md +0 -335
  87. package/doc/evalulations/SWITCH_VISUAL_FIX.md +0 -232
  88. package/doc/evalulations/TAB_EVALUATION.md +0 -626
  89. package/doc/evalulations/TEXTFIELD_EVALUATION.md +0 -747
  90. package/doc/evalulations/TOOLTIP_FIX.md +0 -157
  91. package/doc/evalulations/TREE_EVALUATION.md +0 -708
  92. package/doc/index.html +0 -0
  93. package/doc/package-lock.json +0 -17298
  94. package/doc/package.json +0 -34
  95. package/doc/public/index.html +0 -24
  96. package/doc/scripts/generate-examples.js +0 -129
  97. package/doc/src/App.css +0 -171
  98. package/doc/src/App.js +0 -114
  99. package/doc/src/components/ExamplePage.js +0 -129
  100. package/doc/src/components/WelcomePage.js +0 -84
  101. package/doc/src/index.css +0 -246
  102. package/doc/src/index.js +0 -17
  103. package/doc/src/theme.css +0 -256
  104. package/jest.config.js +0 -24
  105. package/preview.config.js +0 -38
  106. package/publish.sh +0 -6
  107. package/src/desktop/dektop.test.js +0 -11
  108. package/src/domain/CollectionAPI.test.js +0 -19
  109. package/src/domain/ContentEditor.test.js +0 -52
  110. package/src/domain2/CollectionAPI.test.js +0 -19
  111. package/src/domain2/CollectionContext.test.js +0 -71
  112. package/src/domain2/CollectionPage.test.js +0 -112
  113. package/src/domain2/DynamicForm.test.js +0 -47
  114. package/src/html/accordion.test.js +0 -37
  115. package/src/html/accordion.unit.test.js +0 -334
  116. package/src/html/button.example.new.js +0 -416
  117. package/src/html/button.test.js +0 -422
  118. package/src/html/checkbox.test.js +0 -285
  119. package/src/html/chip.test.js +0 -425
  120. package/src/html/color.example.js.backup +0 -527
  121. package/src/html/color.test.js +0 -377
  122. package/src/html/components.example.js.backup +0 -492
  123. package/src/html/components_enhanced.test.js +0 -581
  124. package/src/html/form.example.js.backup +0 -385
  125. package/src/html/form.test.js +0 -369
  126. package/src/html/header2.example.js.backup +0 -411
  127. package/src/html/header2.test.js +0 -377
  128. package/src/html/icon.example.js.backup +0 -268
  129. package/src/html/icon.test.js +0 -231
  130. package/src/html/label.test.js +0 -0
  131. package/src/html/list.example.js.backup +0 -404
  132. package/src/html/list.test.js +0 -383
  133. package/src/html/progress.example.js.backup +0 -424
  134. package/src/html/progress.test.js +0 -313
  135. package/src/html/property.example.js.backup +0 -553
  136. package/src/html/property.test.js +0 -371
  137. package/src/html/radio.example.js.backup +0 -389
  138. package/src/html/radio.test.js +0 -318
  139. package/src/html/section.example.js.backup +0 -99
  140. package/src/html/section.test.js +0 -131
  141. package/src/html/selector.test.js +0 -20
  142. package/src/html/switch.example.js.backup +0 -461
  143. package/src/html/switch.test.js +0 -355
  144. package/src/html/tab.example.js.backup +0 -446
  145. package/src/html/tab.test.js +0 -25
  146. package/src/html/tab_enhanced.test.js +0 -504
  147. package/src/html/table.test.js +0 -70
  148. package/src/html/table2.test.js +0 -582
  149. package/src/html/text.test.js +0 -15
  150. package/src/html/textfield.test.js +0 -51
  151. package/src/html/textfield2.example.js.backup +0 -1370
  152. package/src/html/textfield2.test.js +0 -950
  153. package/src/html/tokenfield.example.js.backup +0 -503
  154. package/src/html/tokenfield.test.js +0 -423
  155. package/src/html/tree.example.js.backup +0 -475
  156. package/src/html/tree.test.js +0 -43
  157. package/src/html/tree_enhanced.test.js +0 -495
  158. package/src/http/token.test.js +0 -50
  159. package/src/incubator/pdfViewer.js +0 -33
  160. package/src/incubator/wizard.test.js +0 -127
  161. package/src/site/site.test.js +0 -230
  162. package/src/site/view.test.js +0 -41
  163. package/src/widgets/calendar/Calendar.test.js +0 -28
  164. package/src/widgets/explorer/Explorer.test.js +0 -121
  165. package/src/widgets/ide/editor.test.js +0 -33
  166. package/src/widgets/kanban/Kanban.test.js +0 -78
  167. package/src/widgets/login/LoginBox.test.js +0 -12
  168. package/src/widgets/login/ResetPasswordBox.test.js +0 -34
  169. package/src/widgets/login/validations.test.js +0 -51
  170. package/src/widgets/planner/Planner.test.js +0 -60
  171. package/src/widgets/upload/Upload.test.js +0 -32
  172. package/table2.test.js +0 -454
@@ -1,12 +0,0 @@
1
- import React from 'react'
2
- import { LoginBox } from './LoginBox'
3
- import { ForgetUserPasswordAction } from './actions'
4
-
5
- const LoginBoxTest = (prop) => {
6
-
7
- return (
8
- <LoginBox message="Error">
9
- <ForgetUserPasswordAction icon={false} />
10
- </LoginBox>
11
- )
12
- }
@@ -1,34 +0,0 @@
1
- import React, { useState } from 'react'
2
- import { ResetPasswordBox } from './ResetPasswordBox'
3
-
4
- /**
5
- * Reset Password Box
6
- */
7
- export const ResetPasswordBoxTest = (prop) => {
8
-
9
- const config = {
10
- userRequired: true,
11
- oldPwdRequired: true,
12
- lang: 'EN',
13
- onOK: (form) => {
14
- console.log('onOK', form)
15
- },
16
- onClose: () => {
17
- console.log('onClose')
18
- }
19
- }
20
- return (
21
- <ResetPasswordBox {...config} >
22
- <div>
23
- <h5>Your password must contain</h5>
24
- <ul>
25
- <li>At least 8 characters</li>
26
- <li>At least one uppercase letter</li>
27
- <li>At least one lowercase letter</li>
28
- <li>At least one number</li>
29
- <li>At least one special character</li>
30
- </ul>
31
- </div>
32
- </ResetPasswordBox>
33
- )
34
- }
@@ -1,51 +0,0 @@
1
- const validations = require('./validations');
2
- const { validatePassword } = validations;
3
-
4
- describe('validatePassword', () => {
5
- test('debería devolver un error si la longitud es menor a 15 caracteres', () => {
6
- const [isValid, error] = validatePassword('Abc123!');
7
- expect(isValid).toBe(false);
8
- expect(error).toBe('La contraseña debe tener entre 15 y 50 caracteres.');
9
- });
10
-
11
- test('debería devolver un error si la longitud es mayor a 50 caracteres', () => {
12
- const [isValid, error] = validatePassword('A'.repeat(51) + '1!aB');
13
- expect(isValid).toBe(false);
14
- expect(error).toBe('La contraseña debe tener entre 15 y 50 caracteres.');
15
- });
16
-
17
- test('debería devolver un error si no contiene letras', () => {
18
- const [isValid, error] = validatePassword('1234567890!@#$%^&*()');
19
- expect(isValid).toBe(false);
20
- expect(error).toBe('La contraseña debe contener al menos una letra (A-Z o a-z).');
21
- });
22
-
23
- test('debería devolver un error si no contiene números', () => {
24
- const [isValid, error] = validatePassword('Aaaaaaaa!aaaaaaa');
25
- expect(isValid).toBe(false);
26
- expect(error).toBe('La contraseña debe contener al menos un número (0-9).');
27
- });
28
-
29
- test('debería devolver un error si no contiene minúsculas', () => {
30
- const [isValid, error] = validatePassword('AAAAAAAAAAAAA1!');
31
- expect(isValid).toBe(false);
32
- expect(error).toBe('La contraseña debe contener al menos una letra en minúscula (a-z).');
33
- });
34
-
35
- test('debería devolver un error si no contiene mayúsculas', () => {
36
- const [isValid, error] = validatePassword('aaaaaaaaaaaaa1!');
37
- expect(isValid).toBe(false);
38
- expect(error).toBe('La contraseña debe contener al menos una letra en mayúscula (A-Z).');
39
- });
40
-
41
- test('debería devolver un error si no contiene un carácter especial', () => {
42
- const [isValid, error] = validatePassword('Aaaaaaaa1Aaaaaaaa');
43
- expect(isValid).toBe(false);
44
- expect(error).toBe('La contraseña debe contener al menos un carácter especial (< > + & ! ? * - _ % . : =).');
45
- });
46
-
47
- test('debería devolver true si la contraseña es válida', () => {
48
- const [isValid, error] = validatePassword('Aaaaaaaa1Aaaaa!a');
49
- expect(isValid).toBe(true);
50
- });
51
- });
@@ -1,60 +0,0 @@
1
- import React, { useEffect, useState } from 'react'
2
- import { Planner } from './Planner'
3
-
4
- const EventCard = (props) => {
5
- const { event = {} } = props
6
- const { id, title, color } = event
7
-
8
- function drag(ev) {
9
- ev.dataTransfer.setData("text", id);
10
- }
11
-
12
- let style = { backgroundColor: "red", color: "white" }
13
- return (
14
- <div draggable onDragStart={drag} id={id} className={`event-card`} style={style}>
15
- {title}
16
- </div>
17
- )
18
- }
19
-
20
- const PlannerTest = (prop) => {
21
-
22
- const [event, setEvent] = useState()
23
-
24
- useEffect(() => {
25
- setEvent("3")
26
- }, [])
27
-
28
- const lanes = [
29
- { id: "lane1", label: "Lane 1" },
30
- { id: "lane2", label: "Lane 2" },
31
- { id: "lane3", label: "Lane 3" },
32
- { id: "lane4", label: "Lane 4" },
33
- { id: "lane5", label: "Lane 5" },
34
- { id: "lane6", label: "Lane 6" },
35
- { id: "lane7", label: "Lane 7" },
36
- ]
37
-
38
- const events = [
39
- { id: "3", lane: "lane1", date: "2022-04-04", color: "yellow", title: "Event One", Renderer: EventCard },
40
- { id: "1", lane: "lane1", date: "2022-04-05", color: "red", title: "Event One", Renderer: EventCard },
41
- { id: "2", lane: "lane1", date: "2022-04-06", color: "blue", title: "Event One", Renderer: EventCard },
42
- { id: "4", lane: "lane1", date: "2022-03-07", color: "red", title: "Event One", Renderer: EventCard },
43
- ]
44
-
45
-
46
- return (
47
- <Planner
48
- title="Planner 1"
49
- lanes={lanes}
50
- events={events}
51
- navigation={true}
52
- //onSelectCell={console.log}
53
- //onChange={(data) => console.log('D&D', data)}
54
- config = {{ range: "week" }}
55
- >
56
-
57
- </Planner>
58
-
59
- )
60
- }
@@ -1,32 +0,0 @@
1
- import React from 'react'
2
- import { UploadArea } from './UploadArea'
3
- import { Uploader } from './Uploader'
4
- import { UploadProgress } from './UploadProgress'
5
- import { UPLOAD_STATES } from './UploadStates'
6
-
7
- const UploadAreaTest = (props) => {
8
- return (
9
- <div style={{ padding: "1rem" }}>
10
- <UploadArea icon="cloud_upload" label="UploadArea Test" disabled={true} />
11
- </div>
12
- )
13
- }
14
-
15
- const UploadProgressTest = (prop) => {
16
- const files = [
17
- { icon: "image", fileName: "fileName1", uploadState: UPLOAD_STATES.RUNNING, progress: () => { return 50 } },
18
- { icon: "image", fileName: "fileName4", uploadState: UPLOAD_STATES.SUCCESS, progress: () => { return 70 } },
19
- { icon: "description", fileName: "fileName2", uploadState: UPLOAD_STATES.ERROR, progress: () => { return 70 }, uploadError: "Unknow error" },
20
- ]
21
- return (
22
- <UploadProgress files={files} />
23
- )
24
- }
25
-
26
- const UploaderTest = (prop) => {
27
- return (
28
- <div style={{ padding: "1rem" }}>
29
- <Uploader view="icon" icon="cloud_upload" target="https://maso.developxp.com/kiosk/api/upload" />
30
- </div>
31
- )
32
- }
package/table2.test.js DELETED
@@ -1,454 +0,0 @@
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
- })