ywana-core8 0.1.16 → 0.1.18

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.16",
3
+ "version": "0.1.18",
4
4
  "description": "ywana-core8",
5
5
  "homepage": "https://ywana.github.io/workspace",
6
6
  "author": "Ernesto Roldan Garcia",
package/src/html/icon.js CHANGED
@@ -5,7 +5,7 @@ import { Tooltip } from './tooltip';
5
5
  /**
6
6
  * Icon
7
7
  */
8
- export const Icon = ({ icon, size = "normal", tooltip, clickable = false, disabled = false, action, eventPropagation = false, className }) => {
8
+ export const Icon = ({ id, icon, size = "normal", tooltip, clickable = false, disabled = false, action, eventPropagation = false, className }) => {
9
9
 
10
10
  function click (event) {
11
11
  if (!eventPropagation) {
@@ -18,12 +18,12 @@ export const Icon = ({ icon, size = "normal", tooltip, clickable = false, disabl
18
18
  const style = disabled ? "disabled" : clickable ? "clickable" : ""
19
19
  return tooltip ? (
20
20
  <Tooltip {...tooltip}>
21
- <i className={`icon ${size} ${style} ${className} material-icons`} onClick={click} >
21
+ <i id={id} className={`icon ${size} ${style} ${className} material-icons`} onClick={click} >
22
22
  {icon}
23
23
  </i>
24
24
  </Tooltip>
25
25
  ) : (
26
- <i className={`icon ${size} ${style} ${className} material-icons`} onClick={click}>
26
+ <i id={id} className={`icon ${size} ${style} ${className} material-icons`} onClick={click}>
27
27
  {icon}
28
28
  </i>
29
29
  )
@@ -12,7 +12,7 @@ import './textarea.css'
12
12
  export const TextField = (props) => {
13
13
 
14
14
  const site = useContext(SiteContext)
15
- const { id, type = 'text', className, label, labelPosition = 'top', placeholder, value, outlined, readOnly = false, canClear = true, onChange, onEnter, onClick, onFocus, onBlur } = props
15
+ const { id, type = 'text', className, label, labelPosition = 'top', placeholder, value, outlined, readOnly = false, canClear = true, onChange, onEnter, onClick, onFocus, onBlur, autoComplete=false } = props
16
16
 
17
17
  function onKeyPress(event) {
18
18
  var key = event.charCode ? event.charCode : event.keyCode ? event.keyCode : 0;
@@ -40,6 +40,21 @@ export const TextField = (props) => {
40
40
  if (onChange) onChange(id, "")
41
41
  }
42
42
 
43
+ function toggle() {
44
+ const input = document.getElementById(id)
45
+ const icon = document.getElementById(`${id}-visibility`)
46
+ if (input) {
47
+ const type = input.getAttribute("type")
48
+ if (type === "password") {
49
+ input.setAttribute("type", "text")
50
+ icon.setHTMLUnsafe("visibility")
51
+ } else {
52
+ input.setAttribute("type", "password")
53
+ icon.setHTMLUnsafe("visibility_off")
54
+ }
55
+ }
56
+ }
57
+
43
58
  const borderStyle = outlined ? "textfield-outlined" : "textfield"
44
59
  const labelStyle = label ? "" : "no-label"
45
60
  const labelPositionStyle = labelPosition == 'left' ? "label-left" : "label-top"
@@ -49,8 +64,9 @@ export const TextField = (props) => {
49
64
 
50
65
  return (
51
66
  <div className={`${style} ${id} ${className}`} onClick={onClick}>
52
- <input id={id} type={type} placeholder={placeholderTxt} value={value} required onChange={change} onKeyDown={onKeyPress} onFocus={focus} onBlur={blur} readOnly={readOnly} step="any" />
67
+ <input id={id} type={type} placeholder={placeholderTxt} value={value} required onChange={change} onKeyDown={onKeyPress} onFocus={focus} onBlur={blur} readOnly={readOnly} step="any" autoComplete={autoComplete} />
53
68
  {readOnly === false && canClear && value && value.length > 0 ? <Icon icon="close" clickable size="small" action={clear} /> : null}
69
+ {type === "password" ? <Icon id={`${id}-visibility`} icon="visibility_off" clickable size="small" action={toggle} /> : null}
54
70
  <span className="bar"></span>
55
71
  {label ? <label>{labelTxt}</label> : null}
56
72
  </div>
@@ -0,0 +1,7 @@
1
+ export const HelloWorld = (props) => {
2
+ return (
3
+ <div>
4
+ <h1>Hello World</h1>
5
+ </div>
6
+ )
7
+ }
@@ -56,7 +56,7 @@ export const LoginBox = ({
56
56
  </header>
57
57
  <main>
58
58
  <TextField label={tx(userLabel)} value={user} onChange={changeUser} onEnter={ok} outlined />
59
- <TextField label={tx(passwordLabel)} value={password} onChange={changePassword} onEnter={ok} type="password" outlined />
59
+ <TextField id="loginbox-password" label={tx(passwordLabel)} value={password} onChange={changePassword} onEnter={ok} type="password" outlined />
60
60
  </main>
61
61
  <footer>
62
62
  { loading ? <div className="load-box"><Icon icon="refresh" /></div> : <Button label={tx(loginLabel)} action={ok} disabled={!canOK()} raised className="login-button" /> }
@@ -23,26 +23,34 @@
23
23
  margin: 1rem 0 0 0;
24
24
  }
25
25
 
26
- .reset-password-box .error {
27
- font-weight: 600;
26
+ .reset-password-box .error-message {
27
+ font-weight: 400;
28
28
  color: red;
29
- padding: 1rem;
30
- text-align: center;
29
+ padding: 0rem;
31
30
  }
32
31
 
33
32
  .reset-password-box>footer {
34
33
  grid-area: footer;
35
34
  margin-top: .5rem;
36
35
  display: flex;
37
- justify-content: space-between;
38
36
  }
39
37
 
40
38
  .reset-password-box>footer>button {
41
- min-width: 6rem;
42
- max-height: 3rem;
39
+ width: 100%;
43
40
  }
44
41
 
45
42
  @keyframes fadeIn {
46
43
  from { opacity: 0; }
47
44
  to { opacity: 1; }
45
+ }
46
+
47
+ .reset-password-form > .textfield-outlined.error {
48
+
49
+ & label {
50
+ color: red;
51
+ }
52
+
53
+ & input {
54
+ border: solid 1px red;
55
+ }
48
56
  }
@@ -1,4 +1,4 @@
1
- import React, { useState, useEffect } from 'react'
1
+ import React, { useState } from 'react'
2
2
  import { TextField, Text, Button } from '../../html'
3
3
  import { validatePassword } from './login_commons'
4
4
  import './ResetPasswordBox.css'
@@ -6,31 +6,89 @@ import './ResetPasswordBox.css'
6
6
  /**
7
7
  * Reset Password
8
8
  */
9
- export const ResetPasswordBox = ({ logo, title, userRequired = true, oldPwdRequired = false, lang = "EN", children, onOK, onClose }) => {
9
+ export const ResetPasswordBox = ({ title, userRequired = true, oldPwdRequired = false, validator, children, onOK }) => {
10
10
 
11
- const [form, setForm] = useState({})
11
+ const [form, setForm] = useState({
12
+ user: "",
13
+ oldPassword: "",
14
+ password1: "",
15
+ password2: ""
16
+ })
12
17
  const [isValid, setIsValid] = useState(false)
13
- const [error, setError] = useState()
14
-
15
- useEffect(() => {
16
- const [valid, error] = validate()
17
- setIsValid(valid)
18
- setError(error)
19
- }, [form.password1, form.password2, form.oldPassword])
20
-
21
- function validate() {
22
- const hasRequiredUser = userRequired ? form.user && form.user.length > 0 : true
23
- const hasRequiredOldPwd = oldPwdRequired ? form.oldPassword && form.oldPassword.length > 0 : true
24
- const hasPassword1 = form.password1 && form.password1.length > 0
25
- let [isValid, error] = hasPassword1 ? validatePassword(form.password1) : [false, "La contraseña es requerida."]
18
+ const [errors, setErrors] = useState({})
19
+
20
+ function validateUser(user) {
21
+ let error = ""
22
+ const isValid = user && user.length > 0
23
+ error = <Text>User is required.</Text>
24
+ return [isValid, error]
25
+ }
26
+
27
+ function validateOldPassword(oldPassword) {
28
+ let error = ""
29
+ const isValid = oldPassword && oldPassword.length > 0
30
+ error = <Text>Old password is required.</Text>
31
+ return [isValid, error]
32
+ }
33
+
34
+ function validateNewPassword(password) {
35
+
36
+ const hasPassword = password && password.length > 0
37
+ if (!hasPassword) {
38
+ const error = <Text>Password is required</Text>
39
+ return [false, error]
40
+ }
41
+
42
+ const [isValid, error] = validator && typeof validator === 'function' ? validator(password) : validatePassword(password)
43
+ if (!isValid) {
44
+ return [false, error]
45
+ }
46
+
47
+ return [true, ""]
48
+ }
49
+
50
+ function validatePasswordsMatch(password1, password2) {
51
+ let error = ""
52
+ const isValid = password1 === password2
53
+ error = <Text>Passwords do not match.</Text>
54
+ return [isValid, error]
55
+ }
56
+
57
+ function validate(form) {
58
+
59
+ let isValid = true
60
+ let nextErrors = Object.assign({}, errors)
61
+
62
+ if (userRequired) {
63
+ const [validation, error] = validateUser(form.user)
64
+ if (isValid) isValid = validation
65
+ nextErrors.user = error
66
+ }
67
+
68
+ if (oldPwdRequired) {
69
+ const [validation, error] = validateOldPassword(form.oldPassword)
70
+ if (isValid) isValid = validation
71
+ nextErrors.oldPassword = error
72
+ }
73
+
74
+ const [pwdValidation, pwdError] = validateNewPassword(form.password1)
75
+ if (isValid) isValid = pwdValidation
76
+ nextErrors.password1 = pwdError
77
+
78
+ const [pwd2Validation, pwd2Error] = validateNewPassword(form.password2)
79
+ const [matchValidation, matchError] = validatePasswordsMatch(form.password1, form.password2)
80
+ if (isValid) isValid = matchValidation && pwd2Validation
81
+ nextErrors.password2 = matchError || pwd2Error
26
82
 
27
- const areEqual = form.password1 === form.password2
28
- if (isValid && !areEqual) error = "Las contraseñas no coinciden."
29
- return [hasRequiredUser && hasRequiredOldPwd && areEqual && isValid, error]
83
+ return [isValid, nextErrors]
30
84
  }
31
85
 
32
86
  function changeField(id, value) {
33
87
  const next = Object.assign({}, form, { [id]: value })
88
+ const [isValid, errors ] = validate(next)
89
+
90
+ setIsValid(isValid)
91
+ setErrors(errors)
34
92
  setForm(next)
35
93
  }
36
94
 
@@ -40,33 +98,39 @@ export const ResetPasswordBox = ({ logo, title, userRequired = true, oldPwdRequi
40
98
  }
41
99
  }
42
100
 
43
- function close() {
44
- if (onClose) onClose()
45
- }
101
+ const userLabel = <Text>User</Text>
102
+ const passwordLabel = <Text>New Password</Text>
103
+ const password2Label = <Text>Confirm New Password</Text>
104
+ const okLabel = <Text>OK</Text>
46
105
 
47
- const text = lang === "EN" ? "CHANGE PASSWORD" : "CAMBIO DE CLAVE"
48
- const userLabel = lang === "EN" ? "User" : "Usuario"
49
- const passwordLabel = lang === "EN" ? "New Password" : "Nueva Clave"
50
- const password2Label = lang === "EN" ? "Confirm New Password" : "Confirmar Nueva Clave"
51
- const okLabel = lang === "EN" ? "OK" : "Aceptar"
52
- const cancelLabel = lang === "EN" ? "Cancel" : "Cancelar"
106
+ const userStyle = errors.user ? "error" : ""
107
+ const oldPasswordStyle = errors.oldPassword ? "error" : ""
108
+ const password1Style = errors.password1 ? "error" : ""
109
+ const password2Style = errors.password2 ? "error" : ""
53
110
 
54
111
  return (
55
112
  <div className="reset-password-box">
56
113
  <header>
57
- {logo ? <img src={logo} /> : null}
58
114
  {title ? <div className="title"><Text>{title}</Text></div> : null}
59
- {children}
60
115
  </header>
61
- <main>
62
- {userRequired ? <TextField id="user" outlined icon="person" label={userLabel} lapse={100} onChange={changeField} onEnter={ok} /> : null}
63
- {oldPwdRequired ? <TextField id="oldPassword" outlined icon="lock" type="password" label="Old Password" lapse={100} onChange={changeField} onEnter={ok} /> : null}
64
- <TextField id="password1" outlined icon="lock" type="password" label={passwordLabel} lapse={100} onChange={changeField} onEnter={ok} />
65
- <TextField id="password2" outlined icon="lock" type="password" label={password2Label} lapse={100} onChange={changeField} onEnter={ok} />
66
- {error ? <div className="error">{error}</div> : null}
116
+ <main className={`reset-password-form`}>
117
+
118
+ {userRequired ? <TextField id="user" className={userStyle} outlined icon="person" label={userLabel} lapse={100} onChange={changeField} onEnter={ok} /> : null}
119
+ {userRequired ? errors.user ? <div className="error-message">{errors.user}</div> : null : null}
120
+
121
+ {oldPwdRequired ? <TextField id="oldPassword" className={oldPasswordStyle} outlined icon="lock" type="password" label="Old Password" lapse={100} onChange={changeField} onEnter={ok} /> : null}
122
+ {oldPwdRequired ? errors.oldPassword ? <div className="error-message">{errors.oldPassword}</div> : null : null}
123
+
124
+ <TextField id="password1" className={password1Style} outlined icon="lock" type="password" label={passwordLabel} lapse={100} onChange={changeField} onEnter={ok} />
125
+ { errors.password1 ? <div className="error-message">{errors.password1}</div> : null }
126
+
127
+ {children}
128
+
129
+ <TextField id="password2" className={password2Style} outlined icon="lock" type="password" label={password2Label} lapse={100} onChange={changeField} onEnter={ok} />
130
+ { errors.password2 ? <div className="error-message">{errors.password2}</div> : null }
131
+
67
132
  </main>
68
133
  <footer>
69
- <Button label={cancelLabel} action={close} />
70
134
  <Button label={okLabel} raised disabled={!isValid} action={ok} />
71
135
  </footer>
72
136
  </div>
@@ -1,5 +1,4 @@
1
1
  import React, { useState } from 'react'
2
- import { Icon , Button, Text, TextField } from '../../html'
3
2
  import { ResetPasswordBox } from './ResetPasswordBox'
4
3
 
5
4
  /**
@@ -9,8 +8,8 @@ export const ResetPasswordBoxTest = (prop) => {
9
8
 
10
9
  const config = {
11
10
  title: 'Reset Password',
12
- userRequired: false,
13
- oldPwdRequired: false,
11
+ userRequired: true,
12
+ oldPwdRequired: true,
14
13
  lang: 'EN',
15
14
  onOK: (form) => {
16
15
  console.log('onOK', form)
@@ -20,6 +19,17 @@ export const ResetPasswordBoxTest = (prop) => {
20
19
  }
21
20
  }
22
21
  return (
23
- <ResetPasswordBox {...config} />
22
+ <ResetPasswordBox {...config} >
23
+ <div>
24
+ <p>Your password must contain</p>
25
+ <ul>
26
+ <li>At least 8 characters</li>
27
+ <li>At least one uppercase letter</li>
28
+ <li>At least one lowercase letter</li>
29
+ <li>At least one number</li>
30
+ <li>At least one special character</li>
31
+ </ul>
32
+ </div>
33
+ </ResetPasswordBox>
24
34
  )
25
35
  }
@@ -4,37 +4,37 @@ export function validatePassword(contraseña) {
4
4
 
5
5
  // Verificar longitud mínima y máxima
6
6
  if (contraseña.length < 15 || contraseña.length > 50) {
7
- error = 'La contraseña debe tener entre 15 y 50 caracteres.';
7
+ error = 'The password must be between 15 and 50 characters.';
8
8
  return [ false, error]
9
9
  }
10
10
 
11
11
  // Verificar al menos una letra (mayúscula o minúscula)
12
12
  if (!/[A-Za-z]/.test(contraseña)) {
13
- error = 'La contraseña debe contener al menos una letra (A-Z o a-z).';
13
+ error = 'The password must contain at least one letter (A-Z or a-z).';
14
14
  return [ false, error]
15
15
  }
16
16
 
17
17
  // Verificar al menos un número
18
18
  if (!/[0-9]/.test(contraseña)) {
19
- error = 'La contraseña debe contener al menos un número (0-9).';
19
+ error = 'The password must contain at least one number (0-9).';
20
20
  return [ false, error]
21
21
  }
22
22
 
23
23
  // Verificar al menos una minúscula
24
24
  if (!/[a-z]/.test(contraseña)) {
25
- error = 'La contraseña debe contener al menos una letra en minúscula (a-z).';
25
+ error = 'The password must contain at least one lowercase letter (a-z).';
26
26
  return [ false, error]
27
27
  }
28
28
 
29
29
  // Verificar al menos una mayúscula
30
30
  if (!/[A-Z]/.test(contraseña)) {
31
- error = 'La contraseña debe contener al menos una letra en mayúscula (A-Z).';
31
+ error = 'The password must contain at least one uppercase letter (A-Z).';
32
32
  return [ false, error]
33
33
  }
34
34
 
35
35
  // Verificar al menos un carácter especial
36
36
  if (!/[<>+&!?*\-_%\.:=]/.test(contraseña)) {
37
- error = 'La contraseña debe contener al menos un carácter especial (< > + & ! ? * - _ % . : =).';
37
+ error = 'The password must contain at least one special character (< > + & ! ? * - _ % . : =).';
38
38
  return [ false, error]
39
39
  }
40
40
 
@@ -1,35 +0,0 @@
1
- // preview.config.js
2
-
3
- /** @type {import("@previewjs/config").PreviewConfig} */
4
- module.exports = {
5
- /**
6
- * Configure custom aliases (auto-detected if you use TypeScript).
7
- */
8
- alias: {
9
- foo: "src/foo"
10
- },
11
-
12
- /**
13
- * Configure a public assets directory.
14
- */
15
- publicDir: "public",
16
-
17
- /**
18
- * Set up a custom component to wrap around previewed components.
19
- *
20
- * Useful to set up context providers and global CSS.
21
- */
22
- wrapper: {
23
- path: "__previewjs__/Wrapper.tsx",
24
- componentName: "Wrapper"
25
- },
26
-
27
- /**
28
- * Specify a custom Vite configuration.
29
- *
30
- * See https://vitejs.dev/config.
31
- */
32
- vite: {
33
-
34
- }
35
- };