ywana-core8 0.1.75 → 0.1.77
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/ACCORDION_EVALUATION.md +583 -0
- package/CHECKBOX_EVALUATION.md +273 -0
- package/CHIP_EVALUATION.md +542 -0
- package/COLOR_EVALUATION.md +524 -0
- package/COMPONENTS_EVALUATION.md +477 -0
- package/FORM_EVALUATION.md +459 -0
- package/HEADER_EVALUATION.md +436 -0
- package/ICON_EVALUATION.md +254 -0
- package/LIST_EVALUATION.md +574 -0
- package/PROGRESS_EVALUATION.md +450 -0
- package/RADIO_EVALUATION.md +439 -0
- package/RADIO_VISUAL_FIX.md +183 -0
- package/SECTION_IMPROVEMENTS.md +153 -0
- package/SWITCH_EVALUATION.md +335 -0
- package/SWITCH_VISUAL_FIX.md +232 -0
- package/TAB_EVALUATION.md +626 -0
- package/TEXTFIELD_EVALUATION.md +747 -0
- package/TOOLTIP_FIX.md +157 -0
- package/TREE_EVALUATION.md +708 -0
- package/dist/index.cjs +10893 -1969
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +7768 -1096
- package/dist/index.css.map +1 -1
- package/dist/index.modern.js +10921 -2005
- package/dist/index.modern.js.map +1 -1
- package/dist/index.umd.js +10893 -1969
- package/dist/index.umd.js.map +1 -1
- package/jest.config.js +24 -0
- package/package.json +10 -1
- package/src/html/accordion.css +208 -4
- package/src/html/accordion.example.js +390 -0
- package/src/html/accordion.js +284 -28
- package/src/html/accordion.unit.test.js +334 -0
- package/src/html/button.css +157 -16
- package/src/html/button.example.js +374 -0
- package/src/html/button.js +240 -60
- package/src/html/button.test.js +422 -0
- package/src/html/checkbox.css +74 -2
- package/src/html/checkbox.example.js +316 -0
- package/src/html/checkbox.js +113 -26
- package/src/html/checkbox.test.js +285 -0
- package/src/html/chip.css +230 -19
- package/src/html/chip.example.js +355 -0
- package/src/html/chip.js +321 -25
- package/src/html/chip.test.js +425 -0
- package/src/html/color.css +435 -6
- package/src/html/color.example.js +527 -0
- package/src/html/color.js +458 -9
- package/src/html/color.test.js +362 -4
- package/src/html/components.example.js +492 -0
- package/src/html/components_enhanced.test.js +581 -0
- package/src/html/form.css +70 -3
- package/src/html/form.example.js +385 -0
- package/src/html/form.js +232 -34
- package/src/html/form.test.js +369 -0
- package/src/html/header2.css +264 -0
- package/src/html/header2.example.js +411 -0
- package/src/html/header2.js +203 -0
- package/src/html/header2.test.js +377 -0
- package/src/html/icon.css +20 -2
- package/src/html/icon.example.js +268 -0
- package/src/html/icon.js +86 -16
- package/src/html/icon.test.js +231 -0
- package/src/html/index.js +4 -1
- package/src/html/list.css +393 -1
- package/src/html/list.example.js +404 -0
- package/src/html/list.js +583 -40
- package/src/html/list.test.js +383 -0
- package/src/html/progress.css +707 -17
- package/src/html/progress.example.js +424 -0
- package/src/html/progress.js +906 -9
- package/src/html/progress.test.js +313 -0
- package/src/html/property.css +399 -0
- package/src/html/property.example.js +553 -0
- package/src/html/property.js +393 -15
- package/src/html/property.test.js +351 -2
- package/src/html/radio-visual-test.js +289 -0
- package/src/html/radio.css +137 -11
- package/src/html/radio.example.js +389 -0
- package/src/html/radio.js +234 -10
- package/src/html/radio.test.js +318 -0
- package/src/html/section.example.js +99 -0
- package/src/html/section.js +40 -3
- package/src/html/section.test.js +131 -0
- package/src/html/selector.css +329 -3
- package/src/html/selector.js +369 -23
- package/src/html/switch-debug.js +197 -0
- package/src/html/switch-test-visual.js +294 -0
- package/src/html/switch.css +200 -0
- package/src/html/switch.example.js +461 -0
- package/src/html/switch.js +283 -23
- package/src/html/switch.test.js +355 -0
- package/src/html/tab.css +289 -0
- package/src/html/tab.example.js +446 -0
- package/src/html/tab.js +387 -22
- package/src/html/tab_enhanced.js +378 -0
- package/src/html/tab_enhanced.test.js +504 -0
- package/src/html/table2.css +576 -0
- package/src/html/table2.example.js +703 -0
- package/src/html/table2.js +1252 -0
- package/src/html/table2.migration.md +328 -0
- package/src/html/table2.test.js +582 -0
- package/src/html/text.css +375 -0
- package/src/html/text.js +311 -20
- package/src/html/textfield2.css +841 -0
- package/src/html/textfield2.example.js +1370 -0
- package/src/html/textfield2.js +1143 -0
- package/src/html/textfield2.test.js +950 -0
- package/src/html/thumbnail.css +289 -2
- package/src/html/thumbnail.js +214 -9
- package/src/html/tokenfield.css +449 -1
- package/src/html/tokenfield.example.js +503 -0
- package/src/html/tokenfield.js +561 -56
- package/src/html/tokenfield.test.js +423 -0
- package/src/html/tooltip-positioning-demo.js +187 -0
- package/src/html/tooltip.css +25 -2
- package/src/html/tree.css +240 -10
- package/src/html/tree.example.js +475 -0
- package/src/html/tree.js +714 -28
- package/src/html/tree_enhanced.test.js +495 -0
- package/table2.test.js +454 -0
- package/src/html/button.tsx +0 -38
package/src/html/selector.js
CHANGED
@@ -1,57 +1,403 @@
|
|
1
|
-
import React, { useEffect, useState } from 'react'
|
1
|
+
import React, { useEffect, useState, useCallback, useRef } from 'react'
|
2
|
+
import PropTypes from 'prop-types'
|
3
|
+
import { Icon } from './icon'
|
2
4
|
import './selector.css'
|
3
5
|
|
4
6
|
/**
|
5
|
-
* Multi Selector
|
7
|
+
* Enhanced Multi Selector component with improved functionality while maintaining 100% compatibility
|
6
8
|
*/
|
7
9
|
export const MultiSelector = (props) => {
|
10
|
+
const {
|
11
|
+
// Original props (100% compatible)
|
12
|
+
options = [],
|
13
|
+
className,
|
14
|
+
onChange,
|
15
|
+
// New enhanced props (all optional for compatibility)
|
16
|
+
disabled = false,
|
17
|
+
maxSelections,
|
18
|
+
minSelections = 0,
|
19
|
+
searchable = false,
|
20
|
+
searchPlaceholder = "Search options...",
|
21
|
+
variant = 'default',
|
22
|
+
size = 'medium',
|
23
|
+
allowClear = false,
|
24
|
+
onClear,
|
25
|
+
loading = false,
|
26
|
+
empty = false,
|
27
|
+
emptyMessage = "No options available",
|
28
|
+
ariaLabel,
|
29
|
+
style,
|
30
|
+
...restProps
|
31
|
+
} = props
|
8
32
|
|
9
|
-
const { options = [], className } = props
|
10
33
|
const [selections, setSelections] = useState([])
|
34
|
+
const [searchTerm, setSearchTerm] = useState('')
|
35
|
+
const selectorRef = useRef(null)
|
11
36
|
|
37
|
+
// Initialize selections (maintaining original logic)
|
12
38
|
useEffect(() => {
|
13
39
|
const initialSelections = options.filter(option => option.selected === true).map(option => option.value)
|
14
40
|
setSelections(initialSelections)
|
41
|
+
}, [options])
|
42
|
+
|
43
|
+
// Validate props
|
44
|
+
useEffect(() => {
|
45
|
+
if (!Array.isArray(options)) {
|
46
|
+
console.warn('MultiSelector: options prop must be an array')
|
47
|
+
}
|
48
|
+
}, [options])
|
49
|
+
|
50
|
+
// Enhanced toggle function (maintaining original behavior)
|
51
|
+
const toggleSelection = useCallback((value) => {
|
52
|
+
if (disabled) return
|
53
|
+
|
54
|
+
setSelections(prev => {
|
55
|
+
const isSelected = prev.includes(value)
|
56
|
+
let next
|
57
|
+
|
58
|
+
if (isSelected) {
|
59
|
+
// Removing selection
|
60
|
+
if (prev.length <= minSelections) {
|
61
|
+
console.warn(`MultiSelector: Cannot remove selection. Minimum ${minSelections} selections required.`)
|
62
|
+
return prev
|
63
|
+
}
|
64
|
+
next = prev.filter(item => item !== value)
|
65
|
+
} else {
|
66
|
+
// Adding selection
|
67
|
+
if (maxSelections && prev.length >= maxSelections) {
|
68
|
+
console.warn(`MultiSelector: Cannot add selection. Maximum ${maxSelections} selections allowed.`)
|
69
|
+
return prev
|
70
|
+
}
|
71
|
+
next = prev.concat([value])
|
72
|
+
}
|
73
|
+
|
74
|
+
if (onChange) onChange(next)
|
75
|
+
return next
|
76
|
+
})
|
77
|
+
}, [disabled, onChange, maxSelections, minSelections])
|
78
|
+
|
79
|
+
// Handle clear all
|
80
|
+
const handleClear = useCallback(() => {
|
81
|
+
if (disabled || minSelections > 0) return
|
82
|
+
|
83
|
+
setSelections([])
|
84
|
+
if (onChange) onChange([])
|
85
|
+
if (onClear) onClear()
|
86
|
+
}, [disabled, minSelections, onChange, onClear])
|
87
|
+
|
88
|
+
// Handle search
|
89
|
+
const handleSearch = useCallback((event) => {
|
90
|
+
setSearchTerm(event.target.value)
|
15
91
|
}, [])
|
16
92
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
}
|
93
|
+
// Filter options based on search
|
94
|
+
const filteredOptions = searchable && searchTerm
|
95
|
+
? options.filter(option =>
|
96
|
+
option.label?.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
97
|
+
option.value?.toString().toLowerCase().includes(searchTerm.toLowerCase())
|
98
|
+
)
|
99
|
+
: options
|
25
100
|
|
26
|
-
|
101
|
+
// Generate items (maintaining original logic)
|
102
|
+
const items = filteredOptions.map(option => ({
|
27
103
|
...option,
|
28
104
|
selected: selections.includes(option.value),
|
29
|
-
onToggle: toggleSelection
|
105
|
+
onToggle: toggleSelection,
|
106
|
+
disabled: disabled || option.disabled,
|
107
|
+
variant,
|
108
|
+
size
|
30
109
|
}))
|
31
110
|
|
111
|
+
// Generate CSS classes
|
112
|
+
const cssClasses = [
|
113
|
+
'multiselector',
|
114
|
+
`multiselector--${variant}`,
|
115
|
+
`multiselector--${size}`,
|
116
|
+
disabled && 'multiselector--disabled',
|
117
|
+
loading && 'multiselector--loading',
|
118
|
+
searchable && 'multiselector--searchable',
|
119
|
+
className
|
120
|
+
].filter(Boolean).join(' ')
|
121
|
+
|
122
|
+
// Accessibility attributes
|
123
|
+
const ariaAttributes = {
|
124
|
+
'aria-label': ariaLabel || 'Multi selector',
|
125
|
+
'aria-disabled': disabled,
|
126
|
+
'aria-busy': loading,
|
127
|
+
role: 'group'
|
128
|
+
}
|
129
|
+
|
130
|
+
// Show loading state
|
131
|
+
if (loading) {
|
132
|
+
return (
|
133
|
+
<div className={cssClasses} style={style} {...ariaAttributes} {...restProps}>
|
134
|
+
<div className="multiselector__loading">
|
135
|
+
<Icon icon="hourglass_empty" size="medium" />
|
136
|
+
<span>Loading options...</span>
|
137
|
+
</div>
|
138
|
+
</div>
|
139
|
+
)
|
140
|
+
}
|
141
|
+
|
142
|
+
// Show empty state
|
143
|
+
if (empty || options.length === 0) {
|
144
|
+
return (
|
145
|
+
<div className={cssClasses} style={style} {...ariaAttributes} {...restProps}>
|
146
|
+
<div className="multiselector__empty">
|
147
|
+
<Icon icon="inbox" size="medium" />
|
148
|
+
<span>{emptyMessage}</span>
|
149
|
+
</div>
|
150
|
+
</div>
|
151
|
+
)
|
152
|
+
}
|
153
|
+
|
32
154
|
return (
|
33
|
-
<
|
34
|
-
{
|
35
|
-
|
155
|
+
<div className={cssClasses} style={style} ref={selectorRef} {...ariaAttributes} {...restProps}>
|
156
|
+
{/* Search input */}
|
157
|
+
{searchable && (
|
158
|
+
<div className="multiselector__search">
|
159
|
+
<input
|
160
|
+
type="text"
|
161
|
+
placeholder={searchPlaceholder}
|
162
|
+
value={searchTerm}
|
163
|
+
onChange={handleSearch}
|
164
|
+
className="multiselector__search-input"
|
165
|
+
disabled={disabled}
|
166
|
+
/>
|
167
|
+
<Icon icon="search" size="small" className="multiselector__search-icon" />
|
168
|
+
</div>
|
169
|
+
)}
|
170
|
+
|
171
|
+
{/* Clear button */}
|
172
|
+
{allowClear && selections.length > 0 && minSelections === 0 && (
|
173
|
+
<div className="multiselector__controls">
|
174
|
+
<button
|
175
|
+
type="button"
|
176
|
+
onClick={handleClear}
|
177
|
+
disabled={disabled}
|
178
|
+
className="multiselector__clear-button"
|
179
|
+
aria-label="Clear all selections"
|
180
|
+
>
|
181
|
+
<Icon icon="clear" size="small" />
|
182
|
+
Clear All ({selections.length})
|
183
|
+
</button>
|
184
|
+
</div>
|
185
|
+
)}
|
186
|
+
|
187
|
+
{/* Options list (maintaining original structure) */}
|
188
|
+
<ul className="multiselector__options">
|
189
|
+
{items.map((option, index) => (
|
190
|
+
<ToggleButton key={option.value || index} {...option} />
|
191
|
+
))}
|
192
|
+
</ul>
|
193
|
+
|
194
|
+
{/* Selection summary */}
|
195
|
+
{(maxSelections || minSelections > 0) && (
|
196
|
+
<div className="multiselector__summary">
|
197
|
+
<span className="multiselector__count">
|
198
|
+
{selections.length}
|
199
|
+
{maxSelections && ` / ${maxSelections}`}
|
200
|
+
{maxSelections ? ' selected' : ` of ${options.length} selected`}
|
201
|
+
</span>
|
202
|
+
{minSelections > 0 && selections.length < minSelections && (
|
203
|
+
<span className="multiselector__warning">
|
204
|
+
Minimum {minSelections} required
|
205
|
+
</span>
|
206
|
+
)}
|
207
|
+
</div>
|
208
|
+
)}
|
209
|
+
</div>
|
36
210
|
)
|
37
211
|
}
|
38
212
|
|
39
213
|
/**
|
40
|
-
* Toggle Button
|
214
|
+
* Enhanced Toggle Button component with improved functionality while maintaining 100% compatibility
|
41
215
|
*/
|
42
216
|
export const ToggleButton = (props) => {
|
217
|
+
const {
|
218
|
+
// Original props (100% compatible)
|
219
|
+
label,
|
220
|
+
value,
|
221
|
+
selected = false,
|
222
|
+
onToggle,
|
223
|
+
// New enhanced props (all optional for compatibility)
|
224
|
+
disabled = false,
|
225
|
+
icon,
|
226
|
+
variant = 'default',
|
227
|
+
size = 'medium',
|
228
|
+
tooltip,
|
229
|
+
className,
|
230
|
+
style,
|
231
|
+
...restProps
|
232
|
+
} = props
|
43
233
|
|
44
|
-
|
45
|
-
|
46
|
-
|
234
|
+
// Handle toggle (maintaining original behavior)
|
235
|
+
const handleToggle = useCallback(() => {
|
236
|
+
if (disabled) return
|
47
237
|
if (onToggle) onToggle(value)
|
238
|
+
}, [disabled, onToggle, value])
|
239
|
+
|
240
|
+
// Handle keyboard interaction
|
241
|
+
const handleKeyDown = useCallback((event) => {
|
242
|
+
if (disabled) return
|
243
|
+
|
244
|
+
switch (event.key) {
|
245
|
+
case 'Enter':
|
246
|
+
case ' ':
|
247
|
+
event.preventDefault()
|
248
|
+
if (onToggle) onToggle(value)
|
249
|
+
break
|
250
|
+
default:
|
251
|
+
break
|
252
|
+
}
|
253
|
+
}, [disabled, onToggle, value])
|
254
|
+
|
255
|
+
// Generate CSS classes (maintaining original logic)
|
256
|
+
const cssClasses = [
|
257
|
+
'toggle-button',
|
258
|
+
selected && 'selected',
|
259
|
+
`toggle-button--${variant}`,
|
260
|
+
`toggle-button--${size}`,
|
261
|
+
disabled && 'toggle-button--disabled',
|
262
|
+
value && `toggle-button--${value}`,
|
263
|
+
className
|
264
|
+
].filter(Boolean).join(' ')
|
265
|
+
|
266
|
+
// Accessibility attributes
|
267
|
+
const ariaAttributes = {
|
268
|
+
'aria-pressed': selected,
|
269
|
+
'aria-disabled': disabled,
|
270
|
+
'aria-label': tooltip || (typeof label === 'string' ? label : `Toggle ${value}`),
|
271
|
+
role: 'button',
|
272
|
+
tabIndex: disabled ? -1 : 0
|
48
273
|
}
|
49
274
|
|
50
|
-
const selectedStyle = selected ? 'selected' : ''
|
51
275
|
return (
|
52
|
-
<li
|
53
|
-
{
|
276
|
+
<li
|
277
|
+
className={cssClasses}
|
278
|
+
onClick={handleToggle}
|
279
|
+
onKeyDown={handleKeyDown}
|
280
|
+
title={tooltip}
|
281
|
+
style={style}
|
282
|
+
{...ariaAttributes}
|
283
|
+
{...restProps}
|
284
|
+
>
|
285
|
+
{/* Icon */}
|
286
|
+
{icon && (
|
287
|
+
<Icon
|
288
|
+
icon={icon}
|
289
|
+
size={size === 'small' ? 'small' : 'medium'}
|
290
|
+
className="toggle-button__icon"
|
291
|
+
disabled={disabled}
|
292
|
+
/>
|
293
|
+
)}
|
294
|
+
|
295
|
+
{/* Label */}
|
296
|
+
<span className="toggle-button__label">
|
297
|
+
{label}
|
298
|
+
</span>
|
299
|
+
|
300
|
+
{/* Selected indicator */}
|
301
|
+
{selected && (
|
302
|
+
<Icon
|
303
|
+
icon="check"
|
304
|
+
size="small"
|
305
|
+
className="toggle-button__check"
|
306
|
+
/>
|
307
|
+
)}
|
54
308
|
</li>
|
55
309
|
)
|
310
|
+
}
|
311
|
+
|
312
|
+
// PropTypes for MultiSelector
|
313
|
+
MultiSelector.propTypes = {
|
314
|
+
/** Array of option objects */
|
315
|
+
options: PropTypes.arrayOf(PropTypes.shape({
|
316
|
+
label: PropTypes.oneOfType([PropTypes.string, PropTypes.node]).isRequired,
|
317
|
+
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
318
|
+
selected: PropTypes.bool,
|
319
|
+
disabled: PropTypes.bool,
|
320
|
+
icon: PropTypes.string
|
321
|
+
})),
|
322
|
+
/** Additional CSS classes */
|
323
|
+
className: PropTypes.string,
|
324
|
+
/** Change callback */
|
325
|
+
onChange: PropTypes.func,
|
326
|
+
/** Disabled state */
|
327
|
+
disabled: PropTypes.bool,
|
328
|
+
/** Maximum selections allowed */
|
329
|
+
maxSelections: PropTypes.number,
|
330
|
+
/** Minimum selections required */
|
331
|
+
minSelections: PropTypes.number,
|
332
|
+
/** Enable search functionality */
|
333
|
+
searchable: PropTypes.bool,
|
334
|
+
/** Search input placeholder */
|
335
|
+
searchPlaceholder: PropTypes.string,
|
336
|
+
/** Visual variant */
|
337
|
+
variant: PropTypes.oneOf(['default', 'outlined', 'filled']),
|
338
|
+
/** Size variant */
|
339
|
+
size: PropTypes.oneOf(['small', 'medium', 'large']),
|
340
|
+
/** Allow clear all button */
|
341
|
+
allowClear: PropTypes.bool,
|
342
|
+
/** Clear callback */
|
343
|
+
onClear: PropTypes.func,
|
344
|
+
/** Loading state */
|
345
|
+
loading: PropTypes.bool,
|
346
|
+
/** Empty state */
|
347
|
+
empty: PropTypes.bool,
|
348
|
+
/** Empty state message */
|
349
|
+
emptyMessage: PropTypes.string,
|
350
|
+
/** ARIA label */
|
351
|
+
ariaLabel: PropTypes.string,
|
352
|
+
/** Inline styles */
|
353
|
+
style: PropTypes.object
|
354
|
+
}
|
355
|
+
|
356
|
+
MultiSelector.defaultProps = {
|
357
|
+
options: [],
|
358
|
+
disabled: false,
|
359
|
+
minSelections: 0,
|
360
|
+
searchable: false,
|
361
|
+
searchPlaceholder: "Search options...",
|
362
|
+
variant: 'default',
|
363
|
+
size: 'medium',
|
364
|
+
allowClear: false,
|
365
|
+
loading: false,
|
366
|
+
empty: false,
|
367
|
+
emptyMessage: "No options available"
|
368
|
+
}
|
369
|
+
|
370
|
+
// PropTypes for ToggleButton
|
371
|
+
ToggleButton.propTypes = {
|
372
|
+
/** Button label */
|
373
|
+
label: PropTypes.oneOfType([PropTypes.string, PropTypes.node]).isRequired,
|
374
|
+
/** Button value */
|
375
|
+
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
376
|
+
/** Selected state */
|
377
|
+
selected: PropTypes.bool,
|
378
|
+
/** Toggle callback */
|
379
|
+
onToggle: PropTypes.func,
|
380
|
+
/** Disabled state */
|
381
|
+
disabled: PropTypes.bool,
|
382
|
+
/** Icon name */
|
383
|
+
icon: PropTypes.string,
|
384
|
+
/** Visual variant */
|
385
|
+
variant: PropTypes.oneOf(['default', 'outlined', 'filled']),
|
386
|
+
/** Size variant */
|
387
|
+
size: PropTypes.oneOf(['small', 'medium', 'large']),
|
388
|
+
/** Tooltip text */
|
389
|
+
tooltip: PropTypes.string,
|
390
|
+
/** Additional CSS classes */
|
391
|
+
className: PropTypes.string,
|
392
|
+
/** Inline styles */
|
393
|
+
style: PropTypes.object
|
394
|
+
}
|
56
395
|
|
396
|
+
ToggleButton.defaultProps = {
|
397
|
+
selected: false,
|
398
|
+
disabled: false,
|
399
|
+
variant: 'default',
|
400
|
+
size: 'medium'
|
57
401
|
}
|
402
|
+
|
403
|
+
export default MultiSelector
|
@@ -0,0 +1,197 @@
|
|
1
|
+
import React, { useState } from 'react'
|
2
|
+
import RSwitch from 'react-switch'
|
3
|
+
import { Switch, Switch2 } from './switch'
|
4
|
+
|
5
|
+
/**
|
6
|
+
* Componente de debug para verificar que los switches se ven correctamente
|
7
|
+
*/
|
8
|
+
export const SwitchDebug = () => {
|
9
|
+
const [checked, setChecked] = useState(false)
|
10
|
+
|
11
|
+
return (
|
12
|
+
<div style={{ padding: '2rem', maxWidth: '600px' }}>
|
13
|
+
<h1>🔍 Debug de Switches</h1>
|
14
|
+
|
15
|
+
{/* React Switch directo */}
|
16
|
+
<section style={{ marginBottom: '2rem' }}>
|
17
|
+
<h3>React Switch Directo (sin wrapper)</h3>
|
18
|
+
<div style={{
|
19
|
+
background: '#fff',
|
20
|
+
padding: '1.5rem',
|
21
|
+
borderRadius: '8px',
|
22
|
+
border: '1px solid #ddd'
|
23
|
+
}}>
|
24
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '1rem', marginBottom: '1rem' }}>
|
25
|
+
<span>Estado: {checked ? 'ON' : 'OFF'}</span>
|
26
|
+
<RSwitch
|
27
|
+
checked={checked}
|
28
|
+
onChange={setChecked}
|
29
|
+
onColor="#2693e6"
|
30
|
+
offColor="#ccc"
|
31
|
+
onHandleColor="#ffffff"
|
32
|
+
offHandleColor="#ffffff"
|
33
|
+
handleDiameter={18}
|
34
|
+
uncheckedIcon={false}
|
35
|
+
checkedIcon={false}
|
36
|
+
boxShadow="0px 2px 4px rgba(0, 0, 0, 0.2)"
|
37
|
+
activeBoxShadow="0px 0px 0px 3px rgba(38, 147, 230, 0.2)"
|
38
|
+
height={20}
|
39
|
+
width={48}
|
40
|
+
/>
|
41
|
+
</div>
|
42
|
+
<p style={{ fontSize: '0.9rem', color: '#666' }}>
|
43
|
+
Este es react-switch sin ningún wrapper. Si no se ve bien, el problema es con la librería o CSS global.
|
44
|
+
</p>
|
45
|
+
</div>
|
46
|
+
</section>
|
47
|
+
|
48
|
+
{/* Nuestro Switch wrapper */}
|
49
|
+
<section style={{ marginBottom: '2rem' }}>
|
50
|
+
<h3>Nuestro Switch (wrapper)</h3>
|
51
|
+
<div style={{
|
52
|
+
background: '#fff',
|
53
|
+
padding: '1.5rem',
|
54
|
+
borderRadius: '8px',
|
55
|
+
border: '1px solid #ddd'
|
56
|
+
}}>
|
57
|
+
<Switch
|
58
|
+
id="debug-switch"
|
59
|
+
label="Switch con wrapper"
|
60
|
+
checked={checked}
|
61
|
+
onChange={(id, value) => setChecked(value)}
|
62
|
+
/>
|
63
|
+
<p style={{ fontSize: '0.9rem', color: '#666', marginTop: '1rem' }}>
|
64
|
+
Este usa nuestro wrapper. Debería verse igual que el de arriba.
|
65
|
+
</p>
|
66
|
+
</div>
|
67
|
+
</section>
|
68
|
+
|
69
|
+
{/* Switch2 para comparación */}
|
70
|
+
<section style={{ marginBottom: '2rem' }}>
|
71
|
+
<h3>Switch2 (Material Icons)</h3>
|
72
|
+
<div style={{
|
73
|
+
background: '#fff',
|
74
|
+
padding: '1.5rem',
|
75
|
+
borderRadius: '8px',
|
76
|
+
border: '1px solid #ddd'
|
77
|
+
}}>
|
78
|
+
<Switch2
|
79
|
+
id="debug-switch2"
|
80
|
+
label="Switch2 con iconos"
|
81
|
+
checked={checked}
|
82
|
+
onChange={(id, value) => setChecked(value)}
|
83
|
+
/>
|
84
|
+
<p style={{ fontSize: '0.9rem', color: '#666', marginTop: '1rem' }}>
|
85
|
+
Este usa iconos Material. Debería mostrar toggle_on/toggle_off.
|
86
|
+
</p>
|
87
|
+
</div>
|
88
|
+
</section>
|
89
|
+
|
90
|
+
{/* Diferentes estados */}
|
91
|
+
<section style={{ marginBottom: '2rem' }}>
|
92
|
+
<h3>Diferentes Estados</h3>
|
93
|
+
<div style={{
|
94
|
+
background: '#fff',
|
95
|
+
padding: '1.5rem',
|
96
|
+
borderRadius: '8px',
|
97
|
+
border: '1px solid #ddd'
|
98
|
+
}}>
|
99
|
+
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))', gap: '1rem' }}>
|
100
|
+
<div>
|
101
|
+
<h4>Normal OFF</h4>
|
102
|
+
<RSwitch
|
103
|
+
checked={false}
|
104
|
+
onChange={() => {}}
|
105
|
+
onColor="#2693e6"
|
106
|
+
offColor="#ccc"
|
107
|
+
height={20}
|
108
|
+
width={48}
|
109
|
+
handleDiameter={18}
|
110
|
+
uncheckedIcon={false}
|
111
|
+
checkedIcon={false}
|
112
|
+
/>
|
113
|
+
</div>
|
114
|
+
<div>
|
115
|
+
<h4>Normal ON</h4>
|
116
|
+
<RSwitch
|
117
|
+
checked={true}
|
118
|
+
onChange={() => {}}
|
119
|
+
onColor="#2693e6"
|
120
|
+
offColor="#ccc"
|
121
|
+
height={20}
|
122
|
+
width={48}
|
123
|
+
handleDiameter={18}
|
124
|
+
uncheckedIcon={false}
|
125
|
+
checkedIcon={false}
|
126
|
+
/>
|
127
|
+
</div>
|
128
|
+
<div>
|
129
|
+
<h4>Disabled OFF</h4>
|
130
|
+
<RSwitch
|
131
|
+
checked={false}
|
132
|
+
onChange={() => {}}
|
133
|
+
disabled={true}
|
134
|
+
onColor="#2693e6"
|
135
|
+
offColor="#ccc"
|
136
|
+
height={20}
|
137
|
+
width={48}
|
138
|
+
handleDiameter={18}
|
139
|
+
uncheckedIcon={false}
|
140
|
+
checkedIcon={false}
|
141
|
+
/>
|
142
|
+
</div>
|
143
|
+
<div>
|
144
|
+
<h4>Disabled ON</h4>
|
145
|
+
<RSwitch
|
146
|
+
checked={true}
|
147
|
+
onChange={() => {}}
|
148
|
+
disabled={true}
|
149
|
+
onColor="#2693e6"
|
150
|
+
offColor="#ccc"
|
151
|
+
height={20}
|
152
|
+
width={48}
|
153
|
+
handleDiameter={18}
|
154
|
+
uncheckedIcon={false}
|
155
|
+
checkedIcon={false}
|
156
|
+
/>
|
157
|
+
</div>
|
158
|
+
</div>
|
159
|
+
</div>
|
160
|
+
</section>
|
161
|
+
|
162
|
+
{/* Información de debug */}
|
163
|
+
<section>
|
164
|
+
<h3>Información de Debug</h3>
|
165
|
+
<div style={{
|
166
|
+
background: '#f8f9fa',
|
167
|
+
padding: '1rem',
|
168
|
+
borderRadius: '4px',
|
169
|
+
border: '1px solid #dee2e6'
|
170
|
+
}}>
|
171
|
+
<h4>¿Qué deberías ver?</h4>
|
172
|
+
<ul>
|
173
|
+
<li><strong>Switch OFF:</strong> Fondo gris (#ccc), handle blanco a la izquierda</li>
|
174
|
+
<li><strong>Switch ON:</strong> Fondo azul (#2693e6), handle blanco a la derecha</li>
|
175
|
+
<li><strong>Handle:</strong> Círculo blanco con sombra sutil</li>
|
176
|
+
<li><strong>Transición:</strong> Animación suave al cambiar estado</li>
|
177
|
+
</ul>
|
178
|
+
|
179
|
+
<h4>Si solo ves un círculo gris:</h4>
|
180
|
+
<ul>
|
181
|
+
<li>Verifica que react-switch esté instalado: <code>npm list react-switch</code></li>
|
182
|
+
<li>Revisa la consola del navegador por errores</li>
|
183
|
+
<li>Verifica que no hay CSS conflictivo</li>
|
184
|
+
<li>Asegúrate de que las props de color se están aplicando</li>
|
185
|
+
</ul>
|
186
|
+
|
187
|
+
<h4>Estado actual:</h4>
|
188
|
+
<pre style={{ background: '#fff', padding: '0.5rem', borderRadius: '4px' }}>
|
189
|
+
{JSON.stringify({ checked }, null, 2)}
|
190
|
+
</pre>
|
191
|
+
</div>
|
192
|
+
</section>
|
193
|
+
</div>
|
194
|
+
)
|
195
|
+
}
|
196
|
+
|
197
|
+
export default SwitchDebug
|