ywana-core8 0.1.80 → 0.1.81

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ywana-core8",
3
- "version": "0.1.80",
3
+ "version": "0.1.81",
4
4
  "description": "ywana-core8",
5
5
  "homepage": "https://ywana.github.io/workspace",
6
6
  "author": "Ernesto Roldan Garcia",
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useState, useCallback } from 'react'
1
+ import React, { useEffect, useState, useCallback, useMemo } from 'react'
2
2
  import PropTypes from 'prop-types'
3
3
  import { Icon } from './icon'
4
4
  import { Text } from './text'
@@ -88,6 +88,24 @@ export const Button = (props) => {
88
88
  'aria-describedby': tooltip ? `${id}-tooltip` : undefined
89
89
  }
90
90
 
91
+ // Label text - support both string and React components
92
+ const labelElement = useMemo(() => {
93
+ if (!label) return null
94
+
95
+ // If label is already a React element, use it directly
96
+ if (React.isValidElement(label)) {
97
+ return label
98
+ }
99
+
100
+ // If label is a string, wrap it in Text component
101
+ if (typeof label === 'string') {
102
+ return <Text>{label}</Text>
103
+ }
104
+
105
+ // Fallback for other types (convert to string)
106
+ return <Text>{String(label)}</Text>
107
+ }, [label])
108
+
91
109
  // Icon configuration
92
110
  const iconProps = {
93
111
  icon: loading ? 'hourglass_empty' : icon,
@@ -111,7 +129,7 @@ export const Button = (props) => {
111
129
  {...restProps}
112
130
  >
113
131
  {(icon || loading) && <Icon {...iconProps} />}
114
- {label && <Text>{label}</Text>}
132
+ {labelElement}
115
133
  {loading && !icon && <span className="loading-text">Loading...</span>}
116
134
  </button>
117
135
  )
@@ -207,8 +225,8 @@ export const ActionButton = (props) => {
207
225
  Button.propTypes = {
208
226
  /** Unique identifier for the button */
209
227
  id: PropTypes.string,
210
- /** Button text label */
211
- label: PropTypes.string,
228
+ /** Button text label - can be string or React element */
229
+ label: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
212
230
  /** Icon name for Material Icons */
213
231
  icon: PropTypes.string,
214
232
  /** Click handler function */
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React, { useMemo } from 'react';
2
2
  import { Icon } from './icon';
3
3
  import { Text } from './text';
4
4
  import './header.css';
@@ -18,11 +18,28 @@ export const Header = (props) => {
18
18
 
19
19
  const style = props.img ? { backgroundImage: `url(${props.img })` } : {}
20
20
 
21
- const title=<Text>{props.title}</Text>
21
+ // Title element - support both string and React components
22
+ const titleElement = useMemo(() => {
23
+ if (!props.title) return null
24
+
25
+ // If title is already a React element, use it directly
26
+ if (React.isValidElement(props.title)) {
27
+ return props.title
28
+ }
29
+
30
+ // If title is a string, wrap it in Text component
31
+ if (typeof props.title === 'string') {
32
+ return <Text>{props.title}</Text>
33
+ }
34
+
35
+ // Fallback for other types (convert to string)
36
+ return <Text>{String(props.title)}</Text>
37
+ }, [props.title])
38
+
22
39
  return (
23
40
  <header className={`header ${caption} ${prominent} ${dense} ${theme} ${props.className}`} style={style}>
24
41
  {icon}
25
- {props.title ? <label>{title}</label> : null }
42
+ {props.title ? <label>{titleElement}</label> : null }
26
43
  <span className="actions">{props.children}</span>
27
44
  </header>
28
45
  )
@@ -1,4 +1,4 @@
1
- import React, { useContext, useEffect, useState } from 'react'
1
+ import React, { useContext, useEffect, useState, useMemo } from 'react'
2
2
  import { SiteContext } from '../site/siteContext'
3
3
  import { Icon } from './icon'
4
4
  import { TEXTFORMATS, Text } from './text'
@@ -59,7 +59,25 @@ export const TextField = (props) => {
59
59
  const labelStyle = label ? "" : "no-label"
60
60
  const labelPositionStyle = labelPosition == 'left' ? "label-left" : "label-top"
61
61
  const style = `${labelStyle} ${labelPositionStyle} ${borderStyle} textfield-${type}`
62
- const labelTxt = <Text>{label}</Text>
62
+
63
+ // Label text - support both string and React components
64
+ const labelTxt = useMemo(() => {
65
+ if (!label) return null
66
+
67
+ // If label is already a React element, use it directly
68
+ if (React.isValidElement(label)) {
69
+ return label
70
+ }
71
+
72
+ // If label is a string, wrap it in Text component
73
+ if (typeof label === 'string') {
74
+ return <Text>{label}</Text>
75
+ }
76
+
77
+ // Fallback for other types (convert to string)
78
+ return <Text>{String(label)}</Text>
79
+ }, [label])
80
+
63
81
  const placeholderTxt = site.translate ? site.translate(placeholder) : placeholder
64
82
 
65
83
  return (
@@ -110,10 +128,26 @@ export const TextArea = (props) => {
110
128
  if (onChange) onChange(id, "")
111
129
  }
112
130
 
113
- const borderStyle = outlined ? "textarea-outlined" : "textarea"
114
131
  const labelStyle = label ? "" : "no-label"
115
132
  const style = `textarea ${labelStyle} textarea-${type}`
116
- const labelTxt = <Text>{label}</Text>
133
+
134
+ // Label text - support both string and React components
135
+ const labelTxt = useMemo(() => {
136
+ if (!label) return null
137
+
138
+ // If label is already a React element, use it directly
139
+ if (React.isValidElement(label)) {
140
+ return label
141
+ }
142
+
143
+ // If label is a string, wrap it in Text component
144
+ if (typeof label === 'string') {
145
+ return <Text>{label}</Text>
146
+ }
147
+
148
+ // Fallback for other types (convert to string)
149
+ return <Text>{String(label)}</Text>
150
+ }, [label])
117
151
 
118
152
  const placeholderTxt = site.translate ? site.translate(placeholder) : placeholder
119
153
 
@@ -222,7 +256,7 @@ export const DropDown = (props) => {
222
256
  */
223
257
  export const DateRange = (props) => {
224
258
 
225
- const { id, label, value, onChange } = props
259
+ const { id, label, onChange } = props
226
260
  const [form, setForm] = useState({})
227
261
 
228
262
  useEffect(() => {
@@ -237,7 +271,23 @@ export const DateRange = (props) => {
237
271
  setForm(next)
238
272
  }
239
273
 
240
- const labelTxt = label ? <Text>{label}</Text> : null
274
+ // Label text - support both string and React components
275
+ const labelTxt = useMemo(() => {
276
+ if (!label) return null
277
+
278
+ // If label is already a React element, use it directly
279
+ if (React.isValidElement(label)) {
280
+ return label
281
+ }
282
+
283
+ // If label is a string, wrap it in Text component
284
+ if (typeof label === 'string') {
285
+ return <Text>{label}</Text>
286
+ }
287
+
288
+ // Fallback for other types (convert to string)
289
+ return <Text>{String(label)}</Text>
290
+ }, [label])
241
291
 
242
292
  return (
243
293
  <div className="date-range">
@@ -257,7 +307,23 @@ export const PasswordField = (props) => {
257
307
  setShow(!show)
258
308
  }
259
309
 
260
- const labelTxt = label ? <Text>{label}</Text> : null
310
+ // Label text - support both string and React components
311
+ const labelTxt = useMemo(() => {
312
+ if (!label) return null
313
+
314
+ // If label is already a React element, use it directly
315
+ if (React.isValidElement(label)) {
316
+ return label
317
+ }
318
+
319
+ // If label is a string, wrap it in Text component
320
+ if (typeof label === 'string') {
321
+ return <Text>{label}</Text>
322
+ }
323
+
324
+ // Fallback for other types (convert to string)
325
+ return <Text>{String(label)}</Text>
326
+ }, [label])
261
327
 
262
328
  return (
263
329
  <div className="password-field">
@@ -204,8 +204,23 @@ export const TextField2 = (props) => {
204
204
  ...restProps
205
205
  }
206
206
 
207
- // Label text
208
- const labelTxt = label ? <Text>{label}</Text> : null
207
+ // Label text - support both string and React components
208
+ const labelTxt = useMemo(() => {
209
+ if (!label) return null
210
+
211
+ // If label is already a React element, use it directly
212
+ if (React.isValidElement(label)) {
213
+ return label
214
+ }
215
+
216
+ // If label is a string, wrap it in Text component
217
+ if (typeof label === 'string') {
218
+ return <Text>{label}</Text>
219
+ }
220
+
221
+ // Fallback for other types (convert to string)
222
+ return <Text>{String(label)}</Text>
223
+ }, [label])
209
224
  const placeholderTxt = site?.translate ? site.translate(placeholder) : placeholder
210
225
 
211
226
  // Error/helper text
@@ -304,8 +319,8 @@ TextField2.propTypes = {
304
319
  type: PropTypes.oneOf(['text', 'email', 'password', 'number', 'tel', 'url', 'search', 'date', 'time', 'datetime-local', 'month', 'week', 'textarea']),
305
320
  /** Additional CSS classes */
306
321
  className: PropTypes.string,
307
- /** Field label */
308
- label: PropTypes.string,
322
+ /** Field label - can be string or React element */
323
+ label: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
309
324
  /** Label position */
310
325
  labelPosition: PropTypes.oneOf(['top', 'left']),
311
326
  /** Placeholder text */
@@ -1,4 +1,4 @@
1
- import React from 'react'
1
+ import React, { useMemo } from 'react'
2
2
  import { Text } from './text'
3
3
  import './tooltip.css'
4
4
 
@@ -11,11 +11,29 @@ export const Tooltip = (props) => {
11
11
 
12
12
  const style = { top, left }
13
13
 
14
+ // Text element - support both string and React components
15
+ const textElement = useMemo(() => {
16
+ if (!text) return null
17
+
18
+ // If text is already a React element, use it directly
19
+ if (React.isValidElement(text)) {
20
+ return text
21
+ }
22
+
23
+ // If text is a string, wrap it in Text component
24
+ if (typeof text === 'string') {
25
+ return <Text>{text}</Text>
26
+ }
27
+
28
+ // Fallback for other types (convert to string)
29
+ return <Text>{String(text)}</Text>
30
+ }, [text])
31
+
14
32
  return (
15
33
  <div className="tooltip" >
16
- <span className="tooltip-text" style={style}><Text>{text}</Text></span>
34
+ <span className="tooltip-text" style={style}>{textElement}</span>
17
35
  {props.children}
18
36
  </div>
19
37
  )
20
38
 
21
- }
39
+ }
@@ -6,6 +6,7 @@
6
6
  padding: 1rem 1rem 0 1rem;
7
7
  display: flex;
8
8
  flex-direction: column;
9
+ gap: 1rem
9
10
  }
10
11
 
11
12
  .login-box .message {
@@ -1,5 +1,5 @@
1
1
  import React, { useState } from 'react'
2
- import { Icon , Button, Text, TextField } from '../../html'
2
+ import { Icon , Button, Text, TextField2 as TextField } from '../../html'
3
3
  import './LoginBox.css'
4
4
 
5
5
  /**
@@ -24,23 +24,46 @@ export const LoginBox = ({
24
24
  if (onOK && canOK()) onOK(user, forcedPwd || password)
25
25
  }
26
26
 
27
+ // Helper function for backward compatibility
28
+ // TextField2 now supports both strings and React elements
27
29
  function tx(txt) {
30
+ // For TextField2, we can pass strings directly for better performance
31
+ // But keep this function for backward compatibility with other components
28
32
  return <Text>{txt}</Text>
29
33
  }
30
34
 
31
- function changeUser(id, value) {
35
+ function changeUser(_, value) {
32
36
  setUser(value)
33
37
  }
34
-
35
- function changePassword(id, value) {
38
+
39
+ function changePassword(_, value) {
36
40
  setPassword(value)
37
41
  }
38
42
 
39
43
  return (
40
44
  <div className="login-box">
41
45
  <main>
42
- <TextField label={tx(userLabel)} value={user} onChange={changeUser} onEnter={ok} outlined autoComplete="on" />
43
- <TextField id="loginbox-password" label={tx(passwordLabel)} value={password} onChange={changePassword} onEnter={ok} type="password" outlined autoComplete="on" />
46
+ <TextField
47
+ id="loginbox-user"
48
+ label={tx(userLabel)}
49
+ value={user}
50
+ onChange={changeUser}
51
+ onEnter={ok}
52
+ outlined
53
+ autoComplete="username"
54
+ required
55
+ />
56
+ <TextField
57
+ id="loginbox-password"
58
+ label={tx(passwordLabel)}
59
+ value={password}
60
+ onChange={changePassword}
61
+ onEnter={ok}
62
+ type="password"
63
+ outlined
64
+ autoComplete="current-password"
65
+ required
66
+ />
44
67
  </main>
45
68
  <footer>
46
69
  { loading ? <div className="load-box"><Icon icon="refresh" /></div> : null }