@pulse-editor/react-api 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/README.md ADDED
@@ -0,0 +1 @@
1
+ This directory contains source code for the NPM package "pulse-editor/api". Third party developers can use context and wrapper utilities to make their Pulse Editor using React.
@@ -0,0 +1,5 @@
1
+ {
2
+ "presets": [
3
+ "@babel/preset-env"
4
+ ]
5
+ }
@@ -0,0 +1,29 @@
1
+ import globals from "globals";
2
+ import pluginJs from "@eslint/js";
3
+ import tseslint from "typescript-eslint";
4
+ import pluginReact from "eslint-plugin-react";
5
+
6
+ /** @type {import('eslint').Linter.Config[]} */
7
+ export default [
8
+ {
9
+ files: ["**/*.{js,mjs,cjs,ts,jsx,tsx}"],
10
+ },
11
+ {
12
+ ignores: ["node_modules/**", "dist/**"],
13
+ },
14
+ {
15
+ languageOptions: { globals: globals.browser },
16
+ settings: {
17
+ react: { version: "detect" },
18
+ },
19
+ },
20
+ pluginJs.configs.recommended,
21
+ ...tseslint.configs.recommended,
22
+ pluginReact.configs.flat.recommended,
23
+ {
24
+ rules: {
25
+ "@typescript-eslint/no-explicit-any": "off",
26
+ "@typescript-eslint/no-unused-vars": "off",
27
+ },
28
+ },
29
+ ];
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@pulse-editor/react-api",
3
+ "version": "0.0.1",
4
+ "main": "src/main.ts",
5
+ "type": "module",
6
+ "scripts": {
7
+ "build": "rollup -c",
8
+ "lint": "eslint ."
9
+ },
10
+ "devDependencies": {
11
+ "@babel/core": "^7.26.0",
12
+ "@babel/preset-env": "^7.26.0",
13
+ "@eslint/js": "^9.18.0",
14
+ "@rollup/plugin-babel": "^6.0.4",
15
+ "@rollup/plugin-node-resolve": "^16.0.0",
16
+ "@rollup/plugin-terser": "^0.4.4",
17
+ "@rollup/plugin-typescript": "^12.1.2",
18
+ "@types/react": "^19.0.7",
19
+ "autoprefixer": "^10.4.20",
20
+ "eslint": "^9.18.0",
21
+ "eslint-plugin-react": "^7.37.4",
22
+ "globals": "^15.14.0",
23
+ "install": "^0.13.0",
24
+ "npm": "^11.0.0",
25
+ "postcss": "^8.5.1",
26
+ "postcss-loader": "^8.1.1",
27
+ "react": "^19.0.0",
28
+ "react-dom": "^19.0.0",
29
+ "rollup": "^4.31.0",
30
+ "rollup-plugin-peer-deps-external": "^2.2.4",
31
+ "rollup-plugin-postcss": "^4.0.2",
32
+ "tailwindcss": "^3.4.17",
33
+ "typescript": "^5.7.3",
34
+ "typescript-eslint": "^8.20.0"
35
+ },
36
+ "peerDependencies": {
37
+ "react": "^19.0.0",
38
+ "react-dom": "^19.0.0",
39
+ "@pulse-editor/types": "*",
40
+ "@pulse-editor/shared-utils": "*"
41
+ }
42
+ }
@@ -0,0 +1,6 @@
1
+ export default {
2
+ plugins: {
3
+ tailwindcss: {},
4
+ autoprefixer: {},
5
+ },
6
+ };
@@ -0,0 +1,40 @@
1
+ import resolve from "@rollup/plugin-node-resolve";
2
+ import peerDepsExternal from "rollup-plugin-peer-deps-external";
3
+ import babel from "@rollup/plugin-babel";
4
+ import typescript from "@rollup/plugin-typescript";
5
+ import postcss from "rollup-plugin-postcss";
6
+ import terser from "@rollup/plugin-terser";
7
+
8
+ // rollup.config.mjs
9
+ export default {
10
+ input: "src/main.ts",
11
+ output: [
12
+ {
13
+ file: "dist/bundle.js",
14
+ format: "cjs",
15
+ },
16
+ {
17
+ file: "dist/bundle.es.js",
18
+ format: "es",
19
+ exports: "named",
20
+ },
21
+ ],
22
+ plugins: [
23
+ postcss({
24
+ plugins: [],
25
+ minimize: true,
26
+ }),
27
+ resolve({
28
+ extensions: [".js", ".ts", ".tsx", ".jsx"],
29
+ }),
30
+ peerDepsExternal(),
31
+ babel({
32
+ babelHelpers: "bundled",
33
+ exclude: ["node_modules/**"],
34
+ }),
35
+ typescript({
36
+ exclude: ["node_modules/**", "src/stories/**"],
37
+ }),
38
+ terser(),
39
+ ],
40
+ };
@@ -0,0 +1,48 @@
1
+ import { InterModuleCommunication } from "@pulse-editor/shared-utils";
2
+ import { AgentTool, IMCMessage, IMCMessageTypeEnum } from "@pulse-editor/types";
3
+ import { useEffect, useState } from "react";
4
+
5
+ export default function useAgentTools(moduleName: string) {
6
+ const [imc, setImc] = useState<InterModuleCommunication | undefined>(
7
+ undefined
8
+ );
9
+ const [isReady, setIsReady] = useState(false);
10
+
11
+ const receiverHandlerMap = new Map<
12
+ IMCMessageTypeEnum,
13
+ (senderWindow: Window, message: IMCMessage) => Promise<void>
14
+ >();
15
+
16
+ const targetWindow = window.parent;
17
+
18
+ useEffect(() => {
19
+ const imc = new InterModuleCommunication(moduleName);
20
+ imc.initThisWindow(window);
21
+ imc.updateReceiverHandlerMap(receiverHandlerMap);
22
+ imc.initOtherWindow(targetWindow);
23
+ setImc(imc);
24
+ setIsReady(true);
25
+
26
+ imc.sendMessage(IMCMessageTypeEnum.Ready);
27
+
28
+ return () => {
29
+ imc.close();
30
+ };
31
+ }, []);
32
+
33
+ async function installAgentTool(tool: AgentTool) {
34
+ if (!imc) {
35
+ throw new Error("IMC not initialized.");
36
+ }
37
+
38
+ await imc
39
+ .sendMessage(IMCMessageTypeEnum.InstallAgentTool, tool)
40
+ .then((response) => {
41
+ if (response.type === IMCMessageTypeEnum.Error) {
42
+ throw new Error(response.payload);
43
+ }
44
+ });
45
+ }
46
+
47
+ return { installAgentTool };
48
+ }
@@ -0,0 +1,80 @@
1
+ import { InterModuleCommunication } from "@pulse-editor/shared-utils";
2
+ import { Agent, IMCMessage, IMCMessageTypeEnum } from "@pulse-editor/types";
3
+ import { useEffect, useState } from "react";
4
+
5
+ export default function useAgents(moduleName: string) {
6
+ const [imc, setImc] = useState<InterModuleCommunication | undefined>(
7
+ undefined
8
+ );
9
+ const [isReady, setIsReady] = useState(false);
10
+
11
+ const receiverHandlerMap = new Map<
12
+ IMCMessageTypeEnum,
13
+ (senderWindow: Window, message: IMCMessage) => Promise<void>
14
+ >();
15
+
16
+ const targetWindow = window.parent;
17
+
18
+ useEffect(() => {
19
+ // Init IMC
20
+ const imc = new InterModuleCommunication(moduleName);
21
+ imc.initThisWindow(window);
22
+ imc.updateReceiverHandlerMap(receiverHandlerMap);
23
+ imc.initOtherWindow(targetWindow);
24
+ setImc(imc);
25
+ setIsReady(true);
26
+
27
+ imc.sendMessage(IMCMessageTypeEnum.Ready);
28
+
29
+ return () => {
30
+ imc.close();
31
+ };
32
+ }, []);
33
+
34
+ async function installAgent(config: Agent) {
35
+ if (!imc) {
36
+ throw new Error("IMC not initialized.");
37
+ }
38
+
39
+ await imc
40
+ .sendMessage(IMCMessageTypeEnum.InstallAgent, config)
41
+ .then((response) => {
42
+ if (response.type === IMCMessageTypeEnum.Error) {
43
+ throw new Error(response.payload);
44
+ }
45
+ });
46
+ }
47
+
48
+ async function runAgentMethod(
49
+ agentName: string,
50
+ methodName: string,
51
+ parameters: Record<string, any>,
52
+ abortSignal?: AbortSignal
53
+ ): Promise<Record<string, any>> {
54
+ if (!imc) {
55
+ throw new Error("IMC not initialized.");
56
+ }
57
+
58
+ const result = await imc
59
+ .sendMessage(
60
+ IMCMessageTypeEnum.RunAgentMethod,
61
+ {
62
+ agentName,
63
+ methodName,
64
+ parameters,
65
+ },
66
+ abortSignal
67
+ )
68
+ .then((response) => {
69
+ return response as Record<string, any>;
70
+ });
71
+
72
+ return result;
73
+ }
74
+
75
+ return {
76
+ installAgent,
77
+ runAgentMethod,
78
+ isReady,
79
+ };
80
+ }
@@ -0,0 +1,45 @@
1
+ import { InterModuleCommunication } from "@pulse-editor/shared-utils";
2
+ import { IMCMessage, IMCMessageTypeEnum } from "@pulse-editor/types";
3
+ import { useEffect, useState } from "react";
4
+
5
+ export default function useFetch(moduleName: string) {
6
+ const [imc, setImc] = useState<InterModuleCommunication | undefined>(
7
+ undefined
8
+ );
9
+
10
+ const receiverHandlerMap = new Map<
11
+ IMCMessageTypeEnum,
12
+ (senderWindow: Window, message: IMCMessage) => Promise<void>
13
+ >();
14
+
15
+ const targetWindow = window.parent;
16
+
17
+ useEffect(() => {
18
+ // Init IMC
19
+ const imc = new InterModuleCommunication(moduleName);
20
+ imc.initThisWindow(window);
21
+ imc.updateReceiverHandlerMap(receiverHandlerMap);
22
+ imc.initOtherWindow(targetWindow);
23
+ setImc(imc);
24
+
25
+ console.log("Sent ready message");
26
+ imc.sendMessage(IMCMessageTypeEnum.Ready);
27
+
28
+ return () => {
29
+ imc.close();
30
+ };
31
+ }, []);
32
+
33
+ function fetch(uri: string, options?: RequestInit): Promise<Response> {
34
+ if (!imc) {
35
+ throw new Error("IMC is not initialized.");
36
+ }
37
+
38
+ return imc.sendMessage(
39
+ IMCMessageTypeEnum.Fetch,
40
+ JSON.stringify({ uri, options })
41
+ );
42
+ }
43
+
44
+ return { fetch };
45
+ }
@@ -0,0 +1,62 @@
1
+ import { InterModuleCommunication } from "@pulse-editor/shared-utils";
2
+ import {
3
+ IMCMessage,
4
+ IMCMessageTypeEnum,
5
+ FileViewModel,
6
+ } from "@pulse-editor/types";
7
+ import { useEffect, useState } from "react";
8
+
9
+ export default function useFileView(moduleName: string) {
10
+ const [viewFile, setViewFile] = useState<FileViewModel | undefined>(
11
+ undefined
12
+ );
13
+ const [isLoaded, setIsLoaded] = useState(false);
14
+
15
+ const targetWindow = window.parent;
16
+
17
+ const receiverHandlerMap = new Map<
18
+ IMCMessageTypeEnum,
19
+ (senderWindow: Window, message: IMCMessage) => Promise<void>
20
+ >();
21
+
22
+ const [imc, setImc] = useState<InterModuleCommunication | undefined>(
23
+ undefined
24
+ );
25
+
26
+ useEffect(() => {
27
+ // Init IMC
28
+ const imc = new InterModuleCommunication(moduleName);
29
+ imc.initThisWindow(window);
30
+ imc.updateReceiverHandlerMap(receiverHandlerMap);
31
+ imc.initOtherWindow(targetWindow);
32
+ setImc(imc);
33
+
34
+ imc.sendMessage(IMCMessageTypeEnum.Ready).then(() => {
35
+ imc.sendMessage(IMCMessageTypeEnum.RequestViewFile).then((model) => {
36
+ setViewFile(model);
37
+ });
38
+ });
39
+
40
+ return () => {
41
+ console.log("Closing IMC for extension: ", moduleName);
42
+ imc.close();
43
+ };
44
+ }, []);
45
+
46
+ useEffect(() => {
47
+ if (isLoaded) {
48
+ imc?.sendMessage(IMCMessageTypeEnum.Loaded);
49
+ }
50
+ }, [isLoaded, imc]);
51
+
52
+ function updateViewFile(file: FileViewModel) {
53
+ // sender.sendMessage(ViewBoxMessageTypeEnum.ViewFile, JSON.stringify(file));
54
+ imc?.sendMessage(IMCMessageTypeEnum.WriteViewFile, file);
55
+ }
56
+
57
+ return {
58
+ viewFile,
59
+ updateViewFile,
60
+ setIsLoaded,
61
+ };
62
+ }
@@ -0,0 +1,48 @@
1
+ import { InterModuleCommunication } from "@pulse-editor/shared-utils";
2
+ import {
3
+ NotificationTypeEnum,
4
+ IMCMessage,
5
+ IMCMessageTypeEnum,
6
+ } from "@pulse-editor/types";
7
+ import { useEffect, useState } from "react";
8
+
9
+ export default function useNotification(moduleName: string) {
10
+ const [imc, setImc] = useState<InterModuleCommunication | undefined>(
11
+ undefined
12
+ );
13
+
14
+ const receiverHandlerMap = new Map<
15
+ IMCMessageTypeEnum,
16
+ (senderWindow: Window, message: IMCMessage) => Promise<void>
17
+ >();
18
+
19
+ const targetWindow = window.parent;
20
+
21
+ useEffect(() => {
22
+ // Init IMC
23
+ const imc = new InterModuleCommunication(moduleName);
24
+ imc.initThisWindow(window);
25
+ imc.updateReceiverHandlerMap(receiverHandlerMap);
26
+ imc.initOtherWindow(targetWindow);
27
+ setImc(imc);
28
+
29
+ console.log("Sent ready message");
30
+ imc.sendMessage(IMCMessageTypeEnum.Ready);
31
+
32
+ return () => {
33
+ imc.close();
34
+ };
35
+ }, []);
36
+
37
+ function openNotification(text: string, type: NotificationTypeEnum) {
38
+ if (!imc) {
39
+ throw new Error("IMC is not initialized.");
40
+ }
41
+ imc.sendMessage(IMCMessageTypeEnum.Notification, {
42
+ text,
43
+ type,
44
+ });
45
+ }
46
+
47
+ return { openNotification };
48
+ }
@@ -0,0 +1,50 @@
1
+ import { InterModuleCommunication } from "@pulse-editor/shared-utils";
2
+ import { IMCMessage, IMCMessageTypeEnum } from "@pulse-editor/types";
3
+ import { useEffect, useState } from "react";
4
+
5
+ export default function useOCR(moduleName: string) {
6
+ const [imc, setImc] = useState<InterModuleCommunication | undefined>(
7
+ undefined
8
+ );
9
+
10
+ const receiverHandlerMap = new Map<
11
+ IMCMessageTypeEnum,
12
+ (senderWindow: Window, message: IMCMessage) => Promise<void>
13
+ >();
14
+
15
+ const targetWindow = window.parent;
16
+
17
+ useEffect(() => {
18
+ // Init IMC
19
+ const imc = new InterModuleCommunication(moduleName);
20
+ imc.initThisWindow(window);
21
+ imc.updateReceiverHandlerMap(receiverHandlerMap);
22
+ imc.initOtherWindow(targetWindow);
23
+ setImc(imc);
24
+
25
+ console.log("Sent ready message");
26
+ imc.sendMessage(IMCMessageTypeEnum.Ready);
27
+
28
+ return () => {
29
+ imc.close();
30
+ };
31
+ }, []);
32
+
33
+ async function recognizeText(uri: string): Promise<string> {
34
+ if (!imc) {
35
+ throw new Error("IMC is not initialized.");
36
+ }
37
+
38
+ // Send the message to the extension
39
+ const result = await imc.sendMessage(
40
+ IMCMessageTypeEnum.OCR,
41
+ { uri }
42
+ );
43
+
44
+ return result.payload.text;
45
+ }
46
+
47
+ return {
48
+ recognizeText,
49
+ };
50
+ }
@@ -0,0 +1,43 @@
1
+ import { InterModuleCommunication } from "@pulse-editor/shared-utils";
2
+ import { IMCMessage, IMCMessageTypeEnum } from "@pulse-editor/types";
3
+ import { useEffect, useState } from "react";
4
+
5
+ export default function useTheme(moduleName: string) {
6
+ const [theme, setTheme] = useState<string>("light");
7
+ const receiverHandlerMap = new Map<
8
+ IMCMessageTypeEnum,
9
+ (senderWindow: Window, message: IMCMessage) => Promise<void>
10
+ >();
11
+
12
+ receiverHandlerMap.set(
13
+ IMCMessageTypeEnum.ThemeChange,
14
+ async (senderWindow: Window, message: IMCMessage) => {
15
+ const theme = message.payload;
16
+ setTheme((prev) => theme);
17
+ }
18
+ );
19
+
20
+ const [, setImc] = useState<InterModuleCommunication | undefined>(undefined);
21
+
22
+ const targetWindow = window.parent;
23
+
24
+ useEffect(() => {
25
+ // Init IMC
26
+ const imc = new InterModuleCommunication(moduleName);
27
+ imc.initThisWindow(window);
28
+ imc.updateReceiverHandlerMap(receiverHandlerMap);
29
+ imc.initOtherWindow(targetWindow);
30
+ setImc(imc);
31
+
32
+ console.log("Sent ready message");
33
+ imc.sendMessage(IMCMessageTypeEnum.Ready);
34
+
35
+ return () => {
36
+ imc.close();
37
+ };
38
+ }, []);
39
+
40
+ return {
41
+ theme,
42
+ };
43
+ }
File without changes
package/src/main.ts ADDED
@@ -0,0 +1,7 @@
1
+ import useFileView from "./hooks/use-file-view";
2
+ import useTheme from "./hooks/use-theme";
3
+ import useNotification from "./hooks/use-notification";
4
+ import useAgents from "./hooks/use-agents";
5
+ import useOCR from "./hooks/use-orc";
6
+
7
+ export { useFileView, useTheme, useNotification, useAgents as useAgent, useOCR };
@@ -0,0 +1,3 @@
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
@@ -0,0 +1,10 @@
1
+ /** @type {import('tailwindcss').Config} */
2
+ export default {
3
+ content: ["./src/**/*.{js,jsx,ts,tsx}"],
4
+ // Toggle dark-mode based on .dark class or data-mode="dark"
5
+ darkMode: ["class", '[data-mode="dark"]'],
6
+ theme: {
7
+ extend: {},
8
+ },
9
+ plugins: [],
10
+ };
package/tsconfig.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "jsx": "react",
5
+ "outDir": "./dist",
6
+ "module": "ESNext",
7
+ "moduleResolution": "bundler",
8
+ "strict": true,
9
+ "declaration": true
10
+ },
11
+ "include": [
12
+ "src/**/*"
13
+ ],
14
+ }