@steveesamson/microform 0.0.10 → 1.0.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.
@@ -1,5 +1,5 @@
1
1
  import { get } from "svelte/store";
2
- import { makeName } from "./utils.js";
2
+ import { makeName, isValidFileSize } from "./utils.js";
3
3
  const regexes = {
4
4
  number: /^[-+]?[0-9]+(\.[0-9]+)?$/g,
5
5
  alpha: /^[A-Z\s]+$/gi,
@@ -9,175 +9,148 @@ const regexes = {
9
9
  url: /^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,}))\.?)(?::\d{2,5})?(?:[/?#]\S*)?$/i,
10
10
  ip: /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/g,
11
11
  };
12
- const getErrorText = (inputName, errorType, extra = '') => {
13
- inputName = makeName(inputName);
14
- switch (errorType.toLowerCase()) {
15
- case 'required':
16
- return inputName + ' is mandatory.';
17
- case 'match':
18
- return inputName + ' does not match ' + makeName(extra);
19
- case 'func':
20
- return inputName + extra;
21
- case 'captcha':
22
- return inputName + ' does not match the image.';
23
- case 'email':
24
- return inputName + ' should be a valid email.';
25
- case 'url':
26
- return inputName + ' should be a valid URL.';
27
- case 'cron':
28
- return inputName + ' should be a valid cron expression.';
29
- case 'ip':
30
- return inputName + ' should be a valid IP.';
31
- case 'integer':
32
- return inputName + ' must be an integer.';
33
- case 'number':
34
- return inputName + ' should be a number.';
35
- case 'alpha':
36
- return inputName + ' should be a string of alphabets.';
37
- case 'alphanum':
38
- return inputName + ' should be a string of alphanumerics starting with alphabets.';
39
- case 'min-length':
40
- return inputName + ' must be at least ' + extra + ' characters long.';
41
- case 'max-length':
42
- return inputName + ' must not be more than ' + extra + ' characters long.';
43
- case 'length':
44
- return inputName + ' must be exactly ' + extra + ' characters long.';
45
- // case 'length':
46
- // return inputName + ' must not be greater than ' + extra + '.';
47
- default:
48
- return errorType;
49
- }
50
- };
51
- const checkFileSize = (node, maxFileSizeInMB) => {
52
- if (!node)
53
- return "";
54
- const { files } = node;
55
- if (!files)
56
- return `${node.name} is required`;
57
- const max = maxFileSizeInMB * 1024 * 1024;
58
- for (const file of files) {
59
- if (file.size > max) {
60
- return `File '${file.name}' is larger the ${maxFileSizeInMB}MB.`;
12
+ export const IS_REQUIRED = "required";
13
+ export const IS_EMAIL = "email";
14
+ export const IS_URL = "url";
15
+ export const IS_IP = "ip";
16
+ export const IS_INTEGER = "integer";
17
+ export const IS_NUMBER = "number";
18
+ export const IS_ALPHA = "alpha";
19
+ export const IS_ALPHANUM = "alphanum";
20
+ export const IS_MIN_LEN = "minlen";
21
+ export const IS_MAX_LEN = "maxlen";
22
+ export const IS_LEN = "len";
23
+ export const IS_MIN = "min";
24
+ export const IS_MAX = "max";
25
+ export const IT_MATCHES = "match";
26
+ export const IS_FILE_SIZE_MB = 'file-size-mb';
27
+ const getDefaultValidators = () => {
28
+ const validators = {
29
+ [IS_REQUIRED]: ({ label, value }) => {
30
+ if (!value || (Array.isArray(value) && !value.length)) {
31
+ return `${label} is mandatory.`;
32
+ }
33
+ return "";
34
+ },
35
+ [IS_EMAIL]: ({ value, label }) => {
36
+ return (!!value && !value.match(regexes['email'])) ? `${label} should be a valid email.` : '';
37
+ },
38
+ [IS_URL]: ({ value, label }) => {
39
+ return !!value && !value.match(regexes['url']) ? `${label} should be a valid URL.` : "";
40
+ },
41
+ [IS_IP]: ({ value, label }) => {
42
+ return !!value && !value.match(regexes['ip']) ? `${label} should be a valid IP.` : "";
43
+ },
44
+ [IS_INTEGER]: ({ value, label }) => {
45
+ return !!value && !value.match(regexes['integer']) ? `${label} must be an integer number.` : "";
46
+ },
47
+ [IS_NUMBER]: ({ value, label }) => {
48
+ return !!value && !value.match(regexes['number']) ? `${label} must be a number.` : "";
49
+ },
50
+ [IS_ALPHA]: ({ value, label }) => {
51
+ return !!value && !value.match(regexes['alpha']) ? `${label} should be a string of alphabets.` : "";
52
+ },
53
+ [IS_ALPHANUM]: ({ value, label }) => {
54
+ return !!value && !value.match(regexes['alphanum']) ? `${label} should be a string of alphanumerics starting with alphabets.` : "";
55
+ },
56
+ [IS_MIN_LEN]: ({ value, label, parts }) => {
57
+ if (!!value) {
58
+ if (!parts || parts.length < 2) {
59
+ return `${label}: min-length validation requires minimum length.`;
60
+ }
61
+ const extra = parts[1].trim();
62
+ return value.length >= parseInt(parts[1], 10) ? "" : `${label} must be at least ${extra} characters long.`;
63
+ }
64
+ return "";
65
+ },
66
+ [IS_MAX_LEN]: ({ value, label, parts }) => {
67
+ if (!!value) {
68
+ if (!parts || parts.length < 2) {
69
+ return `${label}: max-length validation requires maximum length.`;
70
+ }
71
+ const extra = parts[1].trim();
72
+ return value.length <= parseInt(parts[1], 10) ? "" : `${label} must be at most ${extra} characters long.`;
73
+ }
74
+ return "";
75
+ },
76
+ [IS_LEN]: ({ value, label, parts }) => {
77
+ if (!!value) {
78
+ if (!parts || parts.length < 2) {
79
+ return `${label}: length validation requires length.`;
80
+ }
81
+ const extra = parts[1].trim();
82
+ return value.length === parseInt(parts[1], 10) ? "" : `${label} must exactly be ${extra} characters long.`;
83
+ }
84
+ return "";
85
+ },
86
+ [IS_MAX]: ({ value, label, parts }) => {
87
+ if (!!value) {
88
+ if (!parts || parts.length < 2) {
89
+ return `${label}: max validation requires the maximum value.`;
90
+ }
91
+ const extra = parts[1].trim();
92
+ return parseInt(value, 10) <= parseInt(parts[1], 10) ? "" : `${label} must not be greater than ${extra}.`;
93
+ }
94
+ return "";
95
+ },
96
+ [IS_MIN]: ({ value, label, parts }) => {
97
+ if (!!value) {
98
+ if (!parts || parts.length < 2) {
99
+ return `${label}: min validation requires the minimum value.`;
100
+ }
101
+ const extra = parts[1].trim();
102
+ return parseInt(value, 10) >= parseInt(parts[1], 10) ? "" : `${label} must not be less than ${extra}.`;
103
+ }
104
+ return "";
105
+ },
106
+ [IT_MATCHES]: ({ values, value, label, parts }) => {
107
+ if (value) {
108
+ if (!parts || parts.length < 2) {
109
+ return `${label}: match validation requires id of field to match`;
110
+ }
111
+ const partyName = parts[1].trim();
112
+ const partyValue = values[partyName];
113
+ return value === partyValue ? "" : `${label} does not match ${makeName(partyName)}.`;
114
+ }
115
+ return "";
116
+ },
117
+ [IS_FILE_SIZE_MB]: ({ value, node, label, parts }) => {
118
+ if (!!value) {
119
+ if (!parts || parts.length < 2) {
120
+ return `${label}: max file size in MB validation requires maximum file size of mb value.`;
121
+ ;
122
+ }
123
+ const extra = parts[1].trim();
124
+ return isValidFileSize(node, parseInt(extra, 10));
125
+ }
126
+ return "";
61
127
  }
62
- }
63
- return "";
128
+ };
129
+ return validators;
64
130
  };
65
- export const useValidator = (errors, values) => {
131
+ export const useValidator = (errors, values, validators = getDefaultValidators()) => {
66
132
  const setError = (name, error) => {
67
133
  errors.update((prev) => {
68
134
  return { ...prev, [name]: error };
69
135
  });
70
136
  };
71
- return async ({ name, value, validations = '', node = undefined }) => {
72
- let error = '';
73
- if (validations) {
74
- const inputName = name, _validations = validations.split('|');
75
- for (let i = 0; i < _validations.length; ++i) {
76
- const validation = _validations[i], typeDetails = validation.split(':'), type = typeDetails[0].trim();
77
- let partyName, partyValue;
78
- switch (type.toLowerCase()) {
79
- case 'required':
80
- error = !value || !value.length ? getErrorText(inputName, 'required') : '';
81
- setError(name, error);
82
- break;
83
- case 'match':
84
- error = typeDetails.length < 2 ? inputName + ': match validation requires party target' : '';
85
- setError(name, error);
86
- if (error)
87
- break;
88
- partyName = typeDetails[1].trim();
89
- partyValue = get(values)[partyName] || '';
90
- error = !value || value !== partyValue ? getErrorText(inputName, 'match', typeDetails[1]) : '';
91
- setError(name, error);
92
- break;
93
- case 'email':
94
- error = !value || !value.match(regexes['email']) ? getErrorText(inputName, 'email') : '';
95
- setError(name, error);
96
- break;
97
- case 'url':
98
- error = !value || !value.match(regexes['url']) ? getErrorText(inputName, 'url') : '';
99
- setError(name, error);
137
+ return {
138
+ validate: async ({ name, value, validations = [], node = undefined }) => {
139
+ if (validations.length) {
140
+ const _validations = validations.includes('required') ? ['required', ...validations.filter((val) => val !== 'required')] : [...validations];
141
+ for (let i = 0; i < _validations.length; ++i) {
142
+ const validation = _validations[i], parts = validation.split(':'), type = parts[0].trim();
143
+ const validator = validators[type];
144
+ if (!validator)
145
+ return;
146
+ const error = validator({ name, label: makeName(name), value, values: get(values), node, parts });
147
+ setError(name, error ? error : '');
148
+ if (error) {
100
149
  break;
101
- case 'ip':
102
- error = !value || !value.match(regexes['ip']) ? getErrorText(inputName, 'ip') : '';
103
- setError(name, error);
104
- break;
105
- case 'integer':
106
- error = !value || !value.match(regexes['integer']) ? getErrorText(inputName, 'integer') : '';
107
- setError(name, error);
108
- break;
109
- case 'number':
110
- error = !value || !value.match(regexes['number']) ? getErrorText(inputName, 'number') : '';
111
- setError(name, error);
112
- break;
113
- case 'alpha':
114
- error = !value || !value.match(regexes['alpha']) ? getErrorText(inputName, 'alpha') : '';
115
- setError(name, error);
116
- break;
117
- case 'alphanum':
118
- error =
119
- !value || !value.match(regexes['alphanum']) ? getErrorText(inputName, 'alphanum') : '';
120
- setError(name, error);
121
- break;
122
- case 'min-length':
123
- error = typeDetails.length < 2 ? inputName + ': min-length validation requires width' : '';
124
- setError(name, error);
125
- if (error)
126
- break;
127
- error =
128
- !value || value.length < parseInt(typeDetails[1], 10)
129
- ? getErrorText(inputName, 'min-length', typeDetails[1])
130
- : '';
131
- setError(name, error);
132
- break;
133
- case 'max-length':
134
- error = typeDetails.length < 2 ? inputName + ': max-length validation requires width' : '';
135
- setError(name, error);
136
- if (error)
137
- break;
138
- error =
139
- !value || value.length > parseInt(typeDetails[1], 10)
140
- ? getErrorText(inputName, 'max-length', typeDetails[1])
141
- : '';
142
- setError(name, error);
143
- break;
144
- case 'length':
145
- error = typeDetails.length < 2 ? inputName + ': length validation requires width' : '';
146
- setError(name, error);
147
- if (error)
148
- break;
149
- error =
150
- !value || value.length !== parseInt(typeDetails[1], 10)
151
- ? getErrorText(inputName, 'length', typeDetails[1])
152
- : '';
153
- setError(name, error);
154
- break;
155
- case 'max':
156
- error = typeDetails.length < 2 ? inputName + ': max validation requires max value' : '';
157
- setError(name, error);
158
- if (error)
159
- break;
160
- error =
161
- !value || parseInt(value, 10) !== parseInt(typeDetails[1], 10)
162
- ? getErrorText(inputName, 'max', typeDetails[1])
163
- : '';
164
- setError(name, error);
165
- break;
166
- case 'max-file-size-mb':
167
- error = typeDetails.length < 2 ? inputName + ': max file size in MB validation requires max-file-size-mb value' : '';
168
- setError(name, error);
169
- if (error)
170
- break;
171
- error = checkFileSize(node, parseInt(typeDetails[1], 10));
172
- setError(name, error);
173
- break;
174
- default:
175
- }
176
- if (error) {
177
- setError(name, error);
178
- break;
150
+ }
179
151
  }
180
- } //end
181
- }
152
+ }
153
+ },
154
+ validators
182
155
  };
183
156
  };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- export * from "./types.js";
2
- import type { MicroFormProps, MicroFormReturn } from './types.js';
3
- declare const microForm: (props?: MicroFormProps) => MicroFormReturn;
1
+ import { microForm } from "./index.svelte.js";
2
+ export { IS_EMAIL, IS_ALPHA, IS_ALPHANUM, IS_INTEGER, IS_IP, IS_LEN, IT_MATCHES as IS_MATCH_FOR, IS_MAX, IS_FILE_SIZE_MB as IS_MAX_FILE_SIZE, IS_MAX_LEN, IS_MIN, IS_MIN_LEN, IS_NUMBER, IS_REQUIRED, IS_URL } from "./form-validators.js";
4
3
  export default microForm;
package/dist/index.js CHANGED
@@ -1,65 +1,3 @@
1
- export * from "./types.js";
2
- import { writable, derived, get } from 'svelte/store';
3
- import { formAction } from './form-action.js';
4
- const microForm = (props) => {
5
- // form default values
6
- const data = props?.data || {};
7
- // form values
8
- const values = writable(data);
9
- // internal checks
10
- const unfits = writable({});
11
- // external form errors
12
- const errors = writable({});
13
- const isdirty = writable(false);
14
- const isclean = derived(([errors, unfits]), ([$errors, $unfits]) => {
15
- const errVals = Object.values($errors);
16
- const unfitVals = Object.values($unfits);
17
- return (errVals.length === 0 || errVals.reduce((comm, next) => comm && !next, true))
18
- && (unfitVals.length === 0 || unfitVals.reduce((comm, next) => comm && !next, true));
19
- });
20
- const valid = derived(([isclean, isdirty]), ([$isclean, $isdirty]) => {
21
- return $isclean && $isdirty;
22
- });
23
- const validationMap = {};
24
- const { options = {
25
- validateEvent: 'blur'
26
- } } = props || {};
27
- const form = formAction(values, errors, unfits, isdirty, options, validationMap);
28
- const handleSubmit = (e, handler) => {
29
- e.preventDefault();
30
- if (!get(valid))
31
- return;
32
- handler({ ...get(values) });
33
- };
34
- const onsubmit = (handler) => {
35
- const onSubmit = async (e) => {
36
- handleSubmit(e, handler);
37
- };
38
- return onSubmit;
39
- };
40
- const submit = (formNode, handler) => {
41
- formNode.addEventListener('submit', (e) => {
42
- handleSubmit(e, handler);
43
- });
44
- };
45
- const reset = () => {
46
- errors.set({});
47
- unfits.set({});
48
- values.set({ ...data });
49
- for (const [name, { nodeRef, html }] of Object.entries(validationMap).filter(([, { nodeRef }]) => !!nodeRef)) {
50
- if (nodeRef) {
51
- nodeRef[html ? "innerHTML" : 'textContent'] = data[name] || '';
52
- }
53
- }
54
- };
55
- return {
56
- values,
57
- errors,
58
- valid,
59
- form,
60
- submit,
61
- onsubmit,
62
- reset,
63
- };
64
- };
1
+ import { microForm } from "./index.svelte.js";
2
+ export { IS_EMAIL, IS_ALPHA, IS_ALPHANUM, IS_INTEGER, IS_IP, IS_LEN, IT_MATCHES as IS_MATCH_FOR, IS_MAX, IS_FILE_SIZE_MB as IS_MAX_FILE_SIZE, IS_MAX_LEN, IS_MIN, IS_MIN_LEN, IS_NUMBER, IS_REQUIRED, IS_URL } from "./form-validators.js";
65
3
  export default microForm;
@@ -0,0 +1,79 @@
1
+ import { writable, derived, get } from 'svelte/store';
2
+ import { formAction } from './form-action.js';
3
+ import { bindStateToStore } from "./utils.js";
4
+ export const microForm = (props) => {
5
+ // form default values
6
+ const data = props?.data || {};
7
+ // form values
8
+ const _values = writable({ ...data });
9
+ // internal checks
10
+ const unfits = writable({});
11
+ // external form errors
12
+ const _errors = writable({});
13
+ const isdirty = writable(false);
14
+ const isclean = derived(([_errors, unfits]), ([$errors, $unfits]) => {
15
+ const errVals = Object.values($errors);
16
+ const unfitVals = Object.values($unfits);
17
+ return (errVals.length === 0 || errVals.reduce((comm, next) => comm && !next, true))
18
+ && (unfitVals.length === 0 || unfitVals.reduce((comm, next) => comm && !next, true));
19
+ });
20
+ const _valid = derived(([isclean, isdirty]), ([$isclean, $isdirty]) => {
21
+ return $isclean && $isdirty;
22
+ });
23
+ const validationMap = {};
24
+ const { options = {
25
+ validateEvent: 'blur',
26
+ validators: {}
27
+ } } = props || {};
28
+ const form = formAction(_values, _errors, unfits, isdirty, options, validationMap);
29
+ const handleSubmit = (e, handler) => {
30
+ e.preventDefault();
31
+ if (!get(_valid))
32
+ return;
33
+ handler({ ...get(_values) });
34
+ };
35
+ const onsubmit = (handler) => {
36
+ const onSubmit = async (e) => {
37
+ handleSubmit(e, handler);
38
+ };
39
+ return onSubmit;
40
+ };
41
+ const submit = (formNode, handler) => {
42
+ formNode.addEventListener('submit', (e) => {
43
+ handleSubmit(e, handler);
44
+ });
45
+ };
46
+ const reset = () => {
47
+ _errors.set({});
48
+ unfits.set({});
49
+ _values.set({ ...data });
50
+ isdirty.set(false);
51
+ for (const [name, { nodeRef, html }] of Object.entries(validationMap).filter(([, { nodeRef }]) => !!nodeRef)) {
52
+ if (nodeRef) {
53
+ if (nodeRef.isContentEditable) {
54
+ nodeRef[html ? "innerHTML" : 'textContent'] = data[name] || '';
55
+ }
56
+ else {
57
+ nodeRef["value"] = data[name] || '';
58
+ }
59
+ }
60
+ }
61
+ };
62
+ const values = $state({ ...data });
63
+ const errors = $state({});
64
+ const sanity = $state({ ok: get(_valid) });
65
+ bindStateToStore(values, _values);
66
+ bindStateToStore(errors, _errors);
67
+ _valid.subscribe((changes) => {
68
+ sanity.ok = changes;
69
+ });
70
+ return {
71
+ values,
72
+ errors,
73
+ sanity,
74
+ form,
75
+ submit,
76
+ onsubmit,
77
+ reset,
78
+ };
79
+ };
@@ -1,3 +1,4 @@
1
- export type Params = {
2
- [key: string]: string | number | Array<any> | any;
1
+ export type Params<T = any> = {
2
+ [key: string | number | symbol]: T;
3
3
  };
4
+ export type Primitive = string | number | boolean | string[] | number[] | boolean[];
package/dist/types.d.ts CHANGED
@@ -1,28 +1,40 @@
1
1
  /// <reference types="svelte" />
2
- import { type Writable, type Readable } from "svelte/store";
2
+ import { type Writable } from "svelte/store";
3
3
  import type { Params } from "./internal.js";
4
- export type { Params };
5
- export type FieldTypes = "Standard" | "Popover" | "Checkable";
4
+ export type Validator = `max:${number}` | `min:${number}` | `len:${number}` | `minlen:${number}` | `maxlen:${number}` | `file-size-mb:${number}` | `match:${string}` | 'required' | 'email' | 'integer' | 'number' | 'alpha' | 'alphanum' | 'url' | 'ip';
5
+ export type ValidatorKey = 'required' | 'email' | 'integer' | 'number' | 'alpha' | 'alphanum' | 'url' | 'ip' | `max` | `min` | `len` | `minlen` | `maxlen` | `file-size-mb` | `match`;
6
+ export type FieldProps = {
7
+ name: string;
8
+ value: string;
9
+ label: string;
10
+ node?: HTMLElement;
11
+ values: Params;
12
+ parts?: string[];
13
+ };
14
+ export type ValidatorType = (props: FieldProps) => string;
15
+ export type ValidatorMap<T> = {
16
+ [VAL in ValidatorKey]: T;
17
+ };
6
18
  export type InputTypes = 'text' | 'number' | 'color' | 'time' | 'date' | 'range' | 'email' | 'hidden' | 'password' | 'tel' | 'url';
7
19
  export type FieldType = HTMLSelectElement | HTMLInputElement | HTMLTextAreaElement;
8
20
  export type InputType = HTMLSelectElement | HTMLInputElement | HTMLTextAreaElement;
9
21
  export interface ValidateArgs {
10
22
  name: string;
11
23
  value: string;
12
- validations: string;
24
+ validations?: Validator[];
13
25
  node?: HTMLElement;
14
26
  }
15
27
  export type FormReturn = {
16
28
  destroy: () => void;
17
29
  };
18
30
  export type ValidateEvent = 'input' | 'change' | 'keyup' | 'blur';
19
- export type FormValues = Writable<Params>;
20
- export type FormErrors = Writable<Params>;
31
+ export type FormValues = Params;
32
+ export type FormErrors = Params;
21
33
  export type Dirty = Writable<boolean>;
22
34
  export type ActionOptions = {
23
35
  validateEvent?: ValidateEvent;
24
36
  name?: string;
25
- validations?: string;
37
+ validations?: Validator[];
26
38
  node?: HTMLElement;
27
39
  html?: boolean;
28
40
  };
@@ -32,18 +44,21 @@ export type FormSubmitEvent = SubmitEvent & {
32
44
  };
33
45
  export type FormSubmit = (_data: Params) => void;
34
46
  export type FormOptions = {
35
- validateEvent: ValidateEvent;
47
+ validateEvent?: ValidateEvent;
48
+ validators?: Partial<ValidatorMap<ValidatorType>>;
36
49
  };
37
50
  export type MicroFormProps = {
38
51
  data?: Params;
39
52
  options?: FormOptions;
40
53
  };
41
- export type FormSanity = Readable<boolean>;
54
+ export type FormSanity = {
55
+ ok: boolean;
56
+ };
42
57
  export type MicroFormReturn = {
43
58
  values: FormValues;
44
59
  errors: FormErrors;
60
+ sanity: FormSanity;
45
61
  form: (node: HTMLElement, eventProps?: ActionOptions) => FormReturn;
46
- valid: FormSanity;
47
62
  submit: (formNode: HTMLFormElement, handler: FormSubmit) => void;
48
63
  onsubmit: (handler: FormSubmit) => (e: Event) => Promise<void>;
49
64
  reset: () => void;
package/dist/utils.d.ts CHANGED
@@ -1,3 +1,6 @@
1
+ /// <reference types="svelte" />
2
+ import type { Writable } from "svelte/store";
3
+ import type { Params } from "./internal.js";
1
4
  type TEvent = {
2
5
  target: HTMLElement;
3
6
  };
@@ -6,4 +9,6 @@ export declare const getEditableContent: (e: TEvent, isHtml: boolean) => {
6
9
  value: string;
7
10
  };
8
11
  export declare const makeName: (str: string) => string;
12
+ export declare const isValidFileSize: (node: HTMLInputElement | undefined, maxFileSizeInMB: number) => string;
13
+ export declare const bindStateToStore: (state: Params, store: Writable<Params>) => void;
9
14
  export {};
package/dist/utils.js CHANGED
@@ -30,3 +30,24 @@ export const makeName = function (str) {
30
30
  });
31
31
  return new_name;
32
32
  };
33
+ export const isValidFileSize = (node, maxFileSizeInMB) => {
34
+ if (!node)
35
+ return '';
36
+ const { files } = node;
37
+ if (!files)
38
+ return `${node.name} is required`;
39
+ const max = maxFileSizeInMB * 1024 * 1024;
40
+ for (const file of files) {
41
+ if (file.size > max) {
42
+ return `File '${file.name}' is larger the ${maxFileSizeInMB}MB.`;
43
+ }
44
+ }
45
+ return '';
46
+ };
47
+ export const bindStateToStore = (state, store) => {
48
+ store.subscribe((changes) => {
49
+ for (const [k, v] of Object.entries(changes)) {
50
+ state[k] = v;
51
+ }
52
+ });
53
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@steveesamson/microform",
3
- "version": "0.0.10",
3
+ "version": "1.0.0",
4
4
  "scripts": {
5
5
  "dev": "vite dev",
6
6
  "postbuild": "touch ./docs/.nojekyll",
@@ -20,9 +20,8 @@
20
20
  },
21
21
  "exports": {
22
22
  ".": {
23
- "types": "./dist/index.d.ts",
24
- "svelte": "./dist/index.js",
25
- "default": "./dist/index.js"
23
+ "types": "./dist/types.d.ts",
24
+ "svelte": "./dist/index.js"
26
25
  }
27
26
  },
28
27
  "author": "Steve S. Samson <stevee.samson@gmail.com> (http://github.com/steveesamson)",
@@ -33,7 +32,7 @@
33
32
  "!dist/**/*.spec.*"
34
33
  ],
35
34
  "peerDependencies": {
36
- "svelte": "^4.0.0"
35
+ "svelte": "^5.0.0-next.135"
37
36
  },
38
37
  "devDependencies": {
39
38
  "@sveltejs/adapter-auto": "^3.0.0",
@@ -52,14 +51,14 @@
52
51
  "prettier-plugin-svelte": "^3.1.2",
53
52
  "publint": "^0.1.9",
54
53
  "shiki": "^0.14.7",
55
- "svelte": "^4.2.7",
54
+ "svelte": "^5.0.0-next.135",
56
55
  "svelte-check": "^3.6.0",
57
56
  "tslib": "^2.4.1",
58
57
  "typescript": "^5.0.0",
59
58
  "vite": "^5.0.3"
60
59
  },
61
60
  "default": "./dist/index.js",
62
- "types": "./dist/index.d.ts",
61
+ "types": "./dist/types.d.ts",
63
62
  "type": "module",
64
63
  "keywords": [
65
64
  "microform",