@rmc-toolkit/react 0.1.0 → 0.2.3

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,86 @@
1
+ # @rmc-toolkit/react
2
+
3
+ React adapter for [Runtime Module Composition](https://runtime-module-composition.dev). Two factories, for two different slice conventions — pick the one matching how your slices are written, not both for the same slice. Both take your app's own already-resolved `React` instance rather than importing one themselves, so this package never bundles a second, conflicting copy of React.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @rmc-toolkit/react @rmc-toolkit/core react
9
+ ```
10
+
11
+ ## Quick example
12
+
13
+ **Slices share the `mount()`/`unmount()` convention:** use `createReactAdapter`, which wraps the resolve/import/mount lifecycle in a `useRuntimeHost` hook:
14
+
15
+ ```ts
16
+ // src/rmc-adapter.ts
17
+ import React from "react";
18
+ import { createReactAdapter } from "@rmc-toolkit/react";
19
+
20
+ export const { useRuntimeHost } = createReactAdapter(React);
21
+ ```
22
+
23
+ ```tsx
24
+ // App.tsx
25
+ import { useLocation } from "react-router-dom";
26
+ import { useRuntimeHost } from "./rmc-adapter";
27
+ import { manifest } from "./runtime-composition.manifest";
28
+
29
+ function App() {
30
+ const location = useLocation();
31
+ const { ref, status } = useRuntimeHost<HTMLElement>(location.pathname, { manifest });
32
+
33
+ return (
34
+ <div className="app-shell">
35
+ <SiteHeader loading={status.type === "loading"} />
36
+ <main ref={ref} />
37
+ <SiteFooter />
38
+ </div>
39
+ );
40
+ }
41
+ ```
42
+
43
+ **Slices are plain default-exported components (not `mount()`/`unmount()`):** use `createDynamicModuleBoundary` instead:
44
+
45
+ ```tsx
46
+ // src/rmc-adapter.ts
47
+ import React from "react";
48
+ import { createDynamicModuleBoundary } from "@rmc-toolkit/react";
49
+
50
+ export const { DynamicModuleBoundary } = createDynamicModuleBoundary(React);
51
+ ```
52
+
53
+ ```tsx
54
+ // RouteSlot.tsx
55
+ import { resolveRoute } from "@rmc-toolkit/core";
56
+ import { DynamicModuleBoundary } from "./rmc-adapter";
57
+ import { manifest } from "./runtime-composition.manifest";
58
+
59
+ export function RouteSlot() {
60
+ const match = resolveRoute(manifest, window.location.pathname);
61
+ if (!match) return null;
62
+
63
+ return (
64
+ <DynamicModuleBoundary
65
+ specifier={match.specifier}
66
+ context={{ route: match, manifest }}
67
+ fallback={<div>Loading...</div>}
68
+ errorFallback={<div>Unable to load this section.</div>}
69
+ />
70
+ );
71
+ }
72
+ ```
73
+
74
+ ## What's in here
75
+
76
+ - `createReactAdapter(React)` → `{ useRuntimeHost }` — a hook wrapping `createRuntimeHostObservable`'s resolve/import/mount/unmount lifecycle, with loading/error status.
77
+ - `createDynamicModuleBoundary(React)` → `{ DynamicModuleBoundary }` — a `Suspense` + error-boundary component around `React.lazy()`-loading a slice's default-exported component.
78
+
79
+ Full signatures and behavior for both: [API Reference](https://runtime-module-composition.dev/api-reference/#react-adapter-rmc-toolkitreact).
80
+
81
+ ## Documentation
82
+
83
+ - [Getting Started](https://runtime-module-composition.dev/getting-started/) — install and wire up a host + slice end to end
84
+ - [API Reference](https://runtime-module-composition.dev/api-reference/#react-adapter-rmc-toolkitreact)
85
+ - [Technical Implementation](https://runtime-module-composition.dev/technical-implementation/) — the architecture and failure modes behind the pattern
86
+ - [Multi-Framework Demo](https://runtime-module-composition.dev/demo/) — a full, runnable reference implementation, including a React slice
@@ -0,0 +1,13 @@
1
+ import type * as ReactNamespace from "react";
2
+ import { type DynamicImporter, type RuntimeModuleContext } from "@rmc-toolkit/core";
3
+ export type DynamicModuleBoundaryProps = {
4
+ specifier: string;
5
+ context?: RuntimeModuleContext;
6
+ fallback?: ReactNamespace.ReactNode;
7
+ errorFallback?: ReactNamespace.ReactNode;
8
+ importer?: DynamicImporter;
9
+ };
10
+ export declare const createDynamicModuleBoundary: (React: typeof ReactNamespace) => {
11
+ DynamicModuleBoundary: (props: DynamicModuleBoundaryProps) => ReactNamespace.ReactElement;
12
+ };
13
+ //# sourceMappingURL=create-dynamic-module-boundary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-dynamic-module-boundary.d.ts","sourceRoot":"","sources":["../src/create-dynamic-module-boundary.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,cAAc,MAAM,OAAO,CAAC;AAC7C,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,oBAAoB,EAC1B,MAAM,mBAAmB,CAAC;AAM3B,MAAM,MAAM,0BAA0B,GAAG;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,oBAAoB,CAAC;IAC/B,QAAQ,CAAC,EAAE,cAAc,CAAC,SAAS,CAAC;IACpC,aAAa,CAAC,EAAE,cAAc,CAAC,SAAS,CAAC;IACzC,QAAQ,CAAC,EAAE,eAAe,CAAC;CAC5B,CAAC;AAYF,eAAO,MAAM,2BAA2B,GACtC,OAAO,OAAO,cAAc,KAC3B;IACD,qBAAqB,EAAE,CAAC,KAAK,EAAE,0BAA0B,KAAK,cAAc,CAAC,YAAY,CAAC;CAiF3F,CAAC"}
@@ -0,0 +1,65 @@
1
+ import { importModule, } from "@rmc-toolkit/core";
2
+ const defaultImporter = importModule;
3
+ // This file is intentionally `.ts`, not `.tsx`: with "jsx": "react-jsx" in
4
+ // tsconfig.json, any JSX syntax in a file makes the compiler auto-inject a
5
+ // runtime `import ... from "react/jsx-runtime"` that never appears in source.
6
+ // That import would be just as unreconcilable with a host app's own React
7
+ // instance as the top-level `import React from "react"` this factory is
8
+ // fixing. So every element below is built with React.createElement(...)
9
+ // (exactly what JSX desugars to) using the React namespace passed in as a
10
+ // parameter, never a module-level import of "react" as a value.
11
+ export const createDynamicModuleBoundary = (React) => {
12
+ // ErrorBoundary is redefined on every createDynamicModuleBoundary call
13
+ // rather than hoisted out as a module-level class: it extends the
14
+ // injected `React.Component`, and React class instances/statics
15
+ // (getDerivedStateFromError, etc.) are only valid against the exact
16
+ // React copy they were built from. Threading a second DI parameter
17
+ // through just for this base class would be over-engineering -- these
18
+ // factories are called once per host app at module scope, so redefining
19
+ // the class here has no meaningful runtime cost.
20
+ class ErrorBoundary extends React.Component {
21
+ state = { error: null };
22
+ static getDerivedStateFromError(error) {
23
+ return { error };
24
+ }
25
+ render() {
26
+ if (this.state.error) {
27
+ return this.props.fallback;
28
+ }
29
+ return this.props.children;
30
+ }
31
+ }
32
+ const DynamicModuleBoundary = ({ specifier, context, fallback = null, errorFallback = null, importer = defaultImporter, }) => {
33
+ // Memoized by specifier/importer: React.lazy() must return the same
34
+ // component type across renders, or React treats it as a brand-new
35
+ // component and remounts (re-suspending) on every parent re-render.
36
+ const LazyModule = React.useMemo(() => React.lazy(async () => {
37
+ const loadedModule = (await importer(specifier));
38
+ return loadedModule;
39
+ }), [specifier, importer]);
40
+ const moduleProps = context === undefined
41
+ ? {}
42
+ : { context };
43
+ // Equivalent to:
44
+ // <React.Suspense fallback={fallback}>
45
+ // <ErrorBoundary fallback={errorFallback}>
46
+ // <LazyModule {...moduleProps} />
47
+ // </ErrorBoundary>
48
+ // </React.Suspense>
49
+ //
50
+ // `children` is passed inside ErrorBoundary's props object (rather than
51
+ // as a third createElement argument) to satisfy TypeScript's overload
52
+ // resolution, since ErrorBoundary's props type declares `children` as
53
+ // required -- it is the same substitution JSX itself performs, not an
54
+ // accidental extra prop.
55
+ return React.createElement(React.Suspense, { fallback }, React.createElement(ErrorBoundary, {
56
+ // Keyed by specifier so switching modules mounts a fresh
57
+ // ErrorBoundary instance instead of reusing one still holding a
58
+ // previous module's error state.
59
+ key: specifier,
60
+ fallback: errorFallback,
61
+ children: React.createElement(LazyModule, moduleProps),
62
+ }));
63
+ };
64
+ return { DynamicModuleBoundary };
65
+ };
@@ -0,0 +1,11 @@
1
+ import type * as ReactNamespace from "react";
2
+ import { type RuntimeHostObservableOptions, type RuntimeHostStatus } from "@rmc-toolkit/core";
3
+ export type UseRuntimeHostOptions = Omit<RuntimeHostObservableOptions, "target">;
4
+ export type UseRuntimeHostResult<T extends Element> = {
5
+ ref: ReactNamespace.RefObject<T | null>;
6
+ status: RuntimeHostStatus;
7
+ };
8
+ export declare const createReactAdapter: (React: typeof ReactNamespace) => {
9
+ useRuntimeHost<T extends Element>(path: string, options: UseRuntimeHostOptions): UseRuntimeHostResult<T>;
10
+ };
11
+ //# sourceMappingURL=create-react-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-react-adapter.d.ts","sourceRoot":"","sources":["../src/create-react-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,cAAc,MAAM,OAAO,CAAC;AAC7C,OAAO,EAGL,KAAK,4BAA4B,EACjC,KAAK,iBAAiB,EACvB,MAAM,mBAAmB,CAAC;AAE3B,MAAM,MAAM,qBAAqB,GAAG,IAAI,CAAC,4BAA4B,EAAE,QAAQ,CAAC,CAAC;AAEjF,MAAM,MAAM,oBAAoB,CAAC,CAAC,SAAS,OAAO,IAAI;IACpD,GAAG,EAAE,cAAc,CAAC,SAAS,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACxC,MAAM,EAAE,iBAAiB,CAAC;CAC3B,CAAC;AAQF,eAAO,MAAM,kBAAkB,GAC7B,OAAO,OAAO,cAAc,KAC3B;IACD,cAAc,CAAC,CAAC,SAAS,OAAO,EAC9B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,qBAAqB,GAC7B,oBAAoB,CAAC,CAAC,CAAC,CAAC;CAoD5B,CAAC"}
@@ -0,0 +1,45 @@
1
+ import { createRuntimeHostObservable, } from "@rmc-toolkit/core";
2
+ // Shared reference, not an inline `{ type: "idle" }` literal: useSyncExternalStore
3
+ // compares getSnapshot()'s return value by reference and treats any change as "the
4
+ // store changed". A fresh object on every call (before the observable exists) would
5
+ // look like a change on every render and cause an infinite re-render loop.
6
+ const idleStatus = { type: "idle" };
7
+ export const createReactAdapter = (React) => {
8
+ const useRuntimeHost = (path, options) => {
9
+ const ref = React.useRef(null);
10
+ const observableRef = React.useRef(null);
11
+ React.useEffect(() => {
12
+ if (!ref.current) {
13
+ return;
14
+ }
15
+ const observable = createRuntimeHostObservable({ ...options, target: ref.current });
16
+ observableRef.current = observable;
17
+ return () => {
18
+ void observable.destroy();
19
+ observableRef.current = null;
20
+ };
21
+ }, []);
22
+ // Relies on React running a component's effects in declaration order on mount:
23
+ // the creation effect above must run first and populate observableRef.current
24
+ // before this effect's initial run, so the first next(path) call isn't dropped.
25
+ // Do not reorder these effects or merge them into one.
26
+ React.useEffect(() => {
27
+ observableRef.current?.next(path);
28
+ }, [path]);
29
+ // Re-reads observableRef.current lazily on each call rather than capturing the
30
+ // observable once: capturing it here would keep referencing a destroyed
31
+ // observable across a remount or a Strict-Mode mount/unmount/mount cycle, since
32
+ // this callback (memoized with an empty dep array) is not recreated when the
33
+ // creation effect re-runs and assigns a new observable to the ref.
34
+ const subscribe = React.useCallback((onStoreChange) => {
35
+ if (!observableRef.current) {
36
+ return () => { };
37
+ }
38
+ return observableRef.current.subscribe(() => onStoreChange());
39
+ }, []);
40
+ const getSnapshot = React.useCallback(() => observableRef.current?.getSnapshot() ?? idleStatus, []);
41
+ const status = React.useSyncExternalStore(subscribe, getSnapshot);
42
+ return { ref, status };
43
+ };
44
+ return { useRuntimeHost };
45
+ };
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=create-react-adapter.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-react-adapter.test.d.ts","sourceRoot":"","sources":["../src/create-react-adapter.test.tsx"],"names":[],"mappings":""}
@@ -0,0 +1,74 @@
1
+ // @vitest-environment happy-dom
2
+ import { describe, expect, test, vi } from "vitest";
3
+ import * as React from "react";
4
+ import { act } from "react";
5
+ import { createRoot } from "react-dom/client";
6
+ const observers = new Set();
7
+ let currentStatus = { type: "idle" };
8
+ const mockNext = vi.fn((path) => {
9
+ currentStatus = { type: "loading", path };
10
+ observers.forEach((observer) => observer(currentStatus));
11
+ currentStatus = { type: "ready", path };
12
+ observers.forEach((observer) => observer(currentStatus));
13
+ });
14
+ const mockDestroy = vi.fn(async () => { });
15
+ const mockCreateRuntimeHostObservable = vi.fn((_options) => ({
16
+ next: mockNext,
17
+ destroy: mockDestroy,
18
+ subscribe: (observer) => {
19
+ observers.add(observer);
20
+ return () => observers.delete(observer);
21
+ },
22
+ getSnapshot: () => currentStatus,
23
+ }));
24
+ vi.mock("@rmc-toolkit/core", () => ({
25
+ createRuntimeHostObservable: (options) => mockCreateRuntimeHostObservable(options),
26
+ }));
27
+ const { createReactAdapter } = await import("./create-react-adapter.js");
28
+ const manifest = { namespace: "@acme", assetsOrigin: "https://assets.example.com" };
29
+ describe("createReactAdapter", () => {
30
+ test("creates one observable per mounted component, forwards path to next(), and surfaces status", async () => {
31
+ const { useRuntimeHost } = createReactAdapter(React);
32
+ let renderedStatus;
33
+ const TestComponent = ({ path }) => {
34
+ const { ref, status } = useRuntimeHost(path, { manifest });
35
+ renderedStatus = status;
36
+ return React.createElement("div", { ref });
37
+ };
38
+ const container = document.createElement("div");
39
+ const root = createRoot(container);
40
+ await act(async () => {
41
+ root.render(React.createElement(TestComponent, { path: "/search" }));
42
+ });
43
+ expect(mockCreateRuntimeHostObservable).toHaveBeenCalledTimes(1);
44
+ expect(mockNext).toHaveBeenCalledWith("/search");
45
+ expect(renderedStatus).toEqual({ type: "ready", path: "/search" });
46
+ await act(async () => {
47
+ root.unmount();
48
+ });
49
+ expect(mockDestroy).toHaveBeenCalledTimes(1);
50
+ });
51
+ test("forwards a new path to next() when the path prop changes, without recreating the observable", async () => {
52
+ mockCreateRuntimeHostObservable.mockClear();
53
+ mockNext.mockClear();
54
+ const { useRuntimeHost } = createReactAdapter(React);
55
+ const TestComponent = ({ path }) => {
56
+ const { ref } = useRuntimeHost(path, { manifest });
57
+ return React.createElement("div", { ref });
58
+ };
59
+ const container = document.createElement("div");
60
+ const root = createRoot(container);
61
+ await act(async () => {
62
+ root.render(React.createElement(TestComponent, { path: "/search" }));
63
+ });
64
+ await act(async () => {
65
+ root.render(React.createElement(TestComponent, { path: "/cart" }));
66
+ });
67
+ expect(mockCreateRuntimeHostObservable).toHaveBeenCalledTimes(1);
68
+ expect(mockNext).toHaveBeenNthCalledWith(1, "/search");
69
+ expect(mockNext).toHaveBeenNthCalledWith(2, "/cart");
70
+ await act(async () => {
71
+ root.unmount();
72
+ });
73
+ });
74
+ });
package/dist/index.d.ts CHANGED
@@ -1,11 +1,5 @@
1
- import { type DynamicImporter, type RuntimeModuleContext } from "@rmc-toolkit/core";
2
- import React from "react";
3
- export type DynamicModuleBoundaryProps = {
4
- specifier: string;
5
- context?: RuntimeModuleContext;
6
- fallback?: React.ReactNode;
7
- errorFallback?: React.ReactNode;
8
- importer?: DynamicImporter;
9
- };
10
- export declare const DynamicModuleBoundary: ({ specifier, context, fallback, errorFallback, importer, }: DynamicModuleBoundaryProps) => React.ReactElement;
1
+ export { createDynamicModuleBoundary } from "./create-dynamic-module-boundary.js";
2
+ export type { DynamicModuleBoundaryProps } from "./create-dynamic-module-boundary.js";
3
+ export { createReactAdapter } from "./create-react-adapter.js";
4
+ export type { UseRuntimeHostOptions, UseRuntimeHostResult, } from "./create-react-adapter.js";
11
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,oBAAoB,EAC1B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,MAAM,OAAO,CAAC;AAM1B,MAAM,MAAM,0BAA0B,GAAG;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,oBAAoB,CAAC;IAC/B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,aAAa,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAChC,QAAQ,CAAC,EAAE,eAAe,CAAC;CAC5B,CAAC;AA2BF,eAAO,MAAM,qBAAqB,GAAI,4DAMnC,0BAA0B,KAAG,KAAK,CAAC,YAiBrC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,MAAM,qCAAqC,CAAC;AAClF,YAAY,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AAEtF,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,YAAY,EACV,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,2BAA2B,CAAC"}
package/dist/index.js CHANGED
@@ -1,26 +1,2 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { importModule, } from "@rmc-toolkit/core";
3
- import React from "react";
4
- class ErrorBoundary extends React.Component {
5
- state = { error: null };
6
- static getDerivedStateFromError(error) {
7
- return { error };
8
- }
9
- render() {
10
- if (this.state.error) {
11
- return this.props.fallback;
12
- }
13
- return this.props.children;
14
- }
15
- }
16
- const defaultImporter = importModule;
17
- export const DynamicModuleBoundary = ({ specifier, context, fallback = null, errorFallback = null, importer = defaultImporter, }) => {
18
- const LazyModule = React.lazy(async () => {
19
- const loadedModule = (await importer(specifier));
20
- return loadedModule;
21
- });
22
- const moduleProps = context === undefined
23
- ? {}
24
- : { context };
25
- return (_jsx(React.Suspense, { fallback: fallback, children: _jsx(ErrorBoundary, { fallback: errorFallback, children: _jsx(LazyModule, { ...moduleProps }) }) }));
26
- };
1
+ export { createDynamicModuleBoundary } from "./create-dynamic-module-boundary.js";
2
+ export { createReactAdapter } from "./create-react-adapter.js";
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  // @vitest-environment happy-dom
3
3
  import { describe, expect, test, vi } from "vitest";
4
+ import * as React from "react";
4
5
  import { act } from "react";
5
6
  import { createRoot } from "react-dom/client";
6
7
  const FixtureComponent = () => "fixture content";
@@ -10,7 +11,8 @@ const mockImportModule = vi.fn(async () => ({
10
11
  vi.mock("@rmc-toolkit/core", () => ({
11
12
  importModule: mockImportModule,
12
13
  }));
13
- const { DynamicModuleBoundary } = await import("./index.js");
14
+ const { createDynamicModuleBoundary } = await import("./index.js");
15
+ const { DynamicModuleBoundary } = createDynamicModuleBoundary(React);
14
16
  describe("DynamicModuleBoundary", () => {
15
17
  test("default importer delegates to core's importModule", async () => {
16
18
  const container = document.createElement("div");
@@ -22,4 +24,35 @@ describe("DynamicModuleBoundary", () => {
22
24
  expect(container.textContent).toBe("fixture content");
23
25
  root.unmount();
24
26
  });
27
+ test("createDynamicModuleBoundary is injected with the caller's own React instance, not an internally imported one", async () => {
28
+ mockImportModule.mockClear();
29
+ // Two independently-created factories, each given its own React-like
30
+ // namespace object. If the implementation secretly imported "react"
31
+ // itself instead of using the injected parameter, both boundaries would
32
+ // still work identically and this test would give no signal either way
33
+ // -- that create-dynamic-module-boundary.ts has no runtime `import` of
34
+ // "react" is a static fact, verifiable by inspection of its import
35
+ // statements, not something a render test can detect. What this test
36
+ // does prove is that the DI parameter is actually wired through to
37
+ // produce a working component for whichever React instance is passed,
38
+ // by creating two boundaries from two separate calls and rendering both.
39
+ const { DynamicModuleBoundary: BoundaryA } = createDynamicModuleBoundary(React);
40
+ const { DynamicModuleBoundary: BoundaryB } = createDynamicModuleBoundary(React);
41
+ const containerA = document.createElement("div");
42
+ const rootA = createRoot(containerA);
43
+ const containerB = document.createElement("div");
44
+ const rootB = createRoot(containerB);
45
+ await act(async () => {
46
+ rootA.render(_jsx(BoundaryA, { specifier: "specifier-a" }));
47
+ });
48
+ await act(async () => {
49
+ rootB.render(_jsx(BoundaryB, { specifier: "specifier-b" }));
50
+ });
51
+ expect(mockImportModule).toHaveBeenCalledWith("specifier-a");
52
+ expect(mockImportModule).toHaveBeenCalledWith("specifier-b");
53
+ expect(containerA.textContent).toBe("fixture content");
54
+ expect(containerB.textContent).toBe("fixture content");
55
+ rootA.unmount();
56
+ rootB.unmount();
57
+ });
25
58
  });
package/package.json CHANGED
@@ -1,7 +1,12 @@
1
1
  {
2
2
  "name": "@rmc-toolkit/react",
3
- "version": "0.1.0",
3
+ "version": "0.2.3",
4
4
  "type": "module",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/runtime-module-composition/rmc-toolkit",
8
+ "directory": "packages/react"
9
+ },
5
10
  "main": "./dist/index.js",
6
11
  "types": "./dist/index.d.ts",
7
12
  "exports": {
@@ -17,11 +22,11 @@
17
22
  "access": "public"
18
23
  },
19
24
  "peerDependencies": {
20
- "@rmc-toolkit/core": "0.1.0",
25
+ "@rmc-toolkit/core": "0.2.3",
21
26
  "react": ">=18"
22
27
  },
23
28
  "dependencies": {
24
- "@rmc-toolkit/core": "0.1.0"
29
+ "@rmc-toolkit/core": "0.2.3"
25
30
  },
26
31
  "scripts": {
27
32
  "build": "tsc -b"