ywana-core8 0.1.74 → 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 (123) 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/textfield.js +1 -1
  106. package/src/html/textfield2.css +842 -0
  107. package/src/html/textfield2.example.js +499 -0
  108. package/src/html/textfield2.js +1130 -0
  109. package/src/html/textfield2.test.js +950 -0
  110. package/src/html/thumbnail.css +289 -2
  111. package/src/html/thumbnail.js +214 -9
  112. package/src/html/tokenfield.css +449 -1
  113. package/src/html/tokenfield.example.js +503 -0
  114. package/src/html/tokenfield.js +561 -56
  115. package/src/html/tokenfield.test.js +423 -0
  116. package/src/html/tooltip-positioning-demo.js +187 -0
  117. package/src/html/tooltip.css +25 -2
  118. package/src/html/tree.css +228 -0
  119. package/src/html/tree.example.js +475 -0
  120. package/src/html/tree.js +712 -28
  121. package/src/html/tree_enhanced.test.js +495 -0
  122. package/table2.test.js +454 -0
  123. package/src/html/button.tsx +0 -38
package/src/html/color.js CHANGED
@@ -1,19 +1,468 @@
1
- import React, {useState} from 'react'
1
+ import React, { useState, useCallback, useRef, useEffect } from 'react'
2
+ import PropTypes from 'prop-types'
3
+ import { Icon } from './icon'
4
+ import { Text } from './text'
2
5
  import './color.css'
3
6
 
7
+ /**
8
+ * Enhanced ColorField component with improved functionality while maintaining 100% compatibility
9
+ */
4
10
  export const ColorField = (props) => {
11
+ const {
12
+ // Original props (100% compatible)
13
+ id,
14
+ label = "Color",
15
+ value,
16
+ onChange,
17
+ // New enhanced props (all optional for compatibility)
18
+ disabled = false,
19
+ required = false,
20
+ placeholder = "#000000",
21
+ format = 'hex',
22
+ showPreview = true,
23
+ showValue = false,
24
+ allowTransparent = false,
25
+ presetColors = [],
26
+ size = 'medium',
27
+ variant = 'default',
28
+ error,
29
+ helperText,
30
+ onFocus,
31
+ onBlur,
32
+ onClear,
33
+ clearable = false,
34
+ className,
35
+ style,
36
+ ...restProps
37
+ } = props
5
38
 
6
- const {id, label="Color", value, onChange} = props
39
+ const [internalValue, setInternalValue] = useState(value || placeholder)
40
+ const [isFocused, setIsFocused] = useState(false)
41
+ const [isValid, setIsValid] = useState(true)
42
+ const inputRef = useRef(null)
7
43
 
8
- function change(event) {
9
- const color = event.target.value
10
- if (onChange) onChange(id, color)
44
+ // Sync internal value with prop value
45
+ useEffect(() => {
46
+ if (value !== undefined) {
47
+ setInternalValue(value)
48
+ }
49
+ }, [value])
50
+
51
+ // Validate color format
52
+ const validateColor = useCallback((color) => {
53
+ if (!color) return allowTransparent
54
+
55
+ const hexRegex = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/
56
+ const rgbRegex = /^rgb\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*\)$/
57
+ const rgbaRegex = /^rgba\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*,\s*[\d.]+\s*\)$/
58
+ const hslRegex = /^hsl\(\s*\d+\s*,\s*\d+%\s*,\s*\d+%\s*\)$/
59
+ const hslaRegex = /^hsla\(\s*\d+\s*,\s*\d+%\s*,\s*\d+%\s*,\s*[\d.]+\s*\)$/
60
+
61
+ return hexRegex.test(color) || rgbRegex.test(color) || rgbaRegex.test(color) ||
62
+ hslRegex.test(color) || hslaRegex.test(color) ||
63
+ (allowTransparent && color.toLowerCase() === 'transparent')
64
+ }, [allowTransparent])
65
+
66
+ // Convert color to different formats
67
+ const convertColor = useCallback((color, targetFormat) => {
68
+ if (!color || !validateColor(color)) return color
69
+
70
+ try {
71
+ // Create a temporary element to get computed color
72
+ const tempElement = document.createElement('div')
73
+ tempElement.style.color = color
74
+ document.body.appendChild(tempElement)
75
+ const computedColor = window.getComputedStyle(tempElement).color
76
+ document.body.removeChild(tempElement)
77
+
78
+ if (targetFormat === 'hex') {
79
+ // Convert RGB to hex
80
+ const rgbMatch = computedColor.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/)
81
+ if (rgbMatch) {
82
+ const [, r, g, b] = rgbMatch
83
+ return `#${parseInt(r).toString(16).padStart(2, '0')}${parseInt(g).toString(16).padStart(2, '0')}${parseInt(b).toString(16).padStart(2, '0')}`
84
+ }
85
+ }
86
+
87
+ return color
88
+ } catch (error) {
89
+ console.warn('Color conversion failed:', error)
90
+ return color
91
+ }
92
+ }, [validateColor])
93
+
94
+ // Handle change (maintaining original behavior)
95
+ const handleChange = useCallback((event) => {
96
+ const newColor = event.target.value
97
+ setInternalValue(newColor)
98
+
99
+ const isValidColor = validateColor(newColor)
100
+ setIsValid(isValidColor)
101
+
102
+ if (onChange) {
103
+ const convertedColor = format !== 'hex' ? convertColor(newColor, format) : newColor
104
+ onChange(id, convertedColor)
105
+ }
106
+ }, [id, onChange, format, validateColor, convertColor])
107
+
108
+ // Handle focus
109
+ const handleFocus = useCallback((event) => {
110
+ setIsFocused(true)
111
+ if (onFocus) onFocus(event)
112
+ }, [onFocus])
113
+
114
+ // Handle blur
115
+ const handleBlur = useCallback((event) => {
116
+ setIsFocused(false)
117
+ if (onBlur) onBlur(event)
118
+ }, [onBlur])
119
+
120
+ // Handle clear
121
+ const handleClear = useCallback(() => {
122
+ if (disabled) return
123
+
124
+ const clearedValue = allowTransparent ? 'transparent' : placeholder
125
+ setInternalValue(clearedValue)
126
+ setIsValid(true)
127
+
128
+ if (onChange) onChange(id, clearedValue)
129
+ if (onClear) onClear()
130
+ }, [disabled, allowTransparent, placeholder, id, onChange, onClear])
131
+
132
+ // Handle preset color selection
133
+ const handlePresetSelect = useCallback((presetColor) => {
134
+ if (disabled) return
135
+
136
+ setInternalValue(presetColor)
137
+ setIsValid(true)
138
+
139
+ if (onChange) {
140
+ const convertedColor = format !== 'hex' ? convertColor(presetColor, format) : presetColor
141
+ onChange(id, convertedColor)
142
+ }
143
+ }, [disabled, id, onChange, format, convertColor])
144
+
145
+ // Generate CSS classes
146
+ const cssClasses = [
147
+ 'color-field',
148
+ `color-field--${size}`,
149
+ `color-field--${variant}`,
150
+ disabled && 'color-field--disabled',
151
+ required && 'color-field--required',
152
+ isFocused && 'color-field--focused',
153
+ error && 'color-field--error',
154
+ !isValid && 'color-field--invalid',
155
+ showPreview && 'color-field--with-preview',
156
+ className
157
+ ].filter(Boolean).join(' ')
158
+
159
+ // Generate preview style
160
+ const previewStyle = {
161
+ backgroundColor: internalValue && validateColor(internalValue) ? internalValue : 'transparent'
162
+ }
163
+
164
+ return (
165
+ <div className={cssClasses} style={style} {...restProps}>
166
+ {/* Label (maintaining original structure) */}
167
+ <label htmlFor={id} className="color-field__label">
168
+ {label}
169
+ {required && <span className="color-field__required">*</span>}
170
+ </label>
171
+
172
+ {/* Input container */}
173
+ <div className="color-field__input-container">
174
+ {/* Color preview */}
175
+ {showPreview && (
176
+ <div
177
+ className="color-field__preview"
178
+ style={previewStyle}
179
+ title={`Current color: ${internalValue}`}
180
+ >
181
+ {!internalValue || !validateColor(internalValue) ? (
182
+ <Icon icon="block" size="small" className="color-field__no-color" />
183
+ ) : null}
184
+ </div>
185
+ )}
186
+
187
+ {/* Main color input (maintaining original structure) */}
188
+ <input
189
+ ref={inputRef}
190
+ id={id}
191
+ type="color"
192
+ value={internalValue && validateColor(internalValue) ? internalValue : placeholder}
193
+ onChange={handleChange}
194
+ onFocus={handleFocus}
195
+ onBlur={handleBlur}
196
+ disabled={disabled}
197
+ required={required}
198
+ className="color-field__input"
199
+ aria-invalid={!isValid || !!error}
200
+ aria-describedby={helperText ? `${id}-helper` : undefined}
201
+ />
202
+
203
+ {/* Clear button */}
204
+ {clearable && internalValue && internalValue !== placeholder && (
205
+ <button
206
+ type="button"
207
+ onClick={handleClear}
208
+ disabled={disabled}
209
+ className="color-field__clear"
210
+ aria-label="Clear color"
211
+ >
212
+ <Icon icon="clear" size="small" />
213
+ </button>
214
+ )}
215
+ </div>
216
+
217
+ {/* Color value display */}
218
+ {showValue && internalValue && (
219
+ <div className="color-field__value">
220
+ <Text size="sm" color="muted">
221
+ {internalValue}
222
+ </Text>
223
+ </div>
224
+ )}
225
+
226
+ {/* Preset colors */}
227
+ {presetColors.length > 0 && (
228
+ <div className="color-field__presets">
229
+ <Text size="sm" color="muted" className="color-field__presets-label">
230
+ Presets:
231
+ </Text>
232
+ <div className="color-field__presets-grid">
233
+ {presetColors.map((presetColor, index) => (
234
+ <button
235
+ key={index}
236
+ type="button"
237
+ onClick={() => handlePresetSelect(presetColor)}
238
+ disabled={disabled}
239
+ className="color-field__preset"
240
+ style={{ backgroundColor: presetColor }}
241
+ title={presetColor}
242
+ aria-label={`Select preset color ${presetColor}`}
243
+ />
244
+ ))}
245
+ </div>
246
+ </div>
247
+ )}
248
+
249
+ {/* Helper text or error */}
250
+ {(helperText || error) && (
251
+ <div
252
+ id={`${id}-helper`}
253
+ className={`color-field__helper ${error ? 'color-field__helper--error' : ''}`}
254
+ >
255
+ <Text size="sm" color={error ? 'error' : 'muted'}>
256
+ {error || helperText}
257
+ </Text>
258
+ </div>
259
+ )}
260
+ </div>
261
+ )
262
+ }
263
+
264
+ // Color utilities
265
+ export const ColorUtils = {
266
+ /**
267
+ * Convert hex color to RGB
268
+ */
269
+ hexToRgb: (hex) => {
270
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)
271
+ return result ? {
272
+ r: parseInt(result[1], 16),
273
+ g: parseInt(result[2], 16),
274
+ b: parseInt(result[3], 16)
275
+ } : null
276
+ },
277
+
278
+ /**
279
+ * Convert RGB to hex
280
+ */
281
+ rgbToHex: (r, g, b) => {
282
+ return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`
283
+ },
284
+
285
+ /**
286
+ * Get contrast ratio between two colors
287
+ */
288
+ getContrastRatio: (color1, color2) => {
289
+ const getLuminance = (color) => {
290
+ const rgb = ColorUtils.hexToRgb(color)
291
+ if (!rgb) return 0
292
+
293
+ const [r, g, b] = [rgb.r, rgb.g, rgb.b].map(c => {
294
+ c = c / 255
295
+ return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4)
296
+ })
297
+
298
+ return 0.2126 * r + 0.7152 * g + 0.0722 * b
299
+ }
300
+
301
+ const lum1 = getLuminance(color1)
302
+ const lum2 = getLuminance(color2)
303
+ const brightest = Math.max(lum1, lum2)
304
+ const darkest = Math.min(lum1, lum2)
305
+
306
+ return (brightest + 0.05) / (darkest + 0.05)
307
+ },
308
+
309
+ /**
310
+ * Check if color is light or dark
311
+ */
312
+ isLight: (color) => {
313
+ const rgb = ColorUtils.hexToRgb(color)
314
+ if (!rgb) return false
315
+
316
+ const brightness = (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000
317
+ return brightness > 128
318
+ },
319
+
320
+ /**
321
+ * Generate color palette
322
+ */
323
+ generatePalette: (baseColor, count = 5) => {
324
+ const rgb = ColorUtils.hexToRgb(baseColor)
325
+ if (!rgb) return []
326
+
327
+ const palette = []
328
+ for (let i = 0; i < count; i++) {
329
+ const factor = (i + 1) / (count + 1)
330
+ const r = Math.round(rgb.r + (255 - rgb.r) * factor)
331
+ const g = Math.round(rgb.g + (255 - rgb.g) * factor)
332
+ const b = Math.round(rgb.b + (255 - rgb.b) * factor)
333
+ palette.push(ColorUtils.rgbToHex(r, g, b))
334
+ }
335
+ return palette
11
336
  }
337
+ }
338
+
339
+ // Color picker component
340
+ export const ColorPicker = (props) => {
341
+ const {
342
+ value,
343
+ onChange,
344
+ presetColors = [
345
+ '#FF0000', '#00FF00', '#0000FF', '#FFFF00', '#FF00FF', '#00FFFF',
346
+ '#000000', '#FFFFFF', '#808080', '#800000', '#008000', '#000080'
347
+ ],
348
+ disabled = false,
349
+ className,
350
+ ...restProps
351
+ } = props
352
+
353
+ const [isOpen, setIsOpen] = useState(false)
354
+
355
+ const handleColorSelect = useCallback((color) => {
356
+ if (onChange) onChange(color)
357
+ setIsOpen(false)
358
+ }, [onChange])
12
359
 
13
360
  return (
14
- <div className="color-field">
15
- <label htmlFor={id}>{label}</label>
16
- <input id={id} type="color" onChange={change} value={value}/>
361
+ <div className={`color-picker ${className || ''}`} {...restProps}>
362
+ <button
363
+ type="button"
364
+ onClick={() => setIsOpen(!isOpen)}
365
+ disabled={disabled}
366
+ className="color-picker__trigger"
367
+ style={{ backgroundColor: value || '#000000' }}
368
+ aria-label="Open color picker"
369
+ />
370
+
371
+ {isOpen && (
372
+ <div className="color-picker__dropdown">
373
+ <div className="color-picker__grid">
374
+ {presetColors.map((color, index) => (
375
+ <button
376
+ key={index}
377
+ type="button"
378
+ onClick={() => handleColorSelect(color)}
379
+ className="color-picker__option"
380
+ style={{ backgroundColor: color }}
381
+ title={color}
382
+ aria-label={`Select color ${color}`}
383
+ />
384
+ ))}
385
+ </div>
386
+ </div>
387
+ )}
17
388
  </div>
18
389
  )
19
- }
390
+ }
391
+
392
+ // PropTypes
393
+ ColorField.propTypes = {
394
+ /** Field ID */
395
+ id: PropTypes.string,
396
+ /** Field label */
397
+ label: PropTypes.string,
398
+ /** Current color value */
399
+ value: PropTypes.string,
400
+ /** Change callback */
401
+ onChange: PropTypes.func,
402
+ /** Disabled state */
403
+ disabled: PropTypes.bool,
404
+ /** Required field */
405
+ required: PropTypes.bool,
406
+ /** Placeholder color */
407
+ placeholder: PropTypes.string,
408
+ /** Color format */
409
+ format: PropTypes.oneOf(['hex', 'rgb', 'hsl']),
410
+ /** Show color preview */
411
+ showPreview: PropTypes.bool,
412
+ /** Show color value */
413
+ showValue: PropTypes.bool,
414
+ /** Allow transparent colors */
415
+ allowTransparent: PropTypes.bool,
416
+ /** Preset colors array */
417
+ presetColors: PropTypes.arrayOf(PropTypes.string),
418
+ /** Field size */
419
+ size: PropTypes.oneOf(['small', 'medium', 'large']),
420
+ /** Visual variant */
421
+ variant: PropTypes.oneOf(['default', 'outlined', 'filled']),
422
+ /** Error message */
423
+ error: PropTypes.string,
424
+ /** Helper text */
425
+ helperText: PropTypes.string,
426
+ /** Focus callback */
427
+ onFocus: PropTypes.func,
428
+ /** Blur callback */
429
+ onBlur: PropTypes.func,
430
+ /** Clear callback */
431
+ onClear: PropTypes.func,
432
+ /** Show clear button */
433
+ clearable: PropTypes.bool,
434
+ /** Additional CSS classes */
435
+ className: PropTypes.string,
436
+ /** Inline styles */
437
+ style: PropTypes.object
438
+ }
439
+
440
+ ColorField.defaultProps = {
441
+ label: "Color",
442
+ disabled: false,
443
+ required: false,
444
+ placeholder: "#000000",
445
+ format: 'hex',
446
+ showPreview: true,
447
+ showValue: false,
448
+ allowTransparent: false,
449
+ presetColors: [],
450
+ size: 'medium',
451
+ variant: 'default',
452
+ clearable: false
453
+ }
454
+
455
+ ColorPicker.propTypes = {
456
+ /** Current color value */
457
+ value: PropTypes.string,
458
+ /** Change callback */
459
+ onChange: PropTypes.func,
460
+ /** Preset colors */
461
+ presetColors: PropTypes.arrayOf(PropTypes.string),
462
+ /** Disabled state */
463
+ disabled: PropTypes.bool,
464
+ /** Additional CSS classes */
465
+ className: PropTypes.string
466
+ }
467
+
468
+ export default ColorField