@arcote.tech/arc-react 0.0.29 → 0.0.30
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/dist/form/field.d.ts +24 -0
- package/dist/form/form.d.ts +23 -0
- package/dist/form/index.d.ts +6 -0
- package/dist/{form.d.ts → form/legacy_form_resolver.d.ts} +2 -2
- package/dist/form/message.d.ts +3 -0
- package/dist/form/test.d.ts +2 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +207 -26
- package/package.json +1 -1
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type ArcObjectAny, type ArcObjectKeys, type ArcObjectValueByKey } from "@arcote.tech/arc";
|
|
2
|
+
import type { ArcAbstractAny } from "@arcote.tech/arc/elements/abstract";
|
|
3
|
+
import React from "react";
|
|
4
|
+
export type FormFieldContext = {
|
|
5
|
+
errors: any;
|
|
6
|
+
messages: any;
|
|
7
|
+
};
|
|
8
|
+
export declare const FormFieldContext: React.Context<FormFieldContext | null>;
|
|
9
|
+
export declare function useFormField(): FormFieldContext;
|
|
10
|
+
type Translations<E extends ArcAbstractAny> = {
|
|
11
|
+
[K in keyof ReturnType<E["validate"]>]: (data: Exclude<ReturnType<E["validate"]>[K], undefined>) => string;
|
|
12
|
+
};
|
|
13
|
+
type FormFieldProps<T extends ArcObjectAny, K extends ArcObjectKeys<T>> = {
|
|
14
|
+
name: K;
|
|
15
|
+
translations: Translations<ArcObjectValueByKey<T, K>>;
|
|
16
|
+
render: (field: FormFieldData<T>) => React.ReactNode;
|
|
17
|
+
};
|
|
18
|
+
export type FormFieldData<T> = {
|
|
19
|
+
onChange: (value: any) => void;
|
|
20
|
+
value: any;
|
|
21
|
+
};
|
|
22
|
+
export declare function FormField<T extends ArcObjectAny, K extends ArcObjectKeys<T>>({ name, translations, render, }: FormFieldProps<T, K>): import("react/jsx-dev-runtime").JSX.Element;
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=field.d.ts.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type ArcObjectAny, type ArcObjectKeys } from "@arcote.tech/arc";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { FormField } from "./field";
|
|
4
|
+
export type FormContextValue<T extends ArcObjectAny> = {
|
|
5
|
+
values: Partial<Record<ArcObjectKeys<T>, any>>;
|
|
6
|
+
errors: Partial<Record<ArcObjectKeys<T>, Record<string, any>>>;
|
|
7
|
+
dirty: Set<ArcObjectKeys<T>>;
|
|
8
|
+
isSubmitted: boolean;
|
|
9
|
+
setFieldValue: (field: ArcObjectKeys<T>, value: any) => void;
|
|
10
|
+
setFieldDirty: (field: ArcObjectKeys<T>) => void;
|
|
11
|
+
};
|
|
12
|
+
export declare const FormContext: React.Context<FormContextValue<any> | null>;
|
|
13
|
+
export declare function Form<T extends ArcObjectAny>({ render, schema, onSubmit, }: {
|
|
14
|
+
render: (props: {
|
|
15
|
+
FormField: typeof FormField<T, ArcObjectKeys<T>>;
|
|
16
|
+
}) => React.ReactNode;
|
|
17
|
+
schema: T;
|
|
18
|
+
onSubmit: (values: Record<ArcObjectKeys<T>, any>) => void | Promise<void>;
|
|
19
|
+
}): import("react/jsx-dev-runtime").JSX.Element;
|
|
20
|
+
export declare namespace Form {
|
|
21
|
+
var displayName: string;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=form.d.ts.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { ArcObjectAny } from "@arcote.tech/arc";
|
|
2
2
|
export declare function formResolver(schema: ArcObjectAny): (data: any) => Promise<{
|
|
3
3
|
values: any;
|
|
4
4
|
errors: {};
|
|
5
5
|
}>;
|
|
6
|
-
//# sourceMappingURL=
|
|
6
|
+
//# sourceMappingURL=legacy_form_resolver.d.ts.map
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,4 +1,122 @@
|
|
|
1
|
-
// form.
|
|
1
|
+
// form/field.tsx
|
|
2
|
+
import { createContext as createContext2, useCallback as useCallback2, useContext, useMemo as useMemo2 } from "react";
|
|
3
|
+
|
|
4
|
+
// form/form.tsx
|
|
5
|
+
import {
|
|
6
|
+
createContext,
|
|
7
|
+
useCallback,
|
|
8
|
+
useEffect,
|
|
9
|
+
useMemo,
|
|
10
|
+
useState
|
|
11
|
+
} from "react";
|
|
12
|
+
import { jsx } from "react/jsx-runtime";
|
|
13
|
+
"use client";
|
|
14
|
+
var FormContext = createContext(null);
|
|
15
|
+
function Form({
|
|
16
|
+
render,
|
|
17
|
+
schema,
|
|
18
|
+
onSubmit
|
|
19
|
+
}) {
|
|
20
|
+
const [values, setValues] = useState({});
|
|
21
|
+
const [errors, setErrors] = useState({});
|
|
22
|
+
const [dirty, setDirty] = useState(new Set);
|
|
23
|
+
const [isSubmitted, setIsSubmitted] = useState(false);
|
|
24
|
+
const validate = useCallback(() => {
|
|
25
|
+
console.log("validate", values, schema);
|
|
26
|
+
const errors2 = schema.validate(values);
|
|
27
|
+
setErrors(errors2);
|
|
28
|
+
return Object.values(errors2).some((result) => result);
|
|
29
|
+
}, [schema, values]);
|
|
30
|
+
const setFieldValue = useCallback((field, value) => {
|
|
31
|
+
setValues((prev) => ({ ...prev, [field]: value }));
|
|
32
|
+
}, [schema, isSubmitted]);
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
if (isSubmitted) {
|
|
35
|
+
validate();
|
|
36
|
+
}
|
|
37
|
+
}, [isSubmitted, values]);
|
|
38
|
+
const setFieldDirty = useCallback((field) => {
|
|
39
|
+
setDirty((prev) => new Set([...prev, field]));
|
|
40
|
+
}, []);
|
|
41
|
+
const hasErrors = useMemo(() => Object.values(errors).some((result) => result), [errors]);
|
|
42
|
+
const handleSubmit = useCallback(async (e) => {
|
|
43
|
+
e.preventDefault();
|
|
44
|
+
setIsSubmitted(true);
|
|
45
|
+
validate();
|
|
46
|
+
if (!hasErrors) {
|
|
47
|
+
await onSubmit(values);
|
|
48
|
+
}
|
|
49
|
+
}, [schema, values, onSubmit, hasErrors]);
|
|
50
|
+
const FF = useCallback(FormField, []);
|
|
51
|
+
const contextValue = useMemo(() => ({
|
|
52
|
+
values,
|
|
53
|
+
errors,
|
|
54
|
+
dirty,
|
|
55
|
+
isSubmitted,
|
|
56
|
+
setFieldValue,
|
|
57
|
+
setFieldDirty
|
|
58
|
+
}), [values, errors, dirty, isSubmitted, setFieldValue, setFieldDirty]);
|
|
59
|
+
return /* @__PURE__ */ jsx(FormContext.Provider, {
|
|
60
|
+
value: contextValue,
|
|
61
|
+
children: /* @__PURE__ */ jsx("form", {
|
|
62
|
+
onSubmit: handleSubmit,
|
|
63
|
+
children: render({ FormField: FF })
|
|
64
|
+
}, undefined, false, undefined, this)
|
|
65
|
+
}, undefined, false, undefined, this);
|
|
66
|
+
}
|
|
67
|
+
Form.displayName = "Form";
|
|
68
|
+
|
|
69
|
+
// form/field.tsx
|
|
70
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
71
|
+
"use client";
|
|
72
|
+
var FormFieldContext = createContext2(null);
|
|
73
|
+
function useFormField() {
|
|
74
|
+
const context = useContext(FormFieldContext);
|
|
75
|
+
if (!context)
|
|
76
|
+
throw new Error("useFormField must be used within a FormFieldProvider");
|
|
77
|
+
return context;
|
|
78
|
+
}
|
|
79
|
+
function FormField({
|
|
80
|
+
name,
|
|
81
|
+
translations,
|
|
82
|
+
render
|
|
83
|
+
}) {
|
|
84
|
+
const form = useContext(FormContext);
|
|
85
|
+
if (!form)
|
|
86
|
+
throw new Error("FormField must be used within a Form");
|
|
87
|
+
const { values, errors, dirty, isSubmitted, setFieldValue, setFieldDirty } = form;
|
|
88
|
+
const fieldErrors = errors[name] || {};
|
|
89
|
+
const value = values[name] || "";
|
|
90
|
+
const isDirty = dirty.has(name);
|
|
91
|
+
const handleChange = useCallback2((value2) => {
|
|
92
|
+
if (typeof value2 === "string") {
|
|
93
|
+
setFieldValue(name, value2);
|
|
94
|
+
} else if (value2?.target?.value !== undefined) {
|
|
95
|
+
setFieldValue(name, value2.target.value);
|
|
96
|
+
}
|
|
97
|
+
if (!isDirty) {
|
|
98
|
+
setFieldDirty(name);
|
|
99
|
+
}
|
|
100
|
+
}, [name, isDirty, setFieldValue, setFieldDirty]);
|
|
101
|
+
const errorMessages = Object.entries(fieldErrors).map(([key, value2]) => {
|
|
102
|
+
if (!value2)
|
|
103
|
+
return;
|
|
104
|
+
const translation = translations[key];
|
|
105
|
+
return translation?.(value2);
|
|
106
|
+
}).filter(Boolean);
|
|
107
|
+
const contextValue = useMemo2(() => ({
|
|
108
|
+
errors: isSubmitted ? fieldErrors : {},
|
|
109
|
+
messages: errorMessages
|
|
110
|
+
}), [fieldErrors, isSubmitted, errorMessages]);
|
|
111
|
+
return /* @__PURE__ */ jsx2(FormFieldContext.Provider, {
|
|
112
|
+
value: contextValue,
|
|
113
|
+
children: render({
|
|
114
|
+
onChange: handleChange,
|
|
115
|
+
value
|
|
116
|
+
})
|
|
117
|
+
}, undefined, false, undefined, this);
|
|
118
|
+
}
|
|
119
|
+
// form/legacy_form_resolver.ts
|
|
2
120
|
function formResolver(schema) {
|
|
3
121
|
return async (data) => {
|
|
4
122
|
return {
|
|
@@ -7,6 +125,61 @@ function formResolver(schema) {
|
|
|
7
125
|
};
|
|
8
126
|
};
|
|
9
127
|
}
|
|
128
|
+
// form/message.tsx
|
|
129
|
+
import React3 from "react";
|
|
130
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
131
|
+
"use client";
|
|
132
|
+
var FormMessage = React3.forwardRef(({}, ref) => {
|
|
133
|
+
const { messages } = useFormField();
|
|
134
|
+
if (messages.length === 0)
|
|
135
|
+
return null;
|
|
136
|
+
return /* @__PURE__ */ jsx3("div", {
|
|
137
|
+
className: "text-destructive",
|
|
138
|
+
ref,
|
|
139
|
+
children: messages[0]
|
|
140
|
+
}, undefined, false, undefined, this);
|
|
141
|
+
});
|
|
142
|
+
FormMessage.displayName = "FormMessage";
|
|
143
|
+
// form/test.tsx
|
|
144
|
+
import { object, string } from "@arcote.tech/arc";
|
|
145
|
+
import { jsx as jsx4, Fragment } from "react/jsx-runtime";
|
|
146
|
+
"use client";
|
|
147
|
+
function Test() {
|
|
148
|
+
const schema = object({
|
|
149
|
+
username: string().minLength(3).maxLength(10)
|
|
150
|
+
});
|
|
151
|
+
const handleSubmit = async (values) => {
|
|
152
|
+
console.log("Form submitted:", values);
|
|
153
|
+
};
|
|
154
|
+
return /* @__PURE__ */ jsx4(Form, {
|
|
155
|
+
schema,
|
|
156
|
+
onSubmit: handleSubmit,
|
|
157
|
+
render: ({ FormField: FormField2 }) => /* @__PURE__ */ jsx4("div", {
|
|
158
|
+
children: [
|
|
159
|
+
/* @__PURE__ */ jsx4(FormField2, {
|
|
160
|
+
name: "username",
|
|
161
|
+
translations: {
|
|
162
|
+
minLength: ({ minLength }) => `Username must be at least ${minLength} characters long`,
|
|
163
|
+
maxLength: ({ maxLength }) => `Username must be at most ${maxLength} characters long`
|
|
164
|
+
},
|
|
165
|
+
render: (field) => /* @__PURE__ */ jsx4(Fragment, {
|
|
166
|
+
children: [
|
|
167
|
+
/* @__PURE__ */ jsx4("input", {
|
|
168
|
+
className: "border border-gray-300 rounded-md p-2",
|
|
169
|
+
...field
|
|
170
|
+
}, undefined, false, undefined, this),
|
|
171
|
+
/* @__PURE__ */ jsx4(FormMessage, {}, undefined, false, undefined, this)
|
|
172
|
+
]
|
|
173
|
+
}, undefined, true, undefined, this)
|
|
174
|
+
}, undefined, false, undefined, this),
|
|
175
|
+
/* @__PURE__ */ jsx4("button", {
|
|
176
|
+
type: "submit",
|
|
177
|
+
children: "Submit"
|
|
178
|
+
}, undefined, false, undefined, this)
|
|
179
|
+
]
|
|
180
|
+
}, undefined, true, undefined, this)
|
|
181
|
+
}, undefined, false, undefined, this);
|
|
182
|
+
}
|
|
10
183
|
// idb.ts
|
|
11
184
|
import {
|
|
12
185
|
ArcCollection,
|
|
@@ -166,21 +339,22 @@ import {
|
|
|
166
339
|
rtcClientFactory
|
|
167
340
|
} from "@arcote.tech/arc";
|
|
168
341
|
import {
|
|
169
|
-
createContext,
|
|
170
|
-
useContext,
|
|
171
|
-
useEffect,
|
|
172
|
-
useMemo,
|
|
342
|
+
createContext as createContext3,
|
|
343
|
+
useContext as useContext2,
|
|
344
|
+
useEffect as useEffect2,
|
|
345
|
+
useMemo as useMemo3,
|
|
173
346
|
useRef,
|
|
174
|
-
useState
|
|
347
|
+
useState as useState2
|
|
175
348
|
} from "react";
|
|
176
|
-
import { jsx } from "react/jsx-runtime";
|
|
349
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
350
|
+
"use client";
|
|
177
351
|
var reactModel = (arcContext, databaseName) => {
|
|
178
|
-
const LiveModelContext =
|
|
179
|
-
const LocalModelContext =
|
|
352
|
+
const LiveModelContext = createContext3(null);
|
|
353
|
+
const LocalModelContext = createContext3(null);
|
|
180
354
|
let modelMasterDataStorage = null;
|
|
181
355
|
return [
|
|
182
356
|
function LiveModelProvider(props) {
|
|
183
|
-
const dataStorage =
|
|
357
|
+
const dataStorage = useMemo3(() => {
|
|
184
358
|
if (typeof window === "undefined")
|
|
185
359
|
return null;
|
|
186
360
|
const dbAdapterPromise = idbAdapterFactory(databaseName, arcContext.version)(arcContext);
|
|
@@ -188,9 +362,9 @@ var reactModel = (arcContext, databaseName) => {
|
|
|
188
362
|
modelMasterDataStorage = dataStorage2;
|
|
189
363
|
return dataStorage2;
|
|
190
364
|
}, [arcContext, databaseName, arcContext.version]);
|
|
191
|
-
const [syncProgress, setSyncProgress] =
|
|
192
|
-
const [syncDone, setSyncDone] =
|
|
193
|
-
|
|
365
|
+
const [syncProgress, setSyncProgress] = useState2([]);
|
|
366
|
+
const [syncDone, setSyncDone] = useState2(false);
|
|
367
|
+
useEffect2(() => {
|
|
194
368
|
if (typeof window === "undefined" || !dataStorage)
|
|
195
369
|
return;
|
|
196
370
|
const sync = async () => {
|
|
@@ -202,10 +376,10 @@ var reactModel = (arcContext, databaseName) => {
|
|
|
202
376
|
sync();
|
|
203
377
|
}, [dataStorage]);
|
|
204
378
|
if (!dataStorage || !syncDone)
|
|
205
|
-
return /* @__PURE__ */
|
|
379
|
+
return /* @__PURE__ */ jsx5(props.syncView, {
|
|
206
380
|
progress: syncProgress
|
|
207
381
|
}, undefined, false, undefined, this);
|
|
208
|
-
return /* @__PURE__ */
|
|
382
|
+
return /* @__PURE__ */ jsx5(LiveModelContext.Provider, {
|
|
209
383
|
value: {
|
|
210
384
|
dataStorage,
|
|
211
385
|
client: props.client,
|
|
@@ -215,14 +389,14 @@ var reactModel = (arcContext, databaseName) => {
|
|
|
215
389
|
}, undefined, false, undefined, this);
|
|
216
390
|
},
|
|
217
391
|
function LocalModelProvider({ children }) {
|
|
218
|
-
const parentContext =
|
|
392
|
+
const parentContext = useContext2(LiveModelContext);
|
|
219
393
|
if (!parentContext) {
|
|
220
394
|
throw new Error("LocalModelProvider must be used within a LiveModelProvider");
|
|
221
395
|
}
|
|
222
|
-
const [localContext] =
|
|
396
|
+
const [localContext] = useState2(() => ({
|
|
223
397
|
dataStorage: parentContext.dataStorage.fork()
|
|
224
398
|
}));
|
|
225
|
-
return /* @__PURE__ */
|
|
399
|
+
return /* @__PURE__ */ jsx5(LocalModelContext.Provider, {
|
|
226
400
|
value: {
|
|
227
401
|
dataStorage: localContext.dataStorage,
|
|
228
402
|
client: parentContext.client,
|
|
@@ -232,14 +406,14 @@ var reactModel = (arcContext, databaseName) => {
|
|
|
232
406
|
}, undefined, false, undefined, this);
|
|
233
407
|
},
|
|
234
408
|
function useQuery(queryBuilderFn, dependencies = []) {
|
|
235
|
-
const context =
|
|
409
|
+
const context = useContext2(LocalModelContext) || useContext2(LiveModelContext);
|
|
236
410
|
if (!context) {
|
|
237
411
|
throw new Error("useQuery must be used within a ModelProvider");
|
|
238
412
|
}
|
|
239
|
-
const [result, setResult] =
|
|
240
|
-
const [loading, setLoading] =
|
|
413
|
+
const [result, setResult] = useState2(null);
|
|
414
|
+
const [loading, setLoading] = useState2(true);
|
|
241
415
|
const queryRef = useRef(null);
|
|
242
|
-
|
|
416
|
+
useEffect2(() => {
|
|
243
417
|
if (queryRef.current)
|
|
244
418
|
queryRef.current.unsubscribe();
|
|
245
419
|
const queryBuilder = arcContext.queryBuilder();
|
|
@@ -262,7 +436,7 @@ var reactModel = (arcContext, databaseName) => {
|
|
|
262
436
|
return [result, loading];
|
|
263
437
|
},
|
|
264
438
|
function useCommands() {
|
|
265
|
-
const context =
|
|
439
|
+
const context = useContext2(LocalModelContext) || useContext2(LiveModelContext);
|
|
266
440
|
if (!context) {
|
|
267
441
|
throw new Error("useQuery must be used within a ModelProvider");
|
|
268
442
|
}
|
|
@@ -279,7 +453,7 @@ var reactModel = (arcContext, databaseName) => {
|
|
|
279
453
|
return result;
|
|
280
454
|
},
|
|
281
455
|
function useLocalDataStorage() {
|
|
282
|
-
const context =
|
|
456
|
+
const context = useContext2(LocalModelContext);
|
|
283
457
|
if (!context) {
|
|
284
458
|
return null;
|
|
285
459
|
}
|
|
@@ -288,9 +462,16 @@ var reactModel = (arcContext, databaseName) => {
|
|
|
288
462
|
];
|
|
289
463
|
};
|
|
290
464
|
export {
|
|
465
|
+
useFormField,
|
|
291
466
|
reactModel,
|
|
292
467
|
idbAdapterFactory,
|
|
293
|
-
formResolver
|
|
468
|
+
formResolver,
|
|
469
|
+
Test,
|
|
470
|
+
FormMessage,
|
|
471
|
+
FormFieldContext,
|
|
472
|
+
FormField,
|
|
473
|
+
FormContext,
|
|
474
|
+
Form
|
|
294
475
|
};
|
|
295
476
|
|
|
296
|
-
//# debugId=
|
|
477
|
+
//# debugId=1DDD66A12E066C4464756E2164756E21
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"type": "module",
|
|
7
|
-
"version": "0.0.
|
|
7
|
+
"version": "0.0.30",
|
|
8
8
|
"private": false,
|
|
9
9
|
"author": "Przemysław Krasiński [arcote.tech]",
|
|
10
10
|
"description": "React client for the Arc framework, providing utilities for querying data and executing commands, enhancing the development of reactive and efficient user interfaces.",
|