@sio-group/form-react 0.3.0 → 0.4.0
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/CHANGELOG.md +6 -0
- package/dist/index.cjs +21 -271
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +20 -261
- package/package.json +1 -1
- package/src/components/Form.tsx +2 -2
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -75,264 +75,11 @@ var slugify = (string, separator = "_") => {
|
|
|
75
75
|
return string.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().trim().replace(/[^a-z0-9 ]/g, "").replace(/\s+/g, separator);
|
|
76
76
|
};
|
|
77
77
|
|
|
78
|
-
//
|
|
79
|
-
var
|
|
80
|
-
const message = errorMessage?.replace("{label}", label) || `${label} is een verplicht veld.`;
|
|
81
|
-
if (val === null || val === void 0) {
|
|
82
|
-
return message;
|
|
83
|
-
}
|
|
84
|
-
if (typeof val === "string" && val.trim().length === 0) {
|
|
85
|
-
return message;
|
|
86
|
-
}
|
|
87
|
-
if (typeof val === "boolean" && !val) {
|
|
88
|
-
return message;
|
|
89
|
-
}
|
|
90
|
-
if (Array.isArray(val) && val.length === 0) {
|
|
91
|
-
return message;
|
|
92
|
-
}
|
|
93
|
-
return null;
|
|
94
|
-
};
|
|
95
|
-
var isEmail = (errorMessage) => (val, label = "Dit") => {
|
|
96
|
-
if (val === null || val === void 0) {
|
|
97
|
-
return null;
|
|
98
|
-
}
|
|
99
|
-
if (typeof val !== "string") {
|
|
100
|
-
return errorMessage || `${label} is geen geldig e-mailadres.`;
|
|
101
|
-
}
|
|
102
|
-
const trimmed = val.trim();
|
|
103
|
-
if (trimmed.length === 0) {
|
|
104
|
-
return null;
|
|
105
|
-
}
|
|
106
|
-
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/;
|
|
107
|
-
return emailRegex.test(trimmed) ? null : errorMessage || `${label} is geen geldig e-mailadres.`;
|
|
108
|
-
};
|
|
109
|
-
var isUrl = (allowLocalhost = false, allowFtp = false, secureOnly = true) => (val, label = "Dit") => {
|
|
110
|
-
if (val === null || val === void 0) {
|
|
111
|
-
return null;
|
|
112
|
-
}
|
|
113
|
-
if (typeof val !== "string") {
|
|
114
|
-
return `${label} is geen geldige URL.`;
|
|
115
|
-
}
|
|
116
|
-
const trimmed = val.trim();
|
|
117
|
-
if (trimmed.length === 0) {
|
|
118
|
-
return null;
|
|
119
|
-
}
|
|
120
|
-
try {
|
|
121
|
-
const url = new URL(trimmed);
|
|
122
|
-
if (secureOnly && url.protocol !== "https:") {
|
|
123
|
-
return `${label} moet https gebruiken.`;
|
|
124
|
-
}
|
|
125
|
-
if (!allowFtp && url.protocol === "ftp") {
|
|
126
|
-
return `${label} mag geen ftp gebruiken.`;
|
|
127
|
-
}
|
|
128
|
-
if (!allowLocalhost && (url.hostname === "localhost" || url.hostname === "127.0.0.1")) {
|
|
129
|
-
return `${label} mag geen localhost zijn.`;
|
|
130
|
-
}
|
|
131
|
-
return null;
|
|
132
|
-
} catch {
|
|
133
|
-
return `${label} is geen geldige URL.`;
|
|
134
|
-
}
|
|
135
|
-
};
|
|
136
|
-
var isBiggerThan = (min, errorMessage) => (val, label = "Dit") => {
|
|
137
|
-
if (val === null || val === void 0 || val === "") {
|
|
138
|
-
return null;
|
|
139
|
-
}
|
|
140
|
-
const num = Number(val);
|
|
141
|
-
if (Number.isNaN(num)) {
|
|
142
|
-
return `${label} moet een geldig getal zijn.`;
|
|
143
|
-
}
|
|
144
|
-
return min <= num ? null : errorMessage?.replace("{label}", label)?.replace("{min}", min.toString()) || `${label} mag niet kleiner zijn dan ${min}.`;
|
|
145
|
-
};
|
|
146
|
-
var isSmallerThan = (max, errorMessage) => (val, label = "Dit") => {
|
|
147
|
-
if (val === null || val === void 0 || val === "") {
|
|
148
|
-
return null;
|
|
149
|
-
}
|
|
150
|
-
const num = Number(val);
|
|
151
|
-
if (Number.isNaN(num)) {
|
|
152
|
-
return `${label} moet een geldig getal zijn.`;
|
|
153
|
-
}
|
|
154
|
-
return num <= max ? null : errorMessage?.replace("{label}", label)?.replace("{max}", max.toString()) || `${label} mag niet groter zijn dan ${max}.`;
|
|
155
|
-
};
|
|
156
|
-
var parseDateValue = (val) => {
|
|
157
|
-
if (val instanceof Date) {
|
|
158
|
-
return {
|
|
159
|
-
type: hasExplicitTime(val) ? "datetime" : "date",
|
|
160
|
-
value: isNaN(val.getTime()) ? null : val
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
if (typeof val !== "string") {
|
|
164
|
-
return { type: "invalid", value: null };
|
|
165
|
-
}
|
|
166
|
-
const trimmed = val.trim();
|
|
167
|
-
if (trimmed === "") {
|
|
168
|
-
return { type: "invalid", value: null };
|
|
169
|
-
}
|
|
170
|
-
const timeRegex = /^([0-1]?[0-9]|2[0-3]):[0-5][0-9](:[0-5][0-9])?$/;
|
|
171
|
-
if (timeRegex.test(trimmed)) {
|
|
172
|
-
const [hours, minutes, seconds = 0] = trimmed.split(":").map(Number);
|
|
173
|
-
const date = /* @__PURE__ */ new Date();
|
|
174
|
-
date.setHours(hours, minutes, seconds, 0);
|
|
175
|
-
return { type: "time", value: date };
|
|
176
|
-
}
|
|
177
|
-
const dateRegex = /^\d{4}-\d{2}-\d{2}$/;
|
|
178
|
-
if (dateRegex.test(trimmed)) {
|
|
179
|
-
const date = /* @__PURE__ */ new Date(trimmed + "T00:00:00.000Z");
|
|
180
|
-
return {
|
|
181
|
-
type: "date",
|
|
182
|
-
value: isNaN(date.getTime()) ? null : date
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
const dateTimeRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/;
|
|
186
|
-
if (dateTimeRegex.test(trimmed)) {
|
|
187
|
-
const date = /* @__PURE__ */ new Date(trimmed + ".000Z");
|
|
188
|
-
return {
|
|
189
|
-
type: "datetime",
|
|
190
|
-
value: isNaN(date.getTime()) ? null : date
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
return { type: "invalid", value: null };
|
|
194
|
-
};
|
|
195
|
-
function hasExplicitTime(date) {
|
|
196
|
-
return date.getUTCHours() !== 0 || date.getUTCMinutes() !== 0 || date.getUTCSeconds() !== 0 || date.getUTCMilliseconds() !== 0;
|
|
197
|
-
}
|
|
198
|
-
var dateIsBiggerThan = (min, errorMessage) => (val, label = "Dit") => {
|
|
199
|
-
if (val === null || val === void 0 || val === "") {
|
|
200
|
-
return null;
|
|
201
|
-
}
|
|
202
|
-
const parsed = parseDateValue(val);
|
|
203
|
-
if (!parsed.value) {
|
|
204
|
-
return `${label} moet een geldige ${parsed.type === "time" ? "tijd" : "datum"} zijn.`;
|
|
205
|
-
}
|
|
206
|
-
let formattedMin;
|
|
207
|
-
switch (parsed.type) {
|
|
208
|
-
case "time":
|
|
209
|
-
formattedMin = min.toLocaleTimeString("nl-NL", {
|
|
210
|
-
hour: "2-digit",
|
|
211
|
-
minute: "2-digit",
|
|
212
|
-
hour12: false,
|
|
213
|
-
timeZone: "UTC"
|
|
214
|
-
});
|
|
215
|
-
break;
|
|
216
|
-
case "date":
|
|
217
|
-
formattedMin = min.toLocaleDateString("nl-NL", { timeZone: "UTC" });
|
|
218
|
-
break;
|
|
219
|
-
case "datetime":
|
|
220
|
-
formattedMin = min.toLocaleString("nl-NL", {
|
|
221
|
-
year: "numeric",
|
|
222
|
-
month: "2-digit",
|
|
223
|
-
day: "2-digit",
|
|
224
|
-
hour: "2-digit",
|
|
225
|
-
minute: "2-digit",
|
|
226
|
-
hour12: false,
|
|
227
|
-
timeZone: "UTC"
|
|
228
|
-
});
|
|
229
|
-
break;
|
|
230
|
-
default:
|
|
231
|
-
formattedMin = min.toLocaleDateString("nl-NL", { timeZone: "UTC" });
|
|
232
|
-
}
|
|
233
|
-
if (parsed.type === "time") {
|
|
234
|
-
const timeValue = parsed.value.getHours() * 60 + parsed.value.getMinutes();
|
|
235
|
-
const minTime = min.getHours() * 60 + min.getMinutes();
|
|
236
|
-
return timeValue >= minTime ? null : errorMessage?.replace("{label}", label)?.replace("{min}", formattedMin) || `${label} mag niet voor ${formattedMin} zijn.`;
|
|
237
|
-
}
|
|
238
|
-
return min.getTime() <= parsed.value.getTime() ? null : errorMessage?.replace("{label}", label)?.replace("{min}", formattedMin) || `${label} mag niet voor ${formattedMin} zijn.`;
|
|
239
|
-
};
|
|
240
|
-
var dateIsSmallerThan = (max, errorMessage) => (val, label = "Dit") => {
|
|
241
|
-
if (val === null || val === void 0 || val === "") {
|
|
242
|
-
return null;
|
|
243
|
-
}
|
|
244
|
-
const parsed = parseDateValue(val);
|
|
245
|
-
if (!parsed.value) {
|
|
246
|
-
return `${label} moet een geldige ${parsed.type === "time" ? "tijd" : "datum"} zijn.`;
|
|
247
|
-
}
|
|
248
|
-
let formattedMax;
|
|
249
|
-
switch (parsed.type) {
|
|
250
|
-
case "time":
|
|
251
|
-
formattedMax = max.toLocaleTimeString("nl-NL", {
|
|
252
|
-
hour: "2-digit",
|
|
253
|
-
minute: "2-digit",
|
|
254
|
-
hour12: false,
|
|
255
|
-
timeZone: "UTC"
|
|
256
|
-
});
|
|
257
|
-
break;
|
|
258
|
-
case "date":
|
|
259
|
-
formattedMax = max.toLocaleDateString("nl-NL", { timeZone: "UTC" });
|
|
260
|
-
break;
|
|
261
|
-
case "datetime":
|
|
262
|
-
formattedMax = max.toLocaleString("nl-NL", {
|
|
263
|
-
year: "numeric",
|
|
264
|
-
month: "2-digit",
|
|
265
|
-
day: "2-digit",
|
|
266
|
-
hour: "2-digit",
|
|
267
|
-
minute: "2-digit",
|
|
268
|
-
hour12: false,
|
|
269
|
-
timeZone: "UTC"
|
|
270
|
-
});
|
|
271
|
-
break;
|
|
272
|
-
default:
|
|
273
|
-
formattedMax = max.toLocaleDateString("nl-NL", { timeZone: "UTC" });
|
|
274
|
-
}
|
|
275
|
-
if (parsed.type === "time") {
|
|
276
|
-
const timeValue = parsed.value.getHours() * 60 + parsed.value.getMinutes();
|
|
277
|
-
const macTime = max.getHours() * 60 + max.getMinutes();
|
|
278
|
-
return macTime >= timeValue ? null : errorMessage?.replace("{label}", label)?.replace("{min}", formattedMax) || `${label} mag niet na ${formattedMax} zijn.`;
|
|
279
|
-
}
|
|
280
|
-
return parsed.value.getTime() <= max.getTime() ? null : errorMessage?.replace("{label}", label)?.replace("{min}", formattedMax) || `${label} mag niet na ${formattedMax} zijn.`;
|
|
281
|
-
};
|
|
282
|
-
var isValidFile = (maxSize, accept) => (file) => {
|
|
283
|
-
if (!file) {
|
|
284
|
-
return null;
|
|
285
|
-
}
|
|
286
|
-
if (maxSize && file.size / 1024 > maxSize) {
|
|
287
|
-
return `${file.name} is te groot (max ${maxSize} KB).`;
|
|
288
|
-
}
|
|
289
|
-
if (accept) {
|
|
290
|
-
const allowed = accept.split(",").map((s) => s.trim().toLowerCase());
|
|
291
|
-
const ext = `.${file.name.split(".").pop()?.toLowerCase()}`;
|
|
292
|
-
const mime = file.type.toLowerCase();
|
|
293
|
-
const valid = allowed.some((pattern) => {
|
|
294
|
-
if (pattern === mime) return true;
|
|
295
|
-
if (pattern.endsWith("/*")) {
|
|
296
|
-
return mime.startsWith(pattern.replace("/*", "/"));
|
|
297
|
-
}
|
|
298
|
-
return pattern === ext;
|
|
299
|
-
});
|
|
300
|
-
if (!valid) {
|
|
301
|
-
return `${file.name} is niet toegelaten.`;
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
return null;
|
|
305
|
-
};
|
|
306
|
-
var isPattern = (pattern, errorMsg) => (val, label = "Dit") => {
|
|
307
|
-
if (val === null || val === void 0 || val === "") {
|
|
308
|
-
return null;
|
|
309
|
-
}
|
|
310
|
-
if (typeof val !== "string") {
|
|
311
|
-
return errorMsg || `${label} heeft een ongeldig patroon.`;
|
|
312
|
-
}
|
|
313
|
-
const trimmed = val.trim();
|
|
314
|
-
if (trimmed === "") {
|
|
315
|
-
return null;
|
|
316
|
-
}
|
|
317
|
-
let regex;
|
|
318
|
-
if (typeof pattern === "string") {
|
|
319
|
-
if (pattern.startsWith("/") && pattern.lastIndexOf("/") > 0) {
|
|
320
|
-
const lastSlash = pattern.lastIndexOf("/");
|
|
321
|
-
const patternBody = pattern.substring(1, lastSlash);
|
|
322
|
-
const flags = pattern.substring(lastSlash + 1);
|
|
323
|
-
const safeFlags = flags.replace("g", "");
|
|
324
|
-
regex = new RegExp(patternBody, safeFlags);
|
|
325
|
-
} else {
|
|
326
|
-
regex = new RegExp(pattern);
|
|
327
|
-
}
|
|
328
|
-
} else {
|
|
329
|
-
regex = new RegExp(pattern.source, pattern.flags.replace("g", ""));
|
|
330
|
-
}
|
|
331
|
-
return regex.test(trimmed) ? null : errorMsg || `${label} heeft een ongeldig patroon.`;
|
|
332
|
-
};
|
|
78
|
+
// src/utils/create-field-state.ts
|
|
79
|
+
var import_form_validation = require("@sio-group/form-validation");
|
|
333
80
|
|
|
334
81
|
// src/utils/parse-date.ts
|
|
335
|
-
var
|
|
82
|
+
var parseDateValue = (val) => {
|
|
336
83
|
if (val instanceof Date) {
|
|
337
84
|
return isNaN(val.getTime()) ? null : val;
|
|
338
85
|
}
|
|
@@ -402,31 +149,31 @@ function getDefaultValue(config) {
|
|
|
402
149
|
function getDefaultValidations(config) {
|
|
403
150
|
const validations = [];
|
|
404
151
|
if (config.config?.required) {
|
|
405
|
-
validations.push(isRequired());
|
|
152
|
+
validations.push((0, import_form_validation.isRequired)());
|
|
406
153
|
}
|
|
407
154
|
switch (config.type) {
|
|
408
155
|
case "email":
|
|
409
|
-
validations.push(isEmail());
|
|
156
|
+
validations.push((0, import_form_validation.isEmail)());
|
|
410
157
|
break;
|
|
411
158
|
case "number":
|
|
412
159
|
case "range":
|
|
413
|
-
if (config.config?.min) validations.push(isBiggerThan(config.config?.min));
|
|
414
|
-
if (config.config?.max) validations.push(isSmallerThan(config.config?.max));
|
|
160
|
+
if (config.config?.min) validations.push((0, import_form_validation.isBiggerThan)(config.config?.min));
|
|
161
|
+
if (config.config?.max) validations.push((0, import_form_validation.isSmallerThan)(config.config?.max));
|
|
415
162
|
break;
|
|
416
163
|
case "date":
|
|
417
164
|
case "datetime-local":
|
|
418
165
|
case "time":
|
|
419
166
|
const min = config.config?.min;
|
|
420
167
|
const max = config.config?.max;
|
|
421
|
-
const parsedMin =
|
|
422
|
-
const parsedMax =
|
|
423
|
-
if (parsedMin) validations.push(dateIsBiggerThan(parsedMin));
|
|
424
|
-
if (parsedMax) validations.push(dateIsSmallerThan(parsedMax));
|
|
168
|
+
const parsedMin = parseDateValue(min);
|
|
169
|
+
const parsedMax = parseDateValue(max);
|
|
170
|
+
if (parsedMin) validations.push((0, import_form_validation.dateIsBiggerThan)(parsedMin));
|
|
171
|
+
if (parsedMax) validations.push((0, import_form_validation.dateIsSmallerThan)(parsedMax));
|
|
425
172
|
break;
|
|
426
173
|
case "url":
|
|
427
|
-
if (config.config?.pattern) validations.push(isPattern(config.config.pattern));
|
|
174
|
+
if (config.config?.pattern) validations.push((0, import_form_validation.isPattern)(config.config.pattern));
|
|
428
175
|
validations.push(
|
|
429
|
-
isUrl(
|
|
176
|
+
(0, import_form_validation.isUrl)(
|
|
430
177
|
config.config?.allowLocalhost || false,
|
|
431
178
|
config.config?.allowFtp || false,
|
|
432
179
|
config.config?.secureOnly || !(config.config?.allowLocalhost || config.config?.allowFtp)
|
|
@@ -435,7 +182,7 @@ function getDefaultValidations(config) {
|
|
|
435
182
|
break;
|
|
436
183
|
case "text":
|
|
437
184
|
case "tel":
|
|
438
|
-
if (config.config?.pattern) validations.push(isPattern(config.config.pattern));
|
|
185
|
+
if (config.config?.pattern) validations.push((0, import_form_validation.isPattern)(config.config.pattern));
|
|
439
186
|
break;
|
|
440
187
|
}
|
|
441
188
|
return validations;
|
|
@@ -1368,6 +1115,9 @@ var DateInput = ({
|
|
|
1368
1115
|
);
|
|
1369
1116
|
};
|
|
1370
1117
|
|
|
1118
|
+
// src/components/Fields/Input/FileInput/index.tsx
|
|
1119
|
+
var import_form_validation2 = require("@sio-group/form-validation");
|
|
1120
|
+
|
|
1371
1121
|
// src/utils/get-accept-string.ts
|
|
1372
1122
|
var getAccept = (accept) => {
|
|
1373
1123
|
if (Array.isArray(accept)) {
|
|
@@ -1498,7 +1248,7 @@ var FileInput = ({
|
|
|
1498
1248
|
};
|
|
1499
1249
|
const handleChange = (e) => {
|
|
1500
1250
|
const files = Array.from(e.target.files ?? []);
|
|
1501
|
-
const validator = isValidFile(filesize, getAccept(accept));
|
|
1251
|
+
const validator = (0, import_form_validation2.isValidFile)(filesize, getAccept(accept));
|
|
1502
1252
|
let fileList = [...currentFiles];
|
|
1503
1253
|
const errorList = [];
|
|
1504
1254
|
for (let file of files) {
|
|
@@ -2026,7 +1776,7 @@ var Link = import_react7.default.memo(LinkComponent);
|
|
|
2026
1776
|
// src/components/Form.tsx
|
|
2027
1777
|
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
2028
1778
|
var import_react9 = require("react");
|
|
2029
|
-
var DefaultContainer = ({ children
|
|
1779
|
+
var DefaultContainer = ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { children });
|
|
2030
1780
|
var DefaultButtonContainer = ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "btn-group", children });
|
|
2031
1781
|
var Form = ({
|
|
2032
1782
|
fields,
|
|
@@ -2145,8 +1895,8 @@ var Form = ({
|
|
|
2145
1895
|
buttons?.map(renderButton)
|
|
2146
1896
|
] }) : null;
|
|
2147
1897
|
};
|
|
2148
|
-
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
2149
|
-
renderFields(),
|
|
1898
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("form", { className, style, noValidate: true, children: [
|
|
1899
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Container, { children: renderFields() }),
|
|
2150
1900
|
renderButtons()
|
|
2151
1901
|
] });
|
|
2152
1902
|
};
|
package/dist/index.d.cts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import React, { CSSProperties, ComponentType, ComponentPropsWithoutRef, HTMLAttributes } from 'react';
|
|
3
|
-
import { LayoutType, FormField, IconType, AcceptType, CaptureType, SpinnerVariant, SelectOption, Option, FieldConfigMap } from '@sio/form-types';
|
|
3
|
+
import { LayoutType, FormField, IconType, AcceptType, CaptureType, SpinnerVariant, SelectOption, Option, FieldConfigMap } from '@sio-group/form-types';
|
|
4
4
|
import { Properties } from 'csstype';
|
|
5
|
-
import { ValidationRule } from '@sio/form-types/src/core/valudation-rule';
|
|
5
|
+
import { ValidationRule } from '@sio-group/form-types/src/core/valudation-rule';
|
|
6
6
|
|
|
7
7
|
interface FormLayout {
|
|
8
8
|
fields: string[];
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import React, { CSSProperties, ComponentType, ComponentPropsWithoutRef, HTMLAttributes } from 'react';
|
|
3
|
-
import { LayoutType, FormField, IconType, AcceptType, CaptureType, SpinnerVariant, SelectOption, Option, FieldConfigMap } from '@sio/form-types';
|
|
3
|
+
import { LayoutType, FormField, IconType, AcceptType, CaptureType, SpinnerVariant, SelectOption, Option, FieldConfigMap } from '@sio-group/form-types';
|
|
4
4
|
import { Properties } from 'csstype';
|
|
5
|
-
import { ValidationRule } from '@sio/form-types/src/core/valudation-rule';
|
|
5
|
+
import { ValidationRule } from '@sio-group/form-types/src/core/valudation-rule';
|
|
6
6
|
|
|
7
7
|
interface FormLayout {
|
|
8
8
|
fields: string[];
|
package/dist/index.js
CHANGED
|
@@ -26,264 +26,20 @@ var slugify = (string, separator = "_") => {
|
|
|
26
26
|
return string.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().trim().replace(/[^a-z0-9 ]/g, "").replace(/\s+/g, separator);
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
-
//
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
if (Array.isArray(val) && val.length === 0) {
|
|
42
|
-
return message;
|
|
43
|
-
}
|
|
44
|
-
return null;
|
|
45
|
-
};
|
|
46
|
-
var isEmail = (errorMessage) => (val, label = "Dit") => {
|
|
47
|
-
if (val === null || val === void 0) {
|
|
48
|
-
return null;
|
|
49
|
-
}
|
|
50
|
-
if (typeof val !== "string") {
|
|
51
|
-
return errorMessage || `${label} is geen geldig e-mailadres.`;
|
|
52
|
-
}
|
|
53
|
-
const trimmed = val.trim();
|
|
54
|
-
if (trimmed.length === 0) {
|
|
55
|
-
return null;
|
|
56
|
-
}
|
|
57
|
-
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/;
|
|
58
|
-
return emailRegex.test(trimmed) ? null : errorMessage || `${label} is geen geldig e-mailadres.`;
|
|
59
|
-
};
|
|
60
|
-
var isUrl = (allowLocalhost = false, allowFtp = false, secureOnly = true) => (val, label = "Dit") => {
|
|
61
|
-
if (val === null || val === void 0) {
|
|
62
|
-
return null;
|
|
63
|
-
}
|
|
64
|
-
if (typeof val !== "string") {
|
|
65
|
-
return `${label} is geen geldige URL.`;
|
|
66
|
-
}
|
|
67
|
-
const trimmed = val.trim();
|
|
68
|
-
if (trimmed.length === 0) {
|
|
69
|
-
return null;
|
|
70
|
-
}
|
|
71
|
-
try {
|
|
72
|
-
const url = new URL(trimmed);
|
|
73
|
-
if (secureOnly && url.protocol !== "https:") {
|
|
74
|
-
return `${label} moet https gebruiken.`;
|
|
75
|
-
}
|
|
76
|
-
if (!allowFtp && url.protocol === "ftp") {
|
|
77
|
-
return `${label} mag geen ftp gebruiken.`;
|
|
78
|
-
}
|
|
79
|
-
if (!allowLocalhost && (url.hostname === "localhost" || url.hostname === "127.0.0.1")) {
|
|
80
|
-
return `${label} mag geen localhost zijn.`;
|
|
81
|
-
}
|
|
82
|
-
return null;
|
|
83
|
-
} catch {
|
|
84
|
-
return `${label} is geen geldige URL.`;
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
|
-
var isBiggerThan = (min, errorMessage) => (val, label = "Dit") => {
|
|
88
|
-
if (val === null || val === void 0 || val === "") {
|
|
89
|
-
return null;
|
|
90
|
-
}
|
|
91
|
-
const num = Number(val);
|
|
92
|
-
if (Number.isNaN(num)) {
|
|
93
|
-
return `${label} moet een geldig getal zijn.`;
|
|
94
|
-
}
|
|
95
|
-
return min <= num ? null : errorMessage?.replace("{label}", label)?.replace("{min}", min.toString()) || `${label} mag niet kleiner zijn dan ${min}.`;
|
|
96
|
-
};
|
|
97
|
-
var isSmallerThan = (max, errorMessage) => (val, label = "Dit") => {
|
|
98
|
-
if (val === null || val === void 0 || val === "") {
|
|
99
|
-
return null;
|
|
100
|
-
}
|
|
101
|
-
const num = Number(val);
|
|
102
|
-
if (Number.isNaN(num)) {
|
|
103
|
-
return `${label} moet een geldig getal zijn.`;
|
|
104
|
-
}
|
|
105
|
-
return num <= max ? null : errorMessage?.replace("{label}", label)?.replace("{max}", max.toString()) || `${label} mag niet groter zijn dan ${max}.`;
|
|
106
|
-
};
|
|
107
|
-
var parseDateValue = (val) => {
|
|
108
|
-
if (val instanceof Date) {
|
|
109
|
-
return {
|
|
110
|
-
type: hasExplicitTime(val) ? "datetime" : "date",
|
|
111
|
-
value: isNaN(val.getTime()) ? null : val
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
if (typeof val !== "string") {
|
|
115
|
-
return { type: "invalid", value: null };
|
|
116
|
-
}
|
|
117
|
-
const trimmed = val.trim();
|
|
118
|
-
if (trimmed === "") {
|
|
119
|
-
return { type: "invalid", value: null };
|
|
120
|
-
}
|
|
121
|
-
const timeRegex = /^([0-1]?[0-9]|2[0-3]):[0-5][0-9](:[0-5][0-9])?$/;
|
|
122
|
-
if (timeRegex.test(trimmed)) {
|
|
123
|
-
const [hours, minutes, seconds = 0] = trimmed.split(":").map(Number);
|
|
124
|
-
const date = /* @__PURE__ */ new Date();
|
|
125
|
-
date.setHours(hours, minutes, seconds, 0);
|
|
126
|
-
return { type: "time", value: date };
|
|
127
|
-
}
|
|
128
|
-
const dateRegex = /^\d{4}-\d{2}-\d{2}$/;
|
|
129
|
-
if (dateRegex.test(trimmed)) {
|
|
130
|
-
const date = /* @__PURE__ */ new Date(trimmed + "T00:00:00.000Z");
|
|
131
|
-
return {
|
|
132
|
-
type: "date",
|
|
133
|
-
value: isNaN(date.getTime()) ? null : date
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
const dateTimeRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/;
|
|
137
|
-
if (dateTimeRegex.test(trimmed)) {
|
|
138
|
-
const date = /* @__PURE__ */ new Date(trimmed + ".000Z");
|
|
139
|
-
return {
|
|
140
|
-
type: "datetime",
|
|
141
|
-
value: isNaN(date.getTime()) ? null : date
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
return { type: "invalid", value: null };
|
|
145
|
-
};
|
|
146
|
-
function hasExplicitTime(date) {
|
|
147
|
-
return date.getUTCHours() !== 0 || date.getUTCMinutes() !== 0 || date.getUTCSeconds() !== 0 || date.getUTCMilliseconds() !== 0;
|
|
148
|
-
}
|
|
149
|
-
var dateIsBiggerThan = (min, errorMessage) => (val, label = "Dit") => {
|
|
150
|
-
if (val === null || val === void 0 || val === "") {
|
|
151
|
-
return null;
|
|
152
|
-
}
|
|
153
|
-
const parsed = parseDateValue(val);
|
|
154
|
-
if (!parsed.value) {
|
|
155
|
-
return `${label} moet een geldige ${parsed.type === "time" ? "tijd" : "datum"} zijn.`;
|
|
156
|
-
}
|
|
157
|
-
let formattedMin;
|
|
158
|
-
switch (parsed.type) {
|
|
159
|
-
case "time":
|
|
160
|
-
formattedMin = min.toLocaleTimeString("nl-NL", {
|
|
161
|
-
hour: "2-digit",
|
|
162
|
-
minute: "2-digit",
|
|
163
|
-
hour12: false,
|
|
164
|
-
timeZone: "UTC"
|
|
165
|
-
});
|
|
166
|
-
break;
|
|
167
|
-
case "date":
|
|
168
|
-
formattedMin = min.toLocaleDateString("nl-NL", { timeZone: "UTC" });
|
|
169
|
-
break;
|
|
170
|
-
case "datetime":
|
|
171
|
-
formattedMin = min.toLocaleString("nl-NL", {
|
|
172
|
-
year: "numeric",
|
|
173
|
-
month: "2-digit",
|
|
174
|
-
day: "2-digit",
|
|
175
|
-
hour: "2-digit",
|
|
176
|
-
minute: "2-digit",
|
|
177
|
-
hour12: false,
|
|
178
|
-
timeZone: "UTC"
|
|
179
|
-
});
|
|
180
|
-
break;
|
|
181
|
-
default:
|
|
182
|
-
formattedMin = min.toLocaleDateString("nl-NL", { timeZone: "UTC" });
|
|
183
|
-
}
|
|
184
|
-
if (parsed.type === "time") {
|
|
185
|
-
const timeValue = parsed.value.getHours() * 60 + parsed.value.getMinutes();
|
|
186
|
-
const minTime = min.getHours() * 60 + min.getMinutes();
|
|
187
|
-
return timeValue >= minTime ? null : errorMessage?.replace("{label}", label)?.replace("{min}", formattedMin) || `${label} mag niet voor ${formattedMin} zijn.`;
|
|
188
|
-
}
|
|
189
|
-
return min.getTime() <= parsed.value.getTime() ? null : errorMessage?.replace("{label}", label)?.replace("{min}", formattedMin) || `${label} mag niet voor ${formattedMin} zijn.`;
|
|
190
|
-
};
|
|
191
|
-
var dateIsSmallerThan = (max, errorMessage) => (val, label = "Dit") => {
|
|
192
|
-
if (val === null || val === void 0 || val === "") {
|
|
193
|
-
return null;
|
|
194
|
-
}
|
|
195
|
-
const parsed = parseDateValue(val);
|
|
196
|
-
if (!parsed.value) {
|
|
197
|
-
return `${label} moet een geldige ${parsed.type === "time" ? "tijd" : "datum"} zijn.`;
|
|
198
|
-
}
|
|
199
|
-
let formattedMax;
|
|
200
|
-
switch (parsed.type) {
|
|
201
|
-
case "time":
|
|
202
|
-
formattedMax = max.toLocaleTimeString("nl-NL", {
|
|
203
|
-
hour: "2-digit",
|
|
204
|
-
minute: "2-digit",
|
|
205
|
-
hour12: false,
|
|
206
|
-
timeZone: "UTC"
|
|
207
|
-
});
|
|
208
|
-
break;
|
|
209
|
-
case "date":
|
|
210
|
-
formattedMax = max.toLocaleDateString("nl-NL", { timeZone: "UTC" });
|
|
211
|
-
break;
|
|
212
|
-
case "datetime":
|
|
213
|
-
formattedMax = max.toLocaleString("nl-NL", {
|
|
214
|
-
year: "numeric",
|
|
215
|
-
month: "2-digit",
|
|
216
|
-
day: "2-digit",
|
|
217
|
-
hour: "2-digit",
|
|
218
|
-
minute: "2-digit",
|
|
219
|
-
hour12: false,
|
|
220
|
-
timeZone: "UTC"
|
|
221
|
-
});
|
|
222
|
-
break;
|
|
223
|
-
default:
|
|
224
|
-
formattedMax = max.toLocaleDateString("nl-NL", { timeZone: "UTC" });
|
|
225
|
-
}
|
|
226
|
-
if (parsed.type === "time") {
|
|
227
|
-
const timeValue = parsed.value.getHours() * 60 + parsed.value.getMinutes();
|
|
228
|
-
const macTime = max.getHours() * 60 + max.getMinutes();
|
|
229
|
-
return macTime >= timeValue ? null : errorMessage?.replace("{label}", label)?.replace("{min}", formattedMax) || `${label} mag niet na ${formattedMax} zijn.`;
|
|
230
|
-
}
|
|
231
|
-
return parsed.value.getTime() <= max.getTime() ? null : errorMessage?.replace("{label}", label)?.replace("{min}", formattedMax) || `${label} mag niet na ${formattedMax} zijn.`;
|
|
232
|
-
};
|
|
233
|
-
var isValidFile = (maxSize, accept) => (file) => {
|
|
234
|
-
if (!file) {
|
|
235
|
-
return null;
|
|
236
|
-
}
|
|
237
|
-
if (maxSize && file.size / 1024 > maxSize) {
|
|
238
|
-
return `${file.name} is te groot (max ${maxSize} KB).`;
|
|
239
|
-
}
|
|
240
|
-
if (accept) {
|
|
241
|
-
const allowed = accept.split(",").map((s) => s.trim().toLowerCase());
|
|
242
|
-
const ext = `.${file.name.split(".").pop()?.toLowerCase()}`;
|
|
243
|
-
const mime = file.type.toLowerCase();
|
|
244
|
-
const valid = allowed.some((pattern) => {
|
|
245
|
-
if (pattern === mime) return true;
|
|
246
|
-
if (pattern.endsWith("/*")) {
|
|
247
|
-
return mime.startsWith(pattern.replace("/*", "/"));
|
|
248
|
-
}
|
|
249
|
-
return pattern === ext;
|
|
250
|
-
});
|
|
251
|
-
if (!valid) {
|
|
252
|
-
return `${file.name} is niet toegelaten.`;
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
return null;
|
|
256
|
-
};
|
|
257
|
-
var isPattern = (pattern, errorMsg) => (val, label = "Dit") => {
|
|
258
|
-
if (val === null || val === void 0 || val === "") {
|
|
259
|
-
return null;
|
|
260
|
-
}
|
|
261
|
-
if (typeof val !== "string") {
|
|
262
|
-
return errorMsg || `${label} heeft een ongeldig patroon.`;
|
|
263
|
-
}
|
|
264
|
-
const trimmed = val.trim();
|
|
265
|
-
if (trimmed === "") {
|
|
266
|
-
return null;
|
|
267
|
-
}
|
|
268
|
-
let regex;
|
|
269
|
-
if (typeof pattern === "string") {
|
|
270
|
-
if (pattern.startsWith("/") && pattern.lastIndexOf("/") > 0) {
|
|
271
|
-
const lastSlash = pattern.lastIndexOf("/");
|
|
272
|
-
const patternBody = pattern.substring(1, lastSlash);
|
|
273
|
-
const flags = pattern.substring(lastSlash + 1);
|
|
274
|
-
const safeFlags = flags.replace("g", "");
|
|
275
|
-
regex = new RegExp(patternBody, safeFlags);
|
|
276
|
-
} else {
|
|
277
|
-
regex = new RegExp(pattern);
|
|
278
|
-
}
|
|
279
|
-
} else {
|
|
280
|
-
regex = new RegExp(pattern.source, pattern.flags.replace("g", ""));
|
|
281
|
-
}
|
|
282
|
-
return regex.test(trimmed) ? null : errorMsg || `${label} heeft een ongeldig patroon.`;
|
|
283
|
-
};
|
|
29
|
+
// src/utils/create-field-state.ts
|
|
30
|
+
import {
|
|
31
|
+
dateIsBiggerThan,
|
|
32
|
+
dateIsSmallerThan,
|
|
33
|
+
isBiggerThan,
|
|
34
|
+
isEmail,
|
|
35
|
+
isPattern,
|
|
36
|
+
isRequired,
|
|
37
|
+
isSmallerThan,
|
|
38
|
+
isUrl
|
|
39
|
+
} from "@sio-group/form-validation";
|
|
284
40
|
|
|
285
41
|
// src/utils/parse-date.ts
|
|
286
|
-
var
|
|
42
|
+
var parseDateValue = (val) => {
|
|
287
43
|
if (val instanceof Date) {
|
|
288
44
|
return isNaN(val.getTime()) ? null : val;
|
|
289
45
|
}
|
|
@@ -369,8 +125,8 @@ function getDefaultValidations(config) {
|
|
|
369
125
|
case "time":
|
|
370
126
|
const min = config.config?.min;
|
|
371
127
|
const max = config.config?.max;
|
|
372
|
-
const parsedMin =
|
|
373
|
-
const parsedMax =
|
|
128
|
+
const parsedMin = parseDateValue(min);
|
|
129
|
+
const parsedMax = parseDateValue(max);
|
|
374
130
|
if (parsedMin) validations.push(dateIsBiggerThan(parsedMin));
|
|
375
131
|
if (parsedMax) validations.push(dateIsSmallerThan(parsedMax));
|
|
376
132
|
break;
|
|
@@ -1319,6 +1075,9 @@ var DateInput = ({
|
|
|
1319
1075
|
);
|
|
1320
1076
|
};
|
|
1321
1077
|
|
|
1078
|
+
// src/components/Fields/Input/FileInput/index.tsx
|
|
1079
|
+
import { isValidFile } from "@sio-group/form-validation";
|
|
1080
|
+
|
|
1322
1081
|
// src/utils/get-accept-string.ts
|
|
1323
1082
|
var getAccept = (accept) => {
|
|
1324
1083
|
if (Array.isArray(accept)) {
|
|
@@ -1977,7 +1736,7 @@ var Link = React4.memo(LinkComponent);
|
|
|
1977
1736
|
// src/components/Form.tsx
|
|
1978
1737
|
import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1979
1738
|
import { createElement } from "react";
|
|
1980
|
-
var DefaultContainer = ({ children
|
|
1739
|
+
var DefaultContainer = ({ children }) => /* @__PURE__ */ jsx16("div", { children });
|
|
1981
1740
|
var DefaultButtonContainer = ({ children }) => /* @__PURE__ */ jsx16("div", { className: "btn-group", children });
|
|
1982
1741
|
var Form = ({
|
|
1983
1742
|
fields,
|
|
@@ -2096,8 +1855,8 @@ var Form = ({
|
|
|
2096
1855
|
buttons?.map(renderButton)
|
|
2097
1856
|
] }) : null;
|
|
2098
1857
|
};
|
|
2099
|
-
return /* @__PURE__ */ jsxs14(
|
|
2100
|
-
renderFields(),
|
|
1858
|
+
return /* @__PURE__ */ jsxs14("form", { className, style, noValidate: true, children: [
|
|
1859
|
+
/* @__PURE__ */ jsx16(Container, { children: renderFields() }),
|
|
2101
1860
|
renderButtons()
|
|
2102
1861
|
] });
|
|
2103
1862
|
};
|
package/package.json
CHANGED
package/src/components/Form.tsx
CHANGED
|
@@ -8,8 +8,8 @@ import { Checkbox, Input, Radio, Select, Textarea } from "./Fields";
|
|
|
8
8
|
import { Link } from "./Link";
|
|
9
9
|
import { Button } from "./Button";
|
|
10
10
|
|
|
11
|
-
const DefaultContainer: React.FC<FormContainerProps> = ({ children
|
|
12
|
-
<
|
|
11
|
+
const DefaultContainer: React.FC<FormContainerProps> = ({ children }) => (
|
|
12
|
+
<div>{children}</div>
|
|
13
13
|
);
|
|
14
14
|
|
|
15
15
|
const DefaultButtonContainer: React.FC<ButtonContainerProps> = ({ children }) => (
|
package/tsconfig.tsbuildinfo
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["./src/index.ts","./src/hooks/useconnectionstatus.ts","./src/hooks/useform.ts","./src/types/field-props.d.ts","./src/types/field-setters.d.ts","./src/types/field-state.d.ts","./src/types/form-config.d.ts","./src/types/form-layout.d.ts","./src/types/index.ts","./src/types/ui-props.d.ts","./src/types/use-form-options.d.ts","./src/utils/create-field-props.ts","./src/utils/create-field-state.ts","./src/utils/file-type-icon.ts","./src/utils/get-accept-string.ts","./src/utils/get-column-classes.ts","./src/utils/get-file-size.ts","./src/utils/parse-date.ts","./src/utils/slugify.ts","./src/components/form.tsx","./src/components/button/index.tsx","./src/components/fields/index.tsx","./src/components/fields/checkbox/index.tsx","./src/components/fields/input/input.tsx","./src/components/fields/input/dateinput/index.tsx","./src/components/fields/input/fileinput/index.tsx","./src/components/fields/input/numberinput/index.tsx","./src/components/fields/input/rangeinput/index.tsx","./src/components/fields/input/textinput/index.tsx","./src/components/fields/inputwrapper/index.tsx","./src/components/fields/radio/index.tsx","./src/components/fields/select/index.tsx","./src/components/fields/textarea/index.tsx","./src/components/icon/index.tsx","./src/components/link/index.tsx","./src/utils/custom-icons.tsx"],"version":"5.9.3"}
|
|
1
|
+
{"root":["./src/index.ts","./src/hooks/useconnectionstatus.ts","./src/hooks/useform.ts","./src/types/field-props.d.ts","./src/types/field-setters.d.ts","./src/types/field-state.d.ts","./src/types/form-config.d.ts","./src/types/form-layout.d.ts","./src/types/index.ts","./src/types/ui-props.d.ts","./src/types/use-form-options.d.ts","./src/utils/create-field-props.ts","./src/utils/create-field-state.ts","./src/utils/file-type-icon.ts","./src/utils/get-accept-string.ts","./src/utils/get-column-classes.ts","./src/utils/get-file-size.ts","./src/utils/parse-date.ts","./src/utils/slugify.ts","./src/components/form.tsx","./src/components/button/index.tsx","./src/components/fields/index.tsx","./src/components/fields/checkbox/index.tsx","./src/components/fields/input/input.tsx","./src/components/fields/input/dateinput/index.tsx","./src/components/fields/input/fileinput/index.tsx","./src/components/fields/input/numberinput/index.tsx","./src/components/fields/input/rangeinput/index.tsx","./src/components/fields/input/textinput/index.tsx","./src/components/fields/inputwrapper/index.tsx","./src/components/fields/radio/index.tsx","./src/components/fields/select/index.tsx","./src/components/fields/textarea/index.tsx","./src/components/icon/index.tsx","./src/components/link/index.tsx","./src/utils/custom-icons.tsx"],"errors":true,"version":"5.9.3"}
|