@shivaedev/form 0.0.0 → 0.7.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.
Files changed (64) hide show
  1. package/CHANGELOG.md +115 -0
  2. package/LICENSE +21 -0
  3. package/README.md +314 -1
  4. package/dist/client/react.d.ts +27 -0
  5. package/dist/client/react.d.ts.map +1 -0
  6. package/dist/client/react.js +28 -0
  7. package/dist/client/react.js.map +1 -0
  8. package/dist/draft.d.ts +16 -0
  9. package/dist/draft.d.ts.map +1 -0
  10. package/dist/draft.js +80 -0
  11. package/dist/draft.js.map +1 -0
  12. package/dist/draftSession.d.ts +8 -0
  13. package/dist/draftSession.d.ts.map +1 -0
  14. package/dist/draftSession.js +23 -0
  15. package/dist/draftSession.js.map +1 -0
  16. package/dist/emptyAsNull.d.ts +3 -0
  17. package/dist/emptyAsNull.d.ts.map +1 -0
  18. package/dist/emptyAsNull.js +8 -0
  19. package/dist/emptyAsNull.js.map +1 -0
  20. package/dist/form.d.ts +4 -0
  21. package/dist/form.d.ts.map +1 -0
  22. package/dist/form.js +101 -0
  23. package/dist/form.js.map +1 -0
  24. package/dist/messages.d.ts +15 -0
  25. package/dist/messages.d.ts.map +1 -0
  26. package/dist/messages.js +95 -0
  27. package/dist/messages.js.map +1 -0
  28. package/dist/paths.d.ts +13 -0
  29. package/dist/paths.d.ts.map +1 -0
  30. package/dist/paths.js +48 -0
  31. package/dist/paths.js.map +1 -0
  32. package/dist/persistence.d.ts +25 -0
  33. package/dist/persistence.d.ts.map +1 -0
  34. package/dist/persistence.js +84 -0
  35. package/dist/persistence.js.map +1 -0
  36. package/dist/refs.d.ts +5 -0
  37. package/dist/refs.d.ts.map +1 -0
  38. package/dist/refs.js +33 -0
  39. package/dist/refs.js.map +1 -0
  40. package/dist/shape.d.ts +68 -0
  41. package/dist/shape.d.ts.map +1 -0
  42. package/dist/shape.js +18 -0
  43. package/dist/shape.js.map +1 -0
  44. package/dist/statusOf.d.ts +14 -0
  45. package/dist/statusOf.d.ts.map +1 -0
  46. package/dist/statusOf.js +60 -0
  47. package/dist/statusOf.js.map +1 -0
  48. package/dist/trackRejections.d.ts +5 -0
  49. package/dist/trackRejections.d.ts.map +1 -0
  50. package/dist/trackRejections.js +20 -0
  51. package/dist/trackRejections.js.map +1 -0
  52. package/package.json +78 -4
  53. package/src/client/react.ts +54 -0
  54. package/src/draft.ts +98 -0
  55. package/src/draftSession.ts +29 -0
  56. package/src/emptyAsNull.ts +12 -0
  57. package/src/form.ts +142 -0
  58. package/src/messages.ts +114 -0
  59. package/src/paths.ts +63 -0
  60. package/src/persistence.ts +107 -0
  61. package/src/refs.ts +34 -0
  62. package/src/shape.ts +94 -0
  63. package/src/statusOf.ts +70 -0
  64. package/src/trackRejections.ts +23 -0
@@ -0,0 +1,23 @@
1
+ export function draftSession(id) {
2
+ const drafts = new Map();
3
+ let active = true;
4
+ return {
5
+ get active() {
6
+ return active;
7
+ },
8
+ drop: () => {
9
+ active = false;
10
+ for (const clear of drafts.values()) {
11
+ clear();
12
+ }
13
+ drafts.clear();
14
+ },
15
+ id,
16
+ track: (key, clear) => {
17
+ if (active) {
18
+ drafts.set(key, clear);
19
+ }
20
+ },
21
+ };
22
+ }
23
+ //# sourceMappingURL=draftSession.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"draftSession.js","sourceRoot":"","sources":["../src/draftSession.ts"],"names":[],"mappings":"AAOA,MAAM,UAAU,YAAY,CAAC,EAAU;IACtC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAsB,CAAC;IAC7C,IAAI,MAAM,GAAG,IAAI,CAAC;IAClB,OAAO;QACN,IAAI,MAAM;YACT,OAAO,MAAM,CAAC;QACf,CAAC;QACD,IAAI,EAAE,GAAG,EAAE;YACV,MAAM,GAAG,KAAK,CAAC;YACf,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC;gBACrC,KAAK,EAAE,CAAC;YACT,CAAC;YACD,MAAM,CAAC,KAAK,EAAE,CAAC;QAChB,CAAC;QACD,EAAE;QACF,KAAK,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;YACrB,IAAI,MAAM,EAAE,CAAC;gBACZ,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YACxB,CAAC;QACF,CAAC;KACD,CAAC;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Schema } from "effect";
2
+ export declare function emptyAsNull<TSchema extends Schema.Constraint & Schema.Top>(inner: TSchema): Schema.Codec<TSchema["Type"] | null, TSchema["Encoded"] | "", TSchema["DecodingServices"], TSchema["EncodingServices"]>;
3
+ //# sourceMappingURL=emptyAsNull.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emptyAsNull.d.ts","sourceRoot":"","sources":["../src/emptyAsNull.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAgB,MAAM,QAAQ,CAAC;AAE9C,wBAAgB,WAAW,CAAC,OAAO,SAAS,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,GAAG,EACzE,KAAK,EAAE,OAAO,GACZ,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,kBAAkB,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAOzH"}
@@ -0,0 +1,8 @@
1
+ import { Schema, SchemaGetter } from "effect";
2
+ export function emptyAsNull(inner) {
3
+ return Schema.Union([Schema.Literal(""), inner]).pipe(Schema.decodeTo(Schema.NullOr(Schema.toType(inner)), {
4
+ decode: SchemaGetter.transform((value) => (value === "" ? null : value)),
5
+ encode: SchemaGetter.transform((value) => (value === null ? "" : value)),
6
+ }));
7
+ }
8
+ //# sourceMappingURL=emptyAsNull.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emptyAsNull.js","sourceRoot":"","sources":["../src/emptyAsNull.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAE9C,MAAM,UAAU,WAAW,CAC1B,KAAc;IAEd,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CACpD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE;QACpD,MAAM,EAAE,YAAY,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACxE,MAAM,EAAE,YAAY,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;KACxE,CAAC,CACF,CAAC;AACH,CAAC"}
package/dist/form.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ import { type Schema } from "effect";
2
+ import { type Config, type Fields, type Form } from "./shape.ts";
3
+ export declare function form<TFields extends Fields, TValue, TError, TServices, TRuntimeError>(schema: Schema.Struct<TFields>, config: Config<TFields, TValue, TError, TServices, TRuntimeError>): Form<TFields, TValue, TError, TRuntimeError>;
4
+ //# sourceMappingURL=form.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"form.d.ts","sourceRoot":"","sources":["../src/form.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,KAAK,MAAM,EAAkC,MAAM,QAAQ,CAAC;AAS5F,OAAO,EACN,KAAK,MAAM,EAMX,KAAK,MAAM,EACX,KAAK,IAAI,EAMT,MAAM,YAAY,CAAC;AAIpB,wBAAgB,IAAI,CAAC,OAAO,SAAS,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,EACpF,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,EAC9B,MAAM,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,CAAC,GAC/D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,CAAC,CA+G9C"}
package/dist/form.js ADDED
@@ -0,0 +1,101 @@
1
+ import { Effect, Equal, Result, SchemaParser } from "effect";
2
+ import * as AsyncResult from "effect/reactivity/AsyncResult";
3
+ import * as Atom from "effect/reactivity/Atom";
4
+ import { draft } from "./draft.js";
5
+ import { literalChoices, messageAt, messagesByField, schemaFeedback } from "./messages.js";
6
+ import { pathMessageAt } from "./paths.js";
7
+ import { persistence } from "./persistence.js";
8
+ import { fromRef, propertyRef } from "./refs.js";
9
+ import { checkOf, choicesOf, FieldFailure, fieldOf, holder, Invalid, } from "./shape.js";
10
+ import { statusOf } from "./statusOf.js";
11
+ import { trackRejections } from "./trackRejections.js";
12
+ export function form(schema, config) {
13
+ const { initialValues, onSubmit, runtime } = config;
14
+ const debounce = config.debounce ?? "300 millis";
15
+ const checks = new Map(Object.entries(config.checks ?? {}));
16
+ const decode = SchemaParser.decodeUnknownEffect(schema, { errors: "all" });
17
+ const editing = draft(initialValues, config.persistedDraft ? persistence(schema, config.persistedDraft) : undefined);
18
+ const { values } = editing;
19
+ const status = statusOf();
20
+ const noted = trackRejections(holder(values), config.arrayKeys, status);
21
+ const held = new Map();
22
+ function refFor(name) {
23
+ const known = held.get(name);
24
+ if (known !== undefined) {
25
+ return known;
26
+ }
27
+ const made = propertyRef(holder(values), name);
28
+ held.set(name, made);
29
+ return made;
30
+ }
31
+ const offered = new Map();
32
+ for (const [name, member] of Object.entries(schema.fields)) {
33
+ const choices = literalChoices(member.ast);
34
+ if (choices !== undefined) {
35
+ offered.set(name, choices);
36
+ }
37
+ }
38
+ const valuesAtom = fromRef(values);
39
+ const decoded = runtime.atom((get) => decode(get(valuesAtom)).pipe(Effect.match({
40
+ onFailure: (issue) => Result.fail(issue),
41
+ onSuccess: (value) => Result.succeed(value),
42
+ })));
43
+ const schemaErrors = schemaFeedback(decoded);
44
+ const checkError = Atom.family((name) => {
45
+ const check = checks.get(name);
46
+ if (check === undefined) {
47
+ return Atom.make(() => undefined);
48
+ }
49
+ const current = fromRef(refFor(name));
50
+ const settled = Atom.debounce(current, debounce);
51
+ const answered = runtime.atom((get) => {
52
+ const input = get(settled);
53
+ return Effect.map(checkOf(check)(input), (message) => ({
54
+ input,
55
+ message,
56
+ }));
57
+ });
58
+ return Atom.readable((get) => {
59
+ const result = get(answered);
60
+ const value = get(current);
61
+ return AsyncResult.isSuccess(result) && !result.waiting && Equal.equals(result.value.input, value) ? result.value.message : undefined;
62
+ });
63
+ });
64
+ const error = Atom.family((name) => Atom.readable((get) => {
65
+ if (get(status.touched)[name] !== true && !get(status.submitted)) {
66
+ return undefined;
67
+ }
68
+ return messageAt(get(status.failures), name) ?? get(schemaErrors.field(name)) ?? get(checkError(name));
69
+ }));
70
+ const submitter = {
71
+ fail: (path, message) => Effect.fail(new FieldFailure(typeof path === "string" ? { message, path } : { message, path: path[0], segments: path })),
72
+ };
73
+ const submit = runtime.fn()(() => Effect.gen(function* () {
74
+ status.attempt();
75
+ const submission = editing.submission();
76
+ const submitted = submission.values;
77
+ const value = yield* decode(submitted).pipe(Effect.mapError((issue) => new Invalid({ messages: messagesByField(issue) })));
78
+ return yield* onSubmit(value, submitter, submitted).pipe(Effect.tapError(noted(submitted)), Effect.tap(() => Effect.sync(submission.accept)));
79
+ }));
80
+ return {
81
+ blur: status.touch,
82
+ change: (name, value) => {
83
+ refFor(name).set(value);
84
+ status.touch(name);
85
+ },
86
+ choices: (name) => choicesOf(offered.get(name)),
87
+ dirty: editing.dirty,
88
+ error,
89
+ errorAt: Atom.family((path) => {
90
+ const message = schemaErrors.at(path);
91
+ return Atom.readable((get) => get(status.touched)[path[0]] === true || get(status.submitted) ? (pathMessageAt(get(status.paths), path) ?? get(message)) : undefined);
92
+ }),
93
+ field: (name) => fieldOf(refFor(name)),
94
+ receive: editing.receive,
95
+ revert: editing.revert,
96
+ submit,
97
+ submitting: Atom.map(submit, AsyncResult.isWaiting),
98
+ values,
99
+ };
100
+ }
101
+ //# sourceMappingURL=form.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"form.js","sourceRoot":"","sources":["../src/form.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { Result, SchemaAST, SchemaIssue } from "effect";
2
+ import * as AsyncResult from "effect/reactivity/AsyncResult";
3
+ import * as Atom from "effect/reactivity/Atom";
4
+ export type FieldMessages = Readonly<Record<string, string>>;
5
+ export declare const noMessages: FieldMessages;
6
+ export declare function messagesByField(issue: SchemaIssue.Issue): FieldMessages;
7
+ export declare function messageAtPath(issue: SchemaIssue.Issue, path: readonly PropertyKey[]): string | undefined;
8
+ export declare function withoutField(messages: FieldMessages, name: string): FieldMessages;
9
+ export declare function literalChoices(input: SchemaAST.AST): readonly SchemaAST.LiteralValue[] | undefined;
10
+ export declare function messageAt(messages: FieldMessages, name: string): string | undefined;
11
+ export declare function schemaFeedback<A, E>(decoded: Atom.Atom<AsyncResult.AsyncResult<Result.Result<A, SchemaIssue.Issue>, E>>): {
12
+ at: (path: readonly PropertyKey[]) => Atom.Atom<string | undefined>;
13
+ field: (arg: string) => Atom.Atom<string | undefined>;
14
+ };
15
+ //# sourceMappingURL=messages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,MAAM,EAAE,SAAS,EAAE,WAAW,EAAuB,MAAM,QAAQ,CAAC;AACrF,OAAO,KAAK,WAAW,MAAM,+BAA+B,CAAC;AAC7D,OAAO,KAAK,IAAI,MAAM,wBAAwB,CAAC;AAE/C,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAE7D,eAAO,MAAM,UAAU,EAAE,aAAkB,CAAC;AA0B5C,wBAAgB,eAAe,CAAC,KAAK,EAAE,WAAW,CAAC,KAAK,GAAG,aAAa,CAavE;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,WAAW,CAAC,KAAK,EAAE,IAAI,EAAE,SAAS,WAAW,EAAE,GAAG,MAAM,GAAG,SAAS,CAYxG;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,aAAa,CAWjF;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,CAAC,GAAG,GAAG,SAAS,SAAS,CAAC,YAAY,EAAE,GAAG,SAAS,CAalG;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEnF;AAED,wBAAgB,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;IAQtH,EAAE,SAAS,SAAS,WAAW,EAAE;IAUjC,KAAK;EAEN"}
@@ -0,0 +1,95 @@
1
+ import { Option, Result, SchemaAST, SchemaIssue } from "effect";
2
+ import * as AsyncResult from "effect/reactivity/AsyncResult";
3
+ import * as Atom from "effect/reactivity/Atom";
4
+ export const noMessages = {};
5
+ const REQUIRED = "Required";
6
+ const MINIMUM_LENGTH = "effect/schema/isMinLength";
7
+ function refusesEmpty(check) {
8
+ const representation = check.annotations?.representation;
9
+ if (representation === undefined || representation.id !== MINIMUM_LENGTH) {
10
+ return false;
11
+ }
12
+ const payload = representation.payload;
13
+ if (typeof payload !== "object" || payload === null || !("minLength" in payload)) {
14
+ return false;
15
+ }
16
+ return payload.minLength === 1;
17
+ }
18
+ const checkHook = (issue) => SchemaIssue.defaultCheckHook(issue) ?? (refusesEmpty(issue.filter) ? REQUIRED : undefined);
19
+ const formatIssue = SchemaIssue.makeFormatterStandardSchemaV1({ checkHook });
20
+ function segmentKey(segment) {
21
+ return typeof segment === "object" ? String(segment.key) : String(segment);
22
+ }
23
+ export function messagesByField(issue) {
24
+ const messages = Object.create(null);
25
+ for (const entry of formatIssue(issue).issues) {
26
+ const head = entry.path?.[0];
27
+ if (head === undefined) {
28
+ continue;
29
+ }
30
+ const name = segmentKey(head);
31
+ if (!Object.hasOwn(messages, name)) {
32
+ messages[name] = entry.message;
33
+ }
34
+ }
35
+ return messages;
36
+ }
37
+ export function messageAtPath(issue, path) {
38
+ for (const entry of formatIssue(issue).issues) {
39
+ if (path.every((segment, index) => {
40
+ const found = entry.path?.[index];
41
+ return found !== undefined && segment === (typeof found === "object" ? found.key : found);
42
+ })) {
43
+ return entry.message;
44
+ }
45
+ }
46
+ return undefined;
47
+ }
48
+ export function withoutField(messages, name) {
49
+ if (!Object.hasOwn(messages, name)) {
50
+ return messages;
51
+ }
52
+ const next = Object.create(null);
53
+ for (const [key, message] of Object.entries(messages)) {
54
+ if (key !== name) {
55
+ next[key] = message;
56
+ }
57
+ }
58
+ return next;
59
+ }
60
+ export function literalChoices(input) {
61
+ const ast = SchemaAST.toEncoded(input);
62
+ if (ast._tag !== "Union") {
63
+ return undefined;
64
+ }
65
+ const choices = [];
66
+ for (const member of ast.types) {
67
+ if (member._tag !== "Literal") {
68
+ return undefined;
69
+ }
70
+ choices.push(member.literal);
71
+ }
72
+ return choices;
73
+ }
74
+ export function messageAt(messages, name) {
75
+ return Object.hasOwn(messages, name) ? messages[name] : undefined;
76
+ }
77
+ export function schemaFeedback(decoded) {
78
+ const messages = Atom.map(decoded, (result) => Option.match(AsyncResult.value(result), {
79
+ onNone: () => noMessages,
80
+ onSome: (value) => (Result.isFailure(value) ? messagesByField(value.failure) : noMessages),
81
+ }));
82
+ return {
83
+ at: (path) => Atom.map(decoded, (result) => {
84
+ if (result.waiting) {
85
+ return undefined;
86
+ }
87
+ return Option.match(AsyncResult.value(result), {
88
+ onNone: () => undefined,
89
+ onSome: (value) => (Result.isFailure(value) ? messageAtPath(value.failure, path) : undefined),
90
+ });
91
+ }),
92
+ field: Atom.family((name) => Atom.map(messages, (value) => messageAt(value, name))),
93
+ };
94
+ }
95
+ //# sourceMappingURL=messages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.js","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { Path } from "./shape.ts";
2
+ type Key = (element: unknown) => PropertyKey;
3
+ export type KeySelectors = ReadonlyMap<string, Key>;
4
+ export interface PathMessage {
5
+ readonly message: string;
6
+ readonly path: Path;
7
+ }
8
+ export declare function keySelector(selector: unknown): Key;
9
+ export declare function asPath(path: string | Path): Path;
10
+ export declare function retainedPath(path: Path, previous: unknown, current: unknown, keys: KeySelectors): Path | undefined;
11
+ export declare function pathMessageAt(messages: readonly PathMessage[], path: readonly PropertyKey[]): string | undefined;
12
+ export {};
13
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,KAAK,GAAG,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,WAAW,CAAC;AAC7C,MAAM,MAAM,YAAY,GAAG,WAAW,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAEpD,MAAM,WAAW,WAAW;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;CACpB;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,GAAG,CAAC;AAKpD,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAEhD;AAqBD,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI,GAAG,SAAS,CAmBlH;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,EAAE,IAAI,EAAE,SAAS,WAAW,EAAE,GAAG,MAAM,GAAG,SAAS,CAEhH"}
package/dist/paths.js ADDED
@@ -0,0 +1,48 @@
1
+ import { Equal } from "effect";
2
+ export function keySelector(selector) {
3
+ return selector;
4
+ }
5
+ export function asPath(path) {
6
+ return typeof path === "string" ? [path] : path;
7
+ }
8
+ function lookup(value, path) {
9
+ let current = value;
10
+ for (const [index, segment] of path.entries()) {
11
+ if (typeof current !== "object" || current === null) {
12
+ return undefined;
13
+ }
14
+ if (!Object.hasOwn(current, segment)) {
15
+ return index === path.length - 1 && !Array.isArray(current) ? { value: undefined } : undefined;
16
+ }
17
+ current = Reflect.get(current, segment);
18
+ }
19
+ return { value: current };
20
+ }
21
+ function uniqueIndex(values, key, select) {
22
+ const matches = values.flatMap((value, index) => (select(value) === key ? [index] : []));
23
+ return matches.length === 1 ? matches[0] : undefined;
24
+ }
25
+ export function retainedPath(path, previous, current, keys) {
26
+ const select = keys.get(path[0]);
27
+ let next = path;
28
+ if (select !== undefined && typeof path[1] === "number") {
29
+ const before = lookup(previous, [path[0]])?.value;
30
+ const after = lookup(current, [path[0]])?.value;
31
+ if (!(Array.isArray(before) && Array.isArray(after) && Object.hasOwn(before, path[1]))) {
32
+ return undefined;
33
+ }
34
+ const key = select(before[path[1]]);
35
+ const index = uniqueIndex(after, key, select);
36
+ if (index === undefined || uniqueIndex(before, key, select) !== path[1]) {
37
+ return undefined;
38
+ }
39
+ next = [path[0], index, ...path.slice(2)];
40
+ }
41
+ const before = lookup(previous, path);
42
+ const after = lookup(current, next);
43
+ return before !== undefined && after !== undefined && Equal.equals(before.value, after.value) ? next : undefined;
44
+ }
45
+ export function pathMessageAt(messages, path) {
46
+ return messages.find((entry) => path.every((segment, index) => segment === entry.path[index]))?.message;
47
+ }
48
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import { Schema } from "effect";
2
+ import type { DraftSession } from "./draftSession.ts";
3
+ export interface DraftStorage {
4
+ readonly getItem: (key: string) => string | null;
5
+ readonly removeItem: (key: string) => void;
6
+ readonly setItem: (key: string, value: string) => void;
7
+ }
8
+ export interface PersistedDraftConfig {
9
+ readonly key: string;
10
+ readonly maxAgeMs?: number;
11
+ readonly maxBytes?: number;
12
+ readonly session?: DraftSession | undefined;
13
+ readonly storage: () => DraftStorage;
14
+ }
15
+ export interface Persistence<TValues> {
16
+ readonly clear: () => void;
17
+ readonly read: () => {
18
+ readonly baseline: TValues;
19
+ readonly edited: readonly string[];
20
+ readonly values: TValues;
21
+ } | undefined;
22
+ readonly write: (baseline: TValues, values: TValues, edited: readonly string[]) => void;
23
+ }
24
+ export declare function persistence<TSchema extends Schema.Constraint>(schema: TSchema, config: PersistedDraftConfig): Persistence<TSchema["Encoded"]>;
25
+ //# sourceMappingURL=persistence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persistence.d.ts","sourceRoot":"","sources":["../src/persistence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,MAAM,EAAgB,MAAM,QAAQ,CAAC;AAC7D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IACjD,QAAQ,CAAC,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,QAAQ,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACvD;AAED,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,OAAO,EAAE,MAAM,YAAY,CAAC;CACrC;AAED,MAAM,WAAW,WAAW,CAAC,OAAO;IACnC,QAAQ,CAAC,KAAK,EAAE,MAAM,IAAI,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM;QAAE,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;KAAE,GAAG,SAAS,CAAC;IAC9H,QAAQ,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,MAAM,EAAE,KAAK,IAAI,CAAC;CACxF;AAED,wBAAgB,WAAW,CAAC,OAAO,SAAS,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,oBAAoB,GAAG,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAmF7I"}
@@ -0,0 +1,84 @@
1
+ import { Clock, Effect, Schema, SchemaParser } from "effect";
2
+ export function persistence(schema, config) {
3
+ const encoded = Schema.toEncoded(schema);
4
+ const StoredDraft = Schema.Struct({
5
+ baseline: Schema.Unknown,
6
+ edited: Schema.Array(Schema.String),
7
+ session: Schema.String,
8
+ updatedAt: Schema.Number,
9
+ values: Schema.Unknown,
10
+ version: Schema.Literal(1),
11
+ });
12
+ const valid = Schema.is(StoredDraft);
13
+ const decode = SchemaParser.decodeUnknownSync(encoded, { disableChecks: true });
14
+ const maxAgeMs = config.maxAgeMs ?? 7 * 24 * 60 * 60 * 1000;
15
+ const maxBytes = config.maxBytes ?? 256 * 1024;
16
+ function bytes(value) {
17
+ return new TextEncoder().encode(value).byteLength;
18
+ }
19
+ const storage = config.storage;
20
+ const session = config.session?.id ?? "";
21
+ function active() {
22
+ return config.session?.active !== false;
23
+ }
24
+ function attempt(run, failed) {
25
+ try {
26
+ return run();
27
+ }
28
+ catch {
29
+ failed?.();
30
+ return undefined;
31
+ }
32
+ }
33
+ function clear() {
34
+ attempt(() => storage().removeItem(config.key));
35
+ }
36
+ config.session?.track(config.key, clear);
37
+ return {
38
+ clear: () => {
39
+ if (active()) {
40
+ clear();
41
+ }
42
+ },
43
+ read: () => attempt(() => {
44
+ if (!active()) {
45
+ return undefined;
46
+ }
47
+ const raw = storage().getItem(config.key);
48
+ if (raw === null) {
49
+ return undefined;
50
+ }
51
+ const value = bytes(raw) <= maxBytes ? JSON.parse(raw) : undefined;
52
+ const now = Effect.runSync(Clock.currentTimeMillis);
53
+ if (valid(value)
54
+ && value.session === session
55
+ && Number.isFinite(maxAgeMs)
56
+ && Number.isFinite(maxBytes)
57
+ && maxAgeMs > 0
58
+ && maxBytes > 0
59
+ && now - value.updatedAt <= maxAgeMs
60
+ && value.updatedAt <= now) {
61
+ return { baseline: decode(value.baseline), edited: value.edited, values: decode(value.values) };
62
+ }
63
+ clear();
64
+ return undefined;
65
+ }, clear),
66
+ write: (baseline, values, edited) => {
67
+ if (!active()) {
68
+ return;
69
+ }
70
+ attempt(() => {
71
+ const raw = JSON.stringify({ baseline, edited, session, updatedAt: Effect.runSync(Clock.currentTimeMillis), values, version: 1 });
72
+ const parsed = JSON.parse(raw);
73
+ if (!(maxAgeMs > 0 && Number.isFinite(maxAgeMs) && Number.isFinite(maxBytes) && bytes(raw) <= maxBytes && valid(parsed))) {
74
+ clear();
75
+ return;
76
+ }
77
+ decode(parsed.baseline);
78
+ decode(parsed.values);
79
+ storage().setItem(config.key, raw);
80
+ }, clear);
81
+ },
82
+ };
83
+ }
84
+ //# sourceMappingURL=persistence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persistence.js","sourceRoot":"","sources":["../src/persistence.ts"],"names":[],"mappings":"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"}
package/dist/refs.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ import * as Atom from "effect/reactivity/Atom";
2
+ import * as AtomRef from "effect/reactivity/AtomRef";
3
+ export declare function fromRef<TValue>(ref: AtomRef.ReadonlyRef<TValue>): Atom.Atom<TValue>;
4
+ export declare function propertyRef<TValue, TKey extends keyof TValue>(parent: AtomRef.AtomRef<TValue>, name: TKey): AtomRef.AtomRef<TValue[TKey]>;
5
+ //# sourceMappingURL=refs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refs.d.ts","sourceRoot":"","sources":["../src/refs.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,IAAI,MAAM,wBAAwB,CAAC;AAC/C,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AAErD,wBAAgB,OAAO,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAKnF;AAGD,wBAAgB,WAAW,CAAC,MAAM,EAAE,IAAI,SAAS,MAAM,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAqBzI"}
package/dist/refs.js ADDED
@@ -0,0 +1,33 @@
1
+ import { Equal, Hash } from "effect";
2
+ import * as Atom from "effect/reactivity/Atom";
3
+ import * as AtomRef from "effect/reactivity/AtomRef";
4
+ export function fromRef(ref) {
5
+ return Atom.readable((get) => {
6
+ get.addFinalizer(ref.subscribe((value) => get.setSelf(value)));
7
+ return ref.value;
8
+ });
9
+ }
10
+ // Native prop refs retain removed keys; form fields must observe their absence.
11
+ export function propertyRef(parent, name) {
12
+ const read = parent.map((value) => value[name]);
13
+ const write = parent.prop(name);
14
+ const ref = {
15
+ [AtomRef.TypeId]: AtomRef.TypeId,
16
+ [Equal.symbol]: (other) => Equal.equals(read, other),
17
+ [Hash.symbol]: () => Hash.hash(read),
18
+ key: read.key,
19
+ map: (transform) => read.map(transform),
20
+ prop: (key) => propertyRef(ref, key),
21
+ set: (value) => {
22
+ write.set(value);
23
+ return ref;
24
+ },
25
+ subscribe: (listener) => read.subscribe(listener),
26
+ update: (transform) => ref.set(transform(read.value)),
27
+ get value() {
28
+ return read.value;
29
+ },
30
+ };
31
+ return ref;
32
+ }
33
+ //# sourceMappingURL=refs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refs.js","sourceRoot":"","sources":["../src/refs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,KAAK,IAAI,MAAM,wBAAwB,CAAC;AAC/C,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AAErD,MAAM,UAAU,OAAO,CAAS,GAAgC;IAC/D,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAC,GAAG,EAAE,EAAE;QAC5B,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC/D,OAAO,GAAG,CAAC,KAAK,CAAC;IAClB,CAAC,CAAC,CAAC;AACJ,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,WAAW,CAAoC,MAA+B,EAAE,IAAU;IACzG,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IAChD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChC,MAAM,GAAG,GAAkC;QAC1C,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,MAAM;QAChC,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC;QACpD,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;QACpC,GAAG,EAAE,IAAI,CAAC,GAAG;QACb,GAAG,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC;QACvC,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC;QACpC,GAAG,EAAE,CAAC,KAAK,EAAE,EAAE;YACd,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACjB,OAAO,GAAG,CAAC;QACZ,CAAC;QACD,SAAS,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;QACjD,MAAM,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrD,IAAI,KAAK;YACR,OAAO,IAAI,CAAC,KAAK,CAAC;QACnB,CAAC;KACD,CAAC;IACF,OAAO,GAAG,CAAC;AACZ,CAAC"}
@@ -0,0 +1,68 @@
1
+ import { type Duration, type Effect, type Schema, type Scope } from "effect";
2
+ import type * as Atom from "effect/reactivity/Atom";
3
+ import type * as AtomRef from "effect/reactivity/AtomRef";
4
+ import type { AtomRegistry } from "effect/reactivity/AtomRegistry";
5
+ import type { Reactivity } from "effect/reactivity/Reactivity";
6
+ import type { FieldMessages } from "./messages.ts";
7
+ import type { PersistedDraftConfig } from "./persistence.ts";
8
+ export type Fields = Schema.Struct.Fields;
9
+ export type Encoded<TFields extends Fields> = Schema.Struct.Encoded<TFields>;
10
+ export type Decoded<TFields extends Fields> = Schema.Struct.Type<TFields>;
11
+ export type Name<TFields extends Fields> = keyof Encoded<TFields> & string;
12
+ export type Path<TName extends string = string> = readonly [TName, ...PropertyKey[]];
13
+ export type ArrayKeys<TFields extends Fields> = {
14
+ readonly [TKey in Name<TFields>]?: NonNullable<Encoded<TFields>[TKey]> extends readonly (infer TElement)[] ? (element: TElement) => PropertyKey : never;
15
+ };
16
+ export type Services<TFields extends Fields, R> = R | Schema.Struct.DecodingServices<TFields>;
17
+ declare const FieldFailure_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
18
+ readonly _tag: "FieldFailure";
19
+ } & Readonly<A>;
20
+ export declare class FieldFailure extends FieldFailure_base<{
21
+ readonly message: string;
22
+ readonly path: string;
23
+ readonly segments?: Path;
24
+ }> {
25
+ }
26
+ declare const Invalid_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
27
+ readonly _tag: "Invalid";
28
+ } & Readonly<A>;
29
+ export declare class Invalid extends Invalid_base<{
30
+ readonly messages: FieldMessages;
31
+ }> {
32
+ }
33
+ export interface Submitter<TName extends string> {
34
+ readonly fail: (path: TName | Path<TName>, message: string) => Effect.Effect<never, FieldFailure>;
35
+ }
36
+ export type Checks<TFields extends Fields, R> = {
37
+ readonly [TKey in Name<TFields>]?: (value: Encoded<TFields>[TKey]) => Effect.Effect<string | undefined, never, R>;
38
+ };
39
+ export interface Config<TFields extends Fields, A, E, R, TRuntimeError> {
40
+ readonly arrayKeys?: ArrayKeys<TFields>;
41
+ readonly checks?: Checks<TFields, R>;
42
+ readonly debounce?: Duration.Input;
43
+ readonly initialValues: Encoded<TFields>;
44
+ readonly onSubmit: (values: Decoded<TFields>, submitter: Submitter<Name<TFields>>, submitted: Encoded<TFields>) => Effect.Effect<A, E, R | Scope.Scope | AtomRegistry | Reactivity>;
45
+ readonly persistedDraft?: PersistedDraftConfig | undefined;
46
+ readonly runtime: Atom.AtomRuntime<Services<TFields, R>, TRuntimeError>;
47
+ }
48
+ export interface Form<TFields extends Fields, A, E, TRuntimeError> {
49
+ readonly blur: (name: Name<TFields>) => void;
50
+ readonly change: <TKey extends Name<TFields>>(name: TKey, value: Encoded<TFields>[TKey]) => void;
51
+ readonly choices: <TKey extends Name<TFields>>(name: TKey) => readonly Encoded<TFields>[TKey][] | undefined;
52
+ readonly dirty: Atom.Atom<boolean>;
53
+ readonly error: (name: Name<TFields>) => Atom.Atom<string | undefined>;
54
+ readonly errorAt: (path: Path<Name<TFields>>) => Atom.Atom<string | undefined>;
55
+ readonly field: <TKey extends Name<TFields>>(name: TKey) => AtomRef.AtomRef<Encoded<TFields>[TKey]>;
56
+ readonly receive: (values: Encoded<TFields>) => void;
57
+ readonly revert: () => void;
58
+ readonly submit: Atom.AtomResultFn<void, A, E | TRuntimeError | FieldFailure | Invalid>;
59
+ readonly submitting: Atom.Atom<boolean>;
60
+ readonly values: AtomRef.AtomRef<Encoded<TFields>>;
61
+ }
62
+ export type Holder = AtomRef.AtomRef<Readonly<Record<string, unknown>>>;
63
+ export declare function holder(values: object): Holder;
64
+ export declare function fieldOf<TValue>(ref: AtomRef.AtomRef<unknown>): AtomRef.AtomRef<TValue>;
65
+ export declare function choicesOf<TValue>(choices: readonly unknown[] | undefined): readonly TValue[] | undefined;
66
+ export declare function checkOf<R>(check: unknown): (value: unknown) => Effect.Effect<string | undefined, never, R>;
67
+ export {};
68
+ //# sourceMappingURL=shape.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shape.d.ts","sourceRoot":"","sources":["../src/shape.ts"],"names":[],"mappings":"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"}