@steveesamson/microform 1.0.10 → 1.0.12
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/README.md +5 -0
- package/dist/form-action.svelte.d.ts +1 -1
- package/dist/form-action.svelte.js +24 -12
- package/dist/index.svelte.js +25 -44
- package/dist/internal.svelte.d.ts +5 -1
- package/dist/internal.svelte.js +40 -12
- package/dist/types.d.ts +4 -2
- package/dist/utils.d.ts +4 -0
- package/dist/utils.js +26 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -41,6 +41,11 @@ const { form, values, errors, submit, sanity } = uform({
|
|
|
41
41
|
validateEvent:'blur',
|
|
42
42
|
// Configure validators here
|
|
43
43
|
validators:{}
|
|
44
|
+
// Configurable wait time in millis for form field
|
|
45
|
+
// to initialize; default is 200 millis - needed for more involving fields.
|
|
46
|
+
fieldWaitTimeInMilliSecond: 200
|
|
47
|
+
// Default false, set to true to know if changes are happening.
|
|
48
|
+
debug: false
|
|
44
49
|
}
|
|
45
50
|
});
|
|
46
51
|
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { FormOptions, FormAction, FormValues, FormErrors } from './types.js';
|
|
2
2
|
import type { Params } from './internal.svelte.js';
|
|
3
|
-
export declare const formAction: (values: FormValues, errors: FormErrors, unfits: FormErrors,
|
|
3
|
+
export declare const formAction: (values: FormValues, errors: FormErrors, unfits: FormErrors, onSanity: (sanity: boolean) => void, options: FormOptions, validationMap: Params) => FormAction;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useValidator } from './form-validators.js';
|
|
2
|
-
import { getEditableContent } from './utils.js';
|
|
2
|
+
import { debounce, getEditableContent } from './utils.js';
|
|
3
3
|
const isField = (node) => {
|
|
4
4
|
return (node instanceof HTMLSelectElement ||
|
|
5
5
|
node instanceof HTMLInputElement ||
|
|
@@ -19,7 +19,7 @@ const checkFormFitness = (values, validationMap, validate) => {
|
|
|
19
19
|
validate({ name, value: values[name], validations });
|
|
20
20
|
}
|
|
21
21
|
};
|
|
22
|
-
export const formAction = (values, errors, unfits,
|
|
22
|
+
export const formAction = (values, errors, unfits, onSanity, options, validationMap) => {
|
|
23
23
|
const { validators: customValidators } = options;
|
|
24
24
|
const { validate, validators } = useValidator(errors, values);
|
|
25
25
|
// override
|
|
@@ -29,7 +29,29 @@ export const formAction = (values, errors, unfits, reportDirty, options, validat
|
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
const hasError = (next) => !!next;
|
|
32
|
+
let canWatch = false; // $state(false);
|
|
33
|
+
const evaluateSanity = () => {
|
|
34
|
+
const { validate: validateUnfit } = useValidator(unfits, values, validators);
|
|
35
|
+
checkFormFitness(values, validationMap, validateUnfit);
|
|
36
|
+
const withErrors = Object.values(errors).some(hasError);
|
|
37
|
+
const withUnfits = Object.values(unfits).some(hasError);
|
|
38
|
+
onSanity(!withErrors && !withUnfits && canWatch);
|
|
39
|
+
};
|
|
40
|
+
$effect(() => {
|
|
41
|
+
if (options.debug) {
|
|
42
|
+
console.log('values changed...');
|
|
43
|
+
}
|
|
44
|
+
Object.values(values);
|
|
45
|
+
evaluateSanity();
|
|
46
|
+
});
|
|
47
|
+
const start = debounce(() => {
|
|
48
|
+
canWatch = true;
|
|
49
|
+
if (options.debug) {
|
|
50
|
+
console.log('microform initialized...');
|
|
51
|
+
}
|
|
52
|
+
}, options.fieldWaitTimeInMilliSecond);
|
|
32
53
|
return (node, eventProps) => {
|
|
54
|
+
start();
|
|
33
55
|
const nodeName = isField(node) ? node.name : '';
|
|
34
56
|
const { name: dsname = nodeName } = node.dataset || {};
|
|
35
57
|
const { name = dsname, validations = [], validateEvent = (options.validateEvent = 'blur'), html = false } = eventProps || {};
|
|
@@ -45,11 +67,7 @@ export const formAction = (values, errors, unfits, reportDirty, options, validat
|
|
|
45
67
|
node.innerHTML = defValue;
|
|
46
68
|
}
|
|
47
69
|
values[name] = defValue;
|
|
48
|
-
let eventBound = $state(false);
|
|
49
70
|
const updateNode = (e) => {
|
|
50
|
-
if (!eventBound) {
|
|
51
|
-
eventBound = true;
|
|
52
|
-
}
|
|
53
71
|
if (isField(node) && !isExcluded(node)) {
|
|
54
72
|
const value = e.target.value || '';
|
|
55
73
|
values[name] = value;
|
|
@@ -75,13 +93,7 @@ export const formAction = (values, errors, unfits, reportDirty, options, validat
|
|
|
75
93
|
const { value: fvalue } = node;
|
|
76
94
|
values[name] = fvalue;
|
|
77
95
|
}
|
|
78
|
-
const { validate: validateUnfit } = useValidator(unfits, values, validators);
|
|
79
|
-
checkFormFitness(values, validationMap, validateUnfit);
|
|
80
96
|
validate({ name, value: values[name], validations, node });
|
|
81
|
-
const withErrors = Object.values(errors).some(hasError);
|
|
82
|
-
const withUnfits = Object.values(unfits).some(hasError);
|
|
83
|
-
const clean = !withErrors && !withUnfits;
|
|
84
|
-
reportDirty(clean);
|
|
85
97
|
};
|
|
86
98
|
$effect(() => {
|
|
87
99
|
node.addEventListener(validateEvent, updateNode);
|
package/dist/index.svelte.js
CHANGED
|
@@ -1,64 +1,45 @@
|
|
|
1
1
|
import { formAction } from './form-action.svelte.js';
|
|
2
|
-
import {
|
|
2
|
+
import { formStore } from './internal.svelte.js';
|
|
3
3
|
const microform = (props) => {
|
|
4
4
|
// form default values
|
|
5
|
-
const data = props?.data || {};
|
|
6
|
-
|
|
7
|
-
const state = formState(data);
|
|
8
|
-
const validationMap = {};
|
|
9
|
-
const { options = {
|
|
5
|
+
// const data = props?.data || {};
|
|
6
|
+
const defaultOptions = {
|
|
10
7
|
validateEvent: 'blur',
|
|
11
|
-
validators: {}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
state.sanity.ok = isOk;
|
|
8
|
+
validators: {},
|
|
9
|
+
fieldWaitTimeInMilliSecond: 200,
|
|
10
|
+
debug: false
|
|
15
11
|
};
|
|
16
|
-
const
|
|
12
|
+
const { options: userOptions = {}, data = {} } = props || {};
|
|
13
|
+
const options = { ...defaultOptions, ...userOptions };
|
|
14
|
+
// form state
|
|
15
|
+
const { values, errors, unfits, reset, sanity, validationMap } = formStore(data);
|
|
16
|
+
const form = formAction(values, errors, unfits, (_sanity) => {
|
|
17
|
+
sanity.ok = _sanity;
|
|
18
|
+
}, options, validationMap);
|
|
17
19
|
const handleSubmit = (e, handler) => {
|
|
18
20
|
e.preventDefault();
|
|
19
|
-
if (!
|
|
21
|
+
if (!sanity.ok)
|
|
20
22
|
return;
|
|
21
|
-
handler({ ...
|
|
23
|
+
handler({ ...values });
|
|
22
24
|
};
|
|
23
25
|
const onsubmit = (handler) => {
|
|
24
|
-
|
|
26
|
+
return (e) => {
|
|
25
27
|
handleSubmit(e, handler);
|
|
26
28
|
};
|
|
27
|
-
return onSubmit;
|
|
28
29
|
};
|
|
29
30
|
const submit = (formNode, handler) => {
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
$effect(() => {
|
|
32
|
+
const localHandler = (e) => {
|
|
33
|
+
handleSubmit(e, handler);
|
|
34
|
+
};
|
|
35
|
+
formNode.addEventListener('submit', localHandler);
|
|
36
|
+
return () => formNode.removeEventListener('submit', localHandler);
|
|
32
37
|
});
|
|
33
38
|
};
|
|
34
|
-
const reset = () => {
|
|
35
|
-
const defaultKeys = Object.keys({ ...data });
|
|
36
|
-
for (const [key,] of Object.entries(state.values)) {
|
|
37
|
-
if (defaultKeys.includes(key)) {
|
|
38
|
-
state.values[key] = data[key];
|
|
39
|
-
}
|
|
40
|
-
else {
|
|
41
|
-
delete state.values[key];
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
state.errors = {};
|
|
45
|
-
state.unfits = {};
|
|
46
|
-
state.sanity.ok = false;
|
|
47
|
-
for (const [name, { nodeRef, html }] of Object.entries(validationMap).filter(([, { nodeRef }]) => !!nodeRef)) {
|
|
48
|
-
if (nodeRef) {
|
|
49
|
-
if (nodeRef.isContentEditable) {
|
|
50
|
-
nodeRef[html ? 'innerHTML' : 'textContent'] = data[name] || '';
|
|
51
|
-
}
|
|
52
|
-
else {
|
|
53
|
-
nodeRef['value'] = data[name] || '';
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
39
|
return {
|
|
59
|
-
values
|
|
60
|
-
errors
|
|
61
|
-
sanity
|
|
40
|
+
values,
|
|
41
|
+
errors,
|
|
42
|
+
sanity,
|
|
62
43
|
form,
|
|
63
44
|
submit,
|
|
64
45
|
onsubmit,
|
|
@@ -9,4 +9,8 @@ export type FormState = {
|
|
|
9
9
|
sanity: FormSanity;
|
|
10
10
|
unfits: FormErrors;
|
|
11
11
|
};
|
|
12
|
-
export
|
|
12
|
+
export type FormStore = FormState & {
|
|
13
|
+
validationMap: Params;
|
|
14
|
+
reset: () => void;
|
|
15
|
+
};
|
|
16
|
+
export declare const formStore: (data: Params) => FormStore;
|
package/dist/internal.svelte.js
CHANGED
|
@@ -1,15 +1,43 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
//
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
import { resetObject } from "./utils.js";
|
|
2
|
+
export const formStore = (data) => {
|
|
3
|
+
const validationMap = {};
|
|
4
|
+
// form state
|
|
5
|
+
const state = $state({
|
|
6
|
+
values: { ...data },
|
|
7
|
+
errors: {},
|
|
8
|
+
unfits: {},
|
|
9
|
+
sanity: { ok: false }
|
|
10
|
+
});
|
|
9
11
|
return {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
validationMap,
|
|
13
|
+
get values() {
|
|
14
|
+
return state.values;
|
|
15
|
+
},
|
|
16
|
+
get errors() {
|
|
17
|
+
return state.errors;
|
|
18
|
+
},
|
|
19
|
+
get unfits() {
|
|
20
|
+
return state.unfits;
|
|
21
|
+
},
|
|
22
|
+
get sanity() {
|
|
23
|
+
return state.sanity;
|
|
24
|
+
},
|
|
25
|
+
reset() {
|
|
26
|
+
resetObject(state.values, data);
|
|
27
|
+
resetObject(state.errors);
|
|
28
|
+
resetObject(state.unfits);
|
|
29
|
+
state.sanity.ok = false;
|
|
30
|
+
const nodeEntries = Object.entries(validationMap).filter(([, { nodeRef }]) => !!nodeRef);
|
|
31
|
+
for (const [name, { nodeRef, html }] of nodeEntries) {
|
|
32
|
+
if (nodeRef) {
|
|
33
|
+
if (nodeRef.isContentEditable) {
|
|
34
|
+
nodeRef[html ? 'innerHTML' : 'textContent'] = data[name] || '';
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
nodeRef['value'] = data[name] || '';
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
14
42
|
};
|
|
15
43
|
};
|
package/dist/types.d.ts
CHANGED
|
@@ -40,10 +40,12 @@ export type FormAction = (node: HTMLElement, eventProps?: ActionOptions) => void
|
|
|
40
40
|
export type FormSubmitEvent = SubmitEvent & {
|
|
41
41
|
currentTarget: EventTarget & HTMLFormElement;
|
|
42
42
|
};
|
|
43
|
-
export type FormSubmit = (_data: Params) => void;
|
|
43
|
+
export type FormSubmit = (_data: Params) => (void | Promise<void>);
|
|
44
44
|
export type FormOptions = {
|
|
45
45
|
validateEvent?: ValidateEvent;
|
|
46
46
|
validators?: Partial<ValidatorMap<ValidatorType>>;
|
|
47
|
+
fieldWaitTimeInMilliSecond?: number;
|
|
48
|
+
debug?: boolean;
|
|
47
49
|
};
|
|
48
50
|
export type MicroFormProps = {
|
|
49
51
|
data?: Params;
|
|
@@ -58,7 +60,7 @@ export type MicroFormReturn = {
|
|
|
58
60
|
sanity: FormSanity;
|
|
59
61
|
form: (node: HTMLElement, eventProps?: ActionOptions) => void;
|
|
60
62
|
submit: (formNode: HTMLFormElement, handler: FormSubmit) => void;
|
|
61
|
-
onsubmit: (handler: FormSubmit) => (e: Event) =>
|
|
63
|
+
onsubmit: (handler: FormSubmit) => (e: Event) => void;
|
|
62
64
|
reset: () => void;
|
|
63
65
|
};
|
|
64
66
|
export type Microform = (props?: MicroFormProps) => MicroFormReturn;
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { Params } from "./internal.svelte.js";
|
|
2
|
+
import type { FormValues } from "./types.js";
|
|
1
3
|
type TEvent = {
|
|
2
4
|
target: HTMLElement;
|
|
3
5
|
};
|
|
@@ -7,4 +9,6 @@ export declare const getEditableContent: (e: TEvent, isHtml: boolean) => {
|
|
|
7
9
|
};
|
|
8
10
|
export declare const makeName: (str: string) => string;
|
|
9
11
|
export declare const isValidFileSize: (node: HTMLInputElement | undefined, maxFileSizeInMB: number) => string;
|
|
12
|
+
export declare const resetObject: (target: FormValues, data?: Params | undefined) => void;
|
|
13
|
+
export declare const debounce: (func: (...args?: any) => any, delay?: number) => (...par?: any) => void;
|
|
10
14
|
export {};
|
package/dist/utils.js
CHANGED
|
@@ -43,10 +43,29 @@ export const isValidFileSize = (node, maxFileSizeInMB) => {
|
|
|
43
43
|
}
|
|
44
44
|
return '';
|
|
45
45
|
};
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
46
|
+
export const resetObject = (target, data = undefined) => {
|
|
47
|
+
if (data) {
|
|
48
|
+
const defaultKeys = Object.keys({ ...data });
|
|
49
|
+
for (const [key,] of Object.entries(target)) {
|
|
50
|
+
if (defaultKeys.includes(key)) {
|
|
51
|
+
target[key] = data[key];
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
delete target[key];
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
for (const [key,] of Object.entries(target)) {
|
|
60
|
+
target[key] = '';
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
export const debounce = (func, delay = 1000) => {
|
|
65
|
+
let timeoutId;
|
|
66
|
+
return function (...par) {
|
|
67
|
+
const context = this;
|
|
68
|
+
clearTimeout(timeoutId);
|
|
69
|
+
timeoutId = setTimeout(() => func.apply(context, par), delay);
|
|
70
|
+
};
|
|
71
|
+
};
|