@xouteiro/auth_npm 1.0.10 → 1.0.12

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": "@xouteiro/auth_npm",
3
- "version": "1.0.10",
3
+ "version": "1.0.12",
4
4
  "description": "Authentication package for Supabase",
5
5
  "main": "src/index.js",
6
6
  "types": "src/index.d.ts",
@@ -2,19 +2,75 @@ import React, { useState } from 'react';
2
2
  import { signInWithEmail } from '../login';
3
3
  import { registerWithEmail } from '../register';
4
4
 
5
+ // SVG Eye Icon
6
+ const EyeIcon = ({ open }) => (
7
+ <svg
8
+ width="22"
9
+ height="22"
10
+ viewBox="0 0 22 22"
11
+ fill="none"
12
+ style={{ verticalAlign: 'middle' }}
13
+ xmlns="http://www.w3.org/2000/svg"
14
+ >
15
+ {open ? (
16
+ <>
17
+ <path
18
+ d="M1 11C3.5 5.5 11 2 21 11C18.5 16.5 11 20 1 11Z"
19
+ stroke="#0070f3"
20
+ strokeWidth="2"
21
+ fill="none"
22
+ />
23
+ <circle
24
+ cx="11"
25
+ cy="11"
26
+ r="3"
27
+ stroke="#0070f3"
28
+ strokeWidth="2"
29
+ fill="none"
30
+ />
31
+ </>
32
+ ) : (
33
+ <>
34
+ <path
35
+ d="M1 11C3.5 5.5 11 2 21 11C18.5 16.5 11 20 1 11Z"
36
+ stroke="#0070f3"
37
+ strokeWidth="2"
38
+ fill="none"
39
+ />
40
+ <circle
41
+ cx="11"
42
+ cy="11"
43
+ r="3"
44
+ stroke="#0070f3"
45
+ strokeWidth="2"
46
+ fill="none"
47
+ />
48
+ <line
49
+ x1="4"
50
+ y1="18"
51
+ x2="18"
52
+ y2="4"
53
+ stroke="#d32f2f"
54
+ strokeWidth="2"
55
+ />
56
+ </>
57
+ )}
58
+ </svg>
59
+ );
60
+
5
61
  const boxStyle = {
6
- maxWidth: 380,
7
- margin: '40px auto',
8
- padding: 32,
9
- borderRadius: 14,
10
- boxShadow: '0 2px 16px rgba(0,0,0,0.09)',
62
+ maxWidth: 400,
63
+ margin: '48px auto',
64
+ padding: 36,
65
+ borderRadius: 18,
66
+ boxShadow: '0 4px 24px rgba(0,0,0,0.10)',
11
67
  background: '#fff',
12
- fontFamily: 'sans-serif',
68
+ fontFamily: 'Inter, sans-serif',
13
69
  };
14
70
 
15
71
  const tabStyle = (active) => ({
16
72
  flex: 1,
17
- padding: 12,
73
+ padding: 14,
18
74
  border: 'none',
19
75
  borderBottom: active ? '3px solid #0070f3' : '3px solid #eee',
20
76
  background: 'none',
@@ -22,56 +78,89 @@ const tabStyle = (active) => ({
22
78
  color: active ? '#0070f3' : '#444',
23
79
  cursor: 'pointer',
24
80
  outline: 'none',
81
+ fontSize: 18,
82
+ transition: 'border-bottom 0.2s',
25
83
  });
26
84
 
27
85
  const inputStyle = {
28
86
  width: '100%',
29
- padding: 10,
30
- margin: '10px 0',
31
- borderRadius: 6,
32
- border: '1px solid #ddd',
33
- fontSize: 16,
87
+ padding: '12px 44px 12px 12px',
88
+ margin: '12px 0',
89
+ borderRadius: 8,
90
+ border: '1.5px solid #cfd8dc',
91
+ fontSize: 17,
92
+ background: '#f8fafc',
93
+ boxSizing: 'border-box',
94
+ outline: 'none',
95
+ transition: 'border 0.2s',
34
96
  };
35
97
 
36
98
  const buttonStyle = {
37
99
  width: '100%',
38
- padding: 12,
39
- borderRadius: 6,
100
+ padding: 14,
101
+ borderRadius: 8,
40
102
  border: 'none',
41
- background: '#0070f3',
103
+ background: 'linear-gradient(90deg, #0070f3 60%, #0059c1 100%)',
42
104
  color: '#fff',
43
- fontWeight: 600,
44
- fontSize: 16,
45
- marginTop: 10,
105
+ fontWeight: 700,
106
+ fontSize: 18,
107
+ marginTop: 16,
108
+ cursor: 'pointer',
109
+ letterSpacing: 1,
110
+ boxShadow: '0 2px 8px rgba(0,112,243,0.08)',
111
+ transition: 'background 0.2s',
112
+ };
113
+
114
+ const toggleButtonStyle = {
115
+ position: 'absolute',
116
+ right: 12,
117
+ top: '50%',
118
+ transform: 'translateY(-50%)',
119
+ background: 'none',
120
+ border: 'none',
121
+ color: '#0070f3',
46
122
  cursor: 'pointer',
123
+ fontSize: 18,
124
+ padding: 0,
125
+ display: 'flex',
126
+ alignItems: 'center',
127
+ };
128
+
129
+ const inputWrapperStyle = {
130
+ position: 'relative',
131
+ width: '100%',
47
132
  };
48
133
 
49
134
  const messageStyle = (success) => ({
50
- margin: '12px 0',
135
+ margin: '16px 0 0 0',
51
136
  color: success ? '#0a0' : '#d32f2f',
52
137
  background: success ? '#eafbe7' : '#fdeaea',
53
- padding: 8,
54
- borderRadius: 6,
138
+ padding: 10,
139
+ borderRadius: 8,
55
140
  textAlign: 'center',
56
- fontSize: 15,
141
+ fontSize: 16,
142
+ fontWeight: 500,
143
+ letterSpacing: 0.2,
57
144
  });
58
145
 
59
146
  export default function LoginRegisterFlow({ onLoginSuccess, onRegisterSuccess }) {
60
147
  const [mode, setMode] = useState('login');
61
148
  const [identifier, setIdentifier] = useState('');
62
149
  const [password, setPassword] = useState('');
63
- const [username, setUsername] = useState('');
64
- const [phone, setPhone] = useState('');
150
+ const [confirmPassword, setConfirmPassword] = useState('');
65
151
  const [message, setMessage] = useState(null);
66
152
  const [success, setSuccess] = useState(false);
153
+ const [showPassword, setShowPassword] = useState(false);
154
+ const [showConfirmPassword, setShowConfirmPassword] = useState(false);
67
155
 
68
156
  const resetFields = () => {
69
157
  setIdentifier('');
70
158
  setPassword('');
71
- setUsername('');
72
- setPhone('');
159
+ setConfirmPassword('');
73
160
  setMessage(null);
74
161
  setSuccess(false);
162
+ setShowPassword(false);
163
+ setShowConfirmPassword(false);
75
164
  };
76
165
 
77
166
  const handleLogin = async (e) => {
@@ -94,7 +183,12 @@ export default function LoginRegisterFlow({ onLoginSuccess, onRegisterSuccess })
94
183
  e.preventDefault();
95
184
  setMessage(null);
96
185
  setSuccess(false);
97
- const { user, error } = await registerWithEmail(identifier, password, username, phone);
186
+ if (password !== confirmPassword) {
187
+ setMessage("Passwords do not match");
188
+ setSuccess(false);
189
+ return;
190
+ }
191
+ const { user, error } = await registerWithEmail(identifier, password);
98
192
  if (error) {
99
193
  setMessage(error.message || 'Registration failed');
100
194
  setSuccess(false);
@@ -108,32 +202,45 @@ export default function LoginRegisterFlow({ onLoginSuccess, onRegisterSuccess })
108
202
 
109
203
  return (
110
204
  <div style={boxStyle}>
111
- <div style={{ display: 'flex', marginBottom: 24 }}>
205
+ <div style={{ display: 'flex', marginBottom: 28 }}>
112
206
  <button style={tabStyle(mode === 'login')} onClick={() => { setMode('login'); setMessage(null); }}>Login</button>
113
207
  <button style={tabStyle(mode === 'register')} onClick={() => { setMode('register'); setMessage(null); }}>Register</button>
114
208
  </div>
115
209
  {mode === 'login' ? (
116
- <form onSubmit={handleLogin}>
210
+ <form onSubmit={handleLogin} autoComplete="off">
117
211
  <input
118
212
  style={inputStyle}
119
213
  type="text"
120
- placeholder="Email, phone, or username"
214
+ placeholder="Email"
121
215
  value={identifier}
122
216
  onChange={e => setIdentifier(e.target.value)}
123
217
  required
218
+ autoComplete="username"
124
219
  />
125
- <input
126
- style={inputStyle}
127
- type="password"
128
- placeholder="Password"
129
- value={password}
130
- onChange={e => setPassword(e.target.value)}
131
- required
132
- />
220
+ <div style={inputWrapperStyle}>
221
+ <input
222
+ style={inputStyle}
223
+ type={showPassword ? "text" : "password"}
224
+ placeholder="Password"
225
+ value={password}
226
+ onChange={e => setPassword(e.target.value)}
227
+ required
228
+ autoComplete="current-password"
229
+ />
230
+ <button
231
+ type="button"
232
+ style={toggleButtonStyle}
233
+ tabIndex={-1}
234
+ aria-label={showPassword ? "Hide password" : "Show password"}
235
+ onClick={() => setShowPassword(v => !v)}
236
+ >
237
+ <EyeIcon open={showPassword} />
238
+ </button>
239
+ </div>
133
240
  <button style={buttonStyle} type="submit">Login</button>
134
241
  </form>
135
242
  ) : (
136
- <form onSubmit={handleRegister}>
243
+ <form onSubmit={handleRegister} autoComplete="off">
137
244
  <input
138
245
  style={inputStyle}
139
246
  type="text"
@@ -141,29 +248,48 @@ export default function LoginRegisterFlow({ onLoginSuccess, onRegisterSuccess })
141
248
  value={identifier}
142
249
  onChange={e => setIdentifier(e.target.value)}
143
250
  required
251
+ autoComplete="username"
144
252
  />
145
- <input
146
- style={inputStyle}
147
- type="password"
148
- placeholder="Password"
149
- value={password}
150
- onChange={e => setPassword(e.target.value)}
151
- required
152
- />
153
- <input
154
- style={inputStyle}
155
- type="text"
156
- placeholder="Username (optional)"
157
- value={username}
158
- onChange={e => setUsername(e.target.value)}
159
- />
160
- <input
161
- style={inputStyle}
162
- type="text"
163
- placeholder="Phone (optional)"
164
- value={phone}
165
- onChange={e => setPhone(e.target.value)}
166
- />
253
+ <div style={inputWrapperStyle}>
254
+ <input
255
+ style={inputStyle}
256
+ type={showPassword ? "text" : "password"}
257
+ placeholder="Password"
258
+ value={password}
259
+ onChange={e => setPassword(e.target.value)}
260
+ required
261
+ autoComplete="new-password"
262
+ />
263
+ <button
264
+ type="button"
265
+ style={toggleButtonStyle}
266
+ tabIndex={-1}
267
+ aria-label={showPassword ? "Hide password" : "Show password"}
268
+ onClick={() => setShowPassword(v => !v)}
269
+ >
270
+ <EyeIcon open={showPassword} />
271
+ </button>
272
+ </div>
273
+ <div style={inputWrapperStyle}>
274
+ <input
275
+ style={inputStyle}
276
+ type={showConfirmPassword ? "text" : "password"}
277
+ placeholder="Confirm Password"
278
+ value={confirmPassword}
279
+ onChange={e => setConfirmPassword(e.target.value)}
280
+ required
281
+ autoComplete="new-password"
282
+ />
283
+ <button
284
+ type="button"
285
+ style={toggleButtonStyle}
286
+ tabIndex={-1}
287
+ aria-label={showConfirmPassword ? "Hide confirm password" : "Show confirm password"}
288
+ onClick={() => setShowConfirmPassword(v => !v)}
289
+ >
290
+ <EyeIcon open={showConfirmPassword} />
291
+ </button>
292
+ </div>
167
293
  <button style={buttonStyle} type="submit">Register</button>
168
294
  </form>
169
295
  )}