@sio-group/form-react 0.1.0 → 0.1.3
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 +35 -4
- 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 +4 -3
- 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
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { BaseFieldProps, FieldProps, FieldState, FieldSetters } from "../types";
|
|
2
|
+
import { getColumnClasses } from "./get-column-classes";
|
|
3
|
+
|
|
4
|
+
export const createFieldProps = (field: FieldState, setters: FieldSetters, disabled: boolean, renderLayout: boolean = false): FieldProps => {
|
|
5
|
+
const classes: string = getColumnClasses(field.layout, field.styling?.className);
|
|
6
|
+
|
|
7
|
+
const baseProps: BaseFieldProps = {
|
|
8
|
+
id: field.id,
|
|
9
|
+
name: field.name,
|
|
10
|
+
label: field.label,
|
|
11
|
+
placeholder: field.placeholder,
|
|
12
|
+
value: field.value,
|
|
13
|
+
errors: field.errors,
|
|
14
|
+
required: field.required,
|
|
15
|
+
autocomplete: field.autocomplete,
|
|
16
|
+
touched: field.touched,
|
|
17
|
+
focused: field.focused,
|
|
18
|
+
readOnly: field.readOnly,
|
|
19
|
+
disabled,
|
|
20
|
+
icon: field.icon,
|
|
21
|
+
description: field.description,
|
|
22
|
+
onChange: setters.handleChange,
|
|
23
|
+
setFocused: setters.setFocused,
|
|
24
|
+
setTouched: setters.setTouched,
|
|
25
|
+
className: renderLayout ? classes : field.styling?.className,
|
|
26
|
+
style: field.styling?.style,
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
if (field.type === 'textarea') {
|
|
30
|
+
return {
|
|
31
|
+
...baseProps,
|
|
32
|
+
type: field.type,
|
|
33
|
+
rows: field.rows,
|
|
34
|
+
cols: field.cols,
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (field.type === "file") {
|
|
39
|
+
return {
|
|
40
|
+
...baseProps,
|
|
41
|
+
type: field.type,
|
|
42
|
+
accept: field.accept,
|
|
43
|
+
multiple: field.multiple ?? false,
|
|
44
|
+
capture: field.capture ?? false,
|
|
45
|
+
onError: setters.setErrors,
|
|
46
|
+
filesize: field.filesize ?? 10240,
|
|
47
|
+
onFileRemove: field.onFileRemove,
|
|
48
|
+
onRemoveAll: field.onRemoveAll,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (field.type === "range" || field.type === "number") {
|
|
53
|
+
const numberProps = {
|
|
54
|
+
...baseProps,
|
|
55
|
+
type: field.type,
|
|
56
|
+
min: field.min ?? Number.MIN_SAFE_INTEGER,
|
|
57
|
+
max: field.max ?? Number.MAX_SAFE_INTEGER,
|
|
58
|
+
step: field.step ?? 1,
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
if (field.type === "number") {
|
|
62
|
+
return {
|
|
63
|
+
...numberProps,
|
|
64
|
+
spinner: field.spinner ?? true,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (field.type === "range") {
|
|
69
|
+
return {
|
|
70
|
+
...numberProps,
|
|
71
|
+
showValue: field.showValue ?? true,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if(field.type === "date" || field.type === "time" || field.type === 'datetime-local') {
|
|
77
|
+
return {
|
|
78
|
+
...baseProps,
|
|
79
|
+
type: field.type,
|
|
80
|
+
min: field.min ?? '',
|
|
81
|
+
max: field.max ?? '',
|
|
82
|
+
step: field.step ?? 1,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (field.type === "url") {
|
|
87
|
+
return {
|
|
88
|
+
...baseProps,
|
|
89
|
+
type: field.type,
|
|
90
|
+
allowLocalhost: field.allowLocalhost ?? false,
|
|
91
|
+
allowFtp: field.allowFtp ?? false,
|
|
92
|
+
secureOnly: field.secureOnly ?? !(field.allowLocalhost || field.allowFtp),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (field.type === "select" || field.type === "creatable") {
|
|
97
|
+
return {
|
|
98
|
+
...baseProps,
|
|
99
|
+
type: field.type,
|
|
100
|
+
options: field.options || [],
|
|
101
|
+
multiple: field.multiple,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (field.type === "radio") {
|
|
106
|
+
return {
|
|
107
|
+
...baseProps,
|
|
108
|
+
type: field.type,
|
|
109
|
+
options: field.options || [],
|
|
110
|
+
inline: field.inline ?? false,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return { ...baseProps, type: field.type, };
|
|
115
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { FieldConfigMap, FormField } from "@sio-group/form-types";
|
|
2
|
+
import { FieldState, FieldValue } from "../types";
|
|
3
|
+
import { ValidationRule } from "@sio-group/form-types/src/core/valudation-rule";
|
|
4
|
+
import {
|
|
5
|
+
dateIsBiggerThan,
|
|
6
|
+
dateIsSmallerThan,
|
|
7
|
+
isBiggerThan,
|
|
8
|
+
isEmail, isPattern,
|
|
9
|
+
isRequired,
|
|
10
|
+
isSmallerThan,
|
|
11
|
+
isUrl
|
|
12
|
+
} from "@sio-group/form-validation";
|
|
13
|
+
import { parseDateValue } from "./parse-date";
|
|
14
|
+
|
|
15
|
+
export const createFieldState = (name: string, id: string, config: FormField): FieldState => {
|
|
16
|
+
return {
|
|
17
|
+
...config.config,
|
|
18
|
+
id,
|
|
19
|
+
name,
|
|
20
|
+
type: config.type,
|
|
21
|
+
value: config.config?.defaultValue ?? getDefaultValue(config),
|
|
22
|
+
validations: [
|
|
23
|
+
...(config.config?.validations ?? []),
|
|
24
|
+
...getDefaultValidations(config),
|
|
25
|
+
],
|
|
26
|
+
errors: [],
|
|
27
|
+
touched: false,
|
|
28
|
+
focused: false,
|
|
29
|
+
} as FieldState
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function getDefaultValue<T extends keyof FieldConfigMap> (config: FormField): FieldValue<T> {
|
|
33
|
+
switch (config.type) {
|
|
34
|
+
case "checkbox":
|
|
35
|
+
return false;
|
|
36
|
+
case "range":
|
|
37
|
+
return config.config.min ?? 0;
|
|
38
|
+
case "select":
|
|
39
|
+
case "creatable":
|
|
40
|
+
return null;
|
|
41
|
+
case "file":
|
|
42
|
+
return [];
|
|
43
|
+
case "color":
|
|
44
|
+
return "#000000";
|
|
45
|
+
case "number":
|
|
46
|
+
case "text":
|
|
47
|
+
default:
|
|
48
|
+
return "";
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function getDefaultValidations<T extends keyof FieldConfigMap>(config: FormField): ValidationRule<T>[] {
|
|
53
|
+
const validations: ValidationRule<T>[] = [];
|
|
54
|
+
|
|
55
|
+
if (config.config?.required) {
|
|
56
|
+
validations.push(isRequired());
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
switch (config.type) {
|
|
60
|
+
case 'email':
|
|
61
|
+
validations.push(isEmail());
|
|
62
|
+
break;
|
|
63
|
+
|
|
64
|
+
case 'number':
|
|
65
|
+
case 'range':
|
|
66
|
+
if (config.config?.min) validations.push(isBiggerThan(config.config?.min));
|
|
67
|
+
if (config.config?.max) validations.push(isSmallerThan(config.config?.max));
|
|
68
|
+
break;
|
|
69
|
+
|
|
70
|
+
case 'date':
|
|
71
|
+
case 'datetime-local':
|
|
72
|
+
case 'time':
|
|
73
|
+
const min: string | undefined = config.config?.min;
|
|
74
|
+
const max: string | undefined = config.config?.max;
|
|
75
|
+
const parsedMin: Date | null = parseDateValue(min);
|
|
76
|
+
const parsedMax: Date | null = parseDateValue(max);
|
|
77
|
+
if (parsedMin) validations.push(dateIsBiggerThan(parsedMin));
|
|
78
|
+
if (parsedMax) validations.push(dateIsSmallerThan(parsedMax));
|
|
79
|
+
break;
|
|
80
|
+
|
|
81
|
+
case 'url':
|
|
82
|
+
if (config.config?.pattern) validations.push(isPattern(config.config.pattern));
|
|
83
|
+
validations.push(
|
|
84
|
+
isUrl(
|
|
85
|
+
config.config?.allowLocalhost || false,
|
|
86
|
+
config.config?.allowFtp || false,
|
|
87
|
+
config.config?.secureOnly || !(config.config?.allowLocalhost || config.config?.allowFtp),
|
|
88
|
+
),
|
|
89
|
+
);
|
|
90
|
+
break;
|
|
91
|
+
|
|
92
|
+
case 'text':
|
|
93
|
+
case 'tel':
|
|
94
|
+
if (config.config?.pattern) validations.push(isPattern(config.config.pattern));
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return validations;
|
|
99
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
export const CustomIcons = {
|
|
2
|
+
Date: () => (
|
|
3
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5">
|
|
4
|
+
<rect x="3" y="4" width="18" height="18" rx="2" ry="2" stroke="currentColor" fill="none"/>
|
|
5
|
+
<line x1="8" y1="2" x2="8" y2="6" stroke="currentColor"/>
|
|
6
|
+
<line x1="16" y1="2" x2="16" y2="6" stroke="currentColor"/>
|
|
7
|
+
<line x1="3" y1="10" x2="21" y2="10" stroke="currentColor"/>
|
|
8
|
+
</svg>
|
|
9
|
+
),
|
|
10
|
+
Time: () => (
|
|
11
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
|
|
12
|
+
<circle cx="12" cy="12" r="10" />
|
|
13
|
+
<polyline points="12 6 12 12 16 14" />
|
|
14
|
+
<circle cx="12" cy="12" r="1" fill="currentColor" fillOpacity="0.3" stroke="none" />
|
|
15
|
+
</svg>
|
|
16
|
+
),
|
|
17
|
+
DateTime: () => (
|
|
18
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5">
|
|
19
|
+
<rect x="2" y="3" width="14" height="14" rx="2" ry="2" />
|
|
20
|
+
<line x1="5" y1="2" x2="5" y2="5" />
|
|
21
|
+
<line x1="13" y1="2" x2="13" y2="5" />
|
|
22
|
+
<line x1="2" y1="7" x2="16" y2="7" />
|
|
23
|
+
|
|
24
|
+
<circle cx="19" cy="15" r="4" />
|
|
25
|
+
<polyline points="19 13 19 15 21 16" />
|
|
26
|
+
</svg>
|
|
27
|
+
),
|
|
28
|
+
FileUpload: () => (
|
|
29
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5">
|
|
30
|
+
<path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z" />
|
|
31
|
+
<polyline points="13 2 13 9 20 9" />
|
|
32
|
+
<path d="M12 12v6m0-6 2 2m-2-2-2 2" />
|
|
33
|
+
</svg>
|
|
34
|
+
),
|
|
35
|
+
CloudUpload: () => (
|
|
36
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5">
|
|
37
|
+
<path d="M12 16v-6m0 0-2 2m2-2 2 2" />
|
|
38
|
+
<path d="M16 16h3a4 4 0 0 0 0-8h-1.5A5.5 5.5 0 0 0 7 9a5 5 0 0 0-1 9.8" />
|
|
39
|
+
</svg>
|
|
40
|
+
),
|
|
41
|
+
TrashIcon: () => (
|
|
42
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5">
|
|
43
|
+
<path d="M3 6h18" />
|
|
44
|
+
<rect x="6" y="6" width="12" height="14" rx="1" ry="1" />
|
|
45
|
+
|
|
46
|
+
<path d="M9 3h6" />
|
|
47
|
+
<path d="M10 3v3M14 3v3" />
|
|
48
|
+
|
|
49
|
+
<line x1="10" y1="10" x2="10" y2="16" />
|
|
50
|
+
<line x1="14" y1="10" x2="14" y2="16" />
|
|
51
|
+
</svg>
|
|
52
|
+
),
|
|
53
|
+
SimpleTrashIcon: () => (
|
|
54
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5">
|
|
55
|
+
<path d="M3 6h18" />
|
|
56
|
+
<rect x="6" y="8" width="12" height="12" rx="1" ry="1" />
|
|
57
|
+
<path d="M9 4h6" />
|
|
58
|
+
</svg>
|
|
59
|
+
),
|
|
60
|
+
DeleteTrashIcon: () => (
|
|
61
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5">
|
|
62
|
+
<path d="M3 6h18" />
|
|
63
|
+
<rect x="6" y="6" width="12" height="14" rx="1" ry="1" />
|
|
64
|
+
<path d="M9 3h6" />
|
|
65
|
+
<path d="M10 3v3M14 3v3" />
|
|
66
|
+
<line x1="9" y1="10" x2="15" y2="16" />
|
|
67
|
+
<line x1="15" y1="10" x2="9" y2="16" />
|
|
68
|
+
</svg>
|
|
69
|
+
),
|
|
70
|
+
FileIcon: () => (
|
|
71
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5">
|
|
72
|
+
<path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z" />
|
|
73
|
+
<polyline points="13 2 13 9 20 9" />
|
|
74
|
+
</svg>
|
|
75
|
+
),
|
|
76
|
+
Word: () => (
|
|
77
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5">
|
|
78
|
+
<path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"/>
|
|
79
|
+
<polyline points="13 2 13 9 20 9"/>
|
|
80
|
+
<line x1="8" y1="13" x2="16" y2="13"/>
|
|
81
|
+
<line x1="8" y1="16" x2="16" y2="16"/>
|
|
82
|
+
<line x1="8" y1="19" x2="13" y2="19"/>
|
|
83
|
+
</svg>
|
|
84
|
+
),
|
|
85
|
+
Excel: () => (
|
|
86
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5">
|
|
87
|
+
<path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"/>
|
|
88
|
+
<polyline points="13 2 13 9 20 9"/>
|
|
89
|
+
<rect x="7" y="12" width="10" height="7" rx="1"/>
|
|
90
|
+
<line x1="7" y1="15.5" x2="17" y2="15.5"/>
|
|
91
|
+
<line x1="11.5" y1="12" x2="11.5" y2="19"/>
|
|
92
|
+
</svg>
|
|
93
|
+
),
|
|
94
|
+
PowerPoint: () => (
|
|
95
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5">
|
|
96
|
+
<path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"/>
|
|
97
|
+
<polyline points="13 2 13 9 20 9"/>
|
|
98
|
+
<rect x="7" y="12" width="10" height="7" rx="1"/>
|
|
99
|
+
<path d="M9 17l2-3 2 2 2-3"/>
|
|
100
|
+
</svg>
|
|
101
|
+
),
|
|
102
|
+
Pdf: () => (
|
|
103
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5">
|
|
104
|
+
<path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"/>
|
|
105
|
+
<polyline points="13 2 13 9 20 9"/>
|
|
106
|
+
<rect x="7" y="14" width="10" height="4" rx="1"/>
|
|
107
|
+
</svg>
|
|
108
|
+
),
|
|
109
|
+
Image: () => (
|
|
110
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5">
|
|
111
|
+
<path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"/>
|
|
112
|
+
<polyline points="13 2 13 9 20 9"/>
|
|
113
|
+
<circle cx="9" cy="13" r="1.5"/>
|
|
114
|
+
<path d="M7 18l3-3 2 2 3-3 2 4"/>
|
|
115
|
+
</svg>
|
|
116
|
+
),
|
|
117
|
+
Audio: () => (
|
|
118
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5">
|
|
119
|
+
<path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"/>
|
|
120
|
+
<polyline points="13 2 13 9 20 9"/>
|
|
121
|
+
<path d="M8 16v-2"/>
|
|
122
|
+
<path d="M10 17v-4"/>
|
|
123
|
+
<path d="M12 18v-6"/>
|
|
124
|
+
<path d="M14 17v-4"/>
|
|
125
|
+
<path d="M16 16v-2"/>
|
|
126
|
+
</svg>
|
|
127
|
+
),
|
|
128
|
+
Video: () => (
|
|
129
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5">
|
|
130
|
+
<path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"/>
|
|
131
|
+
<polyline points="13 2 13 9 20 9"/>
|
|
132
|
+
<rect x="7" y="12" width="8" height="6" rx="1"/>
|
|
133
|
+
<polygon points="11 14 14 15 11 16"/>
|
|
134
|
+
</svg>
|
|
135
|
+
),
|
|
136
|
+
Globe: () => (
|
|
137
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none"
|
|
138
|
+
stroke="currentColor" strokeWidth="1.5"
|
|
139
|
+
strokeLinecap="round" strokeLinejoin="round">
|
|
140
|
+
<circle cx="12" cy="12" r="10" />
|
|
141
|
+
<path d="M2 12h20" />
|
|
142
|
+
<path d="M12 2a15.3 15.3 0 0 1 0 20 15.3 15.3 0 0 1 0-20z" />
|
|
143
|
+
</svg>
|
|
144
|
+
),
|
|
145
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { CustomIcons } from "./custom-icons";
|
|
2
|
+
|
|
3
|
+
export const FileTypeIcon = (mime: string) => {
|
|
4
|
+
let icon;
|
|
5
|
+
|
|
6
|
+
switch (mime) {
|
|
7
|
+
case 'text/plain':
|
|
8
|
+
icon = CustomIcons.FileIcon();
|
|
9
|
+
break;
|
|
10
|
+
case 'text/uri-list':
|
|
11
|
+
return CustomIcons.Globe();
|
|
12
|
+
case 'application/xls':
|
|
13
|
+
case 'application/vnd.ms-excel':
|
|
14
|
+
case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet':
|
|
15
|
+
case 'application/vnd.ms-excel.sheet.macroEnabled.12':
|
|
16
|
+
case 'application/vnd.ms-excel.sheet.binary.macroEnabled.12':
|
|
17
|
+
icon = CustomIcons.Excel();
|
|
18
|
+
break;
|
|
19
|
+
case 'application/msword':
|
|
20
|
+
case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document':
|
|
21
|
+
case 'application/vnd.ms-word':
|
|
22
|
+
case 'application/vnd.ms-word.document.macroEnabled.12':
|
|
23
|
+
icon = CustomIcons.Word();
|
|
24
|
+
break;
|
|
25
|
+
case 'application/vnd.ms-powerpoint':
|
|
26
|
+
case 'application/vnd.openxmlformats-officedocument.presentationml.presentation':
|
|
27
|
+
case 'application/vnd.ms-powerpoint.presentation.macroEnabled.12':
|
|
28
|
+
case 'application/vnd.openxmlformats-officedocument.presentationml.slideshow':
|
|
29
|
+
icon = CustomIcons.PowerPoint();
|
|
30
|
+
break;
|
|
31
|
+
case 'application/pdf':
|
|
32
|
+
icon = CustomIcons.Pdf();
|
|
33
|
+
break;
|
|
34
|
+
case 'audio/mpeg':
|
|
35
|
+
case 'audio/wav':
|
|
36
|
+
case 'audio/x-wav':
|
|
37
|
+
case 'audio/ogg':
|
|
38
|
+
case 'audio/mp4':
|
|
39
|
+
icon = CustomIcons.Audio();
|
|
40
|
+
break;
|
|
41
|
+
case 'image/jpeg':
|
|
42
|
+
case 'image/png':
|
|
43
|
+
case 'image/bmp':
|
|
44
|
+
case 'image/gif':
|
|
45
|
+
case 'image/webp':
|
|
46
|
+
case 'image/svg+xml':
|
|
47
|
+
case 'image/heic':
|
|
48
|
+
case 'image/heif':
|
|
49
|
+
icon = CustomIcons.Image();
|
|
50
|
+
break;
|
|
51
|
+
case 'video/mp4':
|
|
52
|
+
case 'video/quicktime':
|
|
53
|
+
case 'video/webm':
|
|
54
|
+
case 'video/x-msvideo':
|
|
55
|
+
case 'video/x-matroska':
|
|
56
|
+
icon = CustomIcons.Video();
|
|
57
|
+
break;
|
|
58
|
+
default:
|
|
59
|
+
icon = CustomIcons.FileIcon();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return icon;
|
|
63
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { AcceptType } from "@sio-group/form-types";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Get the accept attribute for file inputs based on the provided accept-type.
|
|
5
|
+
* @param accept - Accept type which can be a string, an array of strings, or shorthand types like 'image', 'video', or 'audio'.
|
|
6
|
+
*/
|
|
7
|
+
export const getAccept = (accept?: AcceptType): string | undefined => {
|
|
8
|
+
if (Array.isArray(accept)) {
|
|
9
|
+
return accept
|
|
10
|
+
.map(item => {
|
|
11
|
+
if (item === 'image') return 'image/*';
|
|
12
|
+
if (item === 'video') return 'video/*';
|
|
13
|
+
if (item === 'audio') return 'audio/*';
|
|
14
|
+
return item;
|
|
15
|
+
})
|
|
16
|
+
.join(', ');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (accept === 'image') return 'image/*';
|
|
20
|
+
if (accept === 'video') return 'video/*';
|
|
21
|
+
if (accept === 'audio') return 'audio/*';
|
|
22
|
+
|
|
23
|
+
return accept;
|
|
24
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { LayoutType } from "@sio-group/form-types";
|
|
2
|
+
|
|
3
|
+
export const getColumnClasses = (layout?: LayoutType, className?: string): string => {
|
|
4
|
+
if (!layout) return 'sio-col-xs-12';
|
|
5
|
+
|
|
6
|
+
const classes: string[] = [];
|
|
7
|
+
|
|
8
|
+
if (className) classes.push(className);
|
|
9
|
+
|
|
10
|
+
if (layout.sm) classes.push(`sio-col-sm-${layout.sm}`);
|
|
11
|
+
if (layout.md) classes.push(`sio-col-md-${layout.md}`);
|
|
12
|
+
if (layout.lg) classes.push(`sio-col-lg-${layout.lg}`);
|
|
13
|
+
|
|
14
|
+
if (layout.order) {
|
|
15
|
+
if (layout.order.sm) classes.push(`sio-order-sm-${layout.order.sm}`);
|
|
16
|
+
if (layout.order.md) classes.push(`sio-order-md-${layout.order.md}`);
|
|
17
|
+
if (layout.order.lg) classes.push(`sio-order-lg-${layout.order.lg}`);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return classes.join(' ');
|
|
21
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const getFileSize = (size: number) => {
|
|
2
|
+
const sizes: string[] = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
|
|
3
|
+
|
|
4
|
+
if (size === 0) return '0 Bytes';
|
|
5
|
+
|
|
6
|
+
const i: number = Math.floor(Math.log(size) / Math.log(1024));
|
|
7
|
+
|
|
8
|
+
return `${Math.round(size / Math.pow(1024, i))} ${sizes[i]}`;
|
|
9
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export const parseDateValue = (val: unknown): Date | null => {
|
|
2
|
+
if (val instanceof Date) {
|
|
3
|
+
return isNaN(val.getTime()) ? null : val;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
if (typeof val !== 'string') {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
if (val.trim() === '') {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const timeRegex = /^([0-1]?[0-9]|2[0-3]):[0-5][0-9](:[0-5][0-9])?$/;
|
|
15
|
+
if (timeRegex.test(val)) {
|
|
16
|
+
const [hours, minutes, seconds = 0] = val.split(':').map(Number);
|
|
17
|
+
const date = new Date();
|
|
18
|
+
date.setHours(hours, minutes, seconds, 0);
|
|
19
|
+
return date;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const dateRegex = /^\d{4}-\d{2}-\d{2}$/;
|
|
23
|
+
if (dateRegex.test(val)) {
|
|
24
|
+
const date = new Date(val + 'T00:00:00');
|
|
25
|
+
return isNaN(date.getTime()) ? null : date;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const dateTimeRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/;
|
|
29
|
+
if (dateTimeRegex.test(val)) {
|
|
30
|
+
const date = new Date(val);
|
|
31
|
+
return isNaN(date.getTime()) ? null : date;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const date = new Date(val);
|
|
35
|
+
return isNaN(date.getTime()) ? null : date;
|
|
36
|
+
};
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tsconfig.base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"composite": false,
|
|
5
|
+
"outDir": "dist",
|
|
6
|
+
"rootDir": "src",
|
|
7
|
+
"jsx": "react-jsx",
|
|
8
|
+
"jsxImportSource": "react"
|
|
9
|
+
},
|
|
10
|
+
"include": ["src/**/*.ts", "src/**/*.tsx"],
|
|
11
|
+
"exclude": ["dist", "node_modules"],
|
|
12
|
+
"references": [
|
|
13
|
+
{ "path": "../form-types" }
|
|
14
|
+
]
|
|
15
|
+
}
|