@arcote.tech/arc-react 0.0.1
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.d.ts +5 -0
- package/dist/idb.d.ts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +13456 -0
- package/dist/reactModel.d.ts +5 -0
- package/form.ts +12 -0
- package/idb.ts +166 -0
- package/index.ts +2 -0
- package/package.json +33 -0
- package/reactModel.tsx +82 -0
- package/tsconfig.types.json +11 -0
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type ArcModelDependencies, type GetAnyCollectionQueryResult, type QueryFactoryFunction } from "@arcote.tech/arc";
|
|
2
|
+
import type { ArcContextWithCommandsAny } from "@arcote.tech/arc/context/context";
|
|
3
|
+
export declare const reactModel: <C extends ArcContextWithCommandsAny>(context: C, dependecies: ArcModelDependencies<C>) => readonly [(props: {
|
|
4
|
+
children: React.ReactNode;
|
|
5
|
+
}) => "Ekran ładowania" | import("react/jsx-runtime").JSX.Element, <QueryBuilderFn extends QueryFactoryFunction<C>>(queryBuilder: QueryBuilderFn, dependencies?: any[]) => [GetAnyCollectionQueryResult<QueryBuilderFn>, false] | [null, true], () => import("@arcote.tech/arc/context/commands").CommandsClient<C["commands"]>];
|
package/form.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type ArcObjectAny } from "@arcote.tech/arc";
|
|
2
|
+
|
|
3
|
+
export function formResolver(schema: ArcObjectAny) {
|
|
4
|
+
return async (data: any) => {
|
|
5
|
+
// const { valid, errors } = await schema.validate(data);
|
|
6
|
+
|
|
7
|
+
return {
|
|
8
|
+
values: data,
|
|
9
|
+
errors: {},
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
}
|
package/idb.ts
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import type { util } from "@arcote.tech/arc";
|
|
2
|
+
import {
|
|
3
|
+
ArcIndexedCollection,
|
|
4
|
+
type ArcCollectionAny,
|
|
5
|
+
type ArcIndexedCollectionAny,
|
|
6
|
+
} from "@arcote.tech/arc/collection/collection";
|
|
7
|
+
import type {
|
|
8
|
+
DatabaseAdapter,
|
|
9
|
+
DBAdapterFactory,
|
|
10
|
+
ReadTransaction,
|
|
11
|
+
ReadWriteTransaction,
|
|
12
|
+
} from "@arcote.tech/arc/collection/db";
|
|
13
|
+
|
|
14
|
+
export const idbAdapterFactory =
|
|
15
|
+
(name: string, version: number): DBAdapterFactory =>
|
|
16
|
+
(context) =>
|
|
17
|
+
new Promise((resolve, reject) => {
|
|
18
|
+
const dbRequest = indexedDB.open(name, version);
|
|
19
|
+
|
|
20
|
+
dbRequest.addEventListener("error", (err) => {
|
|
21
|
+
reject(err);
|
|
22
|
+
});
|
|
23
|
+
dbRequest.addEventListener("success", (ev: any) => {
|
|
24
|
+
resolve(new IDBAdapter(ev.target.result));
|
|
25
|
+
});
|
|
26
|
+
dbRequest.addEventListener("upgradeneeded", (ev: any) => {
|
|
27
|
+
const db = ev.target.result as IDBDatabase;
|
|
28
|
+
|
|
29
|
+
context.collections.forEach((collection) => {
|
|
30
|
+
const name = collection.name;
|
|
31
|
+
if (db.objectStoreNames.contains(name)) {
|
|
32
|
+
db.deleteObjectStore(collection.name);
|
|
33
|
+
}
|
|
34
|
+
const objectStore = db.createObjectStore(collection.name, {
|
|
35
|
+
keyPath: "_id",
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
if (collection instanceof ArcIndexedCollection) {
|
|
39
|
+
Object.entries(collection.indexes).forEach(([name, keyPath]) => {
|
|
40
|
+
objectStore.createIndex(name, keyPath as string[], {
|
|
41
|
+
unique: false,
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
class IDBReadTransaction implements ReadTransaction {
|
|
50
|
+
constructor(protected transaction: IDBTransaction) {}
|
|
51
|
+
|
|
52
|
+
async findById<C extends ArcCollectionAny>(
|
|
53
|
+
collection: C,
|
|
54
|
+
id: util.GetType<C["id"]>
|
|
55
|
+
) {
|
|
56
|
+
return new Promise<util.CollectionItemWithId<C>>((resolve) => {
|
|
57
|
+
const result = this.transaction.objectStore(collection.name).get(id);
|
|
58
|
+
result.onsuccess = (e: any) => {
|
|
59
|
+
const deserialized = collection.deserialize(e.target.result);
|
|
60
|
+
resolve(deserialized as any);
|
|
61
|
+
};
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async findByIndex<C extends ArcIndexedCollectionAny>(
|
|
66
|
+
collection: C,
|
|
67
|
+
index: string,
|
|
68
|
+
data: any
|
|
69
|
+
) {
|
|
70
|
+
return new Promise<util.CollectionItemWithId<C>[]>((resolve) => {
|
|
71
|
+
const idbIndex = this.transaction
|
|
72
|
+
.objectStore(collection.name)
|
|
73
|
+
.index(index);
|
|
74
|
+
const value = (idbIndex.keyPath as string[]).map((key) => data[key]);
|
|
75
|
+
const keyRange = IDBKeyRange.only(value);
|
|
76
|
+
const result = idbIndex.getAll(keyRange);
|
|
77
|
+
result.onsuccess = (e: any) => {
|
|
78
|
+
const deserialized = e.target.result.map((e: any) =>
|
|
79
|
+
collection.deserialize(e)
|
|
80
|
+
);
|
|
81
|
+
resolve(deserialized as any);
|
|
82
|
+
};
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async findAll<C extends ArcCollectionAny>(collection: C): Promise<any[]> {
|
|
87
|
+
return new Promise<util.CollectionItemWithId<C>[]>((resolve) => {
|
|
88
|
+
const result = this.transaction.objectStore(collection.name).getAll();
|
|
89
|
+
result.onsuccess = (e: any) => {
|
|
90
|
+
const deserialized = e.target.result.map((e: any) =>
|
|
91
|
+
collection.deserialize(e)
|
|
92
|
+
);
|
|
93
|
+
resolve(deserialized as any);
|
|
94
|
+
};
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
class IDBReadWriteTransaction
|
|
100
|
+
extends IDBReadTransaction
|
|
101
|
+
implements ReadWriteTransaction
|
|
102
|
+
{
|
|
103
|
+
async set<C extends ArcCollectionAny>(
|
|
104
|
+
collection: C,
|
|
105
|
+
data: util.CollectionItemWithId<C>
|
|
106
|
+
) {
|
|
107
|
+
return new Promise<void>((resolve, reject) => {
|
|
108
|
+
const serialized = collection.serialize(data as any);
|
|
109
|
+
const result = this.transaction
|
|
110
|
+
.objectStore(collection.name)
|
|
111
|
+
.put(serialized);
|
|
112
|
+
result.onsuccess = (e) => {
|
|
113
|
+
resolve();
|
|
114
|
+
};
|
|
115
|
+
result.onerror = (e) => {
|
|
116
|
+
reject(e);
|
|
117
|
+
};
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async remove<C extends ArcCollectionAny>(
|
|
122
|
+
collection: C,
|
|
123
|
+
id: util.GetType<C["id"]>
|
|
124
|
+
) {
|
|
125
|
+
return new Promise<void>((resolve, reject) => {
|
|
126
|
+
const result = this.transaction.objectStore(collection.name).delete(id);
|
|
127
|
+
result.onsuccess = (e) => {
|
|
128
|
+
resolve();
|
|
129
|
+
};
|
|
130
|
+
result.onerror = (e) => {
|
|
131
|
+
reject(e);
|
|
132
|
+
};
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async commit() {
|
|
137
|
+
return new Promise<void>((resolve) => {
|
|
138
|
+
this.transaction.oncomplete = () => {
|
|
139
|
+
resolve();
|
|
140
|
+
};
|
|
141
|
+
this.transaction.commit();
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
class IDBAdapter implements DatabaseAdapter {
|
|
147
|
+
constructor(private db: IDBDatabase) {}
|
|
148
|
+
|
|
149
|
+
readWriteTransaction(collections: ArcCollectionAny[]) {
|
|
150
|
+
const transaction = this.db.transaction(
|
|
151
|
+
collections.map((c) => c.name),
|
|
152
|
+
"readwrite"
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
return new IDBReadWriteTransaction(transaction);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
readTransaction(collections: ArcCollectionAny[]) {
|
|
159
|
+
const transaction = this.db.transaction(
|
|
160
|
+
collections.map((c) => c.name),
|
|
161
|
+
"readonly"
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
return new IDBReadTransaction(transaction);
|
|
165
|
+
}
|
|
166
|
+
}
|
package/index.ts
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@arcote.tech/arc-react",
|
|
3
|
+
"module": "index.ts",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"types": "dist/index.d.ts",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"version": "0.0.1",
|
|
8
|
+
"private": false,
|
|
9
|
+
"author": "Przemysław Krasiński [arcote.tech]",
|
|
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.",
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "bun build --target=node ./index.ts --outfile=dist/index.js && bun run build:declaration",
|
|
13
|
+
"build:declaration": "tsc --emitDeclarationOnly --project tsconfig.types.json",
|
|
14
|
+
"postbuild": "rimraf tsconfig.types.tsbuildinfo",
|
|
15
|
+
"type-check": "tsc"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@arcote.tech/arc": "0.0.1",
|
|
19
|
+
"react": "^18.3.1",
|
|
20
|
+
"rxjs": "^7.8.1"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@arcote.tech/arc": "workspace:*",
|
|
24
|
+
"@types/bun": "latest",
|
|
25
|
+
"@types/react": "^18.3.5",
|
|
26
|
+
"prettier": "^3.0.3",
|
|
27
|
+
"rimraf": "^5.0.5",
|
|
28
|
+
"typescript": "^5.2.2"
|
|
29
|
+
},
|
|
30
|
+
"peerDependencies": {
|
|
31
|
+
"typescript": "^5.0.0"
|
|
32
|
+
}
|
|
33
|
+
}
|
package/reactModel.tsx
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type ArcModelDependencies,
|
|
3
|
+
type GetAnyCollectionQueryResult,
|
|
4
|
+
type QueryFactoryFunction,
|
|
5
|
+
ArcCollectionQuery,
|
|
6
|
+
ArcModel,
|
|
7
|
+
model,
|
|
8
|
+
} from "@arcote.tech/arc";
|
|
9
|
+
import type { ArcContextWithCommandsAny } from "@arcote.tech/arc/context/context";
|
|
10
|
+
import { createContext, useContext, useEffect, useRef, useState } from "react";
|
|
11
|
+
|
|
12
|
+
export const reactModel = <C extends ArcContextWithCommandsAny>(
|
|
13
|
+
context: C,
|
|
14
|
+
dependecies: ArcModelDependencies<C>
|
|
15
|
+
) => {
|
|
16
|
+
const LiveModelContext = createContext<null | {
|
|
17
|
+
client: ArcModel<C>;
|
|
18
|
+
}>(null);
|
|
19
|
+
|
|
20
|
+
return [
|
|
21
|
+
function LiveModelProvider(props: { children: React.ReactNode }) {
|
|
22
|
+
const [client, setClient] = useState<ArcModel<C> | null>(null);
|
|
23
|
+
const clientRef = useRef<ArcModel<C> | null>(null);
|
|
24
|
+
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
if (clientRef.current) return;
|
|
27
|
+
|
|
28
|
+
const client = model(context, dependecies);
|
|
29
|
+
clientRef.current = client;
|
|
30
|
+
setClient(client);
|
|
31
|
+
}, []);
|
|
32
|
+
|
|
33
|
+
if (!client) return "Ekran ładowania";
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<LiveModelContext.Provider
|
|
37
|
+
value={{
|
|
38
|
+
client,
|
|
39
|
+
}}
|
|
40
|
+
>
|
|
41
|
+
{props.children}
|
|
42
|
+
</LiveModelContext.Provider>
|
|
43
|
+
);
|
|
44
|
+
},
|
|
45
|
+
function useQuery<QueryBuilderFn extends QueryFactoryFunction<C>>(
|
|
46
|
+
queryBuilder: QueryBuilderFn,
|
|
47
|
+
dependencies: any[] = []
|
|
48
|
+
): [GetAnyCollectionQueryResult<QueryBuilderFn>, false] | [null, true] {
|
|
49
|
+
const context = useContext(LiveModelContext);
|
|
50
|
+
if (!context)
|
|
51
|
+
throw new Error("useQuery must be used within a LiveModelProvider");
|
|
52
|
+
|
|
53
|
+
if (!context.client) throw new Error("client not found");
|
|
54
|
+
|
|
55
|
+
const [result, setResult] = useState<any>(null);
|
|
56
|
+
const [loading, setLoading] = useState<boolean>(true);
|
|
57
|
+
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
const query = context.client.query(queryBuilder);
|
|
60
|
+
|
|
61
|
+
if (!(query instanceof ArcCollectionQuery)) throw new Error();
|
|
62
|
+
|
|
63
|
+
query.result$.subscribe((result: any) => {
|
|
64
|
+
setResult(result);
|
|
65
|
+
setLoading(false);
|
|
66
|
+
});
|
|
67
|
+
return () => {
|
|
68
|
+
query.unsubscribe();
|
|
69
|
+
};
|
|
70
|
+
}, [context.client, ...dependencies]);
|
|
71
|
+
|
|
72
|
+
return [result, loading];
|
|
73
|
+
},
|
|
74
|
+
function useCommands() {
|
|
75
|
+
const context = useContext(LiveModelContext);
|
|
76
|
+
if (!context)
|
|
77
|
+
throw new Error("useCommands must be used within a LiveModelProvider");
|
|
78
|
+
|
|
79
|
+
return context.client.commands();
|
|
80
|
+
},
|
|
81
|
+
] as const;
|
|
82
|
+
};
|