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.
- 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 +7900 -1615
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +6094 -1122
- package/dist/index.css.map +1 -1
- package/dist/index.modern.js +7929 -1645
- package/dist/index.modern.js.map +1 -1
- package/dist/index.umd.js +7900 -1615
- 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 +1 -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 +288 -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/textfield.js +1 -1
- package/src/html/textfield2.css +842 -0
- package/src/html/textfield2.example.js +499 -0
- package/src/html/textfield2.js +1130 -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 +228 -0
- package/src/html/tree.example.js +475 -0
- package/src/html/tree.js +712 -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/property.js
CHANGED
@@ -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
|
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
|
-
|
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
|
-
|
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={
|
33
|
-
|
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 ?
|
36
|
-
|
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
|