@arcote.tech/arc-react 0.0.28 → 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.
@@ -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,122 @@
1
- // form.ts
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,
@@ -70,6 +243,8 @@ class IDBReadTransaction {
70
243
  const keyPath = idbIndex.keyPath;
71
244
  let keyRange;
72
245
  const getKey = (obj) => {
246
+ if (!obj)
247
+ return;
73
248
  const key = keyPath.map((key2) => obj[key2]);
74
249
  if (key.some((value) => value === undefined))
75
250
  return;
@@ -91,7 +266,6 @@ class IDBReadTransaction {
91
266
  } else {
92
267
  keyRange = IDBKeyRange.only(simpleKey);
93
268
  }
94
- console.log(keyRange);
95
269
  const result = idbIndex.getAll(keyRange);
96
270
  result.onsuccess = (e) => {
97
271
  resolve(e.target.result);
@@ -165,21 +339,22 @@ import {
165
339
  rtcClientFactory
166
340
  } from "@arcote.tech/arc";
167
341
  import {
168
- createContext,
169
- useContext,
170
- useEffect,
171
- useMemo,
342
+ createContext as createContext3,
343
+ useContext as useContext2,
344
+ useEffect as useEffect2,
345
+ useMemo as useMemo3,
172
346
  useRef,
173
- useState
347
+ useState as useState2
174
348
  } from "react";
175
- import { jsx } from "react/jsx-runtime";
349
+ import { jsx as jsx5 } from "react/jsx-runtime";
350
+ "use client";
176
351
  var reactModel = (arcContext, databaseName) => {
177
- const LiveModelContext = createContext(null);
178
- const LocalModelContext = createContext(null);
352
+ const LiveModelContext = createContext3(null);
353
+ const LocalModelContext = createContext3(null);
179
354
  let modelMasterDataStorage = null;
180
355
  return [
181
356
  function LiveModelProvider(props) {
182
- const dataStorage = useMemo(() => {
357
+ const dataStorage = useMemo3(() => {
183
358
  if (typeof window === "undefined")
184
359
  return null;
185
360
  const dbAdapterPromise = idbAdapterFactory(databaseName, arcContext.version)(arcContext);
@@ -187,9 +362,9 @@ var reactModel = (arcContext, databaseName) => {
187
362
  modelMasterDataStorage = dataStorage2;
188
363
  return dataStorage2;
189
364
  }, [arcContext, databaseName, arcContext.version]);
190
- const [syncProgress, setSyncProgress] = useState([]);
191
- const [syncDone, setSyncDone] = useState(false);
192
- useEffect(() => {
365
+ const [syncProgress, setSyncProgress] = useState2([]);
366
+ const [syncDone, setSyncDone] = useState2(false);
367
+ useEffect2(() => {
193
368
  if (typeof window === "undefined" || !dataStorage)
194
369
  return;
195
370
  const sync = async () => {
@@ -201,10 +376,10 @@ var reactModel = (arcContext, databaseName) => {
201
376
  sync();
202
377
  }, [dataStorage]);
203
378
  if (!dataStorage || !syncDone)
204
- return /* @__PURE__ */ jsx(props.syncView, {
379
+ return /* @__PURE__ */ jsx5(props.syncView, {
205
380
  progress: syncProgress
206
381
  }, undefined, false, undefined, this);
207
- return /* @__PURE__ */ jsx(LiveModelContext.Provider, {
382
+ return /* @__PURE__ */ jsx5(LiveModelContext.Provider, {
208
383
  value: {
209
384
  dataStorage,
210
385
  client: props.client,
@@ -214,14 +389,14 @@ var reactModel = (arcContext, databaseName) => {
214
389
  }, undefined, false, undefined, this);
215
390
  },
216
391
  function LocalModelProvider({ children }) {
217
- const parentContext = useContext(LiveModelContext);
392
+ const parentContext = useContext2(LiveModelContext);
218
393
  if (!parentContext) {
219
394
  throw new Error("LocalModelProvider must be used within a LiveModelProvider");
220
395
  }
221
- const [localContext] = useState(() => ({
396
+ const [localContext] = useState2(() => ({
222
397
  dataStorage: parentContext.dataStorage.fork()
223
398
  }));
224
- return /* @__PURE__ */ jsx(LocalModelContext.Provider, {
399
+ return /* @__PURE__ */ jsx5(LocalModelContext.Provider, {
225
400
  value: {
226
401
  dataStorage: localContext.dataStorage,
227
402
  client: parentContext.client,
@@ -231,14 +406,14 @@ var reactModel = (arcContext, databaseName) => {
231
406
  }, undefined, false, undefined, this);
232
407
  },
233
408
  function useQuery(queryBuilderFn, dependencies = []) {
234
- const context = useContext(LocalModelContext) || useContext(LiveModelContext);
409
+ const context = useContext2(LocalModelContext) || useContext2(LiveModelContext);
235
410
  if (!context) {
236
411
  throw new Error("useQuery must be used within a ModelProvider");
237
412
  }
238
- const [result, setResult] = useState(null);
239
- const [loading, setLoading] = useState(true);
413
+ const [result, setResult] = useState2(null);
414
+ const [loading, setLoading] = useState2(true);
240
415
  const queryRef = useRef(null);
241
- useEffect(() => {
416
+ useEffect2(() => {
242
417
  if (queryRef.current)
243
418
  queryRef.current.unsubscribe();
244
419
  const queryBuilder = arcContext.queryBuilder();
@@ -261,7 +436,7 @@ var reactModel = (arcContext, databaseName) => {
261
436
  return [result, loading];
262
437
  },
263
438
  function useCommands() {
264
- const context = useContext(LocalModelContext) || useContext(LiveModelContext);
439
+ const context = useContext2(LocalModelContext) || useContext2(LiveModelContext);
265
440
  if (!context) {
266
441
  throw new Error("useQuery must be used within a ModelProvider");
267
442
  }
@@ -278,7 +453,7 @@ var reactModel = (arcContext, databaseName) => {
278
453
  return result;
279
454
  },
280
455
  function useLocalDataStorage() {
281
- const context = useContext(LocalModelContext);
456
+ const context = useContext2(LocalModelContext);
282
457
  if (!context) {
283
458
  return null;
284
459
  }
@@ -287,9 +462,16 @@ var reactModel = (arcContext, databaseName) => {
287
462
  ];
288
463
  };
289
464
  export {
465
+ useFormField,
290
466
  reactModel,
291
467
  idbAdapterFactory,
292
- formResolver
468
+ formResolver,
469
+ Test,
470
+ FormMessage,
471
+ FormFieldContext,
472
+ FormField,
473
+ FormContext,
474
+ Form
293
475
  };
294
476
 
295
- //# debugId=EB0E8168D4E98EF264756E2164756E21
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.28",
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.",