@sio-group/form-react 0.1.0 → 0.2.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 +23 -82
- package/README.md +2 -2
- package/dist/index.cjs +268 -18
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +258 -17
- package/package.json +6 -5
- package/src/assets/scss/components/button.scss +164 -0
- package/src/assets/scss/components/checkbox.scss +90 -0
- package/src/assets/scss/components/color.scss +29 -0
- package/src/assets/scss/components/form-field.scss +34 -0
- package/src/assets/scss/components/form-states.scss +80 -0
- package/src/assets/scss/components/grid.scss +134 -0
- package/src/assets/scss/components/input.scss +112 -0
- package/src/assets/scss/components/link.scss +66 -0
- package/src/assets/scss/components/radio.scss +104 -0
- package/src/assets/scss/components/range.scss +52 -0
- package/src/assets/scss/components/select.scss +35 -0
- package/src/assets/scss/components/upload.scss +52 -0
- package/src/assets/scss/index.scss +19 -0
- package/src/assets/scss/tokens/_colors.scss +49 -0
- package/src/assets/scss/tokens/_form.scss +6 -0
- package/src/assets/scss/utilities/_mixins.scss +6 -0
- package/src/components/Button/index.tsx +106 -0
- package/src/components/Fields/Checkbox/index.tsx +59 -0
- package/src/components/Fields/Input/DateInput/index.tsx +95 -0
- package/src/components/Fields/Input/FileInput/index.tsx +169 -0
- package/src/components/Fields/Input/Input.tsx +45 -0
- package/src/components/Fields/Input/NumberInput/index.tsx +169 -0
- package/src/components/Fields/Input/RangeInput/index.tsx +77 -0
- package/src/components/Fields/Input/TextInput/index.tsx +65 -0
- package/src/components/Fields/InputWrapper/index.tsx +78 -0
- package/src/components/Fields/Radio/index.tsx +82 -0
- package/src/components/Fields/Select/index.tsx +103 -0
- package/src/components/Fields/Textarea/index.tsx +70 -0
- package/src/components/Fields/index.tsx +11 -0
- package/src/components/Form.tsx +163 -0
- package/src/components/Icon/index.tsx +16 -0
- package/src/components/Link/index.tsx +106 -0
- package/src/hooks/useConnectionStatus.ts +20 -0
- package/src/hooks/useForm.ts +230 -0
- package/src/index.ts +15 -0
- package/src/types/field-props.d.ts +94 -0
- package/src/types/field-setters.d.ts +6 -0
- package/src/types/field-state.d.ts +21 -0
- package/src/types/form-config.d.ts +30 -0
- package/src/types/form-layout.d.ts +6 -0
- package/src/types/index.ts +18 -0
- package/src/types/ui-props.d.ts +33 -0
- package/src/types/use-form-options.d.ts +3 -0
- package/src/utils/create-field-props.ts +115 -0
- package/src/utils/create-field-state.ts +99 -0
- package/src/utils/custom-icons.tsx +145 -0
- package/src/utils/file-type-icon.ts +63 -0
- package/src/utils/get-accept-string.ts +24 -0
- package/src/utils/get-column-classes.ts +21 -0
- package/src/utils/get-file-size.ts +9 -0
- package/src/utils/parse-date.ts +36 -0
- package/src/utils/slugify.ts +9 -0
- package/tsconfig.json +15 -0
package/dist/index.js
CHANGED
|
@@ -26,20 +26,264 @@ 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
|
-
|
|
29
|
+
// ../form-validation/dist/index.js
|
|
30
|
+
var isRequired = (errorMessage) => (val, label = "Dit") => {
|
|
31
|
+
const message = errorMessage?.replace("{label}", label) || `${label} is een verplicht veld.`;
|
|
32
|
+
if (val === null || val === void 0) {
|
|
33
|
+
return message;
|
|
34
|
+
}
|
|
35
|
+
if (typeof val === "string" && val.trim().length === 0) {
|
|
36
|
+
return message;
|
|
37
|
+
}
|
|
38
|
+
if (typeof val === "boolean" && !val) {
|
|
39
|
+
return message;
|
|
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
|
+
};
|
|
40
284
|
|
|
41
285
|
// src/utils/parse-date.ts
|
|
42
|
-
var
|
|
286
|
+
var parseDateValue2 = (val) => {
|
|
43
287
|
if (val instanceof Date) {
|
|
44
288
|
return isNaN(val.getTime()) ? null : val;
|
|
45
289
|
}
|
|
@@ -125,8 +369,8 @@ function getDefaultValidations(config) {
|
|
|
125
369
|
case "time":
|
|
126
370
|
const min = config.config?.min;
|
|
127
371
|
const max = config.config?.max;
|
|
128
|
-
const parsedMin =
|
|
129
|
-
const parsedMax =
|
|
372
|
+
const parsedMin = parseDateValue2(min);
|
|
373
|
+
const parsedMax = parseDateValue2(max);
|
|
130
374
|
if (parsedMin) validations.push(dateIsBiggerThan(parsedMin));
|
|
131
375
|
if (parsedMax) validations.push(dateIsSmallerThan(parsedMax));
|
|
132
376
|
break;
|
|
@@ -1075,9 +1319,6 @@ var DateInput = ({
|
|
|
1075
1319
|
);
|
|
1076
1320
|
};
|
|
1077
1321
|
|
|
1078
|
-
// src/components/Fields/Input/FileInput/index.tsx
|
|
1079
|
-
import { isValidFile } from "@sio-group/form-validation";
|
|
1080
|
-
|
|
1081
1322
|
// src/utils/get-accept-string.ts
|
|
1082
1323
|
var getAccept = (accept) => {
|
|
1083
1324
|
if (Array.isArray(accept)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sio-group/form-react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"private": false,
|
|
4
5
|
"type": "module",
|
|
5
6
|
"main": "./dist/index.cjs",
|
|
6
7
|
"module": "./dist/index.js",
|
|
@@ -26,12 +27,12 @@
|
|
|
26
27
|
"license": "ISC",
|
|
27
28
|
"description": "",
|
|
28
29
|
"dependencies": {
|
|
29
|
-
"@sio/form-types": "0.1.
|
|
30
|
-
"@sio/form-validation": "0.1.
|
|
30
|
+
"@sio-group/form-types": "0.1.3",
|
|
31
|
+
"@sio-group/form-validation": "0.1.3"
|
|
31
32
|
},
|
|
32
33
|
"peerDependencies": {
|
|
33
|
-
"react": "^
|
|
34
|
-
"react-dom": "^
|
|
34
|
+
"react": "^19",
|
|
35
|
+
"react-dom": "^19"
|
|
35
36
|
},
|
|
36
37
|
"devDependencies": {
|
|
37
38
|
"@vitejs/plugin-react": "^4",
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
@use "../utilities/mixins" as *;
|
|
2
|
+
@use "../tokens/colors" as *;
|
|
3
|
+
|
|
4
|
+
:where(.btn--primary) {
|
|
5
|
+
--sio-btn-bg: var(--sio-btn-primary-bg);
|
|
6
|
+
--sio-btn-border: var(--sio-btn-primary-border);
|
|
7
|
+
--sio-btn-text: var(--sio-btn-primary-text);
|
|
8
|
+
|
|
9
|
+
--sio-btn-bg-hover: color-mix(in srgb, var(--sio-btn-bg) 85%, black);
|
|
10
|
+
--sio-btn-border-hover: color-mix(in srgb, var(--sio-btn-border) 85%, black);
|
|
11
|
+
--sio-btn-text-hover: var(--sio-btn-text);
|
|
12
|
+
|
|
13
|
+
--sio-btn-bg-disabled: color-mix(in srgb, var(--sio-btn-bg) 40%, white);
|
|
14
|
+
--sio-btn-border-disabled: color-mix(in srgb, var(--sio-btn-border) 40%, white);
|
|
15
|
+
--sio-btn-text-disabled: color-mix(in srgb, var(--sio-btn-text) 60%, black);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
:where(.btn--secondary) {
|
|
19
|
+
--sio-btn-bg: var(--sio-btn-secondary-bg);
|
|
20
|
+
--sio-btn-border: var(--sio-btn-secondary-border);
|
|
21
|
+
--sio-btn-text: var(--sio-btn-secondary-text);
|
|
22
|
+
|
|
23
|
+
--sio-btn-bg-hover: var(--sio-btn-bg);
|
|
24
|
+
--sio-btn-border-hover: color-mix(in srgb, var(--sio-btn-border) 85%, black);
|
|
25
|
+
--sio-btn-text-hover: var(--sio-btn-text);
|
|
26
|
+
|
|
27
|
+
--sio-btn-bg-disabled: var(--sio-btn-bg);
|
|
28
|
+
--sio-btn-border-disabled: color-mix(in srgb, var(--sio-btn-border) 40%, white);
|
|
29
|
+
--sio-btn-text-disabled: color-mix(in srgb, var(--sio-btn-text) 40%, white);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
:where(.btn--link) {
|
|
33
|
+
--sio-btn-bg: var(--sio-btn-link-bg);
|
|
34
|
+
--sio-btn-border: var(--sio-btn-link-border);
|
|
35
|
+
--sio-btn-text: var(--sio-btn-link-text);
|
|
36
|
+
|
|
37
|
+
--sio-btn-bg-hover: var(--sio-btn-bg);
|
|
38
|
+
--sio-btn-border-hover: var(--sio-btn-border);
|
|
39
|
+
--sio-btn-text-hover: color-mix(in srgb, var(--sio-btn-text) 85%, black);
|
|
40
|
+
|
|
41
|
+
--sio-btn-bg-disabled: var(--sio-btn-bg);
|
|
42
|
+
--sio-btn-border-disabled: var(--sio-btn-border);
|
|
43
|
+
--sio-btn-text-disabled: color-mix(in srgb, var(--sio-btn-text) 40%, white);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
:where(.btn) {
|
|
47
|
+
background-color: var(--sio-btn-bg);
|
|
48
|
+
color: var(--sio-btn-text);
|
|
49
|
+
display: inline-block;
|
|
50
|
+
font-size: .9em;
|
|
51
|
+
font-weight: 500;
|
|
52
|
+
user-select: none;
|
|
53
|
+
text-align: center;
|
|
54
|
+
border: 1px solid var(--sio-btn-border);
|
|
55
|
+
padding: 2px 15px;
|
|
56
|
+
border-radius: 3px;
|
|
57
|
+
cursor: pointer;
|
|
58
|
+
min-height: 22px;
|
|
59
|
+
transition: all .3s ease-in;
|
|
60
|
+
text-decoration: none;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
:where(.btn--link) {
|
|
64
|
+
display: inline;
|
|
65
|
+
font-weight: unset;
|
|
66
|
+
user-select: none;
|
|
67
|
+
text-align: left;
|
|
68
|
+
padding: 0;
|
|
69
|
+
border-radius: unset;
|
|
70
|
+
min-height: unset;
|
|
71
|
+
transition: all 0.3s ease-in;
|
|
72
|
+
text-decoration: underline;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
:where(.btn:hover),
|
|
76
|
+
:where(.btn:active),
|
|
77
|
+
:where(.btn:focus),
|
|
78
|
+
:where(.btn.btn--active) {
|
|
79
|
+
background: var(--sio-btn-bg-hover, var(--sio-btn-bg));
|
|
80
|
+
border-color: var(--sio-btn-border-hover, var(--sio-btn-border));
|
|
81
|
+
color: var(--sio-btn-text-hover, var(--sio-btn-text));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
:where(.btn:disabled),
|
|
85
|
+
:where(.btn.btn--disabled) {
|
|
86
|
+
cursor: not-allowed;
|
|
87
|
+
|
|
88
|
+
background: var(--sio-btn-bg-disabled, var(--sio-btn-bg));
|
|
89
|
+
border-color: var(--sio-btn-border-disabled, var(--sio-btn-border));
|
|
90
|
+
color: var(--sio-btn-text-disabled, var(--sio-btn-text));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
@each $name, $color in $colors {
|
|
94
|
+
:where(.btn--primary.btn--#{$name}) {
|
|
95
|
+
--sio-btn-bg: var(--sio-color-#{$name});
|
|
96
|
+
--sio-btn-border: var(--sio-color-#{$name});
|
|
97
|
+
--sio-btn-text: var(--sio-color-white);
|
|
98
|
+
}
|
|
99
|
+
:where(.btn--secondary.btn--#{$name}) {
|
|
100
|
+
--sio-btn-bg: transparent;
|
|
101
|
+
--sio-btn-border: var(--sio-color-#{$name});
|
|
102
|
+
--sio-btn-text: var(--sio-color-#{$name});
|
|
103
|
+
}
|
|
104
|
+
:where(.btn--link.btn--#{$name}) {
|
|
105
|
+
--sio-btn-bg: transparent;
|
|
106
|
+
--sio-btn-border: transparent;
|
|
107
|
+
--sio-btn-text: var(--sio-color-#{$name});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
:where(.btn--block) {
|
|
112
|
+
display: block;
|
|
113
|
+
width: 100%;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
:where(.btn--lg) {
|
|
117
|
+
padding: 5px 20px;
|
|
118
|
+
font-size: 1.1em;
|
|
119
|
+
min-height: 34px;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
:where(.btn--sm) {
|
|
123
|
+
padding: 2.5px 5px;
|
|
124
|
+
font-size: .7em;
|
|
125
|
+
min-height: 23px;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
:where(.btn--loading) {
|
|
129
|
+
position: relative;
|
|
130
|
+
cursor: wait !important;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
:where(.btn__spinner) {
|
|
134
|
+
display: flex;
|
|
135
|
+
animation: spin 1s infinite linear;
|
|
136
|
+
margin-right: 8px;
|
|
137
|
+
width: 20px;
|
|
138
|
+
height: 20px;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
:where(.btn__spinner svg) {
|
|
142
|
+
display: block;
|
|
143
|
+
width: 100%;
|
|
144
|
+
height: 100%;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
:where(.btn__spinner circle) {
|
|
148
|
+
fill: none;
|
|
149
|
+
stroke: currentColor;
|
|
150
|
+
stroke-width: 2;
|
|
151
|
+
stroke-dasharray: 30 100;
|
|
152
|
+
stroke-linecap: round;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
:where(.btn__loading-text) {
|
|
156
|
+
position: absolute;
|
|
157
|
+
clip: rect(1px, 1px, 1px, 1px);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
:where(.btn-group) {
|
|
161
|
+
display: flex;
|
|
162
|
+
flex-wrap: wrap;
|
|
163
|
+
gap: 5px;
|
|
164
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
:where(.form-field__checkbox label) {
|
|
2
|
+
position: relative;
|
|
3
|
+
padding-left: 32px;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
:where(.form-field__checkbox label > div) {
|
|
7
|
+
display: inline;
|
|
8
|
+
color: var(--sio-color-black);
|
|
9
|
+
font-weight: normal;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
:where(.form-field__checkbox label):before {
|
|
13
|
+
content: '';
|
|
14
|
+
background-color: var(--sio-form-bg);
|
|
15
|
+
position: absolute;
|
|
16
|
+
border-radius: var(--sio-form-border-radius);
|
|
17
|
+
cursor: pointer;
|
|
18
|
+
border: 1px solid var(--sio-form-border);
|
|
19
|
+
width: 17px;
|
|
20
|
+
height: 17px;
|
|
21
|
+
left: 0;
|
|
22
|
+
top: -1px;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
:where(.form-field__checkbox label):after {
|
|
26
|
+
content: '';
|
|
27
|
+
position: absolute;
|
|
28
|
+
background-color: var(--sio-color-primary);
|
|
29
|
+
width: 13px;
|
|
30
|
+
height: 13px;
|
|
31
|
+
top: 2px;
|
|
32
|
+
left: 3px;
|
|
33
|
+
transform: scale(0);
|
|
34
|
+
border-radius: var(--sio-form-border-radius);
|
|
35
|
+
cursor: pointer;
|
|
36
|
+
transition: all .4s;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
:where(.form-field__checkbox input[type='checkbox']) {
|
|
40
|
+
display: none !important;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
:where(.form-field__checkbox.form-field--has-value label):before {
|
|
44
|
+
border-color: var(--sio-color-primary);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
:where(.form-field__checkbox.form-field--has-value label):after {
|
|
48
|
+
transform: scale(1);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
:where(.form-field__checkbox.form-field--has-errors label):before {
|
|
52
|
+
border-color: var(--sio-color-error);
|
|
53
|
+
background: rgba(var(--sio-color-error-rgb), .06);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
:where(.form-field__checkbox.form-field--has-errors.form-field--has-value label):after {
|
|
57
|
+
border-color: var(--sio-color-error);
|
|
58
|
+
background: var(--sio-color-error);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
:where(.form-field__checkbox.form-field--disabled label) {
|
|
63
|
+
cursor: not-allowed;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
:where(.form-field__checkbox.form-field--disabled label):before,
|
|
67
|
+
:where(.form-field__checkbox.form-field--disabled label):after {
|
|
68
|
+
cursor: not-allowed;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
:where(.form-field__checkbox.form-field--disabled label):before {
|
|
72
|
+
border-color: var(--sio-color-light-gray);
|
|
73
|
+
background-color: color-mix(in srgb, var(--sio-color-light-gray) 75%, white);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
:where(.form-field__checkbox.form-field--disabled label):after {
|
|
77
|
+
border-color: color-mix(in srgb, var(--sio-color-light-gray) 75%, black);
|
|
78
|
+
background-color: color-mix(in srgb, var(--sio-color-light-gray) 75%, black);
|
|
79
|
+
|
|
80
|
+
transform: scale(0);
|
|
81
|
+
transition: all .4s;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
:where(.form-field__checkbox.form-field--disabled.form-field--has-value label):before {
|
|
85
|
+
border-color: var(--sio-color-light-gray);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
:where(.form-field__checkbox.form-field--disabled.form-field--has-value label):after {
|
|
89
|
+
transform: scale(1);
|
|
90
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
:where(.form-field__color .form-field__control) {
|
|
2
|
+
max-width: 50px;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
:where(.form-field__color input) {
|
|
6
|
+
padding: 0;
|
|
7
|
+
border-radius: var(--sio-form-border-radius);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
:where(.form-field__color input[type="color" i]) {
|
|
11
|
+
inline-size: 50px;
|
|
12
|
+
block-size: 25.5px;
|
|
13
|
+
padding: 0;
|
|
14
|
+
border: none;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
:where(.form-field__color input[type="color"])::-webkit-color-swatch-wrapper {
|
|
18
|
+
padding-block-end: 3px;
|
|
19
|
+
padding-block-start: 3px;
|
|
20
|
+
padding-inline-start: 3px;
|
|
21
|
+
padding-inline-end: 3px;
|
|
22
|
+
padding: 3px;
|
|
23
|
+
border: none;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
:where(.form-field__color input[type="color"])::-webkit-color-swatch {
|
|
27
|
+
border: none;
|
|
28
|
+
border-radius: 2px;
|
|
29
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
:where(.form-field) {
|
|
2
|
+
position: relative;
|
|
3
|
+
margin: 5px 0 15px 0;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
:where(.form-field label) {
|
|
7
|
+
color: var(--sio-form-label);
|
|
8
|
+
font-size: 0.9em;
|
|
9
|
+
font-weight: 600;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
:where(.form-field label span) {
|
|
13
|
+
color: var(--sio-color-error);
|
|
14
|
+
font-weight: bold;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
:where(.form-field__description) {
|
|
18
|
+
color: var(--sio-color-gray);
|
|
19
|
+
font-weight: 200;
|
|
20
|
+
font-size: 0.9em;
|
|
21
|
+
margin-left: 10px;
|
|
22
|
+
white-space: pre-wrap;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
:where(.form-field__errors) {
|
|
26
|
+
list-style: none;
|
|
27
|
+
padding: 0;
|
|
28
|
+
margin: 5px 0 0;
|
|
29
|
+
color: var(--sio-color-error);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
:where(.form-field__errors-item) {
|
|
33
|
+
font-size: .9em
|
|
34
|
+
}
|