@arcote.tech/arc-react 0.0.29 → 0.0.31

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