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
@@ -0,0 +1,375 @@
1
+ /* Enhanced Text Component Styles */
2
+
3
+ .text {
4
+ display: inline;
5
+ font-family: inherit;
6
+ line-height: inherit;
7
+ margin: 0;
8
+ padding: 0;
9
+ transition: color 0.2s ease;
10
+ }
11
+
12
+ /* Size variants */
13
+ .text--xs {
14
+ font-size: 0.75rem;
15
+ line-height: 1.2;
16
+ }
17
+
18
+ .text--sm {
19
+ font-size: 0.875rem;
20
+ line-height: 1.25;
21
+ }
22
+
23
+ .text--md {
24
+ font-size: 1rem;
25
+ line-height: 1.5;
26
+ }
27
+
28
+ .text--lg {
29
+ font-size: 1.125rem;
30
+ line-height: 1.5;
31
+ }
32
+
33
+ .text--xl {
34
+ font-size: 1.25rem;
35
+ line-height: 1.4;
36
+ }
37
+
38
+ .text--xxl {
39
+ font-size: 1.5rem;
40
+ line-height: 1.3;
41
+ }
42
+
43
+ /* Weight variants */
44
+ .text--light {
45
+ font-weight: 300;
46
+ }
47
+
48
+ .text--normal {
49
+ font-weight: 400;
50
+ }
51
+
52
+ .text--medium {
53
+ font-weight: 500;
54
+ }
55
+
56
+ .text--semibold {
57
+ font-weight: 600;
58
+ }
59
+
60
+ .text--bold {
61
+ font-weight: 700;
62
+ }
63
+
64
+ /* Color variants */
65
+ .text--primary {
66
+ color: var(--primary-color, #2196f3);
67
+ }
68
+
69
+ .text--secondary {
70
+ color: var(--secondary-color, #757575);
71
+ }
72
+
73
+ .text--success {
74
+ color: var(--success-color, #4caf50);
75
+ }
76
+
77
+ .text--warning {
78
+ color: var(--warning-color, #ff9800);
79
+ }
80
+
81
+ .text--error {
82
+ color: var(--error-color, #f44336);
83
+ }
84
+
85
+ .text--muted {
86
+ color: var(--text-color-light, #666666);
87
+ }
88
+
89
+ /* Alignment variants */
90
+ .text--left {
91
+ text-align: left;
92
+ }
93
+
94
+ .text--center {
95
+ text-align: center;
96
+ }
97
+
98
+ .text--right {
99
+ text-align: right;
100
+ }
101
+
102
+ .text--justify {
103
+ text-align: justify;
104
+ }
105
+
106
+ /* Transform variants */
107
+ .text--capitalize {
108
+ text-transform: capitalize;
109
+ }
110
+
111
+ .text--uppercase {
112
+ text-transform: uppercase;
113
+ }
114
+
115
+ .text--lowercase {
116
+ text-transform: lowercase;
117
+ }
118
+
119
+ /* Decoration variants */
120
+ .text--underline {
121
+ text-decoration: underline;
122
+ }
123
+
124
+ .text--line-through {
125
+ text-decoration: line-through;
126
+ }
127
+
128
+ /* State variants */
129
+ .text--truncate {
130
+ overflow: hidden;
131
+ text-overflow: ellipsis;
132
+ white-space: nowrap;
133
+ max-width: 100%;
134
+ }
135
+
136
+ .text--no-select {
137
+ user-select: none;
138
+ -webkit-user-select: none;
139
+ -moz-user-select: none;
140
+ -ms-user-select: none;
141
+ }
142
+
143
+ .text--copyable {
144
+ cursor: pointer;
145
+ position: relative;
146
+ display: inline-flex;
147
+ align-items: center;
148
+ gap: 0.25rem;
149
+ }
150
+
151
+ .text--copyable:hover {
152
+ background-color: var(--hover-color, rgba(0, 0, 0, 0.04));
153
+ border-radius: 2px;
154
+ padding: 0.125rem 0.25rem;
155
+ margin: -0.125rem -0.25rem;
156
+ }
157
+
158
+ .text--copyable:focus {
159
+ outline: 2px solid var(--primary-color, #2196f3);
160
+ outline-offset: 2px;
161
+ border-radius: 2px;
162
+ }
163
+
164
+ .text--loading {
165
+ opacity: 0.7;
166
+ pointer-events: none;
167
+ }
168
+
169
+ .text--skeleton {
170
+ background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
171
+ background-size: 200% 100%;
172
+ animation: skeleton-loading 1.5s infinite;
173
+ border-radius: 2px;
174
+ color: transparent;
175
+ user-select: none;
176
+ }
177
+
178
+ /* Copy indicator */
179
+ .text__copy-indicator {
180
+ opacity: 0;
181
+ transition: opacity 0.2s ease;
182
+ font-size: 0.8em;
183
+ }
184
+
185
+ .text--copyable:hover .text__copy-indicator {
186
+ opacity: 0.6;
187
+ }
188
+
189
+ /* Skeleton placeholder */
190
+ .text__skeleton {
191
+ background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
192
+ background-size: 200% 100%;
193
+ animation: skeleton-loading 1.5s infinite;
194
+ border-radius: 2px;
195
+ color: transparent;
196
+ user-select: none;
197
+ display: inline-block;
198
+ min-width: 4rem;
199
+ min-height: 1em;
200
+ }
201
+
202
+ /* Animations */
203
+ @keyframes skeleton-loading {
204
+ 0% {
205
+ background-position: 200% 0;
206
+ }
207
+ 100% {
208
+ background-position: -200% 0;
209
+ }
210
+ }
211
+
212
+ /* Responsive Design */
213
+ @media (max-width: 768px) {
214
+ .text--xs {
215
+ font-size: 0.7rem;
216
+ }
217
+
218
+ .text--sm {
219
+ font-size: 0.8rem;
220
+ }
221
+
222
+ .text--md {
223
+ font-size: 0.9rem;
224
+ }
225
+
226
+ .text--lg {
227
+ font-size: 1rem;
228
+ }
229
+
230
+ .text--xl {
231
+ font-size: 1.1rem;
232
+ }
233
+
234
+ .text--xxl {
235
+ font-size: 1.25rem;
236
+ }
237
+
238
+ .text--copyable:hover {
239
+ padding: 0.25rem;
240
+ margin: -0.25rem;
241
+ }
242
+ }
243
+
244
+ /* Dark Theme Support */
245
+ @media (prefers-color-scheme: dark) {
246
+ .text--primary {
247
+ color: var(--primary-color-dark, #64b5f6);
248
+ }
249
+
250
+ .text--secondary {
251
+ color: var(--secondary-color-dark, #bdbdbd);
252
+ }
253
+
254
+ .text--success {
255
+ color: var(--success-color-dark, #81c784);
256
+ }
257
+
258
+ .text--warning {
259
+ color: var(--warning-color-dark, #ffb74d);
260
+ }
261
+
262
+ .text--error {
263
+ color: var(--error-color-dark, #e57373);
264
+ }
265
+
266
+ .text--muted {
267
+ color: var(--text-color-light-dark, #cccccc);
268
+ }
269
+
270
+ .text--copyable:hover {
271
+ background-color: var(--hover-color-dark, rgba(255, 255, 255, 0.08));
272
+ }
273
+
274
+ .text--skeleton,
275
+ .text__skeleton {
276
+ background: linear-gradient(90deg, #424242 25%, #616161 50%, #424242 75%);
277
+ background-size: 200% 100%;
278
+ }
279
+ }
280
+
281
+ /* High Contrast Mode */
282
+ @media (prefers-contrast: high) {
283
+ .text--copyable:focus {
284
+ outline-width: 3px;
285
+ outline-color: currentColor;
286
+ }
287
+
288
+ .text--primary,
289
+ .text--secondary,
290
+ .text--success,
291
+ .text--warning,
292
+ .text--error {
293
+ font-weight: 600;
294
+ }
295
+
296
+ .text--underline {
297
+ text-decoration-thickness: 2px;
298
+ }
299
+ }
300
+
301
+ /* Reduced Motion */
302
+ @media (prefers-reduced-motion: reduce) {
303
+ .text {
304
+ transition: none;
305
+ }
306
+
307
+ .text--skeleton,
308
+ .text__skeleton {
309
+ animation: none;
310
+ background: #e0e0e0;
311
+ }
312
+
313
+ .text__copy-indicator {
314
+ transition: none;
315
+ }
316
+ }
317
+
318
+ /* Print Styles */
319
+ @media print {
320
+ .text {
321
+ color: black !important;
322
+ background: transparent !important;
323
+ }
324
+
325
+ .text--copyable {
326
+ cursor: default !important;
327
+ }
328
+
329
+ .text__copy-indicator {
330
+ display: none !important;
331
+ }
332
+
333
+ .text--skeleton,
334
+ .text__skeleton {
335
+ background: #f0f0f0 !important;
336
+ animation: none !important;
337
+ }
338
+
339
+ .text--primary,
340
+ .text--secondary,
341
+ .text--success,
342
+ .text--warning,
343
+ .text--error,
344
+ .text--muted {
345
+ color: black !important;
346
+ }
347
+ }
348
+
349
+ /* Focus visible for better accessibility */
350
+ .text--copyable:focus-visible {
351
+ outline: 2px solid var(--primary-color, #2196f3);
352
+ outline-offset: 2px;
353
+ }
354
+
355
+ /* Selection styling */
356
+ .text::selection {
357
+ background-color: var(--primary-color-light, rgba(33, 150, 243, 0.2));
358
+ color: inherit;
359
+ }
360
+
361
+ /* Ensure proper line height for different sizes */
362
+ .text--xs,
363
+ .text--sm {
364
+ line-height: 1.4;
365
+ }
366
+
367
+ .text--md {
368
+ line-height: 1.5;
369
+ }
370
+
371
+ .text--lg,
372
+ .text--xl,
373
+ .text--xxl {
374
+ line-height: 1.3;
375
+ }
package/src/html/text.js CHANGED
@@ -1,5 +1,7 @@
1
- import React, { useContext } from "react"
1
+ import React, { useContext, useMemo, useCallback } from "react"
2
+ import PropTypes from 'prop-types'
2
3
  import { SiteContext } from "../site/siteContext"
4
+ import './text.css'
3
5
 
4
6
  export const TEXTFORMATS = {
5
7
  NONE: '',
@@ -10,39 +12,328 @@ export const TEXTFORMATS = {
10
12
  HTML: 'HTML',
11
13
  URL: 'URL',
12
14
  STRING: 'string',
15
+ // New formats
16
+ CURRENCY: 'currency',
17
+ PERCENTAGE: 'percentage',
18
+ PHONE: 'phone',
19
+ CAPITALIZE: 'capitalize',
20
+ UPPERCASE: 'uppercase',
21
+ LOWERCASE: 'lowercase',
22
+ TRUNCATE: 'truncate',
23
+ MARKDOWN: 'markdown'
13
24
  }
14
25
 
15
26
  /**
16
- * Text
27
+ * Enhanced Text component with improved functionality while maintaining 100% compatibility
17
28
  */
18
- export const Text = ({ format = TEXTFORMATS.HTML, children, className }) => {
29
+ export const Text = (props) => {
30
+ const {
31
+ // Original props (100% compatible)
32
+ format = TEXTFORMATS.HTML,
33
+ children,
34
+ className,
35
+ // New enhanced props (all optional for compatibility)
36
+ size,
37
+ weight,
38
+ color,
39
+ align,
40
+ transform,
41
+ decoration,
42
+ truncate,
43
+ maxLength,
44
+ locale,
45
+ currency = 'USD',
46
+ minimumFractionDigits,
47
+ maximumFractionDigits,
48
+ dateStyle = 'medium',
49
+ timeStyle = 'medium',
50
+ fallback = '',
51
+ loading = false,
52
+ skeleton = false,
53
+ copyable = false,
54
+ selectable = true,
55
+ as = 'span',
56
+ style,
57
+ onClick,
58
+ ...restProps
59
+ } = props
19
60
 
20
61
  const site = useContext(SiteContext)
21
- let value = children
22
62
 
23
- if (site) {
24
- const { lang, dictionary = {} } = site
25
- const term = dictionary[children]
26
- const text = term ? term[lang] : children
27
- if (text) value = text
28
- }
63
+ // Memoize formatted value for performance
64
+ const formattedValue = useMemo(() => {
65
+ let value = children
66
+
67
+ // Handle empty/null values
68
+ if (children === null || children === undefined || children === '') {
69
+ return fallback || ''
70
+ }
71
+
72
+ // Internationalization (maintaining original logic)
73
+ if (site) {
74
+ const { lang, dictionary = {} } = site
75
+ const term = dictionary[children]
76
+ const text = term ? term[lang] : children
77
+ if (text) value = text
78
+ }
79
+
80
+ // Use provided locale or site locale or browser locale
81
+ const currentLocale = locale || (site && site.lang) || navigator.language || 'en-US'
82
+
83
+ try {
84
+ switch (format) {
85
+ case TEXTFORMATS.NUMERIC: {
86
+ const formatter = new Intl.NumberFormat(currentLocale, {
87
+ minimumFractionDigits,
88
+ maximumFractionDigits
89
+ })
90
+ return formatter.format(Number(children))
91
+ }
92
+
93
+ case TEXTFORMATS.CURRENCY: {
94
+ const formatter = new Intl.NumberFormat(currentLocale, {
95
+ style: 'currency',
96
+ currency,
97
+ minimumFractionDigits,
98
+ maximumFractionDigits
99
+ })
100
+ return formatter.format(Number(children))
101
+ }
102
+
103
+ case TEXTFORMATS.PERCENTAGE: {
104
+ const formatter = new Intl.NumberFormat(currentLocale, {
105
+ style: 'percent',
106
+ minimumFractionDigits,
107
+ maximumFractionDigits
108
+ })
109
+ return formatter.format(Number(children) / 100)
110
+ }
111
+
112
+ case TEXTFORMATS.DATE: {
113
+ const date = new Date(children)
114
+ if (isNaN(date.getTime())) return String(children)
115
+ return date.toLocaleDateString(currentLocale, { dateStyle })
116
+ }
117
+
118
+ case TEXTFORMATS.TIME: {
119
+ const date = new Date(children)
120
+ if (isNaN(date.getTime())) return String(children)
121
+ return date.toLocaleTimeString(currentLocale, { timeStyle })
122
+ }
123
+
124
+ case TEXTFORMATS.EMAIL: {
125
+ return String(value)
126
+ }
127
+
128
+ case TEXTFORMATS.PHONE: {
129
+ // Basic phone formatting for US numbers
130
+ const cleaned = String(value).replace(/\D/g, '')
131
+ if (cleaned.length === 10) {
132
+ return `(${cleaned.slice(0, 3)}) ${cleaned.slice(3, 6)}-${cleaned.slice(6)}`
133
+ }
134
+ return String(value)
135
+ }
136
+
137
+ case TEXTFORMATS.URL: {
138
+ return String(value)
139
+ }
140
+
141
+ case TEXTFORMATS.CAPITALIZE: {
142
+ return String(value).charAt(0).toUpperCase() + String(value).slice(1).toLowerCase()
143
+ }
144
+
145
+ case TEXTFORMATS.UPPERCASE: {
146
+ return String(value).toUpperCase()
147
+ }
29
148
 
30
- const formatter = Intl.NumberFormat()
31
- switch (format) {
32
- case TEXTFORMATS.NUMERIC: value = formatter.format(children); break;
149
+ case TEXTFORMATS.LOWERCASE: {
150
+ return String(value).toLowerCase()
151
+ }
152
+
153
+ case TEXTFORMATS.TRUNCATE: {
154
+ const text = String(value)
155
+ if (maxLength && text.length > maxLength) {
156
+ return text.slice(0, maxLength) + '...'
157
+ }
158
+ return text
159
+ }
160
+
161
+ case TEXTFORMATS.STRING: {
162
+ return String(value)
163
+ }
164
+
165
+ case TEXTFORMATS.HTML:
166
+ default: {
167
+ return String(value)
168
+ }
169
+ }
170
+ } catch (error) {
171
+ console.warn('Text formatting error:', error)
172
+ return String(value)
173
+ }
174
+ }, [children, format, site, locale, currency, minimumFractionDigits, maximumFractionDigits, dateStyle, timeStyle, maxLength, fallback])
175
+
176
+ // Handle copy functionality
177
+ const handleCopy = useCallback(async () => {
178
+ if (!copyable || !formattedValue) return
179
+
180
+ try {
181
+ await navigator.clipboard.writeText(formattedValue)
182
+ // Could trigger a toast notification here
183
+ } catch (error) {
184
+ console.warn('Failed to copy text:', error)
185
+ }
186
+ }, [copyable, formattedValue])
187
+
188
+ // Handle click
189
+ const handleClick = useCallback((event) => {
190
+ if (copyable) {
191
+ handleCopy()
192
+ }
193
+ if (onClick) {
194
+ onClick(event)
195
+ }
196
+ }, [copyable, handleCopy, onClick])
197
+
198
+ // Generate CSS classes
199
+ const cssClasses = [
200
+ 'text',
201
+ size && `text--${size}`,
202
+ weight && `text--${weight}`,
203
+ color && `text--${color}`,
204
+ align && `text--${align}`,
205
+ transform && `text--${transform}`,
206
+ decoration && `text--${decoration}`,
207
+ truncate && 'text--truncate',
208
+ loading && 'text--loading',
209
+ skeleton && 'text--skeleton',
210
+ copyable && 'text--copyable',
211
+ !selectable && 'text--no-select',
212
+ className
213
+ ].filter(Boolean).join(' ')
214
+
215
+ // Generate inline styles
216
+ const inlineStyle = {
217
+ ...style
33
218
  }
34
219
 
35
- switch (format) {
36
- case TEXTFORMATS.DATE: value = new Date(children).toLocaleDateString(); break;
37
- case TEXTFORMATS.TIME: value = new Date(children).toLocaleTimeString(); break;
220
+ // Handle loading state
221
+ if (loading || skeleton) {
222
+ const Component = as
223
+ return (
224
+ <Component
225
+ className={cssClasses}
226
+ style={inlineStyle}
227
+ {...restProps}
228
+ >
229
+ <span className="text__skeleton">
230
+ {skeleton ? '████████' : 'Loading...'}
231
+ </span>
232
+ </Component>
233
+ )
38
234
  }
39
235
 
40
- if (!children) return ''
236
+ // Handle empty content (maintaining original logic)
237
+ if (!children && !fallback) return ''
41
238
 
42
- switch (format) {
43
- case TEXTFORMATS.STRING: return value
44
- default: return <span className={className}>{value}</span>
239
+ // Return string for STRING format (maintaining original logic)
240
+ if (format === TEXTFORMATS.STRING) {
241
+ return formattedValue
45
242
  }
46
243
 
244
+ // Render as component
245
+ const Component = as
246
+
247
+ return (
248
+ <Component
249
+ className={cssClasses}
250
+ style={inlineStyle}
251
+ onClick={handleClick}
252
+ title={copyable ? 'Click to copy' : undefined}
253
+ role={copyable ? 'button' : undefined}
254
+ tabIndex={copyable ? 0 : undefined}
255
+ {...restProps}
256
+ >
257
+ {formattedValue}
258
+ {copyable && (
259
+ <span className="text__copy-indicator" aria-hidden="true">
260
+ 📋
261
+ </span>
262
+ )}
263
+ </Component>
264
+ )
265
+ }
266
+
267
+ // PropTypes
268
+ Text.propTypes = {
269
+ /** Text format */
270
+ format: PropTypes.oneOf(Object.values(TEXTFORMATS)),
271
+ /** Text content */
272
+ children: PropTypes.oneOfType([
273
+ PropTypes.string,
274
+ PropTypes.number,
275
+ PropTypes.node
276
+ ]),
277
+ /** Additional CSS classes */
278
+ className: PropTypes.string,
279
+ /** Text size */
280
+ size: PropTypes.oneOf(['xs', 'sm', 'md', 'lg', 'xl', 'xxl']),
281
+ /** Font weight */
282
+ weight: PropTypes.oneOf(['light', 'normal', 'medium', 'semibold', 'bold']),
283
+ /** Text color */
284
+ color: PropTypes.oneOf(['primary', 'secondary', 'success', 'warning', 'error', 'muted']),
285
+ /** Text alignment */
286
+ align: PropTypes.oneOf(['left', 'center', 'right', 'justify']),
287
+ /** Text transform */
288
+ transform: PropTypes.oneOf(['none', 'capitalize', 'uppercase', 'lowercase']),
289
+ /** Text decoration */
290
+ decoration: PropTypes.oneOf(['none', 'underline', 'line-through']),
291
+ /** Enable truncation */
292
+ truncate: PropTypes.bool,
293
+ /** Maximum length for truncation */
294
+ maxLength: PropTypes.number,
295
+ /** Locale for formatting */
296
+ locale: PropTypes.string,
297
+ /** Currency code for currency format */
298
+ currency: PropTypes.string,
299
+ /** Minimum fraction digits for numbers */
300
+ minimumFractionDigits: PropTypes.number,
301
+ /** Maximum fraction digits for numbers */
302
+ maximumFractionDigits: PropTypes.number,
303
+ /** Date formatting style */
304
+ dateStyle: PropTypes.oneOf(['full', 'long', 'medium', 'short']),
305
+ /** Time formatting style */
306
+ timeStyle: PropTypes.oneOf(['full', 'long', 'medium', 'short']),
307
+ /** Fallback text for empty values */
308
+ fallback: PropTypes.string,
309
+ /** Loading state */
310
+ loading: PropTypes.bool,
311
+ /** Skeleton placeholder */
312
+ skeleton: PropTypes.bool,
313
+ /** Enable copy functionality */
314
+ copyable: PropTypes.bool,
315
+ /** Enable text selection */
316
+ selectable: PropTypes.bool,
317
+ /** HTML element to render as */
318
+ as: PropTypes.string,
319
+ /** Inline styles */
320
+ style: PropTypes.object,
321
+ /** Click handler */
322
+ onClick: PropTypes.func
47
323
  }
48
324
 
325
+ Text.defaultProps = {
326
+ format: TEXTFORMATS.HTML,
327
+ currency: 'USD',
328
+ dateStyle: 'medium',
329
+ timeStyle: 'medium',
330
+ fallback: '',
331
+ loading: false,
332
+ skeleton: false,
333
+ copyable: false,
334
+ selectable: true,
335
+ as: 'span'
336
+ }
337
+
338
+ export default Text
339
+