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.
- package/dist/index.css +4941 -324
- package/dist/index.js +42338 -0
- package/dist/index.js.map +1 -0
- package/dist/index.modern.js +37458 -31678
- package/dist/index.modern.js.map +1 -1
- package/dist/index.umd.js +39634 -34010
- package/dist/index.umd.js.map +1 -1
- package/package.json +26 -29
- package/src/Test.stories.jsx +28 -0
- package/src/desktop/Desktop.stories.jsx +110 -0
- package/src/desktop/WindowContext.js +135 -0
- package/src/desktop/WindowManager.js +355 -0
- package/src/desktop/desktop.css +55 -4
- package/src/desktop/desktop.js +312 -6
- package/src/desktop/index.js +7 -0
- package/src/desktop/window.css +229 -36
- package/src/desktop/window.js +254 -20
- package/src/desktop.backup/desktop.css +6 -0
- package/src/desktop.backup/desktop.js +13 -0
- package/src/desktop.backup/window.css +58 -0
- package/src/desktop.backup/window.js +27 -0
- package/src/html/Accordion.stories.jsx +178 -0
- package/src/html/Button.stories.jsx +175 -0
- package/src/html/Checkbox.stories.jsx +131 -0
- package/src/html/Chip.stories.jsx +189 -0
- package/src/html/Color.stories.jsx +234 -0
- package/src/html/Form.stories.jsx +271 -0
- package/src/html/Icon.stories.jsx +233 -0
- package/src/html/Progress.stories.jsx +247 -0
- package/src/html/Radio.stories.jsx +289 -0
- package/src/html/StyleTest.stories.jsx +81 -0
- package/src/html/Switch.stories.jsx +329 -0
- package/src/html/Tab.stories.jsx +239 -0
- package/src/html/Table.stories.jsx +188 -0
- package/src/html/Table2.stories.jsx +238 -0
- package/src/html/TextField2.stories.jsx +337 -0
- package/src/html/Tree.stories.jsx +285 -0
- package/src/html/accordion.example.js +0 -74
- package/src/html/accordion.js +1 -6
- package/src/html/button.js +2 -13
- package/src/html/checkbox.js +1 -9
- package/src/html/chip.js +2 -19
- package/src/html/color.js +1 -14
- package/src/html/form.js +4 -15
- package/src/html/header2.js +1 -12
- package/src/html/icon.js +1 -7
- package/src/html/index.js +1 -1
- package/src/html/list.js +1 -19
- package/src/html/menu.js +9 -5
- package/src/html/progress.js +5 -53
- package/src/html/property.js +9 -25
- package/src/html/radio.js +2 -16
- package/src/html/section.js +1 -6
- package/src/html/selector.js +2 -19
- package/src/html/switch.css +134 -100
- package/src/html/switch.example.js +46 -36
- package/src/html/switch.js +43 -192
- package/src/html/tab.js +3 -24
- package/src/html/text.js +1 -12
- package/src/html/textfield2.js +5 -42
- package/src/html/thumbnail.js +1 -12
- package/src/html/tokenfield.js +2 -21
- package/src/html/tree.js +3 -35
- package/src/index.js +1 -0
- package/__previewjs__/Wrapper.tsx +0 -14
- package/build-doc.sh +0 -10
- package/db/db.json +0 -89
- package/db/routes.json +0 -0
- package/dist/index.cjs +0 -36722
- package/dist/index.cjs.map +0 -1
- package/dist/index.css.map +0 -1
- package/doc/README.md +0 -196
- package/doc/evalulations/ACCORDION_EVALUATION.md +0 -583
- package/doc/evalulations/CHECKBOX_EVALUATION.md +0 -273
- package/doc/evalulations/CHIP_EVALUATION.md +0 -542
- package/doc/evalulations/COLOR_EVALUATION.md +0 -524
- package/doc/evalulations/COMPONENTS_EVALUATION.md +0 -477
- package/doc/evalulations/FORM_EVALUATION.md +0 -459
- package/doc/evalulations/HEADER_EVALUATION.md +0 -436
- package/doc/evalulations/ICON_EVALUATION.md +0 -254
- package/doc/evalulations/LIST_EVALUATION.md +0 -574
- package/doc/evalulations/PROGRESS_EVALUATION.md +0 -450
- package/doc/evalulations/RADIO_EVALUATION.md +0 -439
- package/doc/evalulations/RADIO_VISUAL_FIX.md +0 -183
- package/doc/evalulations/SECTION_IMPROVEMENTS.md +0 -153
- package/doc/evalulations/SWITCH_EVALUATION.md +0 -335
- package/doc/evalulations/SWITCH_VISUAL_FIX.md +0 -232
- package/doc/evalulations/TAB_EVALUATION.md +0 -626
- package/doc/evalulations/TEXTFIELD_EVALUATION.md +0 -747
- package/doc/evalulations/TOOLTIP_FIX.md +0 -157
- package/doc/evalulations/TREE_EVALUATION.md +0 -708
- package/doc/index.html +0 -0
- package/doc/package-lock.json +0 -17298
- package/doc/package.json +0 -34
- package/doc/public/index.html +0 -24
- package/doc/scripts/generate-examples.js +0 -129
- package/doc/src/App.css +0 -171
- package/doc/src/App.js +0 -114
- package/doc/src/components/ExamplePage.js +0 -129
- package/doc/src/components/WelcomePage.js +0 -84
- package/doc/src/index.css +0 -246
- package/doc/src/index.js +0 -17
- package/doc/src/theme.css +0 -256
- package/jest.config.js +0 -24
- package/preview.config.js +0 -38
- package/publish.sh +0 -6
- package/src/desktop/dektop.test.js +0 -11
- package/src/domain/CollectionAPI.test.js +0 -19
- package/src/domain/ContentEditor.test.js +0 -52
- package/src/domain2/CollectionAPI.test.js +0 -19
- package/src/domain2/CollectionContext.test.js +0 -71
- package/src/domain2/CollectionPage.test.js +0 -112
- package/src/domain2/DynamicForm.test.js +0 -47
- package/src/html/accordion.test.js +0 -37
- package/src/html/accordion.unit.test.js +0 -334
- package/src/html/button.example.new.js +0 -416
- package/src/html/button.test.js +0 -422
- package/src/html/checkbox.test.js +0 -285
- package/src/html/chip.test.js +0 -425
- package/src/html/color.example.js.backup +0 -527
- package/src/html/color.test.js +0 -377
- package/src/html/components.example.js.backup +0 -492
- package/src/html/components_enhanced.test.js +0 -581
- package/src/html/form.example.js.backup +0 -385
- package/src/html/form.test.js +0 -369
- package/src/html/header2.example.js.backup +0 -411
- package/src/html/header2.test.js +0 -377
- package/src/html/icon.example.js.backup +0 -268
- package/src/html/icon.test.js +0 -231
- package/src/html/label.test.js +0 -0
- package/src/html/list.example.js.backup +0 -404
- package/src/html/list.test.js +0 -383
- package/src/html/progress.example.js.backup +0 -424
- package/src/html/progress.test.js +0 -313
- package/src/html/property.example.js.backup +0 -553
- package/src/html/property.test.js +0 -371
- package/src/html/radio.example.js.backup +0 -389
- package/src/html/radio.test.js +0 -318
- package/src/html/section.example.js.backup +0 -99
- package/src/html/section.test.js +0 -131
- package/src/html/selector.test.js +0 -20
- package/src/html/switch.example.js.backup +0 -461
- package/src/html/switch.test.js +0 -355
- package/src/html/tab.example.js.backup +0 -446
- package/src/html/tab.test.js +0 -25
- package/src/html/tab_enhanced.test.js +0 -504
- package/src/html/table.test.js +0 -70
- package/src/html/table2.test.js +0 -582
- package/src/html/text.test.js +0 -15
- package/src/html/textfield.test.js +0 -51
- package/src/html/textfield2.example.js.backup +0 -1370
- package/src/html/textfield2.test.js +0 -950
- package/src/html/tokenfield.example.js.backup +0 -503
- package/src/html/tokenfield.test.js +0 -423
- package/src/html/tree.example.js.backup +0 -475
- package/src/html/tree.test.js +0 -43
- package/src/html/tree_enhanced.test.js +0 -495
- package/src/http/token.test.js +0 -50
- package/src/incubator/pdfViewer.js +0 -33
- package/src/incubator/wizard.test.js +0 -127
- package/src/site/site.test.js +0 -230
- package/src/site/view.test.js +0 -41
- package/src/widgets/calendar/Calendar.test.js +0 -28
- package/src/widgets/explorer/Explorer.test.js +0 -121
- package/src/widgets/ide/editor.test.js +0 -33
- package/src/widgets/kanban/Kanban.test.js +0 -78
- package/src/widgets/login/LoginBox.test.js +0 -12
- package/src/widgets/login/ResetPasswordBox.test.js +0 -34
- package/src/widgets/login/validations.test.js +0 -51
- package/src/widgets/planner/Planner.test.js +0 -60
- package/src/widgets/upload/Upload.test.js +0 -32
- package/table2.test.js +0 -454
package/src/html/icon.test.js
DELETED
@@ -1,231 +0,0 @@
|
|
1
|
-
import React from 'react'
|
2
|
-
import { Icon } from './icon'
|
3
|
-
|
4
|
-
// Pruebas unitarias para el componente Icon
|
5
|
-
describe('Icon Component', () => {
|
6
|
-
// Mock del componente Tooltip
|
7
|
-
const mockTooltip = jest.fn()
|
8
|
-
|
9
|
-
beforeEach(() => {
|
10
|
-
jest.clearAllMocks()
|
11
|
-
|
12
|
-
// Mock del componente Tooltip
|
13
|
-
jest.doMock('./tooltip', () => ({
|
14
|
-
Tooltip: mockTooltip
|
15
|
-
}))
|
16
|
-
|
17
|
-
// Mock de console.warn para las pruebas
|
18
|
-
jest.spyOn(console, 'warn').mockImplementation(() => {})
|
19
|
-
})
|
20
|
-
|
21
|
-
afterEach(() => {
|
22
|
-
console.warn.mockRestore()
|
23
|
-
})
|
24
|
-
|
25
|
-
test('component exports correctly', () => {
|
26
|
-
expect(Icon).toBeDefined()
|
27
|
-
expect(typeof Icon).toBe('function')
|
28
|
-
})
|
29
|
-
|
30
|
-
test('component has correct PropTypes', () => {
|
31
|
-
expect(Icon.propTypes).toBeDefined()
|
32
|
-
expect(Icon.propTypes.id).toBeDefined()
|
33
|
-
expect(Icon.propTypes.icon).toBeDefined()
|
34
|
-
expect(Icon.propTypes.size).toBeDefined()
|
35
|
-
expect(Icon.propTypes.tooltip).toBeDefined()
|
36
|
-
expect(Icon.propTypes.clickable).toBeDefined()
|
37
|
-
expect(Icon.propTypes.disabled).toBeDefined()
|
38
|
-
expect(Icon.propTypes.action).toBeDefined()
|
39
|
-
expect(Icon.propTypes.eventPropagation).toBeDefined()
|
40
|
-
expect(Icon.propTypes.className).toBeDefined()
|
41
|
-
expect(Icon.propTypes.ariaLabel).toBeDefined()
|
42
|
-
})
|
43
|
-
|
44
|
-
test('component has correct defaultProps', () => {
|
45
|
-
expect(Icon.defaultProps).toBeDefined()
|
46
|
-
expect(Icon.defaultProps.size).toBe('normal')
|
47
|
-
expect(Icon.defaultProps.clickable).toBe(false)
|
48
|
-
expect(Icon.defaultProps.disabled).toBe(false)
|
49
|
-
expect(Icon.defaultProps.eventPropagation).toBe(false)
|
50
|
-
expect(Icon.defaultProps.className).toBe('')
|
51
|
-
})
|
52
|
-
|
53
|
-
test('returns null and warns when icon prop is missing', () => {
|
54
|
-
const result = Icon({})
|
55
|
-
|
56
|
-
expect(result).toBeNull()
|
57
|
-
expect(console.warn).toHaveBeenCalledWith('Icon component: icon prop is required')
|
58
|
-
})
|
59
|
-
|
60
|
-
test('handles className safely', () => {
|
61
|
-
// Simular el manejo seguro de className
|
62
|
-
const testClassName = (className) => {
|
63
|
-
const safeClassName = className || ''
|
64
|
-
return `icon normal ${safeClassName} material-icons`
|
65
|
-
}
|
66
|
-
|
67
|
-
expect(testClassName('custom-class')).toBe('icon normal custom-class material-icons')
|
68
|
-
expect(testClassName(undefined)).toBe('icon normal material-icons')
|
69
|
-
expect(testClassName('')).toBe('icon normal material-icons')
|
70
|
-
expect(testClassName(null)).toBe('icon normal material-icons')
|
71
|
-
})
|
72
|
-
|
73
|
-
test('generates correct CSS classes for different states', () => {
|
74
|
-
// Simular la lógica de generación de clases
|
75
|
-
const generateClasses = (size, disabled, clickable, className) => {
|
76
|
-
const style = disabled ? "disabled" : clickable ? "clickable" : ""
|
77
|
-
const safeClassName = className || ''
|
78
|
-
return `icon ${size} ${style} ${safeClassName} material-icons`
|
79
|
-
}
|
80
|
-
|
81
|
-
expect(generateClasses('normal', false, false, '')).toBe('icon normal material-icons')
|
82
|
-
expect(generateClasses('small', false, true, '')).toBe('icon small clickable material-icons')
|
83
|
-
expect(generateClasses('large', true, false, '')).toBe('icon large disabled material-icons')
|
84
|
-
expect(generateClasses('normal', false, true, 'custom')).toBe('icon normal clickable custom material-icons')
|
85
|
-
})
|
86
|
-
|
87
|
-
test('generates correct accessibility attributes', () => {
|
88
|
-
// Simular la lógica de atributos de accesibilidad
|
89
|
-
const generateAriaAttributes = (clickable, disabled, icon, ariaLabel) => {
|
90
|
-
return {
|
91
|
-
role: clickable ? 'button' : 'img',
|
92
|
-
'aria-label': ariaLabel || (clickable ? `${icon} button` : icon),
|
93
|
-
'aria-disabled': disabled,
|
94
|
-
tabIndex: clickable && !disabled ? 0 : -1
|
95
|
-
}
|
96
|
-
}
|
97
|
-
|
98
|
-
// Icono no clickable
|
99
|
-
const nonClickable = generateAriaAttributes(false, false, 'home', null)
|
100
|
-
expect(nonClickable.role).toBe('img')
|
101
|
-
expect(nonClickable['aria-label']).toBe('home')
|
102
|
-
expect(nonClickable.tabIndex).toBe(-1)
|
103
|
-
|
104
|
-
// Icono clickable
|
105
|
-
const clickable = generateAriaAttributes(true, false, 'settings', null)
|
106
|
-
expect(clickable.role).toBe('button')
|
107
|
-
expect(clickable['aria-label']).toBe('settings button')
|
108
|
-
expect(clickable.tabIndex).toBe(0)
|
109
|
-
|
110
|
-
// Icono clickable pero disabled
|
111
|
-
const disabled = generateAriaAttributes(true, true, 'delete', null)
|
112
|
-
expect(disabled.role).toBe('button')
|
113
|
-
expect(disabled['aria-disabled']).toBe(true)
|
114
|
-
expect(disabled.tabIndex).toBe(-1)
|
115
|
-
|
116
|
-
// Con aria-label personalizado
|
117
|
-
const customLabel = generateAriaAttributes(true, false, 'star', 'Favorito')
|
118
|
-
expect(customLabel['aria-label']).toBe('Favorito')
|
119
|
-
})
|
120
|
-
|
121
|
-
test('click handler works correctly', () => {
|
122
|
-
const mockAction = jest.fn()
|
123
|
-
|
124
|
-
// Simular el comportamiento del click handler
|
125
|
-
const simulateClick = (eventPropagation, disabled, action) => {
|
126
|
-
const event = {
|
127
|
-
stopPropagation: jest.fn(),
|
128
|
-
preventDefault: jest.fn()
|
129
|
-
}
|
130
|
-
|
131
|
-
// Lógica del click handler
|
132
|
-
if (!eventPropagation) {
|
133
|
-
event.stopPropagation()
|
134
|
-
event.preventDefault()
|
135
|
-
}
|
136
|
-
if (action && !disabled) action(event)
|
137
|
-
|
138
|
-
return event
|
139
|
-
}
|
140
|
-
|
141
|
-
// Click normal
|
142
|
-
const event1 = simulateClick(false, false, mockAction)
|
143
|
-
expect(event1.stopPropagation).toHaveBeenCalled()
|
144
|
-
expect(event1.preventDefault).toHaveBeenCalled()
|
145
|
-
expect(mockAction).toHaveBeenCalledWith(event1)
|
146
|
-
|
147
|
-
mockAction.mockClear()
|
148
|
-
|
149
|
-
// Click con disabled
|
150
|
-
const event2 = simulateClick(false, true, mockAction)
|
151
|
-
expect(mockAction).not.toHaveBeenCalled()
|
152
|
-
|
153
|
-
// Click con event propagation
|
154
|
-
const event3 = simulateClick(true, false, mockAction)
|
155
|
-
expect(event3.stopPropagation).not.toHaveBeenCalled()
|
156
|
-
expect(event3.preventDefault).not.toHaveBeenCalled()
|
157
|
-
expect(mockAction).toHaveBeenCalledWith(event3)
|
158
|
-
})
|
159
|
-
|
160
|
-
test('keyboard event handling works correctly', () => {
|
161
|
-
const mockAction = jest.fn()
|
162
|
-
|
163
|
-
// Simular el manejo de eventos de teclado
|
164
|
-
const simulateKeyDown = (key, clickable, disabled, action) => {
|
165
|
-
const event = {
|
166
|
-
key,
|
167
|
-
preventDefault: jest.fn()
|
168
|
-
}
|
169
|
-
|
170
|
-
// Lógica del keyboard handler
|
171
|
-
if (clickable && !disabled && (event.key === 'Enter' || event.key === ' ')) {
|
172
|
-
event.preventDefault()
|
173
|
-
// Simular llamada a click
|
174
|
-
if (action) action(event)
|
175
|
-
}
|
176
|
-
|
177
|
-
return event
|
178
|
-
}
|
179
|
-
|
180
|
-
// Enter key
|
181
|
-
const enterEvent = simulateKeyDown('Enter', true, false, mockAction)
|
182
|
-
expect(enterEvent.preventDefault).toHaveBeenCalled()
|
183
|
-
expect(mockAction).toHaveBeenCalledWith(enterEvent)
|
184
|
-
|
185
|
-
mockAction.mockClear()
|
186
|
-
|
187
|
-
// Space key
|
188
|
-
const spaceEvent = simulateKeyDown(' ', true, false, mockAction)
|
189
|
-
expect(spaceEvent.preventDefault).toHaveBeenCalled()
|
190
|
-
expect(mockAction).toHaveBeenCalledWith(spaceEvent)
|
191
|
-
|
192
|
-
mockAction.mockClear()
|
193
|
-
|
194
|
-
// Other key (should not trigger)
|
195
|
-
const otherEvent = simulateKeyDown('a', true, false, mockAction)
|
196
|
-
expect(otherEvent.preventDefault).not.toHaveBeenCalled()
|
197
|
-
expect(mockAction).not.toHaveBeenCalled()
|
198
|
-
|
199
|
-
// Disabled icon (should not trigger)
|
200
|
-
const disabledEvent = simulateKeyDown('Enter', true, true, mockAction)
|
201
|
-
expect(disabledEvent.preventDefault).not.toHaveBeenCalled()
|
202
|
-
expect(mockAction).not.toHaveBeenCalled()
|
203
|
-
})
|
204
|
-
|
205
|
-
test('size variants are handled correctly', () => {
|
206
|
-
const validSizes = ['small', 'normal', 'large']
|
207
|
-
|
208
|
-
validSizes.forEach(size => {
|
209
|
-
const classes = `icon ${size} material-icons`
|
210
|
-
expect(classes).toContain(size)
|
211
|
-
})
|
212
|
-
})
|
213
|
-
|
214
|
-
test('tooltip integration works correctly', () => {
|
215
|
-
// Verificar que el componente puede manejar tooltips
|
216
|
-
const tooltipConfig = {
|
217
|
-
text: 'Test tooltip',
|
218
|
-
top: '-2rem',
|
219
|
-
left: '-1rem'
|
220
|
-
}
|
221
|
-
|
222
|
-
// Simular la lógica de tooltip
|
223
|
-
const hasTooltip = !!tooltipConfig
|
224
|
-
expect(hasTooltip).toBe(true)
|
225
|
-
|
226
|
-
// Verificar que la configuración es válida
|
227
|
-
expect(tooltipConfig.text).toBe('Test tooltip')
|
228
|
-
expect(tooltipConfig.top).toBe('-2rem')
|
229
|
-
expect(tooltipConfig.left).toBe('-1rem')
|
230
|
-
})
|
231
|
-
})
|
package/src/html/label.test.js
DELETED
File without changes
|
@@ -1,404 +0,0 @@
|
|
1
|
-
import React, { useState } from 'react'
|
2
|
-
import { List } from './list'
|
3
|
-
import { Button } from './button'
|
4
|
-
import { Icon } from './icon'
|
5
|
-
|
6
|
-
/**
|
7
|
-
* Ejemplos del componente List mejorado manteniendo 100% compatibilidad
|
8
|
-
*/
|
9
|
-
export const ListExamples = () => {
|
10
|
-
const [selectedItem, setSelectedItem] = useState(null)
|
11
|
-
const [selectedItems, setSelectedItems] = useState([])
|
12
|
-
const [isLoading, setIsLoading] = useState(false)
|
13
|
-
const [showEmpty, setShowEmpty] = useState(false)
|
14
|
-
|
15
|
-
// Datos de ejemplo
|
16
|
-
const basicItems = [
|
17
|
-
{
|
18
|
-
id: 1,
|
19
|
-
line1: 'John Doe',
|
20
|
-
line2: 'Software Engineer',
|
21
|
-
icon: 'person',
|
22
|
-
meta: 'Active',
|
23
|
-
badge: 'New'
|
24
|
-
},
|
25
|
-
{
|
26
|
-
id: 2,
|
27
|
-
line1: 'Jane Smith',
|
28
|
-
line2: 'Product Manager',
|
29
|
-
icon: 'business_center',
|
30
|
-
meta: '2 days ago',
|
31
|
-
avatar: 'https://via.placeholder.com/40x40/2196f3/ffffff?text=JS'
|
32
|
-
},
|
33
|
-
{
|
34
|
-
id: 3,
|
35
|
-
line1: 'Mike Johnson',
|
36
|
-
line2: 'UX Designer',
|
37
|
-
icon: 'design_services',
|
38
|
-
meta: 'Offline',
|
39
|
-
actions: (
|
40
|
-
<div style={{ display: 'flex', gap: '0.25rem' }}>
|
41
|
-
<Button icon="edit" size="small" />
|
42
|
-
<Button icon="delete" size="small" />
|
43
|
-
</div>
|
44
|
-
)
|
45
|
-
},
|
46
|
-
{
|
47
|
-
id: 4,
|
48
|
-
line1: 'Sarah Wilson',
|
49
|
-
line2: 'Data Scientist',
|
50
|
-
icon: 'analytics',
|
51
|
-
meta: 'Online',
|
52
|
-
disabled: true
|
53
|
-
}
|
54
|
-
]
|
55
|
-
|
56
|
-
const groupedItems = [
|
57
|
-
{ id: 1, line1: 'Apple iPhone 14', line2: '$999', category: 'Electronics', icon: 'phone_iphone' },
|
58
|
-
{ id: 2, line1: 'Samsung Galaxy S23', line2: '$899', category: 'Electronics', icon: 'smartphone' },
|
59
|
-
{ id: 3, line1: 'Nike Air Max', line2: '$120', category: 'Clothing', icon: 'sports_soccer' },
|
60
|
-
{ id: 4, line1: 'Adidas Ultraboost', line2: '$180', category: 'Clothing', icon: 'directions_run' },
|
61
|
-
{ id: 5, line1: 'MacBook Pro', line2: '$2499', category: 'Electronics', icon: 'laptop_mac' },
|
62
|
-
{ id: 6, line1: 'Levi\'s Jeans', line2: '$80', category: 'Clothing', icon: 'checkroom' }
|
63
|
-
]
|
64
|
-
|
65
|
-
const handleSelect = (id) => {
|
66
|
-
setSelectedItem(id)
|
67
|
-
console.log('Selected:', id)
|
68
|
-
}
|
69
|
-
|
70
|
-
const handleMultiSelect = (ids) => {
|
71
|
-
setSelectedItems(ids)
|
72
|
-
console.log('Multi-selected:', ids)
|
73
|
-
}
|
74
|
-
|
75
|
-
const handleSort = (sortConfig) => {
|
76
|
-
console.log('Sort config:', sortConfig)
|
77
|
-
}
|
78
|
-
|
79
|
-
const simulateLoading = () => {
|
80
|
-
setIsLoading(true)
|
81
|
-
setTimeout(() => setIsLoading(false), 2000)
|
82
|
-
}
|
83
|
-
|
84
|
-
return (
|
85
|
-
<div style={{ padding: '2rem', maxWidth: '1200px', maxHeight: '100vh', overflow: 'auto' }}>
|
86
|
-
<h1>Componente List Mejorado</h1>
|
87
|
-
|
88
|
-
<div style={{
|
89
|
-
background: '#f8f9fa',
|
90
|
-
padding: '1rem',
|
91
|
-
borderRadius: '8px',
|
92
|
-
marginBottom: '2rem',
|
93
|
-
border: '1px solid #e9ecef'
|
94
|
-
}}>
|
95
|
-
<h3>✅ Mejoras Implementadas (100% Compatibilidad):</h3>
|
96
|
-
<ul>
|
97
|
-
<li>🛡️ <strong>PropTypes completos</strong> - Validación y documentación detallada</li>
|
98
|
-
<li>♿ <strong>Accesibilidad completa</strong> - ARIA, navegación por teclado, focus management</li>
|
99
|
-
<li>🔍 <strong>Búsqueda integrada</strong> - Filtrado en tiempo real por múltiples campos</li>
|
100
|
-
<li>📊 <strong>Ordenamiento</strong> - Sorting ascendente/descendente por cualquier campo</li>
|
101
|
-
<li>✅ <strong>Selección múltiple</strong> - Con Ctrl+click y estados visuales</li>
|
102
|
-
<li>🎭 <strong>Estados avanzados</strong> - loading, empty, disabled, dense</li>
|
103
|
-
<li>👤 <strong>Avatares y badges</strong> - Soporte para imágenes y etiquetas</li>
|
104
|
-
<li>⚡ <strong>Acciones por item</strong> - Botones que aparecen en hover</li>
|
105
|
-
<li>📱 <strong>Responsive total</strong> - Adaptación móvil, dark mode, high contrast</li>
|
106
|
-
<li>🧪 <strong>16 Pruebas unitarias</strong> - Verifican compatibilidad y funcionalidad</li>
|
107
|
-
</ul>
|
108
|
-
</div>
|
109
|
-
|
110
|
-
{/* Controles de demostración */}
|
111
|
-
<section style={{ marginBottom: '2rem' }}>
|
112
|
-
<h3>Controles de Demostración</h3>
|
113
|
-
<div style={{
|
114
|
-
background: '#fff',
|
115
|
-
padding: '1rem',
|
116
|
-
borderRadius: '8px',
|
117
|
-
border: '1px solid #ddd',
|
118
|
-
display: 'flex',
|
119
|
-
gap: '1rem',
|
120
|
-
alignItems: 'center',
|
121
|
-
flexWrap: 'wrap'
|
122
|
-
}}>
|
123
|
-
<Button
|
124
|
-
label="Simulate Loading"
|
125
|
-
icon="refresh"
|
126
|
-
action={simulateLoading}
|
127
|
-
disabled={isLoading}
|
128
|
-
/>
|
129
|
-
<Button
|
130
|
-
label={showEmpty ? "Show Items" : "Show Empty"}
|
131
|
-
icon={showEmpty ? "list" : "inbox"}
|
132
|
-
action={() => setShowEmpty(!showEmpty)}
|
133
|
-
/>
|
134
|
-
<Button
|
135
|
-
label="Clear Selection"
|
136
|
-
icon="clear"
|
137
|
-
action={() => {
|
138
|
-
setSelectedItem(null)
|
139
|
-
setSelectedItems([])
|
140
|
-
}}
|
141
|
-
/>
|
142
|
-
<span style={{ marginLeft: 'auto', color: '#666' }}>
|
143
|
-
Selected: {selectedItem || 'None'} | Multi: [{selectedItems.join(', ')}]
|
144
|
-
</span>
|
145
|
-
</div>
|
146
|
-
</section>
|
147
|
-
|
148
|
-
{/* Lista básica (compatible con versión original) */}
|
149
|
-
<section style={{ marginBottom: '2rem' }}>
|
150
|
-
<h3>Lista Básica (100% Compatible)</h3>
|
151
|
-
<div style={{
|
152
|
-
background: '#fff',
|
153
|
-
border: '1px solid #ddd',
|
154
|
-
borderRadius: '8px',
|
155
|
-
overflow: 'hidden'
|
156
|
-
}}>
|
157
|
-
<List
|
158
|
-
items={basicItems}
|
159
|
-
selected={selectedItem}
|
160
|
-
onSelect={handleSelect}
|
161
|
-
/>
|
162
|
-
</div>
|
163
|
-
</section>
|
164
|
-
|
165
|
-
{/* Lista con búsqueda */}
|
166
|
-
<section style={{ marginBottom: '2rem' }}>
|
167
|
-
<h3>Lista con Búsqueda Integrada</h3>
|
168
|
-
<div style={{
|
169
|
-
background: '#fff',
|
170
|
-
border: '1px solid #ddd',
|
171
|
-
borderRadius: '8px',
|
172
|
-
overflow: 'hidden'
|
173
|
-
}}>
|
174
|
-
<List
|
175
|
-
items={basicItems}
|
176
|
-
selected={selectedItem}
|
177
|
-
onSelect={handleSelect}
|
178
|
-
searchable={true}
|
179
|
-
searchPlaceholder="Buscar personas..."
|
180
|
-
searchBy={['line1', 'line2']}
|
181
|
-
ariaLabel="Lista de personas con búsqueda"
|
182
|
-
/>
|
183
|
-
</div>
|
184
|
-
</section>
|
185
|
-
|
186
|
-
{/* Lista con ordenamiento */}
|
187
|
-
<section style={{ marginBottom: '2rem' }}>
|
188
|
-
<h3>Lista con Ordenamiento</h3>
|
189
|
-
<div style={{
|
190
|
-
background: '#fff',
|
191
|
-
border: '1px solid #ddd',
|
192
|
-
borderRadius: '8px',
|
193
|
-
overflow: 'hidden'
|
194
|
-
}}>
|
195
|
-
<List
|
196
|
-
items={basicItems}
|
197
|
-
selected={selectedItem}
|
198
|
-
onSelect={handleSelect}
|
199
|
-
sortable={true}
|
200
|
-
sortBy="line1"
|
201
|
-
onSort={handleSort}
|
202
|
-
ariaLabel="Lista ordenable de personas"
|
203
|
-
/>
|
204
|
-
</div>
|
205
|
-
</section>
|
206
|
-
|
207
|
-
{/* Lista con selección múltiple */}
|
208
|
-
<section style={{ marginBottom: '2rem' }}>
|
209
|
-
<h3>Lista con Selección Múltiple</h3>
|
210
|
-
<div style={{
|
211
|
-
background: '#fff',
|
212
|
-
border: '1px solid #ddd',
|
213
|
-
borderRadius: '8px',
|
214
|
-
overflow: 'hidden'
|
215
|
-
}}>
|
216
|
-
<List
|
217
|
-
items={basicItems}
|
218
|
-
selected={selectedItems}
|
219
|
-
onSelect={handleSelect}
|
220
|
-
multiSelect={true}
|
221
|
-
onMultiSelect={handleMultiSelect}
|
222
|
-
ariaLabel="Lista con selección múltiple"
|
223
|
-
/>
|
224
|
-
</div>
|
225
|
-
</section>
|
226
|
-
|
227
|
-
{/* Lista agrupada (compatible con versión original) */}
|
228
|
-
<section style={{ marginBottom: '2rem' }}>
|
229
|
-
<h3>Lista Agrupada (100% Compatible)</h3>
|
230
|
-
<div style={{
|
231
|
-
background: '#fff',
|
232
|
-
border: '1px solid #ddd',
|
233
|
-
borderRadius: '8px',
|
234
|
-
overflow: 'hidden'
|
235
|
-
}}>
|
236
|
-
<List
|
237
|
-
items={groupedItems}
|
238
|
-
selected={selectedItem}
|
239
|
-
onSelect={handleSelect}
|
240
|
-
groupBy="category"
|
241
|
-
searchable={true}
|
242
|
-
searchPlaceholder="Buscar productos..."
|
243
|
-
/>
|
244
|
-
</div>
|
245
|
-
</section>
|
246
|
-
|
247
|
-
{/* Lista densa */}
|
248
|
-
<section style={{ marginBottom: '2rem' }}>
|
249
|
-
<h3>Lista Densa</h3>
|
250
|
-
<div style={{
|
251
|
-
background: '#fff',
|
252
|
-
border: '1px solid #ddd',
|
253
|
-
borderRadius: '8px',
|
254
|
-
overflow: 'hidden'
|
255
|
-
}}>
|
256
|
-
<List
|
257
|
-
items={basicItems}
|
258
|
-
selected={selectedItem}
|
259
|
-
onSelect={handleSelect}
|
260
|
-
dense={true}
|
261
|
-
ariaLabel="Lista densa"
|
262
|
-
/>
|
263
|
-
</div>
|
264
|
-
</section>
|
265
|
-
|
266
|
-
{/* Estados especiales */}
|
267
|
-
<section style={{ marginBottom: '2rem' }}>
|
268
|
-
<h3>Estados Especiales</h3>
|
269
|
-
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '1rem' }}>
|
270
|
-
<div style={{
|
271
|
-
background: '#fff',
|
272
|
-
border: '1px solid #ddd',
|
273
|
-
borderRadius: '8px',
|
274
|
-
overflow: 'hidden'
|
275
|
-
}}>
|
276
|
-
<h4 style={{ margin: '1rem', marginBottom: '0' }}>Loading State</h4>
|
277
|
-
<List
|
278
|
-
items={basicItems}
|
279
|
-
loading={isLoading}
|
280
|
-
ariaLabel="Lista en estado de carga"
|
281
|
-
/>
|
282
|
-
</div>
|
283
|
-
|
284
|
-
<div style={{
|
285
|
-
background: '#fff',
|
286
|
-
border: '1px solid #ddd',
|
287
|
-
borderRadius: '8px',
|
288
|
-
overflow: 'hidden'
|
289
|
-
}}>
|
290
|
-
<h4 style={{ margin: '1rem', marginBottom: '0' }}>Empty State</h4>
|
291
|
-
<List
|
292
|
-
items={showEmpty ? [] : basicItems}
|
293
|
-
empty={showEmpty}
|
294
|
-
emptyMessage="No hay elementos para mostrar"
|
295
|
-
emptyIcon="inbox"
|
296
|
-
searchable={true}
|
297
|
-
ariaLabel="Lista vacía"
|
298
|
-
/>
|
299
|
-
</div>
|
300
|
-
</div>
|
301
|
-
</section>
|
302
|
-
|
303
|
-
{/* Lista completa con todas las características */}
|
304
|
-
<section style={{ marginBottom: '2rem' }}>
|
305
|
-
<h3>Lista Completa (Todas las Características)</h3>
|
306
|
-
<div style={{
|
307
|
-
background: '#fff',
|
308
|
-
border: '1px solid #ddd',
|
309
|
-
borderRadius: '8px',
|
310
|
-
overflow: 'hidden'
|
311
|
-
}}>
|
312
|
-
<List
|
313
|
-
items={basicItems}
|
314
|
-
selected={selectedItems}
|
315
|
-
onSelect={handleSelect}
|
316
|
-
multiSelect={true}
|
317
|
-
onMultiSelect={handleMultiSelect}
|
318
|
-
searchable={true}
|
319
|
-
searchPlaceholder="Buscar en la lista completa..."
|
320
|
-
searchBy={['line1', 'line2', 'meta']}
|
321
|
-
sortable={true}
|
322
|
-
sortBy="line1"
|
323
|
-
onSort={handleSort}
|
324
|
-
animated={true}
|
325
|
-
maxHeight="300px"
|
326
|
-
ariaLabel="Lista completa con todas las características"
|
327
|
-
/>
|
328
|
-
</div>
|
329
|
-
</section>
|
330
|
-
|
331
|
-
{/* Comparación antes/después */}
|
332
|
-
<section style={{ marginBottom: '2rem' }}>
|
333
|
-
<h3>Comparación: List Original vs Mejorado</h3>
|
334
|
-
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '1rem' }}>
|
335
|
-
<div style={{
|
336
|
-
background: '#ffebee',
|
337
|
-
padding: '1rem',
|
338
|
-
borderRadius: '4px',
|
339
|
-
border: '1px solid #ffcdd2'
|
340
|
-
}}>
|
341
|
-
<h4>❌ List Original</h4>
|
342
|
-
<ul>
|
343
|
-
<li>Sin PropTypes ni validación</li>
|
344
|
-
<li>Sin accesibilidad</li>
|
345
|
-
<li>Sin búsqueda integrada</li>
|
346
|
-
<li>Sin ordenamiento</li>
|
347
|
-
<li>Selección múltiple básica</li>
|
348
|
-
<li>Sin estados loading/empty</li>
|
349
|
-
<li>CSS básico sin responsive</li>
|
350
|
-
<li>Sin avatares ni badges</li>
|
351
|
-
<li>Sin acciones por item</li>
|
352
|
-
</ul>
|
353
|
-
</div>
|
354
|
-
<div style={{
|
355
|
-
background: '#e8f5e8',
|
356
|
-
padding: '1rem',
|
357
|
-
borderRadius: '4px',
|
358
|
-
border: '1px solid #c8e6c9'
|
359
|
-
}}>
|
360
|
-
<h4>✅ List Mejorado</h4>
|
361
|
-
<ul>
|
362
|
-
<li>PropTypes completos</li>
|
363
|
-
<li>Accesibilidad total (WCAG 2.1 AA)</li>
|
364
|
-
<li>Búsqueda en tiempo real</li>
|
365
|
-
<li>Ordenamiento ascendente/descendente</li>
|
366
|
-
<li>Selección múltiple avanzada</li>
|
367
|
-
<li>Estados loading, empty, disabled</li>
|
368
|
-
<li>CSS responsive con dark mode</li>
|
369
|
-
<li>Avatares, badges y meta</li>
|
370
|
-
<li>Acciones que aparecen en hover</li>
|
371
|
-
</ul>
|
372
|
-
</div>
|
373
|
-
</div>
|
374
|
-
</section>
|
375
|
-
|
376
|
-
{/* Garantía de compatibilidad */}
|
377
|
-
<section style={{ marginBottom: '2rem' }}>
|
378
|
-
<h3>🔒 Garantía de Compatibilidad</h3>
|
379
|
-
<div style={{
|
380
|
-
background: '#fff3cd',
|
381
|
-
padding: '1rem',
|
382
|
-
borderRadius: '4px',
|
383
|
-
border: '1px solid #ffeaa7'
|
384
|
-
}}>
|
385
|
-
<p><strong>100% Compatible con Código Existente:</strong></p>
|
386
|
-
<ul>
|
387
|
-
<li>✅ Todas las props originales funcionan exactamente igual</li>
|
388
|
-
<li>✅ Comportamiento de selección idéntico</li>
|
389
|
-
<li>✅ Agrupación funciona sin cambios</li>
|
390
|
-
<li>✅ CSS original preservado</li>
|
391
|
-
<li>✅ Nuevas características son opcionales</li>
|
392
|
-
<li>✅ No se rompe ningún código existente</li>
|
393
|
-
</ul>
|
394
|
-
<p style={{ marginTop: '1rem', fontSize: '0.9rem', color: '#856404' }}>
|
395
|
-
<strong>Migración:</strong> Simplemente reemplaza el import y todas las
|
396
|
-
mejoras se aplican automáticamente sin cambiar una línea de código existente.
|
397
|
-
</p>
|
398
|
-
</div>
|
399
|
-
</section>
|
400
|
-
</div>
|
401
|
-
)
|
402
|
-
}
|
403
|
-
|
404
|
-
export default ListExamples
|