@codexo/exojs-react 0.14.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Codexo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,99 @@
1
+ # @codexo/exojs-react
2
+
3
+ React 18 / 19 bindings for [ExoJS](https://exojs.dev) — mount an ExoJS
4
+ `Application` into your React tree, drive scenes declaratively, and overlay React
5
+ HUD on the canvas.
6
+
7
+ ## Installation
8
+
9
+ ```sh
10
+ npm install @codexo/exojs @codexo/exojs-react react
11
+ ```
12
+
13
+ `@codexo/exojs` and `react` (>= 18) are peer dependencies; `react-dom` is an
14
+ optional peer. The package ships pre-built ESM (`dist/esm`) with type
15
+ declarations and works on both `@types/react` 18 and 19.
16
+
17
+ ## Two layers, pick what you need
18
+
19
+ This package is intentionally layered:
20
+
21
+ - **`useExoApplication` — headless.** Creates and owns the `Application`, binds
22
+ it to a `<canvas>` you render yourself. No DOM, no wrapper, no styling
23
+ opinions — full control.
24
+ - **`<ExoCanvas>` — batteries-included.** Renders a positioned wrapper `<div>` +
25
+ a React-managed `<canvas>` and provides the app via context, so HUD overlays
26
+ work out of the box.
27
+
28
+ ## Quick start — `<ExoCanvas>`
29
+
30
+ ```tsx
31
+ import { ExoCanvas, Scenes, Scene, useExoApp } from '@codexo/exojs-react';
32
+ import { TitleScene, GameScene } from './scenes';
33
+
34
+ function Game() {
35
+ return (
36
+ <ExoCanvas
37
+ options={{ canvas: { width: 1280, height: 720 }, clearColor: someColor }}
38
+ style={{ width: 1280, height: 720 }}
39
+ >
40
+ <Scenes active="game" transition={{ type: 'fade', duration: 0.3 }}>
41
+ <Scene name="title" component={TitleScene} />
42
+ <Scene name="game" component={GameScene}>
43
+ <Hud /> {/* absolutely-positioned React overlay, over the canvas */}
44
+ </Scene>
45
+ </Scenes>
46
+ </ExoCanvas>
47
+ );
48
+ }
49
+
50
+ function Hud() {
51
+ const app = useExoApp();
52
+ return <div style={{ position: 'absolute', top: 8, left: 8 }}>FPS overlay…</div>;
53
+ }
54
+ ```
55
+
56
+ Layout props (`style`, `className`, …) apply to the **wrapper**; size it to
57
+ drive `'fill'`/`'letterbox'` sizing. Style the canvas itself via `canvasProps`.
58
+
59
+ ## Quick start — headless hook (full control)
60
+
61
+ ```tsx
62
+ import { useExoApplication } from '@codexo/exojs-react';
63
+
64
+ function Game() {
65
+ const { app, canvasRef } = useExoApplication({ canvas: { width: 800, height: 600 } });
66
+ // Render the canvas however and wherever you want.
67
+ return <canvas ref={canvasRef} className="my-canvas" />;
68
+ }
69
+ ```
70
+
71
+ ## API
72
+
73
+ | Export | Kind | Purpose |
74
+ |---|---|---|
75
+ | `ExoCanvas` | component | Batteries-included canvas host (wrapper div + canvas + context). |
76
+ | `useExoApplication(options?, onReady?)` | hook | Headless: owns the `Application`, returns `{ app, canvasRef }`. |
77
+ | `useExoApp()` | hook | The `Application` from the nearest `<ExoCanvas>`/provider. Throws if absent. |
78
+ | `useExoContext()` | hook | Like `useExoApp` but returns `Application \| null` (no throw). |
79
+ | `ExoContext` | context | The underlying context (advanced / testing). |
80
+ | `useScene(SceneClass, deps?)` | hook | Instantiate + activate a single scene; returns it once live. |
81
+ | `Scenes` / `Scene` | components | Declarative scene switch over the one-active-scene model. |
82
+ | `useActiveScene()` | hook | The active scene instance from the nearest `<Scenes>`. |
83
+
84
+ ### Reactivity model
85
+
86
+ The `Application` is recreated only when an **identity** option changes — the
87
+ render `backend` (WebGL2 ↔ WebGPU cannot be hot-swapped). Other supported options
88
+ are applied **live**:
89
+
90
+ - `canvas.width` / `canvas.height` → `app.resize(...)`
91
+ - `canvas.sizingMode` → `app.sizingMode`
92
+ - `clearColor` → `app.clearColor`
93
+
94
+ Options without a live setter (`canvas.pixelRatio`, `seed`, `extensions`, …) are
95
+ captured at creation; change the `backend` or remount to apply them.
96
+
97
+ ## License
98
+
99
+ MIT © Codexo
@@ -0,0 +1,43 @@
1
+ import type { Application } from '@codexo/exojs';
2
+ import { type CanvasHTMLAttributes, type HTMLAttributes, type ReactElement } from 'react';
3
+ import { type ExoApplicationOptions } from './useExoApplication';
4
+ export interface ExoCanvasProps extends HTMLAttributes<HTMLDivElement> {
5
+ /**
6
+ * Options forwarded to the ExoJS {@link Application}. Pass
7
+ * `canvas.width`/`height`/`sizingMode`/etc.; most options are captured at
8
+ * creation, but `canvas.width`/`height`, `canvas.sizingMode` and `clearColor`
9
+ * are applied live (see {@link useExoApplication}).
10
+ */
11
+ options?: ExoApplicationOptions;
12
+ /**
13
+ * Called once each time the {@link Application} is (re)created. The backend
14
+ * (WebGL2 / WebGPU) is not yet initialized at this point — that happens when
15
+ * the first {@link import('./useScene').useScene} child calls `app.start()`.
16
+ */
17
+ onReady?: (app: Application) => void;
18
+ /**
19
+ * Props forwarded to the inner `<canvas>` (e.g. its own `style`/`className`).
20
+ * `ref`, `width` and `height` are managed by the engine and cannot be set.
21
+ */
22
+ canvasProps?: Omit<CanvasHTMLAttributes<HTMLCanvasElement>, 'ref' | 'width' | 'height'>;
23
+ }
24
+ /**
25
+ * Batteries-included canvas host. Renders a **positioned wrapper `<div>`**
26
+ * containing a React-managed `<canvas>` bound to an ExoJS {@link Application},
27
+ * and provides the app to descendant hooks via context. Because the wrapper is
28
+ * `position: relative`, absolutely-positioned `children` (HUD overlays,
29
+ * {@link import('./Scenes').Scenes}) sit over the canvas out of the box.
30
+ *
31
+ * Layout props (`style`, `className`, …) apply to the **wrapper**; size it to
32
+ * size the canvas in `'fill'`/`'letterbox'` modes. Use {@link canvasProps} to
33
+ * style the canvas itself. For full control with no wrapper element, use the
34
+ * headless {@link useExoApplication} hook directly.
35
+ *
36
+ * @example
37
+ * ```tsx
38
+ * <ExoCanvas options={{ canvas: { width: 800, height: 600 } }} style={{ width: 800, height: 600 }}>
39
+ * <Hud /> // absolutely-positioned overlay; works because the wrapper is relative
40
+ * </ExoCanvas>
41
+ * ```
42
+ */
43
+ export declare function ExoCanvas({ options, onReady, canvasProps, children, style, ...divProps }: ExoCanvasProps): ReactElement;
@@ -0,0 +1,36 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import 'react';
3
+ import { ExoContext } from './ExoContext.js';
4
+ import { useExoApplication } from './useExoApplication.js';
5
+
6
+ /** Default canvas style: block layout avoids the inline-element baseline gap. */
7
+ const defaultCanvasStyle = { display: 'block' };
8
+ /**
9
+ * Batteries-included canvas host. Renders a **positioned wrapper `<div>`**
10
+ * containing a React-managed `<canvas>` bound to an ExoJS {@link Application},
11
+ * and provides the app to descendant hooks via context. Because the wrapper is
12
+ * `position: relative`, absolutely-positioned `children` (HUD overlays,
13
+ * {@link import('./Scenes').Scenes}) sit over the canvas out of the box.
14
+ *
15
+ * Layout props (`style`, `className`, …) apply to the **wrapper**; size it to
16
+ * size the canvas in `'fill'`/`'letterbox'` modes. Use {@link canvasProps} to
17
+ * style the canvas itself. For full control with no wrapper element, use the
18
+ * headless {@link useExoApplication} hook directly.
19
+ *
20
+ * @example
21
+ * ```tsx
22
+ * <ExoCanvas options={{ canvas: { width: 800, height: 600 } }} style={{ width: 800, height: 600 }}>
23
+ * <Hud /> // absolutely-positioned overlay; works because the wrapper is relative
24
+ * </ExoCanvas>
25
+ * ```
26
+ */
27
+ function ExoCanvas({ options, onReady, canvasProps, children, style, ...divProps }) {
28
+ const { app, canvasRef } = useExoApplication(options, onReady);
29
+ const { style: canvasStyle, ...restCanvasProps } = canvasProps ?? {};
30
+ const wrapperStyle = { position: 'relative', ...style };
31
+ const mergedCanvasStyle = { ...defaultCanvasStyle, ...canvasStyle };
32
+ return (jsx(ExoContext.Provider, { value: app, children: jsxs("div", { style: wrapperStyle, ...divProps, children: [jsx("canvas", { ref: canvasRef, style: mergedCanvasStyle, ...restCanvasProps }), app !== null && children] }) }));
33
+ }
34
+
35
+ export { ExoCanvas };
36
+ //# sourceMappingURL=ExoCanvas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExoCanvas.js","sources":["../../../src/ExoCanvas.tsx"],"sourcesContent":[null],"names":["_jsx","_jsxs"],"mappings":";;;;;AAMA;AACA,MAAM,kBAAkB,GAAkB,EAAE,OAAO,EAAE,OAAO,EAAE;AAuB9D;;;;;;;;;;;;;;;;;;AAkBG;SACa,SAAS,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,QAAQ,EAAkB,EAAA;AACvG,IAAA,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,iBAAiB,CAAC,OAAO,EAAE,OAAO,CAAC;AAE9D,IAAA,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,eAAe,EAAE,GAAG,WAAW,IAAI,EAAE;IACpE,MAAM,YAAY,GAAkB,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,KAAK,EAAE;IACtE,MAAM,iBAAiB,GAAkB,EAAE,GAAG,kBAAkB,EAAE,GAAG,WAAW,EAAE;AAElF,IAAA,QACEA,GAAA,CAAC,UAAU,CAAC,QAAQ,IAAC,KAAK,EAAE,GAAG,EAAA,QAAA,EAC7BC,cAAK,KAAK,EAAE,YAAY,EAAA,GAAM,QAAQ,EAAA,QAAA,EAAA,CACpCD,GAAA,CAAA,QAAA,EAAA,EAAQ,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,iBAAiB,KAAM,eAAe,EAAA,CAAI,EACxE,GAAG,KAAK,IAAI,IAAI,QAAQ,CAAA,EAAA,CACrB,EAAA,CACc;AAE1B;;;;"}
@@ -0,0 +1,15 @@
1
+ import type { Application } from '@codexo/exojs';
2
+ /**
3
+ * Internal React context that carries the active {@link Application} instance
4
+ * created by {@link ExoCanvas}. Consumers should use the {@link useExoApp}
5
+ * hook rather than reading this context directly; the context object is
6
+ * exported for advanced use (e.g. testing, custom providers).
7
+ */
8
+ export declare const ExoContext: import("react").Context<Application | null>;
9
+ /**
10
+ * Returns the nearest {@link Application} from the React tree, or `null`
11
+ * when called outside of an {@link ExoCanvas}. Prefer {@link useExoApp} for
12
+ * component-level use — it throws an actionable error instead of returning
13
+ * null.
14
+ */
15
+ export declare function useExoContext(): Application | null;
@@ -0,0 +1,23 @@
1
+ import { createContext, useContext } from 'react';
2
+
3
+ /**
4
+ * Internal React context that carries the active {@link Application} instance
5
+ * created by {@link ExoCanvas}. Consumers should use the {@link useExoApp}
6
+ * hook rather than reading this context directly; the context object is
7
+ * exported for advanced use (e.g. testing, custom providers).
8
+ */
9
+ // eslint-disable-next-line @typescript-eslint/naming-convention
10
+ const ExoContext = createContext(null);
11
+ ExoContext.displayName = 'ExoContext';
12
+ /**
13
+ * Returns the nearest {@link Application} from the React tree, or `null`
14
+ * when called outside of an {@link ExoCanvas}. Prefer {@link useExoApp} for
15
+ * component-level use — it throws an actionable error instead of returning
16
+ * null.
17
+ */
18
+ function useExoContext() {
19
+ return useContext(ExoContext);
20
+ }
21
+
22
+ export { ExoContext, useExoContext };
23
+ //# sourceMappingURL=ExoContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExoContext.js","sources":["../../../src/ExoContext.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAGA;;;;;AAKG;AACH;MACa,UAAU,GAAG,aAAa,CAAqB,IAAI;AAChE,UAAU,CAAC,WAAW,GAAG,YAAY;AAErC;;;;;AAKG;SACa,aAAa,GAAA;AAC3B,IAAA,OAAO,UAAU,CAAC,UAAU,CAAC;AAC/B;;;;"}
@@ -0,0 +1,53 @@
1
+ import { type Scene as ExoScene, type SceneTransition } from '@codexo/exojs';
2
+ import { type ReactElement, type ReactNode } from 'react';
3
+ /**
4
+ * Returns the currently-active scene instance from the nearest {@link Scenes},
5
+ * or `null` while none is live. Useful for HUD/overlay components that need to
6
+ * read scene state.
7
+ */
8
+ export declare function useActiveScene<T extends ExoScene = ExoScene>(): T | null;
9
+ /** Props for a {@link Scene} declaration. */
10
+ export interface SceneProps {
11
+ /** Unique name used to select this scene via {@link ScenesProps.active}. */
12
+ readonly name: string;
13
+ /** Scene class to instantiate when this scene becomes active. */
14
+ readonly component: new () => ExoScene;
15
+ /** React overlay (HUD) rendered only while this scene is active. */
16
+ readonly children?: ReactNode;
17
+ }
18
+ /**
19
+ * Declares one scene inside a {@link Scenes} switch. Renders nothing on its own —
20
+ * {@link Scenes} reads its props and renders its {@link SceneProps.children} only
21
+ * while the scene is active.
22
+ */
23
+ export declare function Scene(_props: SceneProps): ReactElement | null;
24
+ /** Props for the {@link Scenes} switch. */
25
+ export interface ScenesProps {
26
+ /** Name of the active {@link Scene}. Changing it switches scenes. */
27
+ readonly active: string;
28
+ /** Optional transition (e.g. a fade) applied when switching scenes. */
29
+ readonly transition?: SceneTransition;
30
+ /** {@link Scene} declarations. */
31
+ readonly children?: ReactNode;
32
+ }
33
+ /**
34
+ * Declarative scene switch over the one-active-scene model. Renders a set of
35
+ * {@link Scene} declarations and activates the one whose `name` equals `active`
36
+ * via `app.start()` (first activation) or `app.scene.setScene()` (subsequent
37
+ * switches, with the optional `transition`). The active scene's React children
38
+ * (HUD overlay) render alongside, and can read the instance via
39
+ * {@link useActiveScene}.
40
+ *
41
+ * @example
42
+ * ```tsx
43
+ * <ExoCanvas>
44
+ * <Scenes active={screen} transition={{ type: 'fade', duration: 0.3 }}>
45
+ * <Scene name="title" component={TitleScene} />
46
+ * <Scene name="game" component={GameScene}>
47
+ * <Hud />
48
+ * </Scene>
49
+ * </Scenes>
50
+ * </ExoCanvas>
51
+ * ```
52
+ */
53
+ export declare function Scenes({ active, transition, children }: ScenesProps): ReactElement;
@@ -0,0 +1,95 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { ApplicationStatus } from '@codexo/exojs';
3
+ import { createContext, useState, useMemo, Children, isValidElement, useEffect, useContext } from 'react';
4
+ import { useExoApp } from './useExoApp.js';
5
+
6
+ /** Carries the active {@link ExoScene} instance to descendants (HUD overlays). */
7
+ const ActiveSceneContext = createContext(null);
8
+ ActiveSceneContext.displayName = 'ExoActiveScene';
9
+ /**
10
+ * Returns the currently-active scene instance from the nearest {@link Scenes},
11
+ * or `null` while none is live. Useful for HUD/overlay components that need to
12
+ * read scene state.
13
+ */
14
+ function useActiveScene() {
15
+ return useContext(ActiveSceneContext);
16
+ }
17
+ /**
18
+ * Declares one scene inside a {@link Scenes} switch. Renders nothing on its own —
19
+ * {@link Scenes} reads its props and renders its {@link SceneProps.children} only
20
+ * while the scene is active.
21
+ */
22
+ function Scene(_props) {
23
+ return null;
24
+ }
25
+ /**
26
+ * Declarative scene switch over the one-active-scene model. Renders a set of
27
+ * {@link Scene} declarations and activates the one whose `name` equals `active`
28
+ * via `app.start()` (first activation) or `app.scene.setScene()` (subsequent
29
+ * switches, with the optional `transition`). The active scene's React children
30
+ * (HUD overlay) render alongside, and can read the instance via
31
+ * {@link useActiveScene}.
32
+ *
33
+ * @example
34
+ * ```tsx
35
+ * <ExoCanvas>
36
+ * <Scenes active={screen} transition={{ type: 'fade', duration: 0.3 }}>
37
+ * <Scene name="title" component={TitleScene} />
38
+ * <Scene name="game" component={GameScene}>
39
+ * <Hud />
40
+ * </Scene>
41
+ * </Scenes>
42
+ * </ExoCanvas>
43
+ * ```
44
+ */
45
+ function Scenes({ active, transition, children }) {
46
+ const app = useExoApp();
47
+ const [instance, setInstance] = useState(null);
48
+ // Collect the <Scene> declarations from children (keyed by name).
49
+ const registry = useMemo(() => {
50
+ const map = new Map();
51
+ Children.forEach(children, child => {
52
+ if (isValidElement(child) && child.type === Scene) {
53
+ const props = child.props;
54
+ map.set(props.name, props);
55
+ }
56
+ });
57
+ return map;
58
+ }, [children]);
59
+ const entry = registry.get(active);
60
+ const SceneClass = entry?.component ?? null;
61
+ useEffect(() => {
62
+ if (SceneClass === null) {
63
+ setInstance(null);
64
+ void app.scene.setScene(null);
65
+ return;
66
+ }
67
+ let cancelled = false;
68
+ const scene = new SceneClass();
69
+ const apply = async () => {
70
+ if (app.status === ApplicationStatus.Stopped) {
71
+ // First activation initializes the backend and starts the frame loop;
72
+ // transitions only apply to subsequent switches.
73
+ await app.start(scene);
74
+ }
75
+ else {
76
+ await app.scene.setScene(scene, transition !== undefined ? { transition } : {});
77
+ }
78
+ if (!cancelled) {
79
+ setInstance(scene);
80
+ }
81
+ };
82
+ void apply();
83
+ return () => {
84
+ cancelled = true;
85
+ setInstance(null);
86
+ };
87
+ // Re-activate when the active name changes. SceneClass/transition derive
88
+ // from `active`; keying on app + active avoids re-instantiating each render.
89
+ // eslint-disable-next-line react-hooks/exhaustive-deps
90
+ }, [app, active]);
91
+ return (jsx(ActiveSceneContext.Provider, { value: instance, children: instance !== null && entry?.children }));
92
+ }
93
+
94
+ export { Scene, Scenes, useActiveScene };
95
+ //# sourceMappingURL=Scenes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Scenes.js","sources":["../../../src/Scenes.tsx"],"sourcesContent":[null],"names":["_jsx"],"mappings":";;;;;AAeA;AACA,MAAM,kBAAkB,GAAG,aAAa,CAAkB,IAAI,CAAC;AAC/D,kBAAkB,CAAC,WAAW,GAAG,gBAAgB;AAEjD;;;;AAIG;SACa,cAAc,GAAA;AAC5B,IAAA,OAAO,UAAU,CAAC,kBAAkB,CAAa;AACnD;AAYA;;;;AAIG;AACG,SAAU,KAAK,CAAC,MAAkB,EAAA;AACtC,IAAA,OAAO,IAAI;AACb;AAYA;;;;;;;;;;;;;;;;;;;AAmBG;AACG,SAAU,MAAM,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAe,EAAA;AAClE,IAAA,MAAM,GAAG,GAAG,SAAS,EAAE;IACvB,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAkB,IAAI,CAAC;;AAG/D,IAAA,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAK;AAC5B,QAAA,MAAM,GAAG,GAAG,IAAI,GAAG,EAAsB;AACzC,QAAA,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,KAAK,IAAG;YACjC,IAAI,cAAc,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,EAAE;AACjD,gBAAA,MAAM,KAAK,GAAG,KAAK,CAAC,KAAmB;gBACvC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC;YAC5B;AACF,QAAA,CAAC,CAAC;AACF,QAAA,OAAO,GAAG;AACZ,IAAA,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC;IAEd,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC;AAClC,IAAA,MAAM,UAAU,GAAG,KAAK,EAAE,SAAS,IAAI,IAAI;IAE3C,SAAS,CAAC,MAAK;AACb,QAAA,IAAI,UAAU,KAAK,IAAI,EAAE;YACvB,WAAW,CAAC,IAAI,CAAC;YACjB,KAAK,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;YAC7B;QACF;QAEA,IAAI,SAAS,GAAG,KAAK;AACrB,QAAA,MAAM,KAAK,GAAG,IAAI,UAAU,EAAE;AAE9B,QAAA,MAAM,KAAK,GAAG,YAA0B;YACtC,IAAI,GAAG,CAAC,MAAM,KAAK,iBAAiB,CAAC,OAAO,EAAE;;;AAG5C,gBAAA,MAAM,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC;YACxB;iBAAO;gBACL,MAAM,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,EAAE,UAAU,KAAK,SAAS,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC;YACjF;YACA,IAAI,CAAC,SAAS,EAAE;gBACd,WAAW,CAAC,KAAK,CAAC;YACpB;AACF,QAAA,CAAC;QAED,KAAK,KAAK,EAAE;AAEZ,QAAA,OAAO,MAAK;YACV,SAAS,GAAG,IAAI;YAChB,WAAW,CAAC,IAAI,CAAC;AACnB,QAAA,CAAC;;;;AAIH,IAAA,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;AAEjB,IAAA,QACEA,GAAA,CAAC,kBAAkB,CAAC,QAAQ,EAAA,EAAC,KAAK,EAAE,QAAQ,YACzC,QAAQ,KAAK,IAAI,IAAI,KAAK,EAAE,QAAQ,EAAA,CACT;AAElC;;;;"}
@@ -0,0 +1,9 @@
1
+ export type { ExoCanvasProps } from './ExoCanvas';
2
+ export { ExoCanvas } from './ExoCanvas';
3
+ export { ExoContext, useExoContext } from './ExoContext';
4
+ export type { SceneProps, ScenesProps } from './Scenes';
5
+ export { Scene, Scenes, useActiveScene } from './Scenes';
6
+ export { useExoApp } from './useExoApp';
7
+ export type { ExoApplicationOptions, UseExoApplicationResult } from './useExoApplication';
8
+ export { useExoApplication } from './useExoApplication';
9
+ export { useScene } from './useScene';
@@ -0,0 +1,7 @@
1
+ export { ExoCanvas } from './ExoCanvas.js';
2
+ export { ExoContext, useExoContext } from './ExoContext.js';
3
+ export { Scene, Scenes, useActiveScene } from './Scenes.js';
4
+ export { useExoApp } from './useExoApp.js';
5
+ export { useExoApplication } from './useExoApplication.js';
6
+ export { useScene } from './useScene.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;"}
@@ -0,0 +1,17 @@
1
+ import type { Application } from '@codexo/exojs';
2
+ /**
3
+ * Returns the {@link Application} instance from the nearest {@link ExoCanvas}
4
+ * ancestor. Throws an informative error when called outside of an
5
+ * `<ExoCanvas>` tree.
6
+ *
7
+ * @throws {Error} When no `<ExoCanvas>` ancestor is present.
8
+ *
9
+ * @example
10
+ * ```tsx
11
+ * function HudOverlay() {
12
+ * const app = useExoApp();
13
+ * return <span>Frame: {app.frameCount}</span>;
14
+ * }
15
+ * ```
16
+ */
17
+ export declare function useExoApp(): Application;
@@ -0,0 +1,27 @@
1
+ import { useExoContext } from './ExoContext.js';
2
+
3
+ /**
4
+ * Returns the {@link Application} instance from the nearest {@link ExoCanvas}
5
+ * ancestor. Throws an informative error when called outside of an
6
+ * `<ExoCanvas>` tree.
7
+ *
8
+ * @throws {Error} When no `<ExoCanvas>` ancestor is present.
9
+ *
10
+ * @example
11
+ * ```tsx
12
+ * function HudOverlay() {
13
+ * const app = useExoApp();
14
+ * return <span>Frame: {app.frameCount}</span>;
15
+ * }
16
+ * ```
17
+ */
18
+ function useExoApp() {
19
+ const app = useExoContext();
20
+ if (app === null) {
21
+ throw new Error('useExoApp must be used inside an <ExoCanvas> component.');
22
+ }
23
+ return app;
24
+ }
25
+
26
+ export { useExoApp };
27
+ //# sourceMappingURL=useExoApp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useExoApp.js","sources":["../../../src/useExoApp.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAIA;;;;;;;;;;;;;;AAcG;SACa,SAAS,GAAA;AACvB,IAAA,MAAM,GAAG,GAAG,aAAa,EAAE;AAE3B,IAAA,IAAI,GAAG,KAAK,IAAI,EAAE;AAChB,QAAA,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC;IAC5E;AAEA,IAAA,OAAO,GAAG;AACZ;;;;"}
@@ -0,0 +1,57 @@
1
+ import { Application, type ApplicationOptions, type CanvasApplicationOptions } from '@codexo/exojs';
2
+ import { type Ref } from 'react';
3
+ /**
4
+ * Options for {@link useExoApplication} / {@link import('./ExoCanvas').ExoCanvas}.
5
+ *
6
+ * Same as {@link ApplicationOptions} but the `canvas.element` and `canvas.mount`
7
+ * fields are managed for you (the Application binds to the canvas the hook
8
+ * references), so they are omitted. You may still pass
9
+ * `canvas.width`/`height`/`sizingMode`/etc.
10
+ */
11
+ export type ExoApplicationOptions = Omit<ApplicationOptions, 'canvas'> & {
12
+ readonly canvas?: Omit<CanvasApplicationOptions, 'element' | 'mount'>;
13
+ };
14
+ /** Return value of {@link useExoApplication}. */
15
+ export interface UseExoApplicationResult {
16
+ /** The Application instance, or `null` until it has been created. */
17
+ readonly app: Application | null;
18
+ /**
19
+ * Attach this to the `<canvas>` element the Application should bind to. Typed
20
+ * as `Ref` (not `RefObject`) so the same code type-checks against both
21
+ * `@types/react` 18 and 19, whose `useRef`/`RefObject` nullability differ.
22
+ */
23
+ readonly canvasRef: Ref<HTMLCanvasElement>;
24
+ }
25
+ /**
26
+ * Creates and owns an ExoJS {@link Application}, binding it to a `<canvas>` you
27
+ * render yourself and attach the returned `canvasRef` to. The hook renders no
28
+ * DOM of its own — you keep full control over the canvas element, its container,
29
+ * and its styling.
30
+ *
31
+ * ```tsx
32
+ * function Game() {
33
+ * const { app, canvasRef } = useExoApplication({ canvas: { width: 800, height: 600 } });
34
+ * return <canvas ref={canvasRef} className="game" />;
35
+ * }
36
+ * ```
37
+ *
38
+ * **Reactivity model.** The Application is recreated only when an *identity*
39
+ * option changes — currently the render `backend` (you cannot hot-swap WebGL2 ↔
40
+ * WebGPU). All other supported options are applied *live* without tearing the
41
+ * app down:
42
+ *
43
+ * - `canvas.width` / `canvas.height` → `app.resize(...)`
44
+ * - `canvas.sizingMode` → `app.sizingMode`
45
+ * - `clearColor` → `app.clearColor`
46
+ *
47
+ * Options without a live setter (e.g. `canvas.pixelRatio`, `seed`, `extensions`)
48
+ * are captured at creation; change the `backend` or remount to apply them.
49
+ *
50
+ * Styling note: with the default `'fixed'` sizing mode the engine never touches
51
+ * the canvas CSS, so you may style it freely. The `'fit'`/`'shrink'`/`'letterbox'`
52
+ * modes manage `canvas.style` themselves — don't fight them with a `style` prop.
53
+ *
54
+ * @param options - Application options (the canvas element is the one you render).
55
+ * @param onReady - Called once each time an Application is created.
56
+ */
57
+ export declare function useExoApplication(options?: ExoApplicationOptions, onReady?: (app: Application) => void): UseExoApplicationResult;
@@ -0,0 +1,103 @@
1
+ import { Application } from '@codexo/exojs';
2
+ import { useRef, useState, useEffect } from 'react';
3
+
4
+ /** Stable string key for the colour so the sync effect can depend on its value. */
5
+ function colorKey(color) {
6
+ return color === undefined ? undefined : `${color.r},${color.g},${color.b},${color.a}`;
7
+ }
8
+ /**
9
+ * Creates and owns an ExoJS {@link Application}, binding it to a `<canvas>` you
10
+ * render yourself and attach the returned `canvasRef` to. The hook renders no
11
+ * DOM of its own — you keep full control over the canvas element, its container,
12
+ * and its styling.
13
+ *
14
+ * ```tsx
15
+ * function Game() {
16
+ * const { app, canvasRef } = useExoApplication({ canvas: { width: 800, height: 600 } });
17
+ * return <canvas ref={canvasRef} className="game" />;
18
+ * }
19
+ * ```
20
+ *
21
+ * **Reactivity model.** The Application is recreated only when an *identity*
22
+ * option changes — currently the render `backend` (you cannot hot-swap WebGL2 ↔
23
+ * WebGPU). All other supported options are applied *live* without tearing the
24
+ * app down:
25
+ *
26
+ * - `canvas.width` / `canvas.height` → `app.resize(...)`
27
+ * - `canvas.sizingMode` → `app.sizingMode`
28
+ * - `clearColor` → `app.clearColor`
29
+ *
30
+ * Options without a live setter (e.g. `canvas.pixelRatio`, `seed`, `extensions`)
31
+ * are captured at creation; change the `backend` or remount to apply them.
32
+ *
33
+ * Styling note: with the default `'fixed'` sizing mode the engine never touches
34
+ * the canvas CSS, so you may style it freely. The `'fit'`/`'shrink'`/`'letterbox'`
35
+ * modes manage `canvas.style` themselves — don't fight them with a `style` prop.
36
+ *
37
+ * @param options - Application options (the canvas element is the one you render).
38
+ * @param onReady - Called once each time an Application is created.
39
+ */
40
+ function useExoApplication(options, onReady) {
41
+ const canvasRef = useRef(null);
42
+ const [app, setApp] = useState(null);
43
+ // Latest onReady without retriggering the lifecycle effect. Updated in an
44
+ // effect (not during render) so the ref-write happens after commit.
45
+ const onReadyRef = useRef(onReady);
46
+ useEffect(() => {
47
+ onReadyRef.current = onReady;
48
+ });
49
+ // Identity: only the backend type forces a full recreation.
50
+ const backendKey = options?.backend?.type ?? 'auto';
51
+ // ── Lifecycle: create on mount / recreate on backend change ───────────────
52
+ useEffect(() => {
53
+ const canvas = canvasRef.current;
54
+ if (!canvas) {
55
+ return;
56
+ }
57
+ // Bind to the React-rendered canvas. The engine never removes a canvas it
58
+ // did not create (Application.destroy leaves it in the DOM), so React stays
59
+ // the sole owner of the element's lifecycle.
60
+ const application = new Application({
61
+ ...options,
62
+ canvas: { ...options?.canvas, element: canvas },
63
+ });
64
+ setApp(application);
65
+ onReadyRef.current?.(application);
66
+ return () => {
67
+ application.destroy();
68
+ setApp(null);
69
+ };
70
+ // Recreate only when the backend identity changes; live options are synced
71
+ // by the effects below. `options` is intentionally read at (re)create time.
72
+ // eslint-disable-next-line react-hooks/exhaustive-deps
73
+ }, [backendKey]);
74
+ // ── Live sync: size ───────────────────────────────────────────────────────
75
+ const width = options?.canvas?.width;
76
+ const height = options?.canvas?.height;
77
+ useEffect(() => {
78
+ if (app !== null && width !== undefined && height !== undefined) {
79
+ app.resize(width, height);
80
+ }
81
+ }, [app, width, height]);
82
+ // ── Live sync: sizing mode ────────────────────────────────────────────────
83
+ const sizingMode = options?.canvas?.sizingMode;
84
+ useEffect(() => {
85
+ if (app !== null && sizingMode !== undefined) {
86
+ app.sizingMode = sizingMode;
87
+ }
88
+ }, [app, sizingMode]);
89
+ // ── Live sync: clear colour ───────────────────────────────────────────────
90
+ const clearColor = options?.clearColor;
91
+ const clearKey = colorKey(clearColor);
92
+ useEffect(() => {
93
+ if (app !== null && clearColor !== undefined) {
94
+ app.clearColor = clearColor;
95
+ }
96
+ // clearColor identity is unstable; depend on its value key instead.
97
+ // eslint-disable-next-line react-hooks/exhaustive-deps
98
+ }, [app, clearKey]);
99
+ return { app, canvasRef };
100
+ }
101
+
102
+ export { useExoApplication };
103
+ //# sourceMappingURL=useExoApplication.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useExoApplication.js","sources":["../../../src/useExoApplication.ts"],"sourcesContent":[null],"names":[],"mappings":";;;AA2BA;AACA,SAAS,QAAQ,CAAC,KAAwB,EAAA;IACxC,OAAO,KAAK,KAAK,SAAS,GAAG,SAAS,GAAG,CAAA,EAAG,KAAK,CAAC,CAAC,CAAA,CAAA,EAAI,KAAK,CAAC,CAAC,CAAA,CAAA,EAAI,KAAK,CAAC,CAAC,CAAA,CAAA,EAAI,KAAK,CAAC,CAAC,CAAA,CAAE;AACxF;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BG;AACG,SAAU,iBAAiB,CAC/B,OAA+B,EAC/B,OAAoC,EAAA;AAEpC,IAAA,MAAM,SAAS,GAAG,MAAM,CAAoB,IAAI,CAAC;IACjD,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,QAAQ,CAAqB,IAAI,CAAC;;;AAIxD,IAAA,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC;IAClC,SAAS,CAAC,MAAK;AACb,QAAA,UAAU,CAAC,OAAO,GAAG,OAAO;AAC9B,IAAA,CAAC,CAAC;;IAGF,MAAM,UAAU,GAAG,OAAO,EAAE,OAAO,EAAE,IAAI,IAAI,MAAM;;IAGnD,SAAS,CAAC,MAAK;AACb,QAAA,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO;QAChC,IAAI,CAAC,MAAM,EAAE;YACX;QACF;;;;AAKA,QAAA,MAAM,WAAW,GAAG,IAAI,WAAW,CAAC;AAClC,YAAA,GAAG,OAAO;YACV,MAAM,EAAE,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE;AAChD,SAAA,CAAC;QAEF,MAAM,CAAC,WAAW,CAAC;AACnB,QAAA,UAAU,CAAC,OAAO,GAAG,WAAW,CAAC;AAEjC,QAAA,OAAO,MAAK;YACV,WAAW,CAAC,OAAO,EAAE;YACrB,MAAM,CAAC,IAAI,CAAC;AACd,QAAA,CAAC;;;;AAIH,IAAA,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC;;AAGhB,IAAA,MAAM,KAAK,GAAG,OAAO,EAAE,MAAM,EAAE,KAAK;AACpC,IAAA,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,EAAE,MAAM;IACtC,SAAS,CAAC,MAAK;AACb,QAAA,IAAI,GAAG,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,IAAI,MAAM,KAAK,SAAS,EAAE;AAC/D,YAAA,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC;QAC3B;IACF,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;;AAGxB,IAAA,MAAM,UAAU,GAAG,OAAO,EAAE,MAAM,EAAE,UAAU;IAC9C,SAAS,CAAC,MAAK;QACb,IAAI,GAAG,KAAK,IAAI,IAAI,UAAU,KAAK,SAAS,EAAE;AAC5C,YAAA,GAAG,CAAC,UAAU,GAAG,UAAU;QAC7B;AACF,IAAA,CAAC,EAAE,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;;AAGrB,IAAA,MAAM,UAAU,GAAG,OAAO,EAAE,UAAU;AACtC,IAAA,MAAM,QAAQ,GAAG,QAAQ,CAAC,UAAU,CAAC;IACrC,SAAS,CAAC,MAAK;QACb,IAAI,GAAG,KAAK,IAAI,IAAI,UAAU,KAAK,SAAS,EAAE;AAC5C,YAAA,GAAG,CAAC,UAAU,GAAG,UAAU;QAC7B;;;AAGF,IAAA,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;AAEnB,IAAA,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE;AAC3B;;;;"}
@@ -0,0 +1,29 @@
1
+ import { type Scene } from '@codexo/exojs';
2
+ import { type DependencyList } from 'react';
3
+ /**
4
+ * Creates an instance of `SceneClass`, activates it on the ExoJS
5
+ * {@link Application}, and returns it once the scene is live.
6
+ *
7
+ * On first call (engine not yet started) this hook calls `app.start(scene)`,
8
+ * which initializes the render backend and begins the per-frame loop. On
9
+ * subsequent dep-change remounts it calls `app.scene.setScene(scene)` to
10
+ * switch scenes without restarting the engine.
11
+ *
12
+ * The scene is cleared (`setScene(null)`) when the component unmounts or
13
+ * when `deps` change — mirroring `useEffect` semantics.
14
+ *
15
+ * @param SceneClass - Constructor for the scene to instantiate.
16
+ * @param deps - Extra deps that trigger scene replacement when changed, in
17
+ * addition to the stable `app` reference (same semantics as `useEffect`).
18
+ * @returns The active scene instance, or `null` while it is loading.
19
+ *
20
+ * @example
21
+ * ```tsx
22
+ * function GameScreen() {
23
+ * const scene = useScene(MyGameScene);
24
+ * if (!scene) return null;
25
+ * return <ScoreHud scene={scene} />;
26
+ * }
27
+ * ```
28
+ */
29
+ export declare function useScene<T extends Scene>(SceneClass: new () => T, deps?: DependencyList): T | null;
@@ -0,0 +1,67 @@
1
+ import { ApplicationStatus } from '@codexo/exojs';
2
+ import { useState, useEffect } from 'react';
3
+ import { useExoApp } from './useExoApp.js';
4
+
5
+ /**
6
+ * Creates an instance of `SceneClass`, activates it on the ExoJS
7
+ * {@link Application}, and returns it once the scene is live.
8
+ *
9
+ * On first call (engine not yet started) this hook calls `app.start(scene)`,
10
+ * which initializes the render backend and begins the per-frame loop. On
11
+ * subsequent dep-change remounts it calls `app.scene.setScene(scene)` to
12
+ * switch scenes without restarting the engine.
13
+ *
14
+ * The scene is cleared (`setScene(null)`) when the component unmounts or
15
+ * when `deps` change — mirroring `useEffect` semantics.
16
+ *
17
+ * @param SceneClass - Constructor for the scene to instantiate.
18
+ * @param deps - Extra deps that trigger scene replacement when changed, in
19
+ * addition to the stable `app` reference (same semantics as `useEffect`).
20
+ * @returns The active scene instance, or `null` while it is loading.
21
+ *
22
+ * @example
23
+ * ```tsx
24
+ * function GameScreen() {
25
+ * const scene = useScene(MyGameScene);
26
+ * if (!scene) return null;
27
+ * return <ScoreHud scene={scene} />;
28
+ * }
29
+ * ```
30
+ */
31
+ // eslint-disable-next-line @typescript-eslint/naming-convention
32
+ function useScene(SceneClass, deps = []) {
33
+ const app = useExoApp();
34
+ const [scene, setScene] = useState(null);
35
+ useEffect(() => {
36
+ let cancelled = false;
37
+ const s = new SceneClass();
38
+ const apply = async () => {
39
+ if (app.status === ApplicationStatus.Stopped) {
40
+ // First activation — initialize the backend and start the frame loop.
41
+ await app.start(s);
42
+ }
43
+ else {
44
+ // Engine already running — switch scenes without restarting.
45
+ await app.scene.setScene(s);
46
+ }
47
+ if (!cancelled) {
48
+ setScene(s);
49
+ }
50
+ };
51
+ void apply();
52
+ return () => {
53
+ cancelled = true;
54
+ setScene(null);
55
+ // Best-effort scene clear; the Application.destroy() called by
56
+ // ExoCanvas cleanup will also handle any remaining active scene.
57
+ void app.scene.setScene(null);
58
+ };
59
+ // SceneClass is intentionally excluded from deps: a new class reference
60
+ // (e.g. inline arrow class) on every render would recreate the scene
61
+ // each frame. Pass an explicit deps array to react to changes.
62
+ }, [app, ...deps]);
63
+ return scene;
64
+ }
65
+
66
+ export { useScene };
67
+ //# sourceMappingURL=useScene.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useScene.js","sources":["../../../src/useScene.ts"],"sourcesContent":[null],"names":[],"mappings":";;;;AAKA;;;;;;;;;;;;;;;;;;;;;;;;;AAyBG;AACH;SACgB,QAAQ,CAAkB,UAAuB,EAAE,OAAuB,EAAE,EAAA;AAC1F,IAAA,MAAM,GAAG,GAAG,SAAS,EAAE;IACvB,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAW,IAAI,CAAC;IAElD,SAAS,CAAC,MAAK;QACb,IAAI,SAAS,GAAG,KAAK;AACrB,QAAA,MAAM,CAAC,GAAG,IAAI,UAAU,EAAE;AAE1B,QAAA,MAAM,KAAK,GAAG,YAA0B;YACtC,IAAI,GAAG,CAAC,MAAM,KAAK,iBAAiB,CAAC,OAAO,EAAE;;AAE5C,gBAAA,MAAM,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;YACpB;iBAAO;;gBAEL,MAAM,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;YAC7B;YAEA,IAAI,CAAC,SAAS,EAAE;gBACd,QAAQ,CAAC,CAAC,CAAC;YACb;AACF,QAAA,CAAC;QAED,KAAK,KAAK,EAAE;AAEZ,QAAA,OAAO,MAAK;YACV,SAAS,GAAG,IAAI;YAChB,QAAQ,CAAC,IAAI,CAAC;;;YAGd,KAAK,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;AAC/B,QAAA,CAAC;;;;IAIH,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;AAElB,IAAA,OAAO,KAAK;AACd;;;;"}
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@codexo/exojs-react",
3
+ "version": "0.14.0",
4
+ "description": "React integration for ExoJS.",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/Exoridus/ExoJS.git",
8
+ "directory": "packages/exojs-react"
9
+ },
10
+ "type": "module",
11
+ "main": "./dist/esm/index.js",
12
+ "module": "./dist/esm/index.js",
13
+ "types": "./dist/esm/index.d.ts",
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/esm/index.d.ts",
17
+ "import": "./dist/esm/index.js",
18
+ "default": "./dist/esm/index.js"
19
+ },
20
+ "./package.json": "./package.json"
21
+ },
22
+ "files": [
23
+ "dist/esm/",
24
+ "README.md",
25
+ "LICENSE"
26
+ ],
27
+ "peerDependencies": {
28
+ "@codexo/exojs": "0.14.x",
29
+ "react": ">=18.0.0",
30
+ "react-dom": ">=18.0.0"
31
+ },
32
+ "peerDependenciesMeta": {
33
+ "react-dom": {
34
+ "optional": true
35
+ }
36
+ },
37
+ "devDependencies": {
38
+ "@types/react": "^18.0.0",
39
+ "@codexo/exojs": "0.14.0",
40
+ "@codexo/exojs-config": "0.0.0"
41
+ },
42
+ "license": "MIT",
43
+ "publishConfig": {
44
+ "access": "public"
45
+ },
46
+ "scripts": {
47
+ "build": "tsx ../../node_modules/rollup/dist/bin/rollup -c --environment EXOJS_ENV:production",
48
+ "build:dev": "tsx ../../node_modules/rollup/dist/bin/rollup -c --environment EXOJS_ENV:development",
49
+ "typecheck": "tsc --noEmit",
50
+ "lint": "eslint \"src/**/*.{ts,tsx}\""
51
+ }
52
+ }