@visns-studio/visns-components 5.14.16 → 5.14.17
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
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
"react-dom": "^17.0.0 || ^18.0.0"
|
|
90
90
|
},
|
|
91
91
|
"name": "@visns-studio/visns-components",
|
|
92
|
-
"version": "5.14.
|
|
92
|
+
"version": "5.14.17",
|
|
93
93
|
"description": "Various packages to assist in the development of our Custom Applications.",
|
|
94
94
|
"main": "src/index.js",
|
|
95
95
|
"files": [
|
package/src/components/Field.jsx
CHANGED
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
X,
|
|
26
26
|
} from 'lucide-react';
|
|
27
27
|
import { toast } from 'react-toastify';
|
|
28
|
+
import validator from 'validator';
|
|
28
29
|
import styles from './styles/Field.module.scss';
|
|
29
30
|
|
|
30
31
|
import CustomFetch from './Fetch';
|
|
@@ -81,6 +82,9 @@ function Field({
|
|
|
81
82
|
const [formItemStyle, setFormItemStyle] = useState({});
|
|
82
83
|
const [formItemClass, setFormItemClass] = useState('');
|
|
83
84
|
const [options, setOptions] = useState([]);
|
|
85
|
+
const [emailError, setEmailError] = useState('');
|
|
86
|
+
const [emailSuggestions, setEmailSuggestions] = useState([]);
|
|
87
|
+
const [showEmailSuggestions, setShowEmailSuggestions] = useState(false);
|
|
84
88
|
|
|
85
89
|
/** Canvas States */
|
|
86
90
|
const [canvasPopupOpen, setCanvasPopupOpen] = useState(false);
|
|
@@ -91,6 +95,91 @@ function Field({
|
|
|
91
95
|
const [lineColor, setLineColor] = useState('rgba(0, 0, 0, 1)');
|
|
92
96
|
const sketchRef = useRef(null);
|
|
93
97
|
|
|
98
|
+
/** Email Functions */
|
|
99
|
+
const validateEmail = (email) => {
|
|
100
|
+
if (!email) {
|
|
101
|
+
setEmailError('');
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (!validator.isEmail(email)) {
|
|
106
|
+
setEmailError('Please enter a valid email address');
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
setEmailError('');
|
|
111
|
+
return true;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const generateEmailSuggestions = (inputEmail) => {
|
|
115
|
+
if (!inputEmail || inputEmail.length < 3) {
|
|
116
|
+
setEmailSuggestions([]);
|
|
117
|
+
setShowEmailSuggestions(false);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const commonDomains = [
|
|
122
|
+
'gmail.com', 'yahoo.com', 'hotmail.com', 'outlook.com',
|
|
123
|
+
'icloud.com', 'live.com', 'msn.com', 'aol.com',
|
|
124
|
+
'company.com', 'business.com', 'work.com'
|
|
125
|
+
];
|
|
126
|
+
|
|
127
|
+
const suggestions = [];
|
|
128
|
+
const [localPart, domainPart] = inputEmail.split('@');
|
|
129
|
+
|
|
130
|
+
if (!localPart) return;
|
|
131
|
+
|
|
132
|
+
if (!domainPart || domainPart.length === 0) {
|
|
133
|
+
// If no @ symbol or no domain part, suggest common domains
|
|
134
|
+
commonDomains.forEach(domain => {
|
|
135
|
+
suggestions.push(`${localPart}@${domain}`);
|
|
136
|
+
});
|
|
137
|
+
} else if (domainPart.length > 0 && domainPart.length < 4) {
|
|
138
|
+
// If domain part is short, suggest completions
|
|
139
|
+
commonDomains.forEach(domain => {
|
|
140
|
+
if (domain.toLowerCase().startsWith(domainPart.toLowerCase())) {
|
|
141
|
+
suggestions.push(`${localPart}@${domain}`);
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
} else {
|
|
145
|
+
// Check for common typos and suggest corrections
|
|
146
|
+
const typoMap = {
|
|
147
|
+
'gmial.com': 'gmail.com',
|
|
148
|
+
'gmai.com': 'gmail.com',
|
|
149
|
+
'yahooo.com': 'yahoo.com',
|
|
150
|
+
'hotmial.com': 'hotmail.com',
|
|
151
|
+
'outlok.com': 'outlook.com',
|
|
152
|
+
'iclou.com': 'icloud.com'
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
if (typoMap[domainPart.toLowerCase()]) {
|
|
156
|
+
suggestions.push(`${localPart}@${typoMap[domainPart.toLowerCase()]}`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
setEmailSuggestions(suggestions.slice(0, 5)); // Limit to 5 suggestions
|
|
161
|
+
setShowEmailSuggestions(suggestions.length > 0);
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
const handleEmailChange = (e) => {
|
|
165
|
+
const email = e.target.value;
|
|
166
|
+
validateEmail(email);
|
|
167
|
+
generateEmailSuggestions(email);
|
|
168
|
+
onChange(e);
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
const selectEmailSuggestion = (suggestion) => {
|
|
172
|
+
const syntheticEvent = {
|
|
173
|
+
target: {
|
|
174
|
+
dataset: { name: settings.id },
|
|
175
|
+
value: suggestion
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
validateEmail(suggestion);
|
|
179
|
+
setShowEmailSuggestions(false);
|
|
180
|
+
onChange(syntheticEvent);
|
|
181
|
+
};
|
|
182
|
+
|
|
94
183
|
/** Canvas Functions */
|
|
95
184
|
const handleCanvasSave = async () => {
|
|
96
185
|
// Save the current canvas state
|
|
@@ -469,6 +558,7 @@ function Field({
|
|
|
469
558
|
'dropdown',
|
|
470
559
|
'dropdown-ajax',
|
|
471
560
|
'dynamicdata',
|
|
561
|
+
'email',
|
|
472
562
|
'file',
|
|
473
563
|
'gallery',
|
|
474
564
|
'image',
|
|
@@ -2073,6 +2163,49 @@ function Field({
|
|
|
2073
2163
|
autoComplete="off"
|
|
2074
2164
|
/>
|
|
2075
2165
|
);
|
|
2166
|
+
case 'email':
|
|
2167
|
+
return (
|
|
2168
|
+
<div className={styles.emailFieldContainer}>
|
|
2169
|
+
<input
|
|
2170
|
+
type="email"
|
|
2171
|
+
data-name={settings.id}
|
|
2172
|
+
className={`${inputClass[settings.id]} ${emailError ? styles.emailError : ''}`}
|
|
2173
|
+
placeholder="Enter email address"
|
|
2174
|
+
onChange={handleEmailChange}
|
|
2175
|
+
onBlur={() => setShowEmailSuggestions(false)}
|
|
2176
|
+
onFocus={() => generateEmailSuggestions(inputValue || '')}
|
|
2177
|
+
value={
|
|
2178
|
+
inputValue && inputValue !== 'null'
|
|
2179
|
+
? inputValue
|
|
2180
|
+
: ''
|
|
2181
|
+
}
|
|
2182
|
+
readOnly={settings.readOnly ? settings.readOnly : false}
|
|
2183
|
+
autoComplete="email"
|
|
2184
|
+
spellCheck={false}
|
|
2185
|
+
/>
|
|
2186
|
+
{emailError && (
|
|
2187
|
+
<div className={styles.emailErrorMessage}>
|
|
2188
|
+
{emailError}
|
|
2189
|
+
</div>
|
|
2190
|
+
)}
|
|
2191
|
+
{showEmailSuggestions && emailSuggestions.length > 0 && (
|
|
2192
|
+
<div className={styles.emailSuggestions}>
|
|
2193
|
+
{emailSuggestions.map((suggestion, index) => (
|
|
2194
|
+
<div
|
|
2195
|
+
key={index}
|
|
2196
|
+
className={styles.emailSuggestion}
|
|
2197
|
+
onMouseDown={(e) => {
|
|
2198
|
+
e.preventDefault(); // Prevent blur event
|
|
2199
|
+
selectEmailSuggestion(suggestion);
|
|
2200
|
+
}}
|
|
2201
|
+
>
|
|
2202
|
+
{suggestion}
|
|
2203
|
+
</div>
|
|
2204
|
+
))}
|
|
2205
|
+
</div>
|
|
2206
|
+
)}
|
|
2207
|
+
</div>
|
|
2208
|
+
);
|
|
2076
2209
|
case 'password':
|
|
2077
2210
|
return (
|
|
2078
2211
|
<input
|
|
@@ -2109,6 +2242,7 @@ function Field({
|
|
|
2109
2242
|
'dropdown',
|
|
2110
2243
|
'dropdown-ajax',
|
|
2111
2244
|
'dynamicdata',
|
|
2245
|
+
'email',
|
|
2112
2246
|
'file',
|
|
2113
2247
|
'gallery',
|
|
2114
2248
|
'image',
|
|
@@ -1303,3 +1303,102 @@ input[type='file']:hover {
|
|
|
1303
1303
|
font-size: 0.85em;
|
|
1304
1304
|
}
|
|
1305
1305
|
}
|
|
1306
|
+
|
|
1307
|
+
/* Email Field Styles */
|
|
1308
|
+
.emailFieldContainer {
|
|
1309
|
+
position: relative;
|
|
1310
|
+
width: 100%;
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
.emailError {
|
|
1314
|
+
border-color: var(--error-color, #dc3545) !important;
|
|
1315
|
+
box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25) !important;
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
.emailErrorMessage {
|
|
1319
|
+
color: var(--error-color, #dc3545);
|
|
1320
|
+
font-size: 0.875rem;
|
|
1321
|
+
margin-top: 0.25rem;
|
|
1322
|
+
display: flex;
|
|
1323
|
+
align-items: center;
|
|
1324
|
+
gap: 0.25rem;
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
.emailErrorMessage::before {
|
|
1328
|
+
content: "⚠";
|
|
1329
|
+
font-size: 1rem;
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
.emailSuggestions {
|
|
1333
|
+
position: absolute;
|
|
1334
|
+
top: 100%;
|
|
1335
|
+
left: 0;
|
|
1336
|
+
right: 0;
|
|
1337
|
+
background: var(--item-color, #fff);
|
|
1338
|
+
border: 1px solid var(--border-color, #e9ecef);
|
|
1339
|
+
border-top: none;
|
|
1340
|
+
border-radius: 0 0 4px 4px; /* Match react-select border radius */
|
|
1341
|
+
box-shadow: none; /* Match react-select no-shadow pattern */
|
|
1342
|
+
z-index: 999; /* Match react-select z-index */
|
|
1343
|
+
max-height: 200px;
|
|
1344
|
+
overflow-y: auto;
|
|
1345
|
+
font-size: 14px; /* Match react-select font size */
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
.emailSuggestion {
|
|
1349
|
+
padding: 8px 12px; /* Match react-select option padding */
|
|
1350
|
+
cursor: pointer;
|
|
1351
|
+
transition: background-color 0.15s ease; /* Match react-select transition */
|
|
1352
|
+
color: var(--text-color, #333);
|
|
1353
|
+
line-height: 1.4;
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
.emailSuggestion:hover {
|
|
1357
|
+
background-color: #f5f5f5; /* Match react-select hover state */
|
|
1358
|
+
color: var(--text-color, #333);
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
.emailSuggestion:active {
|
|
1362
|
+
background-color: var(--primary-color, #007bff);
|
|
1363
|
+
color: white;
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
/* Enhanced email field input styles */
|
|
1367
|
+
.emailFieldContainer input[type="email"] {
|
|
1368
|
+
border-radius: var(--br, 6px);
|
|
1369
|
+
transition: border-color 0.15s ease; /* Match react-select transition */
|
|
1370
|
+
position: relative;
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
.emailFieldContainer input[type="email"]:focus {
|
|
1374
|
+
outline: none;
|
|
1375
|
+
border-color: var(--primary-color, #007bff);
|
|
1376
|
+
box-shadow: none; /* Match react-select no-shadow pattern */
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
.emailFieldContainer input[type="email"]:valid {
|
|
1380
|
+
border-color: var(--success-color, #28a745);
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
.emailFieldContainer input[type="email"]:valid:focus {
|
|
1384
|
+
border-color: var(--success-color, #28a745);
|
|
1385
|
+
box-shadow: none; /* Match react-select no-shadow pattern */
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
/* Dark mode support */
|
|
1389
|
+
@media (prefers-color-scheme: dark) {
|
|
1390
|
+
.emailSuggestions {
|
|
1391
|
+
background: var(--dark-item-color, #2d3748);
|
|
1392
|
+
border-color: var(--dark-border-color, #4a5568);
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
.emailSuggestion {
|
|
1396
|
+
color: var(--dark-text-color, #e2e8f0);
|
|
1397
|
+
border-bottom-color: var(--dark-border-color, #4a5568);
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
.emailSuggestion:hover {
|
|
1401
|
+
background: var(--dark-primary-color, #3182ce);
|
|
1402
|
+
color: var(--dark-primary-text-color, #fff);
|
|
1403
|
+
}
|
|
1404
|
+
}
|