@arcote.tech/arc-react 0.1.2 → 0.1.4
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 +3 -2
- package/dist/form/form-part.d.ts +17 -0
- package/dist/form/form.d.ts +15 -9
- package/dist/form/index.d.ts +1 -0
- package/dist/index.js +216 -68
- package/dist/reactModel.d.ts +3 -3
- package/package.json +1 -1
package/dist/form/field.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ArcElement } from "@arcote.tech/arc
|
|
1
|
+
import type { ArcElement } from "@arcote.tech/arc";
|
|
2
2
|
import React from "react";
|
|
3
3
|
export type FormFieldContext = {
|
|
4
4
|
errors: any;
|
|
@@ -16,8 +16,9 @@ type FormFieldProps<E extends ArcElement> = {
|
|
|
16
16
|
export type FormFieldData<T> = {
|
|
17
17
|
onChange: (value: any) => void;
|
|
18
18
|
value: any;
|
|
19
|
+
defaultValue?: any;
|
|
19
20
|
name: string;
|
|
20
21
|
};
|
|
21
|
-
export declare function FormField<E extends ArcElement>(name: string): ({ translations, render }: FormFieldProps<E>) => import("react/jsx-dev-runtime").JSX.Element;
|
|
22
|
+
export declare function FormField<E extends ArcElement>(name: string, defaultValue?: any): ({ translations, render }: FormFieldProps<E>) => import("react/jsx-dev-runtime").JSX.Element;
|
|
22
23
|
export {};
|
|
23
24
|
//# sourceMappingURL=field.d.ts.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type ArcObjectAny } from "@arcote.tech/arc";
|
|
2
|
+
import React from "react";
|
|
3
|
+
export type FormPartContextValue = {
|
|
4
|
+
registerField: (field: string) => void;
|
|
5
|
+
unregisterField: (field: string) => void;
|
|
6
|
+
validatePart: () => boolean;
|
|
7
|
+
};
|
|
8
|
+
export declare const FormPartContext: React.Context<FormPartContextValue | null>;
|
|
9
|
+
export declare function FormPart({ children }: {
|
|
10
|
+
children: React.ReactNode;
|
|
11
|
+
}): import("react/jsx-dev-runtime").JSX.Element;
|
|
12
|
+
export declare namespace FormPart {
|
|
13
|
+
var displayName: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function useFormPart<T extends ArcObjectAny>(): FormPartContextValue;
|
|
16
|
+
export declare function useFormPartField(fieldName: string): FormPartContextValue | null;
|
|
17
|
+
//# sourceMappingURL=form-part.d.ts.map
|
package/dist/form/form.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ArcObjectAny, type ArcObjectKeys, type ArcObjectValueByKey } from "@arcote.tech/arc";
|
|
1
|
+
import { type $type, type ArcObjectAny, type ArcObjectKeys, type ArcObjectValueByKey } from "@arcote.tech/arc";
|
|
2
2
|
import React from "react";
|
|
3
3
|
import { FormField } from "./field";
|
|
4
4
|
export type FormContextValue<T extends ArcObjectAny> = {
|
|
@@ -8,16 +8,22 @@ export type FormContextValue<T extends ArcObjectAny> = {
|
|
|
8
8
|
isSubmitted: boolean;
|
|
9
9
|
setFieldValue: (field: ArcObjectKeys<T>, value: any) => void;
|
|
10
10
|
setFieldDirty: (field: ArcObjectKeys<T>) => void;
|
|
11
|
+
validatePartial: (keys: ArcObjectKeys<T>[]) => boolean;
|
|
11
12
|
};
|
|
12
|
-
export
|
|
13
|
-
|
|
13
|
+
export type FormRef<T extends ArcObjectAny> = {
|
|
14
|
+
submit: () => Promise<void>;
|
|
15
|
+
getValues: () => Partial<$type<T>>;
|
|
16
|
+
validate: () => boolean;
|
|
17
|
+
};
|
|
18
|
+
export type FormProps<T extends ArcObjectAny> = {
|
|
14
19
|
render: (props: {
|
|
15
20
|
[K in ArcObjectKeys<T> as Capitalize<`${K}`>]: ReturnType<typeof FormField<ArcObjectValueByKey<T, K>>>;
|
|
16
|
-
}) => React.ReactNode;
|
|
21
|
+
}, values: Partial<$type<T>>) => React.ReactNode;
|
|
17
22
|
schema: T;
|
|
18
|
-
onSubmit: (values:
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
onSubmit: (values: $type<T>) => void | Promise<void>;
|
|
24
|
+
onUnvalidatedSubmit?: (values: Partial<$type<T>>, errors: any) => void;
|
|
25
|
+
defaults?: Partial<$type<T>>;
|
|
26
|
+
};
|
|
27
|
+
export declare const FormContext: React.Context<FormContextValue<any> | null>;
|
|
28
|
+
export declare const Form: <T extends ArcObjectAny>(props: FormProps<T> & React.RefAttributes<FormRef<T>>) => JSX.Element;
|
|
23
29
|
//# sourceMappingURL=form.d.ts.map
|
package/dist/form/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,99 +1,195 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
// form/field.tsx
|
|
3
|
-
import { createContext as
|
|
3
|
+
import { createContext as createContext3, useCallback as useCallback3, useContext as useContext2, useMemo as useMemo2 } from "react";
|
|
4
4
|
|
|
5
5
|
// form/form.tsx
|
|
6
|
+
import {
|
|
7
|
+
deepMerge
|
|
8
|
+
} from "@arcote.tech/arc";
|
|
6
9
|
import {
|
|
7
10
|
createContext,
|
|
11
|
+
forwardRef,
|
|
8
12
|
useCallback,
|
|
9
13
|
useEffect,
|
|
14
|
+
useImperativeHandle,
|
|
10
15
|
useMemo,
|
|
11
16
|
useState
|
|
12
17
|
} from "react";
|
|
13
18
|
import { jsx } from "react/jsx-runtime";
|
|
14
19
|
var FormContext = createContext(null);
|
|
15
|
-
|
|
16
|
-
render,
|
|
17
|
-
schema,
|
|
18
|
-
onSubmit
|
|
19
|
-
}) {
|
|
20
|
+
var Form = forwardRef(function Form2(props, ref) {
|
|
21
|
+
const { render, schema, onSubmit, defaults, onUnvalidatedSubmit } = props;
|
|
20
22
|
const [values, setValues] = useState({});
|
|
21
23
|
const [errors, setErrors] = useState({});
|
|
22
24
|
const [dirty, setDirty] = useState(new Set);
|
|
23
25
|
const [isSubmitted, setIsSubmitted] = useState(false);
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
if (defaults) {
|
|
28
|
+
setValues((prev) => ({
|
|
29
|
+
...prev,
|
|
30
|
+
...defaults
|
|
31
|
+
}));
|
|
32
|
+
}
|
|
33
|
+
}, [defaults]);
|
|
24
34
|
const validate = useCallback(() => {
|
|
25
35
|
const errors2 = schema.validate(values);
|
|
26
36
|
setErrors(errors2);
|
|
37
|
+
setDirty(new Set(schema.entries().map(([key]) => key)));
|
|
27
38
|
return Object.values(errors2).some((result) => result);
|
|
28
39
|
}, [schema, values]);
|
|
40
|
+
const validatePartial = useCallback((keys) => {
|
|
41
|
+
const partialValues = keys.reduce((acc, key) => ({ ...acc, [key]: values[key] }), {});
|
|
42
|
+
const errors2 = schema.validatePartial(partialValues);
|
|
43
|
+
if (errors2)
|
|
44
|
+
setErrors((prev) => deepMerge(prev, errors2));
|
|
45
|
+
setDirty((prev) => {
|
|
46
|
+
const newSet = new Set([...prev, ...keys]);
|
|
47
|
+
if (newSet.size === prev.size && [...prev].every((key) => newSet.has(key))) {
|
|
48
|
+
return prev;
|
|
49
|
+
}
|
|
50
|
+
return newSet;
|
|
51
|
+
});
|
|
52
|
+
return Object.values(errors2).some((result) => result);
|
|
53
|
+
}, [schema, values, dirty]);
|
|
29
54
|
const setFieldValue = useCallback((field, value) => {
|
|
30
55
|
setValues((prev) => ({ ...prev, [field]: value }));
|
|
31
|
-
}, [
|
|
32
|
-
useEffect(() => {
|
|
33
|
-
if (isSubmitted) {
|
|
34
|
-
validate();
|
|
35
|
-
}
|
|
36
|
-
}, [isSubmitted, values]);
|
|
56
|
+
}, []);
|
|
37
57
|
const setFieldDirty = useCallback((field) => {
|
|
38
58
|
setDirty((prev) => new Set([...prev, field]));
|
|
39
59
|
}, []);
|
|
40
|
-
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
const partialValues = Array.from(dirty).reduce((acc, key) => ({ ...acc, [key]: values[key] }), {});
|
|
62
|
+
const errors2 = schema.validatePartial(partialValues);
|
|
63
|
+
setErrors(errors2);
|
|
64
|
+
}, [values, dirty]);
|
|
41
65
|
const handleSubmit = useCallback(async (e) => {
|
|
42
|
-
e
|
|
66
|
+
if (e) {
|
|
67
|
+
e.preventDefault();
|
|
68
|
+
}
|
|
43
69
|
setIsSubmitted(true);
|
|
44
|
-
const
|
|
45
|
-
if (!
|
|
70
|
+
const hasErrors = validate();
|
|
71
|
+
if (!hasErrors) {
|
|
46
72
|
await onSubmit(values);
|
|
73
|
+
} else {
|
|
74
|
+
onUnvalidatedSubmit?.(values, errors);
|
|
47
75
|
}
|
|
48
|
-
}, [schema, values, onSubmit,
|
|
76
|
+
}, [schema, values, onSubmit, validate, errors, onUnvalidatedSubmit]);
|
|
77
|
+
useImperativeHandle(ref, () => ({
|
|
78
|
+
submit: handleSubmit,
|
|
79
|
+
getValues: () => values,
|
|
80
|
+
validate
|
|
81
|
+
}), [handleSubmit, values, validate]);
|
|
49
82
|
const Fields = useMemo(() => {
|
|
50
83
|
return Object.fromEntries(schema.entries().map(([key, value]) => [
|
|
51
84
|
key.charAt(0).toUpperCase() + key.slice(1),
|
|
52
|
-
FormField(key)
|
|
85
|
+
FormField(key, defaults?.[key])
|
|
53
86
|
]));
|
|
54
|
-
}, [schema]);
|
|
87
|
+
}, [schema, defaults]);
|
|
55
88
|
const contextValue = useMemo(() => ({
|
|
56
89
|
values,
|
|
57
90
|
errors,
|
|
58
91
|
dirty,
|
|
59
92
|
isSubmitted,
|
|
60
93
|
setFieldValue,
|
|
61
|
-
setFieldDirty
|
|
62
|
-
|
|
94
|
+
setFieldDirty,
|
|
95
|
+
validatePartial
|
|
96
|
+
}), [
|
|
97
|
+
values,
|
|
98
|
+
errors,
|
|
99
|
+
dirty,
|
|
100
|
+
isSubmitted,
|
|
101
|
+
setFieldValue,
|
|
102
|
+
setFieldDirty,
|
|
103
|
+
validatePartial
|
|
104
|
+
]);
|
|
63
105
|
return /* @__PURE__ */ jsx(FormContext.Provider, {
|
|
64
106
|
value: contextValue,
|
|
65
107
|
children: /* @__PURE__ */ jsx("form", {
|
|
66
108
|
onSubmit: handleSubmit,
|
|
67
|
-
children: render(Fields)
|
|
109
|
+
children: render(Fields, values)
|
|
68
110
|
}, undefined, false, undefined, this)
|
|
69
111
|
}, undefined, false, undefined, this);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// form/form-part.tsx
|
|
115
|
+
import React2, { createContext as createContext2, useCallback as useCallback2, useContext, useState as useState2 } from "react";
|
|
116
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
117
|
+
var FormPartContext = createContext2(null);
|
|
118
|
+
function FormPart({ children }) {
|
|
119
|
+
const formContext = useContext(FormContext);
|
|
120
|
+
if (!formContext) {
|
|
121
|
+
throw new Error("FormPart must be used within a Form");
|
|
122
|
+
}
|
|
123
|
+
const [registeredFields, setRegisteredFields] = useState2(new Set);
|
|
124
|
+
const registerField = useCallback2((field) => {
|
|
125
|
+
setRegisteredFields((prev) => new Set([...prev, field]));
|
|
126
|
+
}, []);
|
|
127
|
+
const unregisterField = useCallback2((field) => {
|
|
128
|
+
setRegisteredFields((prev) => {
|
|
129
|
+
const newSet = new Set(prev);
|
|
130
|
+
newSet.delete(field);
|
|
131
|
+
return newSet;
|
|
132
|
+
});
|
|
133
|
+
}, []);
|
|
134
|
+
const validatePart = useCallback2(() => {
|
|
135
|
+
const { validatePartial } = formContext;
|
|
136
|
+
return validatePartial(Array.from(registeredFields));
|
|
137
|
+
}, [formContext, registeredFields]);
|
|
138
|
+
return /* @__PURE__ */ jsx2(FormPartContext.Provider, {
|
|
139
|
+
value: {
|
|
140
|
+
registerField,
|
|
141
|
+
unregisterField,
|
|
142
|
+
validatePart
|
|
143
|
+
},
|
|
144
|
+
children
|
|
145
|
+
}, undefined, false, undefined, this);
|
|
146
|
+
}
|
|
147
|
+
FormPart.displayName = "FormPart";
|
|
148
|
+
function useFormPart() {
|
|
149
|
+
const context = useContext(FormPartContext);
|
|
150
|
+
if (!context) {
|
|
151
|
+
throw new Error("useFormPart must be used within a FormPart");
|
|
152
|
+
}
|
|
153
|
+
return context;
|
|
154
|
+
}
|
|
155
|
+
function useFormPartField(fieldName) {
|
|
156
|
+
const context = useContext(FormPartContext);
|
|
157
|
+
if (!context)
|
|
158
|
+
return null;
|
|
159
|
+
React2.useEffect(() => {
|
|
160
|
+
context.registerField(fieldName);
|
|
161
|
+
return () => {
|
|
162
|
+
context.unregisterField(fieldName);
|
|
163
|
+
};
|
|
164
|
+
}, [fieldName]);
|
|
165
|
+
return context;
|
|
70
166
|
}
|
|
71
|
-
Form.displayName = "Form";
|
|
72
167
|
|
|
73
168
|
// form/field.tsx
|
|
74
|
-
import { jsx as
|
|
75
|
-
var FormFieldContext =
|
|
169
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
170
|
+
var FormFieldContext = createContext3(null);
|
|
76
171
|
function useFormField() {
|
|
77
|
-
const context =
|
|
172
|
+
const context = useContext2(FormFieldContext);
|
|
78
173
|
if (!context)
|
|
79
174
|
throw new Error("useFormField must be used within a FormFieldProvider");
|
|
80
175
|
return context;
|
|
81
176
|
}
|
|
82
|
-
function FormField(name) {
|
|
177
|
+
function FormField(name, defaultValue) {
|
|
83
178
|
return ({ translations, render }) => {
|
|
84
|
-
const form =
|
|
179
|
+
const form = useContext2(FormContext);
|
|
85
180
|
if (!form)
|
|
86
181
|
throw new Error("FormField must be used within a Form");
|
|
182
|
+
useFormPartField(name);
|
|
87
183
|
const { values, errors, dirty, isSubmitted, setFieldValue, setFieldDirty } = form;
|
|
88
184
|
const schemaErrors = errors?.["schema"] || {};
|
|
89
185
|
const fieldErrors = schemaErrors[name] || false;
|
|
90
|
-
const value = values[name]
|
|
186
|
+
const value = values[name] ?? defaultValue ?? "";
|
|
91
187
|
const isDirty = dirty.has(name);
|
|
92
|
-
const handleChange =
|
|
93
|
-
if (
|
|
94
|
-
setFieldValue(name, value2);
|
|
95
|
-
} else if (value2?.target?.value !== undefined) {
|
|
188
|
+
const handleChange = useCallback3((value2) => {
|
|
189
|
+
if (value2?.target?.value !== undefined) {
|
|
96
190
|
setFieldValue(name, value2.target.value);
|
|
191
|
+
} else {
|
|
192
|
+
setFieldValue(name, value2);
|
|
97
193
|
}
|
|
98
194
|
if (!isDirty) {
|
|
99
195
|
setFieldDirty(name);
|
|
@@ -116,12 +212,13 @@ function FormField(name) {
|
|
|
116
212
|
errors: isSubmitted ? fieldErrors : false,
|
|
117
213
|
messages: errorMessages
|
|
118
214
|
}), [fieldErrors, isSubmitted, errorMessages]);
|
|
119
|
-
return /* @__PURE__ */
|
|
215
|
+
return /* @__PURE__ */ jsx3(FormFieldContext.Provider, {
|
|
120
216
|
value: contextValue,
|
|
121
217
|
children: render({
|
|
122
218
|
onChange: handleChange,
|
|
123
219
|
name: name.toString(),
|
|
124
|
-
value
|
|
220
|
+
value,
|
|
221
|
+
defaultValue
|
|
125
222
|
})
|
|
126
223
|
}, undefined, false, undefined, this);
|
|
127
224
|
};
|
|
@@ -136,12 +233,12 @@ function formResolver(schema) {
|
|
|
136
233
|
};
|
|
137
234
|
}
|
|
138
235
|
// form/message.tsx
|
|
139
|
-
import { jsx as
|
|
236
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
140
237
|
function FormMessage({ ...props }) {
|
|
141
238
|
const { messages } = useFormField();
|
|
142
239
|
if (messages.length === 0)
|
|
143
240
|
return null;
|
|
144
|
-
return /* @__PURE__ */
|
|
241
|
+
return /* @__PURE__ */ jsx4("span", {
|
|
145
242
|
...props,
|
|
146
243
|
children: messages[0]
|
|
147
244
|
}, undefined, false, undefined, this);
|
|
@@ -155,12 +252,13 @@ import {
|
|
|
155
252
|
rtcClientFactory
|
|
156
253
|
} from "@arcote.tech/arc";
|
|
157
254
|
import {
|
|
158
|
-
createContext as
|
|
159
|
-
|
|
255
|
+
createContext as createContext4,
|
|
256
|
+
useCallback as useCallback4,
|
|
257
|
+
useContext as useContext3,
|
|
160
258
|
useEffect as useEffect2,
|
|
161
259
|
useMemo as useMemo3,
|
|
162
260
|
useRef,
|
|
163
|
-
useState as
|
|
261
|
+
useState as useState3
|
|
164
262
|
} from "react";
|
|
165
263
|
|
|
166
264
|
// sqliteWasmAdapter.ts
|
|
@@ -174,19 +272,22 @@ var sqliteWasmAdapterFactory = (db) => {
|
|
|
174
272
|
};
|
|
175
273
|
|
|
176
274
|
// reactModel.tsx
|
|
177
|
-
import { jsx as
|
|
275
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
178
276
|
var reactModel = (arcContextPromise, options) => {
|
|
179
|
-
const LiveModelContext =
|
|
180
|
-
const LocalModelContext =
|
|
277
|
+
const LiveModelContext = createContext4(null);
|
|
278
|
+
const LocalModelContext = createContext4(null);
|
|
181
279
|
let masterModel = null;
|
|
182
280
|
return [
|
|
183
281
|
function LiveModelProvider(props) {
|
|
184
|
-
const [context, setContext] =
|
|
282
|
+
const [context, setContext] = useState3(null);
|
|
185
283
|
useEffect2(() => {
|
|
186
284
|
arcContextPromise.then((arcContext) => {
|
|
187
285
|
setContext(arcContext);
|
|
188
286
|
});
|
|
189
287
|
}, [arcContextPromise]);
|
|
288
|
+
useEffect2(() => {
|
|
289
|
+
model?.setAuthToken(props.token);
|
|
290
|
+
}, [props.token]);
|
|
190
291
|
const model = useMemo3(() => {
|
|
191
292
|
if (typeof window === "undefined")
|
|
192
293
|
return null;
|
|
@@ -201,13 +302,13 @@ var reactModel = (arcContextPromise, options) => {
|
|
|
201
302
|
} else {
|
|
202
303
|
const dbAdapterPromise = sqliteWasmAdapterFactory(options.sqliteAdapter)(context);
|
|
203
304
|
const dataStorage = new MasterDataStorage(dbAdapterPromise, rtcClientFactory(props.token), context);
|
|
204
|
-
const model2 = new Model(context, dataStorage, props.
|
|
305
|
+
const model2 = new Model(context, dataStorage, props.catchErrorCallback);
|
|
205
306
|
masterModel = model2;
|
|
206
307
|
return model2;
|
|
207
308
|
}
|
|
208
309
|
}, [context, options, props.client]);
|
|
209
|
-
const [syncProgress, setSyncProgress] =
|
|
210
|
-
const [syncDone, setSyncDone] =
|
|
310
|
+
const [syncProgress, setSyncProgress] = useState3([]);
|
|
311
|
+
const [syncDone, setSyncDone] = useState3(false);
|
|
211
312
|
useEffect2(() => {
|
|
212
313
|
if (typeof window === "undefined" || !model)
|
|
213
314
|
return;
|
|
@@ -222,81 +323,128 @@ var reactModel = (arcContextPromise, options) => {
|
|
|
222
323
|
sync();
|
|
223
324
|
}, [model]);
|
|
224
325
|
if (!model || !syncDone)
|
|
225
|
-
return props.syncView ? /* @__PURE__ */
|
|
326
|
+
return props.syncView ? /* @__PURE__ */ jsx5(props.syncView, {
|
|
226
327
|
progress: syncProgress
|
|
227
328
|
}, undefined, false, undefined, this) : null;
|
|
228
|
-
return /* @__PURE__ */
|
|
329
|
+
return /* @__PURE__ */ jsx5(LiveModelContext.Provider, {
|
|
229
330
|
value: model,
|
|
230
331
|
children: props.children
|
|
231
332
|
}, undefined, false, undefined, this);
|
|
232
333
|
},
|
|
233
334
|
function LocalModelProvider({ children }) {
|
|
234
|
-
const parentModel =
|
|
335
|
+
const parentModel = useContext3(LiveModelContext);
|
|
235
336
|
if (!parentModel || !(parentModel instanceof Model)) {
|
|
236
337
|
throw new Error("LocalModelProvider must be used within a LiveModelProvider");
|
|
237
338
|
}
|
|
238
|
-
const [localModel] =
|
|
239
|
-
return /* @__PURE__ */
|
|
339
|
+
const [localModel] = useState3(() => parentModel);
|
|
340
|
+
return /* @__PURE__ */ jsx5(LocalModelContext.Provider, {
|
|
240
341
|
value: localModel,
|
|
241
342
|
children
|
|
242
343
|
}, undefined, false, undefined, this);
|
|
243
344
|
},
|
|
244
|
-
function useQuery(queryBuilderFn, dependencies = []) {
|
|
245
|
-
const model =
|
|
345
|
+
function useQuery(queryBuilderFn, dependencies = [], cacheKey) {
|
|
346
|
+
const model = useContext3(LocalModelContext) || useContext3(LiveModelContext);
|
|
246
347
|
if (!model) {
|
|
247
348
|
throw new Error("useQuery must be used within a ModelProvider");
|
|
248
349
|
}
|
|
249
|
-
const [result, setResult] =
|
|
250
|
-
const [
|
|
350
|
+
const [result, setResult] = useState3(null);
|
|
351
|
+
const [revalidationTrigger, setRevalidationTrigger] = useState3(0);
|
|
251
352
|
const unsubscribeRef = useRef(null);
|
|
353
|
+
useEffect2(() => {
|
|
354
|
+
if (cacheKey) {
|
|
355
|
+
if (!model.__cacheRegistry) {
|
|
356
|
+
model.__cacheRegistry = new Map;
|
|
357
|
+
}
|
|
358
|
+
if (!model.__cacheRegistry.has(cacheKey)) {
|
|
359
|
+
model.__cacheRegistry.set(cacheKey, new Set);
|
|
360
|
+
}
|
|
361
|
+
const revalidateFn = () => {
|
|
362
|
+
setRevalidationTrigger((prev) => prev + 1);
|
|
363
|
+
};
|
|
364
|
+
model.__cacheRegistry.get(cacheKey).add(revalidateFn);
|
|
365
|
+
return () => {
|
|
366
|
+
const registry = model.__cacheRegistry?.get(cacheKey);
|
|
367
|
+
if (registry) {
|
|
368
|
+
registry.delete(revalidateFn);
|
|
369
|
+
if (registry.size === 0) {
|
|
370
|
+
model.__cacheRegistry.delete(cacheKey);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
}, [model, cacheKey]);
|
|
252
376
|
useEffect2(() => {
|
|
253
377
|
if (unsubscribeRef.current) {
|
|
254
378
|
unsubscribeRef.current();
|
|
255
379
|
}
|
|
380
|
+
const defaultAuthContext = { userId: "react-user", roles: ["user"] };
|
|
256
381
|
const { unsubscribe, result: result2 } = model.subscribe(queryBuilderFn, (newResult) => {
|
|
257
382
|
setResult(newResult);
|
|
258
|
-
|
|
259
|
-
});
|
|
383
|
+
}, defaultAuthContext);
|
|
260
384
|
unsubscribeRef.current = unsubscribe;
|
|
261
|
-
result2.then(() => {
|
|
262
|
-
setLoading(false);
|
|
263
|
-
});
|
|
264
385
|
return () => {
|
|
265
386
|
if (unsubscribeRef.current) {
|
|
266
387
|
unsubscribeRef.current();
|
|
267
388
|
unsubscribeRef.current = null;
|
|
268
389
|
}
|
|
269
390
|
};
|
|
270
|
-
}, [model, ...dependencies]);
|
|
271
|
-
return [result
|
|
391
|
+
}, [model, revalidationTrigger, ...dependencies]);
|
|
392
|
+
return [result];
|
|
393
|
+
},
|
|
394
|
+
function useRevalidate() {
|
|
395
|
+
const model = useContext3(LocalModelContext) || useContext3(LiveModelContext);
|
|
396
|
+
if (!model) {
|
|
397
|
+
throw new Error("useRevalidate must be used within a ModelProvider");
|
|
398
|
+
}
|
|
399
|
+
return useCallback4((cacheKey) => {
|
|
400
|
+
const registry = model.__cacheRegistry;
|
|
401
|
+
if (registry && registry.has(cacheKey)) {
|
|
402
|
+
const revalidators = registry.get(cacheKey);
|
|
403
|
+
revalidators?.forEach((revalidateFn) => {
|
|
404
|
+
revalidateFn();
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
}, [model]);
|
|
272
408
|
},
|
|
273
409
|
function useCommands() {
|
|
274
|
-
const model =
|
|
410
|
+
const model = useContext3(LocalModelContext) || useContext3(LiveModelContext);
|
|
275
411
|
if (!model) {
|
|
276
412
|
throw new Error("useCommands must be used within a ModelProvider");
|
|
277
413
|
}
|
|
278
|
-
|
|
414
|
+
const defaultAuthContext = { userId: "react-user", roles: ["user"] };
|
|
415
|
+
return model.commands(defaultAuthContext);
|
|
279
416
|
},
|
|
280
417
|
async function query(queryBuilderFn, model) {
|
|
281
418
|
if (!model)
|
|
282
419
|
model = masterModel;
|
|
283
420
|
if (!model)
|
|
284
421
|
throw new Error("Model not found");
|
|
285
|
-
|
|
422
|
+
const defaultAuthContext = { userId: "react-user", roles: ["user"] };
|
|
423
|
+
return model.query(queryBuilderFn, defaultAuthContext);
|
|
286
424
|
},
|
|
287
425
|
function useLocalModel() {
|
|
288
|
-
const model =
|
|
426
|
+
const model = useContext3(LocalModelContext);
|
|
289
427
|
if (!model) {
|
|
290
428
|
return null;
|
|
291
429
|
}
|
|
292
430
|
return model;
|
|
431
|
+
},
|
|
432
|
+
function useModel(token) {
|
|
433
|
+
const parentModel = useContext3(LiveModelContext);
|
|
434
|
+
if (!parentModel)
|
|
435
|
+
throw new Error("useModel have to be used in Provider");
|
|
436
|
+
return parentModel;
|
|
293
437
|
}
|
|
294
438
|
];
|
|
295
439
|
};
|
|
296
440
|
export {
|
|
441
|
+
useFormPartField,
|
|
442
|
+
useFormPart,
|
|
297
443
|
useFormField,
|
|
298
444
|
reactModel,
|
|
299
445
|
formResolver,
|
|
446
|
+
FormPartContext,
|
|
447
|
+
FormPart,
|
|
300
448
|
FormMessage,
|
|
301
449
|
FormFieldContext,
|
|
302
450
|
FormField,
|
|
@@ -304,4 +452,4 @@ export {
|
|
|
304
452
|
Form
|
|
305
453
|
};
|
|
306
454
|
|
|
307
|
-
//# debugId=
|
|
455
|
+
//# debugId=8ECE7A0A6915EECC64756E2164756E21
|
package/dist/reactModel.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { SQLiteDatabase } from "@arcote.tech/arc";
|
|
1
|
+
import { Model, type ArcContextAny, type IArcQueryBuilder, type ModelBase, type QueryBuilderFunctionResult, type QueryFactoryFunction, type UnaryFunction } from "@arcote.tech/arc";
|
|
2
|
+
import type { ArcContextElementMethodReturnType, SQLiteDatabase } from "@arcote.tech/arc";
|
|
3
3
|
export declare const reactModel: <C extends ArcContextAny>(arcContextPromise: Promise<C>, options: {
|
|
4
4
|
sqliteAdapter: SQLiteDatabase;
|
|
5
5
|
} | {
|
|
@@ -17,5 +17,5 @@ export declare const reactModel: <C extends ArcContextAny>(arcContextPromise: Pr
|
|
|
17
17
|
catchErrorCallback: (error: any) => void;
|
|
18
18
|
}) => import("react/jsx-dev-runtime").JSX.Element | null, ({ children }: {
|
|
19
19
|
children: React.ReactNode;
|
|
20
|
-
}) => import("react/jsx-dev-runtime").JSX.Element, <Q extends IArcQueryBuilder>(queryBuilderFn: UnaryFunction<ReturnType<C["queryBuilder"]>, Q>, dependencies?: any[]) => [ReturnType<Q["toQuery"]>["lastResult"],
|
|
20
|
+
}) => import("react/jsx-dev-runtime").JSX.Element, <Q extends IArcQueryBuilder>(queryBuilderFn: UnaryFunction<ReturnType<C["queryBuilder"]>, Q>, dependencies?: any[], cacheKey?: string) => [ReturnType<Q["toQuery"]>["lastResult"]], () => (cacheKey: string) => void, () => ArcContextElementMethodReturnType<C["elements"], "commandClient">, <QueryBuilderFn extends QueryFactoryFunction<C>>(queryBuilderFn: QueryBuilderFn, model?: ModelBase<C> | null) => Promise<QueryBuilderFunctionResult<QueryBuilderFn>>, () => Model<C> | null, (token: string) => ModelBase<C>];
|
|
21
21
|
//# sourceMappingURL=reactModel.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arcote.tech/arc-react",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.4",
|
|
5
5
|
"private": false,
|
|
6
6
|
"author": "Przemysław Krasiński [arcote.tech]",
|
|
7
7
|
"description": "React client for the Arc framework, providing utilities for querying data and executing commands, enhancing the development of reactive and efficient user interfaces.",
|