@animaapp/anima-sdk-react 0.1.0
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/.turbo/turbo-build.log +21 -0
- package/dist/index.cjs +22 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.js +5293 -0
- package/dist/index.js.map +1 -0
- package/package.json +44 -0
- package/src/index.ts +2 -0
- package/src/useAnimaCodegen.ts +202 -0
- package/src/useFigmaFile.ts +44 -0
- package/vite.config.ts +27 -0
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@animaapp/anima-sdk-react",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Anima's JavaScript utilities library",
|
|
6
|
+
"author": "Anima App, Inc.",
|
|
7
|
+
"license": "ISC",
|
|
8
|
+
"packageManager": "yarn@4.6.0",
|
|
9
|
+
"exports": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"require": "./dist/index.cjs"
|
|
12
|
+
},
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/AnimaApp/anima-sdk.git"
|
|
17
|
+
},
|
|
18
|
+
"publishConfig": {
|
|
19
|
+
"access": "public",
|
|
20
|
+
"registry": "https://registry.npmjs.org/"
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "vite build",
|
|
24
|
+
"tests": "vitest run --dir ./tests",
|
|
25
|
+
"prepack": "yarn build"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"eventsource": "^3.0.5",
|
|
29
|
+
"immer": "^10.1.1",
|
|
30
|
+
"swr": "^2.3.2",
|
|
31
|
+
"use-immer": "^0.11.0"
|
|
32
|
+
},
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"@animaapp/anima-sdk": "workspace:*",
|
|
35
|
+
"react": "^17.x.x || ^18.x.x || ^19.x.x"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@animaapp/anima-sdk": "workspace:*",
|
|
39
|
+
"vite": "^6.0.11",
|
|
40
|
+
"vite-plugin-dts": "^4.5.0",
|
|
41
|
+
"vite-tsconfig-paths": "^5.1.4",
|
|
42
|
+
"vitest": "^3.0.5"
|
|
43
|
+
}
|
|
44
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AnimaSDKResult,
|
|
3
|
+
GetCodeParams,
|
|
4
|
+
StreamCodgenMessage,
|
|
5
|
+
} from "@animaapp/anima-sdk";
|
|
6
|
+
import { convertCodegenFilesToAnimaFiles } from "@animaapp/anima-sdk";
|
|
7
|
+
import { EventSource } from "eventsource";
|
|
8
|
+
import { useImmer } from "use-immer";
|
|
9
|
+
|
|
10
|
+
type Status = "idle" | "pending" | "success" | "aborted" | "error";
|
|
11
|
+
|
|
12
|
+
type TaskStatus = "pending" | "running" | "finished";
|
|
13
|
+
|
|
14
|
+
type CodegenStatus = {
|
|
15
|
+
status: Status;
|
|
16
|
+
error: Error | null;
|
|
17
|
+
result: AnimaSDKResult | null;
|
|
18
|
+
tasks: {
|
|
19
|
+
fetchDesign: { status: TaskStatus };
|
|
20
|
+
codeGeneration: { status: TaskStatus; progress: number };
|
|
21
|
+
uploadAssets: { status: TaskStatus };
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const defaultProgress: CodegenStatus = {
|
|
26
|
+
status: "idle",
|
|
27
|
+
error: null,
|
|
28
|
+
result: null,
|
|
29
|
+
tasks: {
|
|
30
|
+
fetchDesign: { status: "pending" },
|
|
31
|
+
codeGeneration: { status: "pending", progress: 0 },
|
|
32
|
+
uploadAssets: { status: "pending" },
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
type StreamMessageByType<T extends StreamCodgenMessage['type']> = Extract<StreamCodgenMessage, { type: T }>;
|
|
37
|
+
|
|
38
|
+
export const useAnimaCodegen = ({
|
|
39
|
+
url,
|
|
40
|
+
method = "POST",
|
|
41
|
+
}: {
|
|
42
|
+
url: string;
|
|
43
|
+
method?: string;
|
|
44
|
+
}) => {
|
|
45
|
+
const [status, updateStatus] = useImmer<CodegenStatus>(defaultProgress);
|
|
46
|
+
|
|
47
|
+
const getCode = async <T = GetCodeParams>(params: T) => {
|
|
48
|
+
updateStatus((draft) => {
|
|
49
|
+
draft.status = "pending";
|
|
50
|
+
draft.error = null;
|
|
51
|
+
draft.result = null;
|
|
52
|
+
draft.tasks = defaultProgress.tasks;
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const es = new EventSource(url, {
|
|
56
|
+
fetch: (url, init) =>
|
|
57
|
+
fetch(url, {
|
|
58
|
+
...init,
|
|
59
|
+
method,
|
|
60
|
+
body: JSON.stringify(params),
|
|
61
|
+
}),
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const promise = new Promise<{
|
|
65
|
+
result: AnimaSDKResult | null;
|
|
66
|
+
error: Error | null;
|
|
67
|
+
}>((resolve) => {
|
|
68
|
+
|
|
69
|
+
const result: Partial<AnimaSDKResult> = {};
|
|
70
|
+
|
|
71
|
+
// Add specific event listeners
|
|
72
|
+
es.addEventListener('start', (event) => {
|
|
73
|
+
const message = JSON.parse(event.data) as StreamMessageByType<'start'>;
|
|
74
|
+
result.sessionId = message.sessionId;
|
|
75
|
+
|
|
76
|
+
updateStatus((draft) => {
|
|
77
|
+
draft.tasks.fetchDesign.status = "running";
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
es.addEventListener('pre_codegen', (event) => {
|
|
82
|
+
const message = JSON.parse(event.data) as StreamMessageByType<'pre_codegen'>;
|
|
83
|
+
if (message.message === "Anima model built") {
|
|
84
|
+
updateStatus((draft) => {
|
|
85
|
+
draft.tasks.fetchDesign.status = "finished";
|
|
86
|
+
draft.tasks.codeGeneration.status = "running";
|
|
87
|
+
draft.tasks.uploadAssets.status = "running";
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
es.addEventListener('figma_metadata', (e) => {
|
|
93
|
+
const message = JSON.parse(e.data) as StreamMessageByType<'figma_metadata'>;
|
|
94
|
+
result.figmaFileName = message.figmaFileName;
|
|
95
|
+
result.figmaSelectedFrameName = message.figmaSelectedFrameName;
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
es.addEventListener('aborted', (e) => {
|
|
99
|
+
updateStatus((draft) => {
|
|
100
|
+
draft.status = "aborted";
|
|
101
|
+
});
|
|
102
|
+
resolve({
|
|
103
|
+
result: null,
|
|
104
|
+
error: new Error("The request was aborted"),
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
es.addEventListener('generating_code', (e) => {
|
|
109
|
+
const message = JSON.parse(e.data) as StreamMessageByType<'generating_code'>;
|
|
110
|
+
if (message.payload.status === "success") {
|
|
111
|
+
const codegenFiles = message.payload.files as Record<
|
|
112
|
+
string,
|
|
113
|
+
{ code: string; type: "code" }
|
|
114
|
+
>;
|
|
115
|
+
|
|
116
|
+
result.files = convertCodegenFilesToAnimaFiles(codegenFiles);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
updateStatus((draft) => {
|
|
120
|
+
draft.tasks.codeGeneration.progress = message.payload.progress;
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
es.addEventListener('codegen_completed', (e) => {
|
|
125
|
+
updateStatus((draft) => {
|
|
126
|
+
draft.tasks.codeGeneration.status = "finished";
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
es.addEventListener('assets_uploaded', (e) => {
|
|
131
|
+
updateStatus((draft) => {
|
|
132
|
+
draft.tasks.uploadAssets.status = "finished";
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
es.addEventListener('error', (e: ErrorEvent | MessageEvent) => {
|
|
137
|
+
// Differentiate between an error message from the server and an error event from the EventSource
|
|
138
|
+
if (e instanceof MessageEvent) {
|
|
139
|
+
const message = JSON.parse(e.data) as StreamMessageByType<'error'>;
|
|
140
|
+
updateStatus((draft) => {
|
|
141
|
+
draft.status = "error";
|
|
142
|
+
draft.error = new Error(message.payload.message);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
resolve({
|
|
146
|
+
result: null,
|
|
147
|
+
error: new Error(message.payload.message),
|
|
148
|
+
});
|
|
149
|
+
} else {
|
|
150
|
+
// It's an EventSource error (e.g. HTTP error)
|
|
151
|
+
console.error('EventSource error:', e);
|
|
152
|
+
|
|
153
|
+
updateStatus((draft) => {
|
|
154
|
+
draft.status = "error";
|
|
155
|
+
draft.error = new Error("HTTP error: " + e.message);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
resolve({
|
|
159
|
+
result: null,
|
|
160
|
+
error: new Error("HTTP error: " + e.message),
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
es.addEventListener('done', (event) => {
|
|
166
|
+
updateStatus((draft) => {
|
|
167
|
+
draft.status = "success";
|
|
168
|
+
draft.result = result as AnimaSDKResult;
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
resolve({ result: result as AnimaSDKResult, error: null });
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
try {
|
|
176
|
+
const { result, error } = await promise;
|
|
177
|
+
|
|
178
|
+
if (error) {
|
|
179
|
+
return { result: null, error };
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (Object.keys(result?.files ?? {}).length === 0) {
|
|
183
|
+
return {
|
|
184
|
+
result: null,
|
|
185
|
+
error: new Error("No files received"),
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return { result, error };
|
|
190
|
+
} finally {
|
|
191
|
+
es.close();
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
return {
|
|
196
|
+
getCode,
|
|
197
|
+
status: status.status,
|
|
198
|
+
tasks: status.tasks,
|
|
199
|
+
error: status.error,
|
|
200
|
+
result: status.result,
|
|
201
|
+
};
|
|
202
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import useSWR from "swr";
|
|
2
|
+
import { getFigmaFile } from "@animaapp/anima-sdk";
|
|
3
|
+
|
|
4
|
+
export const useFigmaFile = ({
|
|
5
|
+
fileKey,
|
|
6
|
+
authToken,
|
|
7
|
+
enabled = true,
|
|
8
|
+
params = {},
|
|
9
|
+
}: {
|
|
10
|
+
fileKey: string;
|
|
11
|
+
authToken: string;
|
|
12
|
+
enabled?: boolean;
|
|
13
|
+
params?: {
|
|
14
|
+
depth?: number;
|
|
15
|
+
};
|
|
16
|
+
}) => {
|
|
17
|
+
const isEnabled = Boolean(enabled && fileKey && authToken);
|
|
18
|
+
|
|
19
|
+
const { data, isLoading, error } = useSWR(
|
|
20
|
+
["figma", fileKey, authToken, params],
|
|
21
|
+
() => {
|
|
22
|
+
if (!isEnabled) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return getFigmaFile({
|
|
27
|
+
fileKey,
|
|
28
|
+
authToken,
|
|
29
|
+
params,
|
|
30
|
+
});
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
revalidateIfStale: false,
|
|
34
|
+
revalidateOnFocus: false,
|
|
35
|
+
revalidateOnReconnect: false,
|
|
36
|
+
}
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
data: data ?? null,
|
|
41
|
+
isLoading,
|
|
42
|
+
error,
|
|
43
|
+
};
|
|
44
|
+
};
|
package/vite.config.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { defineConfig } from "vite";
|
|
2
|
+
import dts from "vite-plugin-dts";
|
|
3
|
+
import tsconfigPaths from "vite-tsconfig-paths";
|
|
4
|
+
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
build: {
|
|
7
|
+
lib: {
|
|
8
|
+
entry: "./src/index.ts",
|
|
9
|
+
formats: ["cjs", "es"],
|
|
10
|
+
fileName: "index",
|
|
11
|
+
},
|
|
12
|
+
outDir: "./dist",
|
|
13
|
+
emptyOutDir: true,
|
|
14
|
+
target: "es6",
|
|
15
|
+
sourcemap: true,
|
|
16
|
+
rollupOptions: {
|
|
17
|
+
external: ["react"],
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
plugins: [
|
|
21
|
+
tsconfigPaths(),
|
|
22
|
+
dts({
|
|
23
|
+
rollupTypes: true,
|
|
24
|
+
insertTypesEntry: true,
|
|
25
|
+
}),
|
|
26
|
+
],
|
|
27
|
+
});
|