effectweb 0.2.2 → 0.3.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/LICENSE +1 -1
- package/README.md +94 -2
- package/dist/AsyncContent.d.ts +2 -2
- package/dist/AsyncContent.js +36 -24
- package/dist/actions.d.ts +4 -4
- package/dist/actions.js +1 -1
- package/dist/cache-internals.d.ts +14 -0
- package/dist/cache-internals.js +11 -0
- package/dist/cache.d.ts +17 -15
- package/dist/cache.js +98 -27
- package/dist/collection.d.ts +10 -10
- package/dist/collection.js +32 -6
- package/dist/component.d.ts +8 -7
- package/dist/diagnostics.d.ts +25 -0
- package/dist/diagnostics.js +167 -1
- package/dist/dom-attributes.json +71 -0
- package/dist/dom.d.ts +36 -13
- package/dist/dom.js +547 -84
- package/dist/form.d.ts +61 -0
- package/dist/form.js +98 -0
- package/dist/html-attributes.d.ts +602 -0
- package/dist/html-attributes.js +1 -0
- package/dist/http.d.ts +5 -0
- package/dist/http.js +7 -0
- package/dist/index.d.ts +12 -10
- package/dist/index.js +7 -5
- package/dist/jsx.d.ts +165 -33
- package/dist/jsx.js +2 -1
- package/dist/lazy.d.ts +23 -0
- package/dist/lazy.js +58 -0
- package/dist/load.d.ts +3 -4
- package/dist/mount.d.ts +8 -11
- package/dist/mount.js +1 -3
- package/dist/owner.d.ts +11 -9
- package/dist/owner.js +27 -38
- package/dist/pages.d.ts +23 -23
- package/dist/pages.js +15 -10
- package/dist/program.d.ts +19 -10
- package/dist/program.js +172 -66
- package/dist/query-internals.d.ts +11 -0
- package/dist/query-internals.js +10 -0
- package/dist/query.d.ts +24 -20
- package/dist/query.js +60 -7
- package/dist/resource.d.ts +4 -10
- package/dist/resource.js +14 -5
- package/dist/runtime.d.ts +1 -2
- package/dist/runtime.js +3 -3
- package/dist/session.d.ts +12 -18
- package/dist/session.js +15 -15
- package/dist/share.d.ts +5 -4
- package/dist/share.js +5 -44
- package/dist/sharing.d.ts +6 -0
- package/dist/sharing.js +93 -0
- package/dist/snapshot.d.ts +16 -5
- package/dist/snapshot.js +6 -7
- package/dist/state.d.ts +0 -1
- package/dist/state.js +0 -1
- package/dist/svg-attributes.d.ts +12 -0
- package/dist/svg-attributes.js +1 -0
- package/dist/task.d.ts +9 -8
- package/dist/task.js +75 -47
- package/dist/tasks.d.ts +20 -15
- package/dist/tasks.js +39 -25
- package/dist/testing.d.ts +10 -15
- package/package.json +5 -1
package/dist/form.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import type { Cause, Effect } from 'effect';
|
|
2
|
+
import { type Transition } from './program.js';
|
|
3
|
+
import type { Snapshot } from './snapshot.js';
|
|
1
4
|
import type { EffectEventRequest } from './effectEvent.js';
|
|
2
5
|
type EventResult = void | boolean | EffectEventRequest;
|
|
3
6
|
type ValueEvent<T> = {
|
|
@@ -16,4 +19,62 @@ export declare const inputNumber: (change: (value: number | undefined) => EventR
|
|
|
16
19
|
}>) => EventResult;
|
|
17
20
|
/** Prevention always runs during the native event, before task drop/replace policy is applied. */
|
|
18
21
|
export declare const submit: (run: () => EventResult) => (event: Pick<SubmitEvent, "preventDefault">) => EventResult;
|
|
22
|
+
/** Parsing never rewrites the draft: incomplete input remains editable. */
|
|
23
|
+
export type FieldResult<Value> = {
|
|
24
|
+
readonly ok: true;
|
|
25
|
+
readonly value: Value;
|
|
26
|
+
} | {
|
|
27
|
+
readonly ok: false;
|
|
28
|
+
readonly error: string;
|
|
29
|
+
};
|
|
30
|
+
export interface FieldState<Draft, Value> {
|
|
31
|
+
readonly draft: Draft;
|
|
32
|
+
readonly initial: Draft;
|
|
33
|
+
readonly parsed: FieldResult<Value>;
|
|
34
|
+
readonly touched: boolean;
|
|
35
|
+
readonly dirty: boolean;
|
|
36
|
+
readonly validation: 'idle' | 'pending' | 'valid' | 'invalid';
|
|
37
|
+
/** Display error; parse failures remain hidden until the configured validation event. */
|
|
38
|
+
readonly error: string | undefined;
|
|
39
|
+
readonly revision: number;
|
|
40
|
+
}
|
|
41
|
+
export type FieldMessage<Draft> = {
|
|
42
|
+
readonly type: 'Change';
|
|
43
|
+
readonly draft: Draft;
|
|
44
|
+
} | {
|
|
45
|
+
readonly type: 'Blur';
|
|
46
|
+
} | {
|
|
47
|
+
readonly type: 'Validate';
|
|
48
|
+
}
|
|
49
|
+
/** A supplied draft becomes the new reset baseline. */
|
|
50
|
+
| {
|
|
51
|
+
readonly type: 'Reset';
|
|
52
|
+
readonly draft?: Draft;
|
|
53
|
+
} | {
|
|
54
|
+
readonly type: 'Validated';
|
|
55
|
+
readonly revision: number;
|
|
56
|
+
readonly error: string | undefined;
|
|
57
|
+
};
|
|
58
|
+
export interface FieldController<Draft, Value, R = never> {
|
|
59
|
+
readonly init: (draft: Draft) => FieldState<Draft, Value>;
|
|
60
|
+
readonly update: (model: Snapshot<FieldState<Draft, Value>>, message: FieldMessage<Draft>) => Transition<FieldState<Draft, Value>, FieldMessage<Draft>, R>;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Immutable editable field, composed into a program/component with mapCommand.
|
|
64
|
+
* Each definition owns a unique operation token. Commands inherit the program's scope;
|
|
65
|
+
* edits, reset and replacement validations cancel the field's previous command.
|
|
66
|
+
*
|
|
67
|
+
* Parsing runs on init/change/reset. Display validation runs only on validateOn
|
|
68
|
+
* (default: blur) or explicit Validate. Change clears previous display errors.
|
|
69
|
+
* Async validators run only after parsing succeeds and must return an error or undefined.
|
|
70
|
+
*/
|
|
71
|
+
export declare function defineField<Draft extends string | boolean, Value, E = never, R = never>(options: {
|
|
72
|
+
readonly id: string;
|
|
73
|
+
readonly parse: (draft: Draft) => FieldResult<Value>;
|
|
74
|
+
readonly validateOn?: 'change' | 'blur' | 'submit';
|
|
75
|
+
readonly validate?: (value: Snapshot<{
|
|
76
|
+
value: Value;
|
|
77
|
+
}>['value']) => Effect.Effect<string | undefined, E, R>;
|
|
78
|
+
readonly onFailure?: (cause: Cause.Cause<E>) => string;
|
|
79
|
+
}): FieldController<Draft, Value, R>;
|
|
19
80
|
export {};
|
package/dist/form.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { commandSlot, effectCommand } from './program.js';
|
|
1
2
|
/** Capture native values synchronously; returned Effect requests retain the listener's owner. */
|
|
2
3
|
export const inputText = (change) => (event) => change(event.currentTarget.value);
|
|
3
4
|
export const inputChecked = (change) => (event) => change(event.currentTarget.checked);
|
|
@@ -11,3 +12,100 @@ export const submit = (run) => (event) => {
|
|
|
11
12
|
event.preventDefault();
|
|
12
13
|
return run();
|
|
13
14
|
};
|
|
15
|
+
/**
|
|
16
|
+
* Immutable editable field, composed into a program/component with mapCommand.
|
|
17
|
+
* Each definition owns a unique operation token. Commands inherit the program's scope;
|
|
18
|
+
* edits, reset and replacement validations cancel the field's previous command.
|
|
19
|
+
*
|
|
20
|
+
* Parsing runs on init/change/reset. Display validation runs only on validateOn
|
|
21
|
+
* (default: blur) or explicit Validate. Change clears previous display errors.
|
|
22
|
+
* Async validators run only after parsing succeeds and must return an error or undefined.
|
|
23
|
+
*/
|
|
24
|
+
export function defineField(options) {
|
|
25
|
+
const slot = commandSlot(`field:${options.id}`);
|
|
26
|
+
const init = (draft) => ({
|
|
27
|
+
draft,
|
|
28
|
+
initial: draft,
|
|
29
|
+
parsed: options.parse(draft),
|
|
30
|
+
touched: false,
|
|
31
|
+
dirty: false,
|
|
32
|
+
validation: 'idle',
|
|
33
|
+
error: undefined,
|
|
34
|
+
revision: 0,
|
|
35
|
+
});
|
|
36
|
+
const validate = (model) => {
|
|
37
|
+
const revision = model.revision + 1;
|
|
38
|
+
if (!model.parsed.ok) {
|
|
39
|
+
return {
|
|
40
|
+
model: { ...model, revision, validation: 'invalid', error: model.parsed.error },
|
|
41
|
+
cancel: [slot],
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
const value = model.parsed.value;
|
|
45
|
+
if (!options.validate) {
|
|
46
|
+
return {
|
|
47
|
+
model: { ...model, revision, validation: 'valid', error: undefined },
|
|
48
|
+
cancel: [slot],
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
const check = options.validate;
|
|
52
|
+
return {
|
|
53
|
+
model: { ...model, revision, validation: 'pending', error: undefined },
|
|
54
|
+
commands: [
|
|
55
|
+
effectCommand(slot, () => check(value), {
|
|
56
|
+
policy: 'replace',
|
|
57
|
+
onSuccess: (error) => ({ type: 'Validated', revision, error }),
|
|
58
|
+
onFailure: (cause) => ({
|
|
59
|
+
type: 'Validated',
|
|
60
|
+
revision,
|
|
61
|
+
error: options.onFailure?.(cause) ?? 'Validation is unavailable. Try again.',
|
|
62
|
+
}),
|
|
63
|
+
}),
|
|
64
|
+
],
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
return {
|
|
68
|
+
init,
|
|
69
|
+
update(model, message) {
|
|
70
|
+
switch (message.type) {
|
|
71
|
+
case 'Change': {
|
|
72
|
+
const next = {
|
|
73
|
+
...model,
|
|
74
|
+
// Drafts are primitive; freshly parsed data is published through the owner's guard.
|
|
75
|
+
draft: message.draft,
|
|
76
|
+
parsed: options.parse(message.draft),
|
|
77
|
+
dirty: !Object.is(message.draft, model.initial),
|
|
78
|
+
revision: model.revision + 1,
|
|
79
|
+
validation: 'idle',
|
|
80
|
+
error: undefined,
|
|
81
|
+
};
|
|
82
|
+
return options.validateOn === 'change' ? validate(next) : { model: next, cancel: [slot] };
|
|
83
|
+
}
|
|
84
|
+
case 'Blur': {
|
|
85
|
+
const next = { ...model, touched: true };
|
|
86
|
+
return (options.validateOn ?? 'blur') === 'blur' ? validate(next) : { model: next };
|
|
87
|
+
}
|
|
88
|
+
case 'Validate':
|
|
89
|
+
return validate({ ...model, touched: true });
|
|
90
|
+
case 'Reset':
|
|
91
|
+
return {
|
|
92
|
+
model: {
|
|
93
|
+
...init(message.draft ?? model.initial),
|
|
94
|
+
revision: model.revision + 1,
|
|
95
|
+
},
|
|
96
|
+
cancel: [slot],
|
|
97
|
+
};
|
|
98
|
+
case 'Validated':
|
|
99
|
+
return message.revision === model.revision && model.validation === 'pending'
|
|
100
|
+
? {
|
|
101
|
+
model: {
|
|
102
|
+
...model,
|
|
103
|
+
validation: message.error === undefined ? 'valid' : 'invalid',
|
|
104
|
+
error: message.error,
|
|
105
|
+
},
|
|
106
|
+
}
|
|
107
|
+
: { model };
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
}
|