foundry-vtt-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/README.md +39 -0
- package/dist/chunk-U6WX7YSY.mjs +43 -0
- package/dist/chunk-U6WX7YSY.mjs.map +1 -0
- package/dist/index.d.mts +101 -0
- package/dist/index.mjs +117 -0
- package/dist/index.mjs.map +1 -0
- package/dist/util/dev-setup.d.mts +14 -0
- package/dist/util/dev-setup.mjs +7 -0
- package/dist/util/dev-setup.mjs.map +1 -0
- package/package.json +47 -0
package/README.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Foundry VTT React
|
|
2
|
+
|
|
3
|
+
This package provides extensions of various Foundry VTT classes to support React applications development within Foundry.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Currently supported FoundryVTT classes:
|
|
8
|
+
|
|
9
|
+
- `ReactApplicationV2`: A base application class for creating React-based applications in Foundry VTT.
|
|
10
|
+
- `ReactActorSheetV2`: An actor sheet class that uses React for rendering the UI, allowing the React app to listen for changes to the document using the native ActoSheetV2 lifecycle events.
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
There are two important pieces to developing React applications in Foundry.
|
|
15
|
+
|
|
16
|
+
1. Creating your ReactApplicationV2 instance and passing in your React component.
|
|
17
|
+
2. Configuring ViteJS development server to work with your local FoundryVTT instance.
|
|
18
|
+
|
|
19
|
+
### Creating a ReactApplicationV2 Instance
|
|
20
|
+
|
|
21
|
+
To create a new React-powered Foundry application, you can instantiate the `ReactApplicationV2` class and provide your React component along with any initial properties and window options.
|
|
22
|
+
|
|
23
|
+
```javascript
|
|
24
|
+
// Basic component
|
|
25
|
+
function MyReactComponent(props) {
|
|
26
|
+
return <div>Hello, {props.data}!</div>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Declare an instance and render it as a Foundry application
|
|
30
|
+
const app = new ReactApplicationV2({
|
|
31
|
+
reactApp: MyReactComponent,
|
|
32
|
+
initialProps: { data: "example" },
|
|
33
|
+
window: { title: "My React App" },
|
|
34
|
+
position: { width: 300, height: 200 },
|
|
35
|
+
});
|
|
36
|
+
app.render(true);
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+

|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// lib/util/logger.ts
|
|
2
|
+
var logger = (namespace) => (message) => {
|
|
3
|
+
console.log(`%c[foundry-vtt-react][${namespace}]`, "color: tomato;", message);
|
|
4
|
+
};
|
|
5
|
+
var logger_default = logger;
|
|
6
|
+
|
|
7
|
+
// lib/util/dev-setup.ts
|
|
8
|
+
var log = logger_default("dev-setup");
|
|
9
|
+
function devSetup(appId, entrypoint) {
|
|
10
|
+
const refreshScriptId = `foundry-react-refresh-script-${appId}`;
|
|
11
|
+
if (document.getElementById(refreshScriptId)) {
|
|
12
|
+
log("Script tag already exists, not adding again");
|
|
13
|
+
return;
|
|
14
|
+
} else {
|
|
15
|
+
log("Adding script tag for react refresh");
|
|
16
|
+
const scriptInner = `
|
|
17
|
+
import { injectIntoGlobalHook } from "/modules/${appId}/dist/@react-refresh";
|
|
18
|
+
injectIntoGlobalHook(window);
|
|
19
|
+
window.$RefreshReg$ = () => {};
|
|
20
|
+
window.$RefreshSig$ = () => (type) => type;
|
|
21
|
+
`;
|
|
22
|
+
const tag = document.createElement("script");
|
|
23
|
+
tag.type = "module";
|
|
24
|
+
tag.id = refreshScriptId;
|
|
25
|
+
tag.innerHTML = scriptInner;
|
|
26
|
+
document.head.prepend(tag);
|
|
27
|
+
}
|
|
28
|
+
const devEntrypointId = `foundry-react-dev-entrypoint-${appId}`;
|
|
29
|
+
if (document.getElementById(devEntrypointId)) {
|
|
30
|
+
log("Dev entrypoint script tag already exists, not adding again");
|
|
31
|
+
return;
|
|
32
|
+
} else {
|
|
33
|
+
const mainScript = document.createElement("script");
|
|
34
|
+
mainScript.type = "module";
|
|
35
|
+
mainScript.src = `/modules/${appId}${entrypoint.startsWith("/") ? "" : "/"}${entrypoint}`;
|
|
36
|
+
document.body.appendChild(mainScript);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export {
|
|
41
|
+
devSetup
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=chunk-U6WX7YSY.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../lib/util/logger.ts","../lib/util/dev-setup.ts"],"sourcesContent":["const logger =\n (namespace: string): ((message: string) => void) =>\n (message: string) => {\n console.log(`%c[foundry-vtt-react][${namespace}]`, \"color: tomato;\", message);\n };\n\nexport default logger;\n","import logger from \"../util/logger.js\";\nconst log = logger(\"dev-setup\");\n\n/**\n * devSetup.js\n *\n * Utility function to set up development environment for React applications in Foundry VTT. Used in conjunction\n * with a Vite development server, this function injects necessary scripts to enable React Fast Refresh and loads\n * the React application entrypoint.\n *\n * @param {string} appId - The application ID used to construct module paths, typically the `id` value in `module.json`.\n * @param {string} entrypoint - The path to the React application entrypoint script relative to the module root. This should match\n * the entrypoint defined in the Vite configuration.\n */\nexport function devSetup(appId: string, entrypoint: string) {\n const refreshScriptId = `foundry-react-refresh-script-${appId}`;\n\n if (document.getElementById(refreshScriptId)) {\n log(\"Script tag already exists, not adding again\");\n return;\n } else {\n log(\"Adding script tag for react refresh\");\n\n const scriptInner = `\n import { injectIntoGlobalHook } from \"/modules/${appId}/dist/@react-refresh\";\n injectIntoGlobalHook(window);\n window.$RefreshReg$ = () => {};\n window.$RefreshSig$ = () => (type) => type;\n `;\n\n const tag = document.createElement(\"script\");\n tag.type = \"module\";\n tag.id = refreshScriptId;\n tag.innerHTML = scriptInner;\n document.head.prepend(tag);\n }\n\n const devEntrypointId = `foundry-react-dev-entrypoint-${appId}`;\n if (document.getElementById(devEntrypointId)) {\n log(\"Dev entrypoint script tag already exists, not adding again\");\n return;\n } else {\n const mainScript = document.createElement(\"script\");\n mainScript.type = \"module\";\n mainScript.src = `/modules/${appId}${entrypoint.startsWith(\"/\") ? \"\" : \"/\"}${entrypoint}`;\n document.body.appendChild(mainScript);\n }\n}\n"],"mappings":";AAAA,IAAM,SACJ,CAAC,cACD,CAAC,YAAoB;AACnB,UAAQ,IAAI,yBAAyB,SAAS,KAAK,kBAAkB,OAAO;AAC9E;AAEF,IAAO,iBAAQ;;;ACLf,IAAM,MAAM,eAAO,WAAW;AAavB,SAAS,SAAS,OAAe,YAAoB;AAC1D,QAAM,kBAAkB,gCAAgC,KAAK;AAE7D,MAAI,SAAS,eAAe,eAAe,GAAG;AAC5C,QAAI,6CAA6C;AACjD;AAAA,EACF,OAAO;AACL,QAAI,qCAAqC;AAEzC,UAAM,cAAc;AAAA,uDAC+B,KAAK;AAAA;AAAA;AAAA;AAAA;AAMxD,UAAM,MAAM,SAAS,cAAc,QAAQ;AAC3C,QAAI,OAAO;AACX,QAAI,KAAK;AACT,QAAI,YAAY;AAChB,aAAS,KAAK,QAAQ,GAAG;AAAA,EAC3B;AAEA,QAAM,kBAAkB,gCAAgC,KAAK;AAC7D,MAAI,SAAS,eAAe,eAAe,GAAG;AAC5C,QAAI,4DAA4D;AAChE;AAAA,EACF,OAAO;AACL,UAAM,aAAa,SAAS,cAAc,QAAQ;AAClD,eAAW,OAAO;AAClB,eAAW,MAAM,YAAY,KAAK,GAAG,WAAW,WAAW,GAAG,IAAI,KAAK,GAAG,GAAG,UAAU;AACvF,aAAS,KAAK,YAAY,UAAU;AAAA,EACtC;AACF;","names":[]}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
export { devSetup } from './util/dev-setup.mjs';
|
|
2
|
+
|
|
3
|
+
declare class ContextConnector<T> extends EventTarget {
|
|
4
|
+
static UPDATE: string;
|
|
5
|
+
constructor();
|
|
6
|
+
publishContext(context: T): void;
|
|
7
|
+
on(event: string, callback: (data: T) => void): void;
|
|
8
|
+
onUpdate(callback: (data: T) => void): void;
|
|
9
|
+
tearDown(fn: (data: T) => void): void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
declare const ReactApplicationV2_base: {
|
|
13
|
+
new ({ reactApp, initialProps, ...options }: {
|
|
14
|
+
reactApp: React.ComponentType<any>;
|
|
15
|
+
initialProps?: Record<string, any>;
|
|
16
|
+
} & any): {
|
|
17
|
+
[x: string]: any;
|
|
18
|
+
reactApp: React.ComponentType<any>;
|
|
19
|
+
uuid: string;
|
|
20
|
+
rootId: string;
|
|
21
|
+
innerSelector: string;
|
|
22
|
+
contextConnector: ContextConnector<any>;
|
|
23
|
+
initialProps: {};
|
|
24
|
+
get appIsRendered(): boolean;
|
|
25
|
+
_onRender(context: any, options: any): Promise<void>;
|
|
26
|
+
_replaceHTML(result: HTMLElement, content: HTMLElement): void;
|
|
27
|
+
_prepareContext(options: any): Promise<any>;
|
|
28
|
+
_renderHTML(): Promise<HTMLDivElement>;
|
|
29
|
+
};
|
|
30
|
+
[x: string]: any;
|
|
31
|
+
DEFAULT_OPTIONS: {
|
|
32
|
+
position: {
|
|
33
|
+
width: number;
|
|
34
|
+
height: number;
|
|
35
|
+
};
|
|
36
|
+
window: {
|
|
37
|
+
title: string;
|
|
38
|
+
resizable: boolean;
|
|
39
|
+
minimizable: boolean;
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* A Foundry VTT Application class that integrates React components with the Foundry application framework.
|
|
45
|
+
* Extends ApplicationV2 to provide seamless React app mounting and rendering capabilities.
|
|
46
|
+
*
|
|
47
|
+
* @class FoundryReactApplication
|
|
48
|
+
* @extends foundry.applications.api.ApplicationV2
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* // Create a new React-powered Foundry application
|
|
52
|
+
* const app = new FoundryReactApplication({
|
|
53
|
+
* reactApp: MyReactComponent,
|
|
54
|
+
* initialProps: { data: 'example' },
|
|
55
|
+
* window: { title: "My React App" },
|
|
56
|
+
* position: { width: 600, height: 400 }
|
|
57
|
+
* });
|
|
58
|
+
*
|
|
59
|
+
* @property {React.Component} reactApp - The React component to be mounted
|
|
60
|
+
* @property {string} template - Path to the Handlebars template for the application shell
|
|
61
|
+
* @property {Object} initialProps - Initial properties passed to the React component
|
|
62
|
+
* @property {string} rootId - ID added to the root element where the React app will be mounted
|
|
63
|
+
*/
|
|
64
|
+
declare class ReactApplicationV2 extends ReactApplicationV2_base {
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
declare const ReactActorSheetV2_base: {
|
|
68
|
+
new ({ reactApp, initialProps, ...options }: {
|
|
69
|
+
reactApp: React.ComponentType<any>;
|
|
70
|
+
initialProps?: Record<string, any>;
|
|
71
|
+
} & any): {
|
|
72
|
+
[x: string]: any;
|
|
73
|
+
reactApp: React.ComponentType<any>;
|
|
74
|
+
uuid: string;
|
|
75
|
+
rootId: string;
|
|
76
|
+
innerSelector: string;
|
|
77
|
+
contextConnector: ContextConnector<any>;
|
|
78
|
+
initialProps: {};
|
|
79
|
+
get appIsRendered(): boolean;
|
|
80
|
+
_onRender(context: any, options: any): Promise<void>;
|
|
81
|
+
_replaceHTML(result: HTMLElement, content: HTMLElement): void;
|
|
82
|
+
_prepareContext(options: any): Promise<any>;
|
|
83
|
+
_renderHTML(): Promise<HTMLDivElement>;
|
|
84
|
+
};
|
|
85
|
+
[x: string]: any;
|
|
86
|
+
DEFAULT_OPTIONS: {
|
|
87
|
+
position: {
|
|
88
|
+
width: number;
|
|
89
|
+
height: number;
|
|
90
|
+
};
|
|
91
|
+
window: {
|
|
92
|
+
title: string;
|
|
93
|
+
resizable: boolean;
|
|
94
|
+
minimizable: boolean;
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
declare class ReactActorSheetV2 extends ReactActorSheetV2_base {
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export { ContextConnector, ReactActorSheetV2, ReactApplicationV2 };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import {
|
|
2
|
+
devSetup
|
|
3
|
+
} from "./chunk-U6WX7YSY.mjs";
|
|
4
|
+
|
|
5
|
+
// lib/context-connector.ts
|
|
6
|
+
var ContextConnector = class _ContextConnector extends EventTarget {
|
|
7
|
+
static UPDATE = "contextUpdate";
|
|
8
|
+
constructor() {
|
|
9
|
+
super();
|
|
10
|
+
}
|
|
11
|
+
publishContext(context) {
|
|
12
|
+
this.dispatchEvent(new CustomEvent("contextUpdate", { detail: context }));
|
|
13
|
+
}
|
|
14
|
+
on(event, callback) {
|
|
15
|
+
this.addEventListener(event, (e) => {
|
|
16
|
+
callback(e.detail);
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
onUpdate(callback) {
|
|
20
|
+
this.on(_ContextConnector.UPDATE, callback);
|
|
21
|
+
}
|
|
22
|
+
tearDown(fn) {
|
|
23
|
+
this.removeEventListener(_ContextConnector.UPDATE, fn);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// lib/util/mount-app.tsx
|
|
28
|
+
import { createRoot } from "react-dom/client";
|
|
29
|
+
import { jsx } from "react/jsx-runtime";
|
|
30
|
+
function mountApp({
|
|
31
|
+
App,
|
|
32
|
+
element,
|
|
33
|
+
initialProps = {},
|
|
34
|
+
innerSelector
|
|
35
|
+
}) {
|
|
36
|
+
const root = createRoot(element);
|
|
37
|
+
root.render(
|
|
38
|
+
/* @__PURE__ */ jsx("div", { id: innerSelector, children: /* @__PURE__ */ jsx(App, { ...initialProps }) })
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// lib/react-application-mixin.ts
|
|
43
|
+
function ReactApplicationMixin(Superclass) {
|
|
44
|
+
return class ReactApplication extends Superclass {
|
|
45
|
+
reactApp;
|
|
46
|
+
uuid = foundry.utils.randomID(12);
|
|
47
|
+
rootId = `react-app-root-${this.uuid}`;
|
|
48
|
+
innerSelector = `react-application-inner-${this.rootId}`;
|
|
49
|
+
contextConnector;
|
|
50
|
+
static DEFAULT_OPTIONS = {
|
|
51
|
+
position: {
|
|
52
|
+
width: 400,
|
|
53
|
+
height: 300
|
|
54
|
+
},
|
|
55
|
+
window: {
|
|
56
|
+
title: "Hello React-powered Foundry applications",
|
|
57
|
+
resizable: true,
|
|
58
|
+
minimizable: true
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
initialProps = {};
|
|
62
|
+
constructor({ reactApp, initialProps, ...options }) {
|
|
63
|
+
super(options);
|
|
64
|
+
this.reactApp = reactApp;
|
|
65
|
+
this.contextConnector = new ContextConnector();
|
|
66
|
+
this.initialProps = initialProps || {};
|
|
67
|
+
}
|
|
68
|
+
get appIsRendered() {
|
|
69
|
+
return !!document.querySelector(`#${this.innerSelector}`);
|
|
70
|
+
}
|
|
71
|
+
async _onRender(context, options) {
|
|
72
|
+
await super._onRender(context, options);
|
|
73
|
+
const el = this.element.querySelectorAll(`#${this.rootId}`);
|
|
74
|
+
if (el && !this.appIsRendered) {
|
|
75
|
+
mountApp({
|
|
76
|
+
App: this.reactApp,
|
|
77
|
+
element: el[0],
|
|
78
|
+
initialProps: context.initialProps,
|
|
79
|
+
innerSelector: this.innerSelector
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
this.contextConnector.publishContext(context);
|
|
83
|
+
}
|
|
84
|
+
_replaceHTML(result, content) {
|
|
85
|
+
if (!this.appIsRendered) {
|
|
86
|
+
content.appendChild(result);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
async _prepareContext(options) {
|
|
90
|
+
const context = await super._prepareContext(options);
|
|
91
|
+
context.initialProps = this.initialProps;
|
|
92
|
+
return context;
|
|
93
|
+
}
|
|
94
|
+
async _renderHTML() {
|
|
95
|
+
const tempEl = document.createElement("div");
|
|
96
|
+
tempEl.id = this.rootId;
|
|
97
|
+
tempEl.innerHTML = `<span>Uh oh, something went wrong</span>`;
|
|
98
|
+
return tempEl;
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
var react_application_mixin_default = ReactApplicationMixin;
|
|
103
|
+
|
|
104
|
+
// lib/react-application-v2.ts
|
|
105
|
+
var ReactApplicationV2 = class extends react_application_mixin_default(foundry.applications.api.ApplicationV2) {
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
// lib/react-actor-sheet-v2.ts
|
|
109
|
+
var ReactActorSheetV2 = class extends react_application_mixin_default(foundry.applications.sheets.ActorSheetV2) {
|
|
110
|
+
};
|
|
111
|
+
export {
|
|
112
|
+
ContextConnector,
|
|
113
|
+
ReactActorSheetV2,
|
|
114
|
+
ReactApplicationV2,
|
|
115
|
+
devSetup
|
|
116
|
+
};
|
|
117
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../lib/context-connector.ts","../lib/util/mount-app.tsx","../lib/react-application-mixin.ts","../lib/react-application-v2.ts","../lib/react-actor-sheet-v2.ts"],"sourcesContent":["export class ContextConnector<T> extends EventTarget {\n static UPDATE = \"contextUpdate\";\n\n constructor() {\n super();\n }\n\n publishContext(context: T) {\n this.dispatchEvent(new CustomEvent(\"contextUpdate\", { detail: context }));\n }\n\n on(event: string, callback: (data: T) => void) {\n this.addEventListener(event, (e: CustomEventInit<T>) => {\n callback(e.detail!);\n });\n }\n\n onUpdate(callback: (data: T) => void) {\n this.on(ContextConnector.UPDATE, callback);\n }\n\n tearDown(fn: (data: T) => void) {\n this.removeEventListener(ContextConnector.UPDATE, fn as EventListener);\n }\n}\n","import { createRoot } from \"react-dom/client\";\n\nexport function mountApp({\n App,\n element,\n initialProps = {},\n innerSelector,\n}: {\n /* eslint-disable-next-line @typescript-eslint/no-explicit-any */\n App: React.ComponentType<any>;\n element: Element;\n initialProps?: {};\n innerSelector: string;\n}) {\n const root = createRoot(element);\n root.render(\n <div id={innerSelector}>\n <App {...initialProps} />\n </div>\n );\n}\n","import { ContextConnector } from \"./context-connector\";\nimport { mountApp } from \"./util/mount-app\";\n\n/**\n * A mixin that integrates React components with Foundry VTT's Application class.\n * This mixin enables the use of React applications within Foundry VTT's application framework.\n *\n * @param superclass - The base class to extend, typically a Foundry VTT Application class\n * @returns A class that extends the superclass with React integration capabilities\n *\n * @remarks\n * This mixin provides the following features:\n * - Mounting React components within Foundry VTT applications\n * - Context management through ContextConnector\n * - Automatic cleanup and rendering lifecycle management\n * - Default window options for position and configuration\n *\n * @example\n * ```typescript\n * class MyReactApp extends ReactApplicationMixin(Application) {\n * constructor(options) {\n * super({\n * reactApp: MyReactComponent,\n * initialProps: { data: \"example\" },\n * ...options\n * });\n * }\n * }\n * ```\n */\n\ntype ReactApplicationProps = {\n reactApp: React.ComponentType<any>;\n initialProps?: Record<string, any>;\n};\n\nfunction ReactApplicationMixin(Superclass: any) {\n return class ReactApplication extends Superclass {\n reactApp: React.ComponentType<any>;\n uuid = foundry.utils.randomID(12);\n rootId = `react-app-root-${this.uuid}`;\n innerSelector = `react-application-inner-${this.rootId}`;\n contextConnector: ContextConnector<any>;\n\n static DEFAULT_OPTIONS = {\n position: {\n width: 400,\n height: 300,\n },\n window: {\n title: \"Hello React-powered Foundry applications\",\n resizable: true,\n minimizable: true,\n },\n };\n\n initialProps = {};\n\n constructor({ reactApp, initialProps, ...options }: ReactApplicationProps & any) {\n super(options);\n this.reactApp = reactApp;\n this.contextConnector = new ContextConnector();\n this.initialProps = initialProps || {};\n }\n\n get appIsRendered() {\n return !!document.querySelector(`#${this.innerSelector}`);\n }\n\n async _onRender(context: any, options: any) {\n await super._onRender(context, options);\n const el = this.element.querySelectorAll(`#${this.rootId}`);\n\n if (el && !this.appIsRendered) {\n mountApp({\n App: this.reactApp,\n element: el[0],\n initialProps: context.initialProps,\n innerSelector: this.innerSelector,\n });\n }\n this.contextConnector.publishContext(context);\n }\n\n _replaceHTML(result: HTMLElement, content: HTMLElement) {\n if (!this.appIsRendered) {\n content.appendChild(result);\n }\n }\n\n async _prepareContext(options: any) {\n const context = (await super._prepareContext(options)) as any;\n context.initialProps = this.initialProps;\n return context;\n }\n\n async _renderHTML() {\n const tempEl = document.createElement(\"div\");\n tempEl.id = this.rootId;\n tempEl.innerHTML = `<span>Uh oh, something went wrong</span>`;\n return tempEl;\n }\n };\n}\n\nexport default ReactApplicationMixin;\n","import ReactApplicationMixin from \"./react-application-mixin\";\n\n/**\n * A Foundry VTT Application class that integrates React components with the Foundry application framework.\n * Extends ApplicationV2 to provide seamless React app mounting and rendering capabilities.\n *\n * @class FoundryReactApplication\n * @extends foundry.applications.api.ApplicationV2\n *\n * @example\n * // Create a new React-powered Foundry application\n * const app = new FoundryReactApplication({\n * reactApp: MyReactComponent,\n * initialProps: { data: 'example' },\n * window: { title: \"My React App\" },\n * position: { width: 600, height: 400 }\n * });\n *\n * @property {React.Component} reactApp - The React component to be mounted\n * @property {string} template - Path to the Handlebars template for the application shell\n * @property {Object} initialProps - Initial properties passed to the React component\n * @property {string} rootId - ID added to the root element where the React app will be mounted\n */\nexport class ReactApplicationV2 extends ReactApplicationMixin(foundry.applications.api.ApplicationV2) {}\n","/**\n * A React-enabled version of Foundry VTT's ActorSheetV2 class.\n *\n * This class extends the core ActorSheetV2 functionality by applying the ReactApplicationMixin,\n * which enables React component rendering within the actor sheet application.\n *\n * @extends {foundry.applications.sheets.ActorSheetV2}\n * @mixes ReactApplicationMixin\n *\n * @example\n * ```typescript\n * class MyActorSheet extends ReactActorSheetV2 {\n * // Your custom React-enabled actor sheet implementation\n * }\n * ```\n */\nimport ReactApplicationMixin from \"./react-application-mixin\";\n\nexport class ReactActorSheetV2 extends ReactApplicationMixin(foundry.applications.sheets.ActorSheetV2) {}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* devSetup.js
|
|
3
|
+
*
|
|
4
|
+
* Utility function to set up development environment for React applications in Foundry VTT. Used in conjunction
|
|
5
|
+
* with a Vite development server, this function injects necessary scripts to enable React Fast Refresh and loads
|
|
6
|
+
* the React application entrypoint.
|
|
7
|
+
*
|
|
8
|
+
* @param {string} appId - The application ID used to construct module paths, typically the `id` value in `module.json`.
|
|
9
|
+
* @param {string} entrypoint - The path to the React application entrypoint script relative to the module root. This should match
|
|
10
|
+
* the entrypoint defined in the Vite configuration.
|
|
11
|
+
*/
|
|
12
|
+
declare function devSetup(appId: string, entrypoint: string): void;
|
|
13
|
+
|
|
14
|
+
export { devSetup };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "foundry-vtt-react",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Extensions of various FoundryVTT classes to support React applications.",
|
|
5
|
+
"packageManager": "pnpm@10.30.3",
|
|
6
|
+
"main": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.mts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.mts",
|
|
11
|
+
"import": "./dist/index.mjs"
|
|
12
|
+
},
|
|
13
|
+
"./dev-setup": {
|
|
14
|
+
"types": "./dist/util/dev-setup.d.mts",
|
|
15
|
+
"import": "./dist/util/dev-setup.mjs"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsup",
|
|
23
|
+
"build:watch": "tsup --watch",
|
|
24
|
+
"prepublishOnly": "pnpm build"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [],
|
|
27
|
+
"author": "",
|
|
28
|
+
"license": "ISC",
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"fvtt-types": "^13",
|
|
31
|
+
"tsup": "^8.5.1",
|
|
32
|
+
"typescript": "^5.9.3"
|
|
33
|
+
},
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"react": "^19.2.0",
|
|
36
|
+
"react-dom": "^19.2.0"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@types/react": "^19.2.5",
|
|
40
|
+
"@types/react-dom": "^19.2.3"
|
|
41
|
+
},
|
|
42
|
+
"pnpm": {
|
|
43
|
+
"onlyBuiltDependencies": [
|
|
44
|
+
"@league-of-foundry-developers/foundry-vtt-types"
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
}
|