ywana-core8 0.1.75 → 0.1.76

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/ACCORDION_EVALUATION.md +583 -0
  2. package/CHECKBOX_EVALUATION.md +273 -0
  3. package/CHIP_EVALUATION.md +542 -0
  4. package/COLOR_EVALUATION.md +524 -0
  5. package/COMPONENTS_EVALUATION.md +477 -0
  6. package/FORM_EVALUATION.md +459 -0
  7. package/HEADER_EVALUATION.md +436 -0
  8. package/ICON_EVALUATION.md +254 -0
  9. package/LIST_EVALUATION.md +574 -0
  10. package/PROGRESS_EVALUATION.md +450 -0
  11. package/RADIO_EVALUATION.md +439 -0
  12. package/RADIO_VISUAL_FIX.md +183 -0
  13. package/SECTION_IMPROVEMENTS.md +153 -0
  14. package/SWITCH_EVALUATION.md +335 -0
  15. package/SWITCH_VISUAL_FIX.md +232 -0
  16. package/TAB_EVALUATION.md +626 -0
  17. package/TEXTFIELD_EVALUATION.md +747 -0
  18. package/TOOLTIP_FIX.md +157 -0
  19. package/TREE_EVALUATION.md +708 -0
  20. package/dist/index.cjs +7900 -1615
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.css +6094 -1122
  23. package/dist/index.css.map +1 -1
  24. package/dist/index.modern.js +7929 -1645
  25. package/dist/index.modern.js.map +1 -1
  26. package/dist/index.umd.js +7900 -1615
  27. package/dist/index.umd.js.map +1 -1
  28. package/jest.config.js +24 -0
  29. package/package.json +10 -1
  30. package/src/html/accordion.css +208 -4
  31. package/src/html/accordion.example.js +390 -0
  32. package/src/html/accordion.js +284 -28
  33. package/src/html/accordion.unit.test.js +334 -0
  34. package/src/html/button.css +157 -16
  35. package/src/html/button.example.js +374 -0
  36. package/src/html/button.js +240 -60
  37. package/src/html/button.test.js +422 -0
  38. package/src/html/checkbox.css +74 -2
  39. package/src/html/checkbox.example.js +316 -0
  40. package/src/html/checkbox.js +113 -26
  41. package/src/html/checkbox.test.js +285 -0
  42. package/src/html/chip.css +230 -19
  43. package/src/html/chip.example.js +355 -0
  44. package/src/html/chip.js +321 -25
  45. package/src/html/chip.test.js +425 -0
  46. package/src/html/color.css +435 -6
  47. package/src/html/color.example.js +527 -0
  48. package/src/html/color.js +458 -9
  49. package/src/html/color.test.js +362 -4
  50. package/src/html/components.example.js +492 -0
  51. package/src/html/components_enhanced.test.js +581 -0
  52. package/src/html/form.css +70 -3
  53. package/src/html/form.example.js +385 -0
  54. package/src/html/form.js +232 -34
  55. package/src/html/form.test.js +369 -0
  56. package/src/html/header2.css +264 -0
  57. package/src/html/header2.example.js +411 -0
  58. package/src/html/header2.js +203 -0
  59. package/src/html/header2.test.js +377 -0
  60. package/src/html/icon.css +20 -2
  61. package/src/html/icon.example.js +268 -0
  62. package/src/html/icon.js +86 -16
  63. package/src/html/icon.test.js +231 -0
  64. package/src/html/index.js +1 -1
  65. package/src/html/list.css +393 -1
  66. package/src/html/list.example.js +404 -0
  67. package/src/html/list.js +583 -40
  68. package/src/html/list.test.js +383 -0
  69. package/src/html/progress.css +707 -17
  70. package/src/html/progress.example.js +424 -0
  71. package/src/html/progress.js +906 -9
  72. package/src/html/progress.test.js +313 -0
  73. package/src/html/property.css +399 -0
  74. package/src/html/property.example.js +553 -0
  75. package/src/html/property.js +393 -15
  76. package/src/html/property.test.js +351 -2
  77. package/src/html/radio-visual-test.js +289 -0
  78. package/src/html/radio.css +137 -11
  79. package/src/html/radio.example.js +389 -0
  80. package/src/html/radio.js +234 -10
  81. package/src/html/radio.test.js +318 -0
  82. package/src/html/section.example.js +99 -0
  83. package/src/html/section.js +40 -3
  84. package/src/html/section.test.js +131 -0
  85. package/src/html/selector.css +329 -3
  86. package/src/html/selector.js +369 -23
  87. package/src/html/switch-debug.js +197 -0
  88. package/src/html/switch-test-visual.js +294 -0
  89. package/src/html/switch.css +200 -0
  90. package/src/html/switch.example.js +461 -0
  91. package/src/html/switch.js +283 -23
  92. package/src/html/switch.test.js +355 -0
  93. package/src/html/tab.css +288 -0
  94. package/src/html/tab.example.js +446 -0
  95. package/src/html/tab.js +387 -22
  96. package/src/html/tab_enhanced.js +378 -0
  97. package/src/html/tab_enhanced.test.js +504 -0
  98. package/src/html/table2.css +576 -0
  99. package/src/html/table2.example.js +703 -0
  100. package/src/html/table2.js +1252 -0
  101. package/src/html/table2.migration.md +328 -0
  102. package/src/html/table2.test.js +582 -0
  103. package/src/html/text.css +375 -0
  104. package/src/html/text.js +311 -20
  105. package/src/html/textfield2.css +842 -0
  106. package/src/html/textfield2.example.js +499 -0
  107. package/src/html/textfield2.js +1130 -0
  108. package/src/html/textfield2.test.js +950 -0
  109. package/src/html/thumbnail.css +289 -2
  110. package/src/html/thumbnail.js +214 -9
  111. package/src/html/tokenfield.css +449 -1
  112. package/src/html/tokenfield.example.js +503 -0
  113. package/src/html/tokenfield.js +561 -56
  114. package/src/html/tokenfield.test.js +423 -0
  115. package/src/html/tooltip-positioning-demo.js +187 -0
  116. package/src/html/tooltip.css +25 -2
  117. package/src/html/tree.css +228 -0
  118. package/src/html/tree.example.js +475 -0
  119. package/src/html/tree.js +712 -28
  120. package/src/html/tree_enhanced.test.js +495 -0
  121. package/table2.test.js +454 -0
  122. package/src/html/button.tsx +0 -38
@@ -1,40 +1,418 @@
1
- import React from 'react'
1
+ import React, { useState, useCallback, useRef, useEffect } from 'react'
2
+ import PropTypes from 'prop-types'
2
3
  import { Icon } from './icon'
3
4
  import { Text } from './text'
4
5
  import './property.css'
5
6
 
6
7
  /**
7
- * Property
8
+ * Enhanced Property component with improved functionality while maintaining 100% compatibility
8
9
  */
9
10
  export const Property = (props) => {
11
+ const {
12
+ // Original props (100% compatible)
13
+ id,
14
+ className,
15
+ label,
16
+ name,
17
+ initial,
18
+ value,
19
+ editable = false,
20
+ onChange,
21
+ options,
22
+ // New enhanced props (all optional for compatibility)
23
+ type = 'text',
24
+ disabled = false,
25
+ required = false,
26
+ placeholder,
27
+ multiline = false,
28
+ rows = 3,
29
+ maxLength,
30
+ minLength,
31
+ pattern,
32
+ validateValue,
33
+ size = 'medium',
34
+ variant = 'default',
35
+ layout = 'horizontal',
36
+ nameWidth = '50%',
37
+ copyable = false,
38
+ error,
39
+ helperText,
40
+ onFocus,
41
+ onBlur,
42
+ onValidationError,
43
+ clearable = true,
44
+ readOnly = false,
45
+ loading = false,
46
+ skeleton = false,
47
+ style,
48
+ ...restProps
49
+ } = props
10
50
 
11
- const { id, className, label, name, initial, value, editable = false, onChange, options } = props
51
+ const [isFocused, setIsFocused] = useState(false)
52
+ const [isValid, setIsValid] = useState(true)
53
+ const [validationError, setValidationError] = useState('')
54
+ const inputRef = useRef(null)
55
+
56
+ // Validate props
57
+ useEffect(() => {
58
+ if (options && !Array.isArray(options)) {
59
+ console.warn('Property: options prop must be an array')
60
+ }
61
+ }, [options])
62
+
63
+ // Validate value
64
+ const validateValueFunc = useCallback((val) => {
65
+ if (!val && required) {
66
+ return { isValid: false, error: 'This field is required' }
67
+ }
68
+
69
+ if (val && minLength && val.length < minLength) {
70
+ return { isValid: false, error: `Minimum ${minLength} characters required` }
71
+ }
72
+
73
+ if (val && maxLength && val.length > maxLength) {
74
+ return { isValid: false, error: `Maximum ${maxLength} characters allowed` }
75
+ }
76
+
77
+ if (val && pattern) {
78
+ const regex = new RegExp(pattern)
79
+ if (!regex.test(val)) {
80
+ return { isValid: false, error: 'Invalid format' }
81
+ }
82
+ }
83
+
84
+ if (validateValue) {
85
+ const customValidation = validateValue(val)
86
+ if (customValidation && !customValidation.isValid) {
87
+ return customValidation
88
+ }
89
+ }
90
+
91
+ return { isValid: true }
92
+ }, [required, minLength, maxLength, pattern, validateValue])
93
+
94
+ // Enhanced change function (maintaining original behavior)
95
+ const change = useCallback((event) => {
96
+ if (disabled || readOnly) return
97
+
98
+ const newValue = event.target.value
99
+
100
+ // Validate value
101
+ const validation = validateValueFunc(newValue)
102
+ setIsValid(validation.isValid)
103
+ setValidationError(validation.error || '')
104
+
105
+ if (!validation.isValid && onValidationError) {
106
+ onValidationError(validation.error, newValue)
107
+ }
12
108
 
13
- function change(event) {
14
109
  if (onChange) {
15
- const value = event.target.value
16
- onChange(id, value)
110
+ onChange(id, newValue)
17
111
  }
18
- }
112
+ }, [disabled, readOnly, validateValueFunc, onValidationError, onChange, id])
113
+
114
+ // Enhanced clear function (maintaining original behavior)
115
+ const clear = useCallback(() => {
116
+ if (disabled || readOnly) return
117
+
118
+ setIsValid(true)
119
+ setValidationError('')
19
120
 
20
- function clear() {
21
121
  if (onChange) onChange(id, "")
22
- }
122
+ }, [disabled, readOnly, onChange, id])
123
+
124
+ // Handle focus
125
+ const handleFocus = useCallback((event) => {
126
+ setIsFocused(true)
127
+ if (onFocus) onFocus(event)
128
+ }, [onFocus])
129
+
130
+ // Handle blur
131
+ const handleBlur = useCallback((event) => {
132
+ setIsFocused(false)
23
133
 
24
- let value2 = value || initial
134
+ // Validate on blur
135
+ const validation = validateValueFunc(event.target.value)
136
+ setIsValid(validation.isValid)
137
+ setValidationError(validation.error || '')
138
+
139
+ if (onBlur) onBlur(event)
140
+ }, [onBlur, validateValueFunc])
141
+
142
+ // Handle copy
143
+ const handleCopy = useCallback(async () => {
144
+ if (!copyable || !value2) return
145
+
146
+ try {
147
+ await navigator.clipboard.writeText(value2)
148
+ // Could trigger a toast notification here
149
+ } catch (error) {
150
+ console.warn('Failed to copy property value:', error)
151
+ }
152
+ }, [copyable, value])
153
+
154
+ // Handle keyboard events
155
+ const handleKeyDown = useCallback((event) => {
156
+ if (event.key === 'Enter' && !multiline) {
157
+ event.preventDefault()
158
+ inputRef.current?.blur()
159
+ }
160
+
161
+ if (event.key === 'Escape') {
162
+ inputRef.current?.blur()
163
+ }
164
+ }, [multiline])
165
+
166
+ // Process value (maintaining original logic)
167
+ let value2 = value || initial || ''
25
168
 
26
169
  if (options && Array.isArray(options)) {
27
170
  const opt = options.find(option => option.value == value2)
28
171
  if (opt) value2 = opt.label
29
172
  }
30
173
 
174
+ // Generate CSS classes
175
+ const cssClasses = [
176
+ 'property',
177
+ `property-${id}`,
178
+ `property--${size}`,
179
+ `property--${variant}`,
180
+ `property--${layout}`,
181
+ disabled && 'property--disabled',
182
+ readOnly && 'property--readonly',
183
+ required && 'property--required',
184
+ isFocused && 'property--focused',
185
+ error && 'property--error',
186
+ !isValid && 'property--invalid',
187
+ loading && 'property--loading',
188
+ skeleton && 'property--skeleton',
189
+ copyable && 'property--copyable',
190
+ className
191
+ ].filter(Boolean).join(' ')
192
+
193
+ // Generate accessibility attributes
194
+ const ariaAttributes = {
195
+ 'aria-label': `Property: ${name || label}`,
196
+ 'aria-disabled': disabled,
197
+ 'aria-readonly': readOnly,
198
+ 'aria-required': required,
199
+ 'aria-invalid': !isValid || !!error,
200
+ 'aria-describedby': helperText ? `${id}-helper` : undefined
201
+ }
202
+
203
+ // Render loading/skeleton state
204
+ if (loading || skeleton) {
205
+ return (
206
+ <div className={cssClasses} style={style} {...ariaAttributes} {...restProps}>
207
+ <div className="property-name" style={{ width: nameWidth }}>
208
+ <Text skeleton={skeleton}>{name || label}</Text>
209
+ </div>
210
+ <div className="property-value">
211
+ <Text skeleton={skeleton}>
212
+ {skeleton ? '████████████' : 'Loading...'}
213
+ </Text>
214
+ </div>
215
+ </div>
216
+ )
217
+ }
218
+
31
219
  return (
32
- <div className={`property property-${id} ${className}`}>
33
- <div className="property-name"><Text>{name || label}</Text></div>
220
+ <div className={cssClasses} style={style} {...ariaAttributes} {...restProps}>
221
+ {/* Property name (maintaining original structure) */}
222
+ <div className="property-name" style={{ width: nameWidth }}>
223
+ <Text className="property-name__text">
224
+ {name || label}
225
+ {required && <span className="property__required">*</span>}
226
+ </Text>
227
+ </div>
228
+
229
+ {/* Property value (maintaining original structure) */}
34
230
  <div className="property-value">
35
- {editable ? <input type="text" value={value2} onChange={change}/> : value2}
36
- {editable && value2.length > 0 ? <Icon icon="close" size="small" clickable action={clear} /> : null }
231
+ {editable ? (
232
+ <>
233
+ {multiline ? (
234
+ <textarea
235
+ ref={inputRef}
236
+ type={type}
237
+ value={value2}
238
+ onChange={change}
239
+ onFocus={handleFocus}
240
+ onBlur={handleBlur}
241
+ onKeyDown={handleKeyDown}
242
+ disabled={disabled}
243
+ readOnly={readOnly}
244
+ required={required}
245
+ placeholder={placeholder}
246
+ maxLength={maxLength}
247
+ minLength={minLength}
248
+ pattern={pattern}
249
+ rows={rows}
250
+ className="property-value__textarea"
251
+ aria-invalid={!isValid || !!error}
252
+ />
253
+ ) : (
254
+ <input
255
+ ref={inputRef}
256
+ type={type}
257
+ value={value2}
258
+ onChange={change}
259
+ onFocus={handleFocus}
260
+ onBlur={handleBlur}
261
+ onKeyDown={handleKeyDown}
262
+ disabled={disabled}
263
+ readOnly={readOnly}
264
+ required={required}
265
+ placeholder={placeholder}
266
+ maxLength={maxLength}
267
+ minLength={minLength}
268
+ pattern={pattern}
269
+ className="property-value__input"
270
+ aria-invalid={!isValid || !!error}
271
+ />
272
+ )}
273
+
274
+ {/* Clear button (maintaining original logic) */}
275
+ {clearable && editable && value2 && value2.length > 0 && !disabled && !readOnly && (
276
+ <Icon
277
+ icon="close"
278
+ size="small"
279
+ clickable
280
+ action={clear}
281
+ className="property-value__clear"
282
+ aria-label="Clear value"
283
+ />
284
+ )}
285
+ </>
286
+ ) : (
287
+ <>
288
+ {/* Display value */}
289
+ <span
290
+ className={`property-value__display ${copyable ? 'property-value__display--copyable' : ''}`}
291
+ onClick={copyable ? handleCopy : undefined}
292
+ title={copyable ? 'Click to copy' : undefined}
293
+ >
294
+ {value2 || (placeholder && <span className="property-value__placeholder">{placeholder}</span>)}
295
+ </span>
296
+
297
+ {/* Copy indicator */}
298
+ {copyable && value2 && (
299
+ <Icon
300
+ icon="content_copy"
301
+ size="small"
302
+ className="property-value__copy"
303
+ aria-label="Copy value"
304
+ />
305
+ )}
306
+ </>
307
+ )}
37
308
  </div>
309
+
310
+ {/* Helper text or error */}
311
+ {(helperText || error || validationError) && (
312
+ <div
313
+ id={`${id}-helper`}
314
+ className={`property__helper ${error || validationError ? 'property__helper--error' : ''}`}
315
+ >
316
+ <Text size="sm" color={error || validationError ? 'error' : 'muted'}>
317
+ {error || validationError || helperText}
318
+ </Text>
319
+ </div>
320
+ )}
38
321
  </div>
39
322
  )
40
- }
323
+ }
324
+
325
+ // PropTypes
326
+ Property.propTypes = {
327
+ /** Property ID */
328
+ id: PropTypes.string,
329
+ /** Additional CSS classes */
330
+ className: PropTypes.string,
331
+ /** Property label */
332
+ label: PropTypes.string,
333
+ /** Property name (alternative to label) */
334
+ name: PropTypes.string,
335
+ /** Initial value */
336
+ initial: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
337
+ /** Current value */
338
+ value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
339
+ /** Enable editing */
340
+ editable: PropTypes.bool,
341
+ /** Change callback */
342
+ onChange: PropTypes.func,
343
+ /** Options for dropdown display */
344
+ options: PropTypes.arrayOf(PropTypes.shape({
345
+ label: PropTypes.string,
346
+ value: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
347
+ })),
348
+ /** Input type */
349
+ type: PropTypes.string,
350
+ /** Disabled state */
351
+ disabled: PropTypes.bool,
352
+ /** Required field */
353
+ required: PropTypes.bool,
354
+ /** Input placeholder */
355
+ placeholder: PropTypes.string,
356
+ /** Enable multiline input */
357
+ multiline: PropTypes.bool,
358
+ /** Number of rows for textarea */
359
+ rows: PropTypes.number,
360
+ /** Maximum length */
361
+ maxLength: PropTypes.number,
362
+ /** Minimum length */
363
+ minLength: PropTypes.number,
364
+ /** Validation pattern */
365
+ pattern: PropTypes.string,
366
+ /** Custom validation function */
367
+ validateValue: PropTypes.func,
368
+ /** Property size */
369
+ size: PropTypes.oneOf(['small', 'medium', 'large']),
370
+ /** Visual variant */
371
+ variant: PropTypes.oneOf(['default', 'outlined', 'filled']),
372
+ /** Layout direction */
373
+ layout: PropTypes.oneOf(['horizontal', 'vertical']),
374
+ /** Name column width */
375
+ nameWidth: PropTypes.string,
376
+ /** Enable copy functionality */
377
+ copyable: PropTypes.bool,
378
+ /** Error message */
379
+ error: PropTypes.string,
380
+ /** Helper text */
381
+ helperText: PropTypes.string,
382
+ /** Focus callback */
383
+ onFocus: PropTypes.func,
384
+ /** Blur callback */
385
+ onBlur: PropTypes.func,
386
+ /** Validation error callback */
387
+ onValidationError: PropTypes.func,
388
+ /** Show clear button */
389
+ clearable: PropTypes.bool,
390
+ /** Read-only state */
391
+ readOnly: PropTypes.bool,
392
+ /** Loading state */
393
+ loading: PropTypes.bool,
394
+ /** Skeleton placeholder */
395
+ skeleton: PropTypes.bool,
396
+ /** Inline styles */
397
+ style: PropTypes.object
398
+ }
399
+
400
+ Property.defaultProps = {
401
+ editable: false,
402
+ type: 'text',
403
+ disabled: false,
404
+ required: false,
405
+ multiline: false,
406
+ rows: 3,
407
+ size: 'medium',
408
+ variant: 'default',
409
+ layout: 'horizontal',
410
+ nameWidth: '50%',
411
+ copyable: false,
412
+ clearable: true,
413
+ readOnly: false,
414
+ loading: false,
415
+ skeleton: false
416
+ }
417
+
418
+ export default Property