@react-arch/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/LICENSE +21 -0
- package/README.md +59 -0
- package/dist/index.d.ts +178 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +508 -0
- package/dist/index.js.map +1 -0
- package/package.json +48 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 React Arch
|
|
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,59 @@
|
|
|
1
|
+
# @react-arch/react
|
|
2
|
+
|
|
3
|
+
Declarative React components for describing buildings, plus the reconciler that
|
|
4
|
+
turns your component tree into the canonical `@react-arch/core` model.
|
|
5
|
+
|
|
6
|
+
This is the layer that makes **code the source of truth** (see ADR 0002). It is
|
|
7
|
+
a real [`react-reconciler`](https://npmjs.com/package/react-reconciler) host
|
|
8
|
+
renderer, so anything React can do — composition, hooks, props, `.map()` — works
|
|
9
|
+
when authoring buildings.
|
|
10
|
+
|
|
11
|
+
## Components
|
|
12
|
+
|
|
13
|
+
`Building`, `Floor`, `Room`, `Wall`, `Door`, `Window`, `Opening`, `Furniture`
|
|
14
|
+
(`Fixture`), `Material`, `Group`, plus reserved `Slab` / `Roof` / `Stairs`.
|
|
15
|
+
|
|
16
|
+
```tsx
|
|
17
|
+
import { Building, Floor, Room, Door, Window } from "@react-arch/react";
|
|
18
|
+
|
|
19
|
+
export function House() {
|
|
20
|
+
return (
|
|
21
|
+
<Building name="Modern House" units="metric">
|
|
22
|
+
<Floor id="ground" name="Ground Floor" elevation={0} height={2.8}>
|
|
23
|
+
<Room id="living" name="Living Room" x={0} y={0} width={5} depth={4}>
|
|
24
|
+
<Door wall="south" offset={1} width={0.9} />
|
|
25
|
+
<Window wall="west" offset={2} width={2.2} height={1.4} />
|
|
26
|
+
</Room>
|
|
27
|
+
</Floor>
|
|
28
|
+
</Building>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
A rectangular `<Room>` (`x`, `y`, `width`, `depth`) generates its four perimeter
|
|
34
|
+
walls; `<Door>`/`<Window>` attach to a named side (`north`/`south`/`east`/`west`)
|
|
35
|
+
at an `offset` along that wall. Coordinates are metres, X→right, Y→down.
|
|
36
|
+
|
|
37
|
+
## Rendering to the model
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import { renderToDocument } from "@react-arch/react";
|
|
41
|
+
const doc = renderToDocument(<House />); // → BuildingDocument
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Registration (Remotion-style)
|
|
45
|
+
|
|
46
|
+
```tsx
|
|
47
|
+
import { Composition } from "@react-arch/react";
|
|
48
|
+
|
|
49
|
+
export function Root() {
|
|
50
|
+
return (
|
|
51
|
+
<>
|
|
52
|
+
<Composition id="house" name="Modern House" component={House} />
|
|
53
|
+
</>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The Studio mounts `Root`, reads the registry (`getCompositions`), and renders
|
|
59
|
+
the selected composition to a model with `renderComposition`.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { ComponentType, ReactElement, ReactNode } from "react";
|
|
2
|
+
import { Building as BuildingModel, BuildingDocument, BuildingDocument as BuildingDocument$1, Floor as FloorModel, Opening as OpeningModel, Room as RoomModel, Wall as WallModel } from "@react-arch/core";
|
|
3
|
+
|
|
4
|
+
//#region src/tags.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Internal host element tags. Users never type these — the public components
|
|
7
|
+
* in `components.tsx` create them. The reconciler builds an instance tree of
|
|
8
|
+
* these tags, which `convert.ts` turns into a BuildingDocument.
|
|
9
|
+
*/
|
|
10
|
+
declare const TAG: {
|
|
11
|
+
readonly building: "ra-building";
|
|
12
|
+
readonly floor: "ra-floor";
|
|
13
|
+
readonly room: "ra-room";
|
|
14
|
+
readonly wall: "ra-wall";
|
|
15
|
+
readonly door: "ra-door";
|
|
16
|
+
readonly window: "ra-window";
|
|
17
|
+
readonly opening: "ra-opening";
|
|
18
|
+
readonly furniture: "ra-furniture";
|
|
19
|
+
readonly material: "ra-material";
|
|
20
|
+
readonly group: "ra-group";
|
|
21
|
+
readonly slab: "ra-slab";
|
|
22
|
+
readonly roof: "ra-roof";
|
|
23
|
+
readonly stairs: "ra-stairs";
|
|
24
|
+
readonly text: "ra-text";
|
|
25
|
+
};
|
|
26
|
+
/** Side of a rectangular room a door/window attaches to. */
|
|
27
|
+
type RoomSide = "north" | "south" | "east" | "west";
|
|
28
|
+
//#endregion
|
|
29
|
+
//#region src/components.d.ts
|
|
30
|
+
type WithChildren<T> = T & {
|
|
31
|
+
children?: ReactNode;
|
|
32
|
+
};
|
|
33
|
+
interface BuildingProps {
|
|
34
|
+
id?: string;
|
|
35
|
+
name?: string;
|
|
36
|
+
units?: "metric" | "imperial";
|
|
37
|
+
}
|
|
38
|
+
declare function Building(props: WithChildren<BuildingProps>): import("react").DOMElement<Record<string, unknown>, Element>;
|
|
39
|
+
interface FloorProps {
|
|
40
|
+
id?: string;
|
|
41
|
+
name?: string;
|
|
42
|
+
elevation?: number;
|
|
43
|
+
height?: number;
|
|
44
|
+
}
|
|
45
|
+
declare function Floor(props: WithChildren<FloorProps>): import("react").DOMElement<Record<string, unknown>, Element>;
|
|
46
|
+
interface RoomProps {
|
|
47
|
+
id?: string;
|
|
48
|
+
name?: string;
|
|
49
|
+
/** Top-left corner X (metres, X increases right). */
|
|
50
|
+
x?: number;
|
|
51
|
+
/** Top-left corner Y (metres, Y increases down). */
|
|
52
|
+
y?: number;
|
|
53
|
+
/** Extent along X. */
|
|
54
|
+
width?: number;
|
|
55
|
+
/** Extent along Y. */
|
|
56
|
+
depth?: number;
|
|
57
|
+
height?: number;
|
|
58
|
+
wallThickness?: number;
|
|
59
|
+
floorMaterial?: string;
|
|
60
|
+
ceilingMaterial?: string;
|
|
61
|
+
usage?: string;
|
|
62
|
+
}
|
|
63
|
+
declare function Room(props: WithChildren<RoomProps>): import("react").DOMElement<Record<string, unknown>, Element>;
|
|
64
|
+
interface WallProps {
|
|
65
|
+
id?: string;
|
|
66
|
+
from: [number, number];
|
|
67
|
+
to: [number, number];
|
|
68
|
+
thickness?: number;
|
|
69
|
+
height?: number;
|
|
70
|
+
materialId?: string;
|
|
71
|
+
}
|
|
72
|
+
declare function Wall(props: WallProps): import("react").DOMElement<Record<string, unknown>, Element>;
|
|
73
|
+
interface OpeningCommonProps {
|
|
74
|
+
id?: string;
|
|
75
|
+
/** Which side of the parent room this attaches to. */
|
|
76
|
+
wall?: RoomSide;
|
|
77
|
+
/** Distance along the wall centerline from its start corner. */
|
|
78
|
+
offset?: number;
|
|
79
|
+
width?: number;
|
|
80
|
+
height?: number;
|
|
81
|
+
sillHeight?: number;
|
|
82
|
+
}
|
|
83
|
+
declare function Door(props: OpeningCommonProps): import("react").DOMElement<Record<string, unknown>, Element>;
|
|
84
|
+
declare function Window(props: OpeningCommonProps): import("react").DOMElement<Record<string, unknown>, Element>;
|
|
85
|
+
declare function Opening(props: OpeningCommonProps): import("react").DOMElement<Record<string, unknown>, Element>;
|
|
86
|
+
interface FurnitureProps {
|
|
87
|
+
id?: string;
|
|
88
|
+
type: string;
|
|
89
|
+
x?: number;
|
|
90
|
+
y?: number;
|
|
91
|
+
z?: number;
|
|
92
|
+
rotation?: number;
|
|
93
|
+
scaleX?: number;
|
|
94
|
+
scaleY?: number;
|
|
95
|
+
scaleZ?: number;
|
|
96
|
+
assetId?: string;
|
|
97
|
+
}
|
|
98
|
+
declare function Furniture(props: FurnitureProps): import("react").DOMElement<Record<string, unknown>, Element>;
|
|
99
|
+
/** Alias used inside reusable room modules. */
|
|
100
|
+
declare const Fixture: typeof Furniture;
|
|
101
|
+
interface MaterialProps {
|
|
102
|
+
id: string;
|
|
103
|
+
name?: string;
|
|
104
|
+
category?: string;
|
|
105
|
+
baseColor: string;
|
|
106
|
+
roughness?: number;
|
|
107
|
+
metalness?: number;
|
|
108
|
+
opacity?: number;
|
|
109
|
+
textureUrl?: string;
|
|
110
|
+
}
|
|
111
|
+
declare function Material(props: MaterialProps): import("react").DOMElement<Record<string, unknown>, Element>;
|
|
112
|
+
declare function Group(props: WithChildren<{
|
|
113
|
+
id?: string;
|
|
114
|
+
}>): import("react").DOMElement<Record<string, unknown>, Element>;
|
|
115
|
+
declare function Slab(props: WithChildren<{
|
|
116
|
+
id?: string;
|
|
117
|
+
}>): import("react").DOMElement<Record<string, unknown>, Element>;
|
|
118
|
+
declare function Roof(props: WithChildren<{
|
|
119
|
+
id?: string;
|
|
120
|
+
type?: string;
|
|
121
|
+
}>): import("react").DOMElement<Record<string, unknown>, Element>;
|
|
122
|
+
declare function Stairs(props: WithChildren<{
|
|
123
|
+
id?: string;
|
|
124
|
+
}>): import("react").DOMElement<Record<string, unknown>, Element>;
|
|
125
|
+
//#endregion
|
|
126
|
+
//#region src/registry.d.ts
|
|
127
|
+
interface BuildingComposition {
|
|
128
|
+
id: string;
|
|
129
|
+
name: string;
|
|
130
|
+
component: ComponentType<Record<string, unknown>>;
|
|
131
|
+
defaultProps?: Record<string, unknown>;
|
|
132
|
+
}
|
|
133
|
+
/** Increments whenever the registry changes (incl. hot-reload re-registration). */
|
|
134
|
+
declare function getCompositionsVersion(): number;
|
|
135
|
+
declare function __registerComposition(c: BuildingComposition): void;
|
|
136
|
+
declare function __unregisterComposition(id: string): void;
|
|
137
|
+
declare function getCompositions(): BuildingComposition[];
|
|
138
|
+
declare function subscribeCompositions(fn: () => void): () => void;
|
|
139
|
+
/**
|
|
140
|
+
* Register the root component (mirrors Remotion's registerRoot). The Studio
|
|
141
|
+
* mounts this so its <Composition> children register themselves.
|
|
142
|
+
*/
|
|
143
|
+
declare function registerRoot(component: ComponentType): void;
|
|
144
|
+
declare function getRoot(): ComponentType | null;
|
|
145
|
+
/**
|
|
146
|
+
* Declares a building composition. Renders nothing visible; on mount it
|
|
147
|
+
* registers itself into the module registry the Studio reads.
|
|
148
|
+
*/
|
|
149
|
+
declare function Composition(props: BuildingComposition): null;
|
|
150
|
+
/** Render any React Arch element tree to the canonical model. */
|
|
151
|
+
declare function renderToDocument(element: ReactElement, fallbackName?: string): BuildingDocument$1;
|
|
152
|
+
/** Render a registered composition (component + its default props) to a model. */
|
|
153
|
+
declare function renderComposition(comp: BuildingComposition): BuildingDocument$1;
|
|
154
|
+
//#endregion
|
|
155
|
+
//#region src/renderer.d.ts
|
|
156
|
+
/** A node in the intermediate instance tree built by the reconciler. */
|
|
157
|
+
interface Instance {
|
|
158
|
+
tag: string;
|
|
159
|
+
props: Record<string, unknown>;
|
|
160
|
+
children: Instance[];
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Render a React element tree through the React Arch reconciler and return the
|
|
164
|
+
* resulting intermediate instance tree. Synchronous (legacy root) so the tree
|
|
165
|
+
* is fully built when this returns.
|
|
166
|
+
*/
|
|
167
|
+
declare function renderToInstances(element: ReactElement): Instance[];
|
|
168
|
+
//#endregion
|
|
169
|
+
//#region src/convert.d.ts
|
|
170
|
+
/**
|
|
171
|
+
* Convert a rendered instance tree into the canonical BuildingDocument.
|
|
172
|
+
* `fallbackName` is used when the <Building> has no `name` prop (e.g. the
|
|
173
|
+
* registered composition name).
|
|
174
|
+
*/
|
|
175
|
+
declare function convert(instances: Instance[], fallbackName?: string): BuildingDocument$1;
|
|
176
|
+
//#endregion
|
|
177
|
+
export { Building, BuildingComposition, type BuildingDocument, type BuildingModel, BuildingProps, Composition, Door, Fixture, Floor, type FloorModel, FloorProps, Furniture, FurnitureProps, Group, type Instance, Material, MaterialProps, Opening, OpeningCommonProps, type OpeningModel, Roof, Room, type RoomModel, RoomProps, type RoomSide, Slab, Stairs, TAG, Wall, type WallModel, WallProps, Window, __registerComposition, __unregisterComposition, convert, getCompositions, getCompositionsVersion, getRoot, registerRoot, renderComposition, renderToDocument, renderToInstances, subscribeCompositions };
|
|
178
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/tags.ts","../src/components.tsx","../src/registry.ts","../src/renderer.ts","../src/convert.ts"],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,508 @@
|
|
|
1
|
+
import { createElement, useEffect } from "react";
|
|
2
|
+
import Reconciler from "react-reconciler";
|
|
3
|
+
import { createId, round } from "@react-arch/shared";
|
|
4
|
+
import { normalize, sub } from "@react-arch/geometry";
|
|
5
|
+
import { DEFAULT_MATERIALS, MODEL_VERSION } from "@react-arch/core";
|
|
6
|
+
//#region src/tags.ts
|
|
7
|
+
/**
|
|
8
|
+
* Internal host element tags. Users never type these — the public components
|
|
9
|
+
* in `components.tsx` create them. The reconciler builds an instance tree of
|
|
10
|
+
* these tags, which `convert.ts` turns into a BuildingDocument.
|
|
11
|
+
*/
|
|
12
|
+
const TAG = {
|
|
13
|
+
building: "ra-building",
|
|
14
|
+
floor: "ra-floor",
|
|
15
|
+
room: "ra-room",
|
|
16
|
+
wall: "ra-wall",
|
|
17
|
+
door: "ra-door",
|
|
18
|
+
window: "ra-window",
|
|
19
|
+
opening: "ra-opening",
|
|
20
|
+
furniture: "ra-furniture",
|
|
21
|
+
material: "ra-material",
|
|
22
|
+
group: "ra-group",
|
|
23
|
+
slab: "ra-slab",
|
|
24
|
+
roof: "ra-roof",
|
|
25
|
+
stairs: "ra-stairs",
|
|
26
|
+
text: "ra-text"
|
|
27
|
+
};
|
|
28
|
+
//#endregion
|
|
29
|
+
//#region src/components.tsx
|
|
30
|
+
const h = (tag, props) => createElement(tag, props);
|
|
31
|
+
function Building(props) {
|
|
32
|
+
return h(TAG.building, props);
|
|
33
|
+
}
|
|
34
|
+
function Floor(props) {
|
|
35
|
+
return h(TAG.floor, props);
|
|
36
|
+
}
|
|
37
|
+
function Room(props) {
|
|
38
|
+
return h(TAG.room, props);
|
|
39
|
+
}
|
|
40
|
+
function Wall(props) {
|
|
41
|
+
return h(TAG.wall, props);
|
|
42
|
+
}
|
|
43
|
+
function Door(props) {
|
|
44
|
+
return h(TAG.door, props);
|
|
45
|
+
}
|
|
46
|
+
function Window(props) {
|
|
47
|
+
return h(TAG.window, props);
|
|
48
|
+
}
|
|
49
|
+
function Opening(props) {
|
|
50
|
+
return h(TAG.opening, props);
|
|
51
|
+
}
|
|
52
|
+
function Furniture(props) {
|
|
53
|
+
return h(TAG.furniture, props);
|
|
54
|
+
}
|
|
55
|
+
/** Alias used inside reusable room modules. */
|
|
56
|
+
const Fixture = Furniture;
|
|
57
|
+
function Material(props) {
|
|
58
|
+
return h(TAG.material, props);
|
|
59
|
+
}
|
|
60
|
+
function Group(props) {
|
|
61
|
+
return h(TAG.group, props);
|
|
62
|
+
}
|
|
63
|
+
function Slab(props) {
|
|
64
|
+
return h(TAG.slab, props);
|
|
65
|
+
}
|
|
66
|
+
function Roof(props) {
|
|
67
|
+
return h(TAG.roof, props);
|
|
68
|
+
}
|
|
69
|
+
function Stairs(props) {
|
|
70
|
+
return h(TAG.stairs, props);
|
|
71
|
+
}
|
|
72
|
+
//#endregion
|
|
73
|
+
//#region src/renderer.ts
|
|
74
|
+
function stripChildren(props) {
|
|
75
|
+
const { children, ...rest } = props;
|
|
76
|
+
return rest;
|
|
77
|
+
}
|
|
78
|
+
const reconciler = Reconciler({
|
|
79
|
+
supportsMutation: true,
|
|
80
|
+
supportsPersistence: false,
|
|
81
|
+
supportsHydration: false,
|
|
82
|
+
isPrimaryRenderer: false,
|
|
83
|
+
noTimeout: -1,
|
|
84
|
+
now: () => 0,
|
|
85
|
+
getRootHostContext: () => ({}),
|
|
86
|
+
getChildHostContext: (parent) => parent,
|
|
87
|
+
getPublicInstance: (instance) => instance,
|
|
88
|
+
prepareForCommit: () => null,
|
|
89
|
+
resetAfterCommit: () => {},
|
|
90
|
+
preparePortalMount: () => {},
|
|
91
|
+
createInstance(tag, props) {
|
|
92
|
+
return {
|
|
93
|
+
tag,
|
|
94
|
+
props: stripChildren(props),
|
|
95
|
+
children: []
|
|
96
|
+
};
|
|
97
|
+
},
|
|
98
|
+
createTextInstance(text) {
|
|
99
|
+
return {
|
|
100
|
+
tag: "ra-text",
|
|
101
|
+
props: { text },
|
|
102
|
+
children: []
|
|
103
|
+
};
|
|
104
|
+
},
|
|
105
|
+
appendInitialChild(parent, child) {
|
|
106
|
+
parent.children.push(child);
|
|
107
|
+
},
|
|
108
|
+
appendChild(parent, child) {
|
|
109
|
+
parent.children.push(child);
|
|
110
|
+
},
|
|
111
|
+
appendChildToContainer(container, child) {
|
|
112
|
+
container.children.push(child);
|
|
113
|
+
},
|
|
114
|
+
insertBefore(parent, child, before) {
|
|
115
|
+
const i = parent.children.indexOf(before);
|
|
116
|
+
parent.children.splice(i, 0, child);
|
|
117
|
+
},
|
|
118
|
+
insertInContainerBefore(container, child, before) {
|
|
119
|
+
const i = container.children.indexOf(before);
|
|
120
|
+
container.children.splice(i, 0, child);
|
|
121
|
+
},
|
|
122
|
+
removeChild(parent, child) {
|
|
123
|
+
parent.children = parent.children.filter((c) => c !== child);
|
|
124
|
+
},
|
|
125
|
+
removeChildFromContainer(container, child) {
|
|
126
|
+
container.children = container.children.filter((c) => c !== child);
|
|
127
|
+
},
|
|
128
|
+
finalizeInitialChildren: () => false,
|
|
129
|
+
shouldSetTextContent: () => false,
|
|
130
|
+
clearContainer(container) {
|
|
131
|
+
container.children = [];
|
|
132
|
+
},
|
|
133
|
+
prepareUpdate: () => true,
|
|
134
|
+
commitUpdate(instance, _payload, _tag, _old, newProps) {
|
|
135
|
+
instance.props = stripChildren(newProps);
|
|
136
|
+
},
|
|
137
|
+
commitTextUpdate(instance, _old, text) {
|
|
138
|
+
instance.props = { text };
|
|
139
|
+
},
|
|
140
|
+
getCurrentEventPriority: () => 16,
|
|
141
|
+
detachDeletedInstance: () => {},
|
|
142
|
+
prepareScopeUpdate: () => {},
|
|
143
|
+
getInstanceFromScope: () => null,
|
|
144
|
+
getInstanceFromNode: () => null,
|
|
145
|
+
beforeActiveInstanceBlur: () => {},
|
|
146
|
+
afterActiveInstanceBlur: () => {},
|
|
147
|
+
scheduleTimeout: setTimeout,
|
|
148
|
+
cancelTimeout: clearTimeout
|
|
149
|
+
});
|
|
150
|
+
const LegacyRoot = 0;
|
|
151
|
+
/**
|
|
152
|
+
* Render a React element tree through the React Arch reconciler and return the
|
|
153
|
+
* resulting intermediate instance tree. Synchronous (legacy root) so the tree
|
|
154
|
+
* is fully built when this returns.
|
|
155
|
+
*/
|
|
156
|
+
function renderToInstances(element) {
|
|
157
|
+
const container = { children: [] };
|
|
158
|
+
const root = reconciler.createContainer(container, LegacyRoot, null, false, null, "react-arch", (error) => {
|
|
159
|
+
console.error("[react-arch] render error", error);
|
|
160
|
+
}, null);
|
|
161
|
+
reconciler.updateContainer(element, root, null, null);
|
|
162
|
+
return container.children;
|
|
163
|
+
}
|
|
164
|
+
//#endregion
|
|
165
|
+
//#region src/convert.ts
|
|
166
|
+
function num(props, key, fallback) {
|
|
167
|
+
const v = props[key];
|
|
168
|
+
return typeof v === "number" && Number.isFinite(v) ? v : fallback;
|
|
169
|
+
}
|
|
170
|
+
function str(props, key) {
|
|
171
|
+
const v = props[key];
|
|
172
|
+
return typeof v === "string" ? v : void 0;
|
|
173
|
+
}
|
|
174
|
+
function vec2(v) {
|
|
175
|
+
if (Array.isArray(v) && v.length === 2 && typeof v[0] === "number" && typeof v[1] === "number") return [v[0], v[1]];
|
|
176
|
+
}
|
|
177
|
+
/** Expand transparent <Group> nodes and drop text nodes. */
|
|
178
|
+
function flatten(nodes) {
|
|
179
|
+
const out = [];
|
|
180
|
+
for (const n of nodes) {
|
|
181
|
+
if (n.tag === TAG.text) continue;
|
|
182
|
+
if (n.tag === TAG.group) out.push(...flatten(n.children));
|
|
183
|
+
else out.push(n);
|
|
184
|
+
}
|
|
185
|
+
return out;
|
|
186
|
+
}
|
|
187
|
+
function toMaterial(node) {
|
|
188
|
+
const p = node.props;
|
|
189
|
+
return {
|
|
190
|
+
id: str(p, "id") ?? createId("mat"),
|
|
191
|
+
name: str(p, "name") ?? "Material",
|
|
192
|
+
category: str(p, "category") ?? "custom",
|
|
193
|
+
baseColor: str(p, "baseColor") ?? "#cccccc",
|
|
194
|
+
roughness: typeof p.roughness === "number" ? p.roughness : void 0,
|
|
195
|
+
metalness: typeof p.metalness === "number" ? p.metalness : void 0,
|
|
196
|
+
opacity: typeof p.opacity === "number" ? p.opacity : void 0,
|
|
197
|
+
textureUrl: str(p, "textureUrl")
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
const OPENING_DEFAULTS = {
|
|
201
|
+
door: {
|
|
202
|
+
width: .9,
|
|
203
|
+
height: 2.1,
|
|
204
|
+
sill: 0
|
|
205
|
+
},
|
|
206
|
+
window: {
|
|
207
|
+
width: 1.2,
|
|
208
|
+
height: 1.4,
|
|
209
|
+
sill: .9
|
|
210
|
+
},
|
|
211
|
+
opening: {
|
|
212
|
+
width: 1,
|
|
213
|
+
height: 2.1,
|
|
214
|
+
sill: 0
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
function toObject(node, floorId) {
|
|
218
|
+
const p = node.props;
|
|
219
|
+
return {
|
|
220
|
+
id: str(p, "id") ?? createId("object"),
|
|
221
|
+
floorId,
|
|
222
|
+
type: str(p, "type") ?? "object",
|
|
223
|
+
position: [
|
|
224
|
+
num(p, "x", 0),
|
|
225
|
+
num(p, "y", 0),
|
|
226
|
+
num(p, "z", 0)
|
|
227
|
+
],
|
|
228
|
+
rotation: [
|
|
229
|
+
0,
|
|
230
|
+
0,
|
|
231
|
+
num(p, "rotation", 0)
|
|
232
|
+
],
|
|
233
|
+
scale: [
|
|
234
|
+
num(p, "scaleX", 1),
|
|
235
|
+
num(p, "scaleY", 1),
|
|
236
|
+
num(p, "scaleZ", 1)
|
|
237
|
+
],
|
|
238
|
+
assetId: str(p, "assetId")
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
function convertFloor(node, buildingId, materials) {
|
|
242
|
+
const p = node.props;
|
|
243
|
+
const floor = {
|
|
244
|
+
id: str(p, "id") ?? createId("floor"),
|
|
245
|
+
buildingId,
|
|
246
|
+
name: str(p, "name") ?? "Floor",
|
|
247
|
+
elevation: num(p, "elevation", 0),
|
|
248
|
+
height: num(p, "height", 2.8),
|
|
249
|
+
visible: true,
|
|
250
|
+
locked: false,
|
|
251
|
+
walls: [],
|
|
252
|
+
rooms: [],
|
|
253
|
+
openings: [],
|
|
254
|
+
objects: []
|
|
255
|
+
};
|
|
256
|
+
const makeWall = (start, end, thickness, materialId) => {
|
|
257
|
+
const w = {
|
|
258
|
+
id: createId("wall"),
|
|
259
|
+
floorId: floor.id,
|
|
260
|
+
start,
|
|
261
|
+
end,
|
|
262
|
+
thickness,
|
|
263
|
+
height: floor.height,
|
|
264
|
+
materialId
|
|
265
|
+
};
|
|
266
|
+
floor.walls.push(w);
|
|
267
|
+
return w;
|
|
268
|
+
};
|
|
269
|
+
for (const child of flatten(node.children)) switch (child.tag) {
|
|
270
|
+
case TAG.material:
|
|
271
|
+
materials.push(toMaterial(child));
|
|
272
|
+
break;
|
|
273
|
+
case TAG.wall: {
|
|
274
|
+
const w = makeWall(vec2(child.props.from) ?? [0, 0], vec2(child.props.to) ?? [0, 0], num(child.props, "thickness", .2), str(child.props, "materialId"));
|
|
275
|
+
if (str(child.props, "id")) w.id = str(child.props, "id");
|
|
276
|
+
if (typeof child.props.height === "number") w.height = child.props.height;
|
|
277
|
+
break;
|
|
278
|
+
}
|
|
279
|
+
case TAG.room: {
|
|
280
|
+
const x = num(child.props, "x", 0);
|
|
281
|
+
const y = num(child.props, "y", 0);
|
|
282
|
+
const w = num(child.props, "width", 4);
|
|
283
|
+
const d = num(child.props, "depth", 4);
|
|
284
|
+
const thickness = num(child.props, "wallThickness", .2);
|
|
285
|
+
const polygon = [
|
|
286
|
+
[x, y],
|
|
287
|
+
[x + w, y],
|
|
288
|
+
[x + w, y + d],
|
|
289
|
+
[x, y + d]
|
|
290
|
+
];
|
|
291
|
+
const room = {
|
|
292
|
+
id: str(child.props, "id") ?? createId("room"),
|
|
293
|
+
floorId: floor.id,
|
|
294
|
+
name: str(child.props, "name") ?? "Room",
|
|
295
|
+
polygon,
|
|
296
|
+
floorMaterialId: str(child.props, "floorMaterial"),
|
|
297
|
+
ceilingMaterialId: str(child.props, "ceilingMaterial"),
|
|
298
|
+
usageType: str(child.props, "usage"),
|
|
299
|
+
height: typeof child.props.height === "number" ? child.props.height : void 0
|
|
300
|
+
};
|
|
301
|
+
floor.rooms.push(room);
|
|
302
|
+
const sides = {
|
|
303
|
+
north: makeWall([x, y], [x + w, y], thickness),
|
|
304
|
+
south: makeWall([x, y + d], [x + w, y + d], thickness),
|
|
305
|
+
west: makeWall([x, y], [x, y + d], thickness),
|
|
306
|
+
east: makeWall([x + w, y], [x + w, y + d], thickness)
|
|
307
|
+
};
|
|
308
|
+
room.boundaryWallIds = Object.values(sides).map((s) => s.id);
|
|
309
|
+
for (const o of flatten(child.children)) {
|
|
310
|
+
if (o.tag === TAG.furniture) {
|
|
311
|
+
floor.objects.push(toObject(o, floor.id));
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
if (o.tag !== TAG.door && o.tag !== TAG.window && o.tag !== TAG.opening) continue;
|
|
315
|
+
const type = o.tag === TAG.door ? "door" : o.tag === TAG.window ? "window" : "opening";
|
|
316
|
+
const def = OPENING_DEFAULTS[type];
|
|
317
|
+
const side = str(o.props, "wall") ?? "south";
|
|
318
|
+
const wall = sides[side] ?? sides.south;
|
|
319
|
+
const wallLen = side === "north" || side === "south" ? w : d;
|
|
320
|
+
const opening = {
|
|
321
|
+
id: str(o.props, "id") ?? createId("opening"),
|
|
322
|
+
floorId: floor.id,
|
|
323
|
+
wallId: wall.id,
|
|
324
|
+
type,
|
|
325
|
+
offset: num(o.props, "offset", wallLen / 2),
|
|
326
|
+
width: num(o.props, "width", def.width),
|
|
327
|
+
height: num(o.props, "height", def.height),
|
|
328
|
+
sillHeight: num(o.props, "sillHeight", def.sill)
|
|
329
|
+
};
|
|
330
|
+
floor.openings.push(opening);
|
|
331
|
+
}
|
|
332
|
+
break;
|
|
333
|
+
}
|
|
334
|
+
case TAG.furniture:
|
|
335
|
+
floor.objects.push(toObject(child, floor.id));
|
|
336
|
+
break;
|
|
337
|
+
default: break;
|
|
338
|
+
}
|
|
339
|
+
mergeCoincidentWalls(floor);
|
|
340
|
+
return floor;
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Two adjacent rooms each generate their own perimeter walls, producing a pair
|
|
344
|
+
* of coincident walls on their shared edge. Without merging, a door declared on
|
|
345
|
+
* one room only cuts that room's wall and the neighbour's wall stays solid
|
|
346
|
+
* behind it — the opening never passes through (and the walls z-fight in 3D).
|
|
347
|
+
*
|
|
348
|
+
* This collapses coincident, equal-thickness walls into one survivor and
|
|
349
|
+
* re-points openings (re-projecting their offset) and room boundaries onto it,
|
|
350
|
+
* so an interior door becomes a real passage between the rooms.
|
|
351
|
+
*/
|
|
352
|
+
function mergeCoincidentWalls(floor) {
|
|
353
|
+
const key = (w) => {
|
|
354
|
+
const a = [round(w.start[0]), round(w.start[1])];
|
|
355
|
+
const b = [round(w.end[0]), round(w.end[1])];
|
|
356
|
+
const [p, q] = a[0] < b[0] || a[0] === b[0] && a[1] <= b[1] ? [a, b] : [b, a];
|
|
357
|
+
return `${p[0]},${p[1]}|${q[0]},${q[1]}|${round(w.thickness)}`;
|
|
358
|
+
};
|
|
359
|
+
const groups = /* @__PURE__ */ new Map();
|
|
360
|
+
for (const w of floor.walls) {
|
|
361
|
+
const k = key(w);
|
|
362
|
+
const g = groups.get(k);
|
|
363
|
+
if (g) g.push(w);
|
|
364
|
+
else groups.set(k, [w]);
|
|
365
|
+
}
|
|
366
|
+
const survivors = [];
|
|
367
|
+
const survivorOf = /* @__PURE__ */ new Map();
|
|
368
|
+
for (const group of groups.values()) {
|
|
369
|
+
const survivor = group[0];
|
|
370
|
+
survivors.push(survivor);
|
|
371
|
+
for (const w of group) survivorOf.set(w.id, survivor);
|
|
372
|
+
}
|
|
373
|
+
if (survivors.length === floor.walls.length) return;
|
|
374
|
+
const wallById = new Map(floor.walls.map((w) => [w.id, w]));
|
|
375
|
+
for (const o of floor.openings) {
|
|
376
|
+
const survivor = survivorOf.get(o.wallId);
|
|
377
|
+
if (!survivor || survivor.id === o.wallId) continue;
|
|
378
|
+
const orig = wallById.get(o.wallId);
|
|
379
|
+
if (orig) {
|
|
380
|
+
const od = normalize(sub(orig.end, orig.start));
|
|
381
|
+
const cx = orig.start[0] + od[0] * o.offset;
|
|
382
|
+
const cy = orig.start[1] + od[1] * o.offset;
|
|
383
|
+
const sd = normalize(sub(survivor.end, survivor.start));
|
|
384
|
+
o.offset = (cx - survivor.start[0]) * sd[0] + (cy - survivor.start[1]) * sd[1];
|
|
385
|
+
}
|
|
386
|
+
o.wallId = survivor.id;
|
|
387
|
+
}
|
|
388
|
+
for (const r of floor.rooms) if (r.boundaryWallIds) r.boundaryWallIds = Array.from(new Set(r.boundaryWallIds.map((id) => survivorOf.get(id)?.id ?? id)));
|
|
389
|
+
floor.walls = survivors;
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Convert a rendered instance tree into the canonical BuildingDocument.
|
|
393
|
+
* `fallbackName` is used when the <Building> has no `name` prop (e.g. the
|
|
394
|
+
* registered composition name).
|
|
395
|
+
*/
|
|
396
|
+
function convert(instances, fallbackName = "Untitled") {
|
|
397
|
+
const tops = flatten(instances);
|
|
398
|
+
const materials = [...DEFAULT_MATERIALS];
|
|
399
|
+
for (const n of tops) if (n.tag === TAG.material) materials.push(toMaterial(n));
|
|
400
|
+
const buildingNodes = tops.filter((n) => n.tag === TAG.building);
|
|
401
|
+
const buildings = [];
|
|
402
|
+
let units = "metric";
|
|
403
|
+
let docName = fallbackName;
|
|
404
|
+
const sources = buildingNodes.length > 0 ? buildingNodes : [{
|
|
405
|
+
tag: TAG.building,
|
|
406
|
+
props: {},
|
|
407
|
+
children: tops
|
|
408
|
+
}];
|
|
409
|
+
for (const bn of sources) {
|
|
410
|
+
const buildingId = str(bn.props, "id") ?? createId("bld");
|
|
411
|
+
const name = str(bn.props, "name") ?? fallbackName;
|
|
412
|
+
if (str(bn.props, "units") === "imperial") units = "imperial";
|
|
413
|
+
docName = name;
|
|
414
|
+
const floors = flatten(bn.children).filter((c) => c.tag === TAG.floor).map((fn) => convertFloor(fn, buildingId, materials));
|
|
415
|
+
floors.sort((a, b) => a.elevation - b.elevation);
|
|
416
|
+
buildings.push({
|
|
417
|
+
id: buildingId,
|
|
418
|
+
name,
|
|
419
|
+
floors
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
return {
|
|
423
|
+
id: createId("doc"),
|
|
424
|
+
version: MODEL_VERSION,
|
|
425
|
+
name: docName,
|
|
426
|
+
units,
|
|
427
|
+
buildings,
|
|
428
|
+
materials,
|
|
429
|
+
assets: [],
|
|
430
|
+
metadata: { source: "react" }
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
//#endregion
|
|
434
|
+
//#region src/registry.ts
|
|
435
|
+
const compositions = /* @__PURE__ */ new Map();
|
|
436
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
437
|
+
let rootComponent = null;
|
|
438
|
+
let snapshot = [];
|
|
439
|
+
let version = 0;
|
|
440
|
+
function emit() {
|
|
441
|
+
snapshot = [...compositions.values()];
|
|
442
|
+
version += 1;
|
|
443
|
+
for (const fn of listeners) fn();
|
|
444
|
+
}
|
|
445
|
+
/** Increments whenever the registry changes (incl. hot-reload re-registration). */
|
|
446
|
+
function getCompositionsVersion() {
|
|
447
|
+
return version;
|
|
448
|
+
}
|
|
449
|
+
function __registerComposition(c) {
|
|
450
|
+
compositions.set(c.id, c);
|
|
451
|
+
emit();
|
|
452
|
+
}
|
|
453
|
+
function __unregisterComposition(id) {
|
|
454
|
+
compositions.delete(id);
|
|
455
|
+
emit();
|
|
456
|
+
}
|
|
457
|
+
function getCompositions() {
|
|
458
|
+
return snapshot;
|
|
459
|
+
}
|
|
460
|
+
function subscribeCompositions(fn) {
|
|
461
|
+
listeners.add(fn);
|
|
462
|
+
return () => listeners.delete(fn);
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* Register the root component (mirrors Remotion's registerRoot). The Studio
|
|
466
|
+
* mounts this so its <Composition> children register themselves.
|
|
467
|
+
*/
|
|
468
|
+
function registerRoot(component) {
|
|
469
|
+
rootComponent = component;
|
|
470
|
+
emit();
|
|
471
|
+
}
|
|
472
|
+
function getRoot() {
|
|
473
|
+
return rootComponent;
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* Declares a building composition. Renders nothing visible; on mount it
|
|
477
|
+
* registers itself into the module registry the Studio reads.
|
|
478
|
+
*/
|
|
479
|
+
function Composition(props) {
|
|
480
|
+
const { id, name, component, defaultProps } = props;
|
|
481
|
+
useEffect(() => {
|
|
482
|
+
__registerComposition({
|
|
483
|
+
id,
|
|
484
|
+
name,
|
|
485
|
+
component,
|
|
486
|
+
defaultProps
|
|
487
|
+
});
|
|
488
|
+
return () => __unregisterComposition(id);
|
|
489
|
+
}, [
|
|
490
|
+
id,
|
|
491
|
+
name,
|
|
492
|
+
component,
|
|
493
|
+
defaultProps
|
|
494
|
+
]);
|
|
495
|
+
return null;
|
|
496
|
+
}
|
|
497
|
+
/** Render any React Arch element tree to the canonical model. */
|
|
498
|
+
function renderToDocument(element, fallbackName) {
|
|
499
|
+
return convert(renderToInstances(element), fallbackName);
|
|
500
|
+
}
|
|
501
|
+
/** Render a registered composition (component + its default props) to a model. */
|
|
502
|
+
function renderComposition(comp) {
|
|
503
|
+
return renderToDocument(createElement(comp.component, comp.defaultProps ?? {}), comp.name);
|
|
504
|
+
}
|
|
505
|
+
//#endregion
|
|
506
|
+
export { Building, Composition, Door, Fixture, Floor, Furniture, Group, Material, Opening, Roof, Room, Slab, Stairs, TAG, Wall, Window, __registerComposition, __unregisterComposition, convert, getCompositions, getCompositionsVersion, getRoot, registerRoot, renderComposition, renderToDocument, renderToInstances, subscribeCompositions };
|
|
507
|
+
|
|
508
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/tags.ts","../src/components.tsx","../src/renderer.ts","../src/convert.ts","../src/registry.ts"],"sourcesContent":["/**\n * Internal host element tags. Users never type these — the public components\n * in `components.tsx` create them. The reconciler builds an instance tree of\n * these tags, which `convert.ts` turns into a BuildingDocument.\n */\nexport const TAG = {\n building: \"ra-building\",\n floor: \"ra-floor\",\n room: \"ra-room\",\n wall: \"ra-wall\",\n door: \"ra-door\",\n window: \"ra-window\",\n opening: \"ra-opening\",\n furniture: \"ra-furniture\",\n material: \"ra-material\",\n group: \"ra-group\",\n slab: \"ra-slab\",\n roof: \"ra-roof\",\n stairs: \"ra-stairs\",\n text: \"ra-text\",\n} as const;\n\nexport type Tag = (typeof TAG)[keyof typeof TAG];\n\n/** Side of a rectangular room a door/window attaches to. */\nexport type RoomSide = \"north\" | \"south\" | \"east\" | \"west\";\n","import { createElement, type ReactNode } from \"react\";\nimport { TAG, type RoomSide } from \"./tags.js\";\n\ntype WithChildren<T> = T & { children?: ReactNode };\nconst h = (tag: string, props: object) =>\n createElement(tag, props as Record<string, unknown>);\n\nexport interface BuildingProps {\n id?: string;\n name?: string;\n units?: \"metric\" | \"imperial\";\n}\nexport function Building(props: WithChildren<BuildingProps>) {\n return h(TAG.building, props);\n}\n\nexport interface FloorProps {\n id?: string;\n name?: string;\n elevation?: number;\n height?: number;\n}\nexport function Floor(props: WithChildren<FloorProps>) {\n return h(TAG.floor, props);\n}\n\nexport interface RoomProps {\n id?: string;\n name?: string;\n /** Top-left corner X (metres, X increases right). */\n x?: number;\n /** Top-left corner Y (metres, Y increases down). */\n y?: number;\n /** Extent along X. */\n width?: number;\n /** Extent along Y. */\n depth?: number;\n height?: number;\n wallThickness?: number;\n floorMaterial?: string;\n ceilingMaterial?: string;\n usage?: string;\n}\nexport function Room(props: WithChildren<RoomProps>) {\n return h(TAG.room, props);\n}\n\nexport interface WallProps {\n id?: string;\n from: [number, number];\n to: [number, number];\n thickness?: number;\n height?: number;\n materialId?: string;\n}\nexport function Wall(props: WallProps) {\n return h(TAG.wall, props);\n}\n\nexport interface OpeningCommonProps {\n id?: string;\n /** Which side of the parent room this attaches to. */\n wall?: RoomSide;\n /** Distance along the wall centerline from its start corner. */\n offset?: number;\n width?: number;\n height?: number;\n sillHeight?: number;\n}\nexport function Door(props: OpeningCommonProps) {\n return h(TAG.door, props);\n}\nexport function Window(props: OpeningCommonProps) {\n return h(TAG.window, props);\n}\nexport function Opening(props: OpeningCommonProps) {\n return h(TAG.opening, props);\n}\n\nexport interface FurnitureProps {\n id?: string;\n type: string;\n x?: number;\n y?: number;\n z?: number;\n rotation?: number;\n scaleX?: number;\n scaleY?: number;\n scaleZ?: number;\n assetId?: string;\n}\nexport function Furniture(props: FurnitureProps) {\n return h(TAG.furniture, props);\n}\n/** Alias used inside reusable room modules. */\nexport const Fixture = Furniture;\n\nexport interface MaterialProps {\n id: string;\n name?: string;\n category?: string;\n baseColor: string;\n roughness?: number;\n metalness?: number;\n opacity?: number;\n textureUrl?: string;\n}\nexport function Material(props: MaterialProps) {\n return h(TAG.material, props);\n}\n\nexport function Group(props: WithChildren<{ id?: string }>) {\n return h(TAG.group, props);\n}\n\n// Reserved primitives — accepted in the tree, modelled minimally for the MVP.\nexport function Slab(props: WithChildren<{ id?: string }>) {\n return h(TAG.slab, props);\n}\nexport function Roof(props: WithChildren<{ id?: string; type?: string }>) {\n return h(TAG.roof, props);\n}\nexport function Stairs(props: WithChildren<{ id?: string }>) {\n return h(TAG.stairs, props);\n}\n","import Reconciler from \"react-reconciler\";\nimport type { ReactElement } from \"react\";\n\n/** A node in the intermediate instance tree built by the reconciler. */\nexport interface Instance {\n tag: string;\n props: Record<string, unknown>;\n children: Instance[];\n}\n\nexport interface Container {\n children: Instance[];\n}\n\nfunction stripChildren(props: Record<string, unknown>): Record<string, unknown> {\n const { children, ...rest } = props;\n void children;\n return rest;\n}\n\n// react-reconciler's types are notoriously strict; the host config is plain.\nconst hostConfig: any = {\n supportsMutation: true,\n supportsPersistence: false,\n supportsHydration: false,\n isPrimaryRenderer: false,\n noTimeout: -1,\n now: () => 0,\n\n getRootHostContext: () => ({}),\n getChildHostContext: (parent: unknown) => parent,\n getPublicInstance: (instance: Instance) => instance,\n\n prepareForCommit: () => null,\n resetAfterCommit: () => {},\n preparePortalMount: () => {},\n\n createInstance(tag: string, props: Record<string, unknown>): Instance {\n return { tag, props: stripChildren(props), children: [] };\n },\n\n createTextInstance(text: string): Instance {\n return { tag: \"ra-text\", props: { text }, children: [] };\n },\n\n appendInitialChild(parent: Instance, child: Instance) {\n parent.children.push(child);\n },\n appendChild(parent: Instance, child: Instance) {\n parent.children.push(child);\n },\n appendChildToContainer(container: Container, child: Instance) {\n container.children.push(child);\n },\n\n insertBefore(parent: Instance, child: Instance, before: Instance) {\n const i = parent.children.indexOf(before);\n parent.children.splice(i, 0, child);\n },\n insertInContainerBefore(container: Container, child: Instance, before: Instance) {\n const i = container.children.indexOf(before);\n container.children.splice(i, 0, child);\n },\n\n removeChild(parent: Instance, child: Instance) {\n parent.children = parent.children.filter((c) => c !== child);\n },\n removeChildFromContainer(container: Container, child: Instance) {\n container.children = container.children.filter((c) => c !== child);\n },\n\n finalizeInitialChildren: () => false,\n shouldSetTextContent: () => false,\n clearContainer(container: Container) {\n container.children = [];\n },\n\n prepareUpdate: () => true,\n commitUpdate(instance: Instance, _payload: unknown, _tag: string, _old: unknown, newProps: Record<string, unknown>) {\n instance.props = stripChildren(newProps);\n },\n commitTextUpdate(instance: Instance, _old: string, text: string) {\n instance.props = { text };\n },\n\n getCurrentEventPriority: () => 16,\n detachDeletedInstance: () => {},\n prepareScopeUpdate: () => {},\n getInstanceFromScope: () => null,\n getInstanceFromNode: () => null,\n beforeActiveInstanceBlur: () => {},\n afterActiveInstanceBlur: () => {},\n scheduleTimeout: setTimeout,\n cancelTimeout: clearTimeout,\n};\n\nconst reconciler = Reconciler(hostConfig);\n\nconst LegacyRoot = 0;\n\n/**\n * Render a React element tree through the React Arch reconciler and return the\n * resulting intermediate instance tree. Synchronous (legacy root) so the tree\n * is fully built when this returns.\n */\nexport function renderToInstances(element: ReactElement): Instance[] {\n const container: Container = { children: [] };\n const root = reconciler.createContainer(\n container,\n LegacyRoot,\n null,\n false,\n null,\n \"react-arch\",\n (error: unknown) => {\n // Surface render errors loudly; the studio shows them as diagnostics.\n console.error(\"[react-arch] render error\", error);\n },\n null,\n );\n reconciler.updateContainer(element, root, null, null);\n return container.children;\n}\n","import { createId, round, type Units, type Vec2 } from \"@react-arch/shared\";\nimport { normalize, sub } from \"@react-arch/geometry\";\nimport {\n DEFAULT_MATERIALS,\n MODEL_VERSION,\n type Building,\n type BuildingDocument,\n type BuildingObject,\n type Floor,\n type Material,\n type Opening,\n type Room,\n type Wall,\n} from \"@react-arch/core\";\nimport { TAG, type RoomSide } from \"./tags.js\";\nimport type { Instance } from \"./renderer.js\";\n\nfunction num(props: Record<string, unknown>, key: string, fallback: number): number {\n const v = props[key];\n return typeof v === \"number\" && Number.isFinite(v) ? v : fallback;\n}\nfunction str(props: Record<string, unknown>, key: string): string | undefined {\n const v = props[key];\n return typeof v === \"string\" ? v : undefined;\n}\nfunction vec2(v: unknown): Vec2 | undefined {\n if (Array.isArray(v) && v.length === 2 && typeof v[0] === \"number\" && typeof v[1] === \"number\") {\n return [v[0], v[1]];\n }\n return undefined;\n}\n\n/** Expand transparent <Group> nodes and drop text nodes. */\nfunction flatten(nodes: Instance[]): Instance[] {\n const out: Instance[] = [];\n for (const n of nodes) {\n if (n.tag === TAG.text) continue;\n if (n.tag === TAG.group) out.push(...flatten(n.children));\n else out.push(n);\n }\n return out;\n}\n\nfunction toMaterial(node: Instance): Material {\n const p = node.props;\n return {\n id: str(p, \"id\") ?? createId(\"mat\"),\n name: str(p, \"name\") ?? \"Material\",\n category: (str(p, \"category\") as Material[\"category\"]) ?? \"custom\",\n baseColor: str(p, \"baseColor\") ?? \"#cccccc\",\n roughness: typeof p.roughness === \"number\" ? p.roughness : undefined,\n metalness: typeof p.metalness === \"number\" ? p.metalness : undefined,\n opacity: typeof p.opacity === \"number\" ? p.opacity : undefined,\n textureUrl: str(p, \"textureUrl\"),\n };\n}\n\ninterface OpeningDefaults {\n width: number;\n height: number;\n sill: number;\n}\nconst OPENING_DEFAULTS: Record<string, OpeningDefaults> = {\n door: { width: 0.9, height: 2.1, sill: 0 },\n window: { width: 1.2, height: 1.4, sill: 0.9 },\n opening: { width: 1.0, height: 2.1, sill: 0 },\n};\n\nfunction toObject(node: Instance, floorId: string): BuildingObject {\n const p = node.props;\n return {\n id: str(p, \"id\") ?? createId(\"object\"),\n floorId,\n type: str(p, \"type\") ?? \"object\",\n position: [num(p, \"x\", 0), num(p, \"y\", 0), num(p, \"z\", 0)],\n rotation: [0, 0, num(p, \"rotation\", 0)],\n scale: [num(p, \"scaleX\", 1), num(p, \"scaleY\", 1), num(p, \"scaleZ\", 1)],\n assetId: str(p, \"assetId\"),\n };\n}\n\nfunction convertFloor(node: Instance, buildingId: string, materials: Material[]): Floor {\n const p = node.props;\n const floor: Floor = {\n id: str(p, \"id\") ?? createId(\"floor\"),\n buildingId,\n name: str(p, \"name\") ?? \"Floor\",\n elevation: num(p, \"elevation\", 0),\n height: num(p, \"height\", 2.8),\n visible: true,\n locked: false,\n walls: [],\n rooms: [],\n openings: [],\n objects: [],\n };\n\n const makeWall = (start: Vec2, end: Vec2, thickness: number, materialId?: string): Wall => {\n const w: Wall = {\n id: createId(\"wall\"),\n floorId: floor.id,\n start,\n end,\n thickness,\n height: floor.height,\n materialId,\n };\n floor.walls.push(w);\n return w;\n };\n\n for (const child of flatten(node.children)) {\n switch (child.tag) {\n case TAG.material:\n materials.push(toMaterial(child));\n break;\n\n case TAG.wall: {\n const from = vec2(child.props.from) ?? [0, 0];\n const to = vec2(child.props.to) ?? [0, 0];\n const w = makeWall(from, to, num(child.props, \"thickness\", 0.2), str(child.props, \"materialId\"));\n if (str(child.props, \"id\")) w.id = str(child.props, \"id\")!;\n if (typeof child.props.height === \"number\") w.height = child.props.height;\n break;\n }\n\n case TAG.room: {\n const x = num(child.props, \"x\", 0);\n const y = num(child.props, \"y\", 0);\n const w = num(child.props, \"width\", 4);\n const d = num(child.props, \"depth\", 4);\n const thickness = num(child.props, \"wallThickness\", 0.2);\n const polygon: Vec2[] = [\n [x, y],\n [x + w, y],\n [x + w, y + d],\n [x, y + d],\n ];\n const room: Room = {\n id: str(child.props, \"id\") ?? createId(\"room\"),\n floorId: floor.id,\n name: str(child.props, \"name\") ?? \"Room\",\n polygon,\n floorMaterialId: str(child.props, \"floorMaterial\"),\n ceilingMaterialId: str(child.props, \"ceilingMaterial\"),\n usageType: str(child.props, \"usage\"),\n height: typeof child.props.height === \"number\" ? child.props.height : undefined,\n };\n floor.rooms.push(room);\n\n // Generate perimeter walls. Offsets increase in a natural reading\n // direction per side (L→R for horizontal, T→B for vertical).\n const sides: Record<RoomSide, Wall> = {\n north: makeWall([x, y], [x + w, y], thickness),\n south: makeWall([x, y + d], [x + w, y + d], thickness),\n west: makeWall([x, y], [x, y + d], thickness),\n east: makeWall([x + w, y], [x + w, y + d], thickness),\n };\n room.boundaryWallIds = Object.values(sides).map((s) => s.id);\n\n for (const o of flatten(child.children)) {\n // Furniture/fixtures are commonly declared inside a room.\n if (o.tag === TAG.furniture) {\n floor.objects.push(toObject(o, floor.id));\n continue;\n }\n if (o.tag !== TAG.door && o.tag !== TAG.window && o.tag !== TAG.opening) continue;\n const type = o.tag === TAG.door ? \"door\" : o.tag === TAG.window ? \"window\" : \"opening\";\n const def = OPENING_DEFAULTS[type]!;\n const side = (str(o.props, \"wall\") as RoomSide) ?? \"south\";\n const wall = sides[side] ?? sides.south;\n const wallLen = side === \"north\" || side === \"south\" ? w : d;\n const opening: Opening = {\n id: str(o.props, \"id\") ?? createId(\"opening\"),\n floorId: floor.id,\n wallId: wall.id,\n type,\n offset: num(o.props, \"offset\", wallLen / 2),\n width: num(o.props, \"width\", def.width),\n height: num(o.props, \"height\", def.height),\n sillHeight: num(o.props, \"sillHeight\", def.sill),\n };\n floor.openings.push(opening);\n }\n break;\n }\n\n case TAG.furniture:\n floor.objects.push(toObject(child, floor.id));\n break;\n\n default:\n // slab / roof / stairs are reserved; ignored for the MVP model.\n break;\n }\n }\n\n mergeCoincidentWalls(floor);\n return floor;\n}\n\n/**\n * Two adjacent rooms each generate their own perimeter walls, producing a pair\n * of coincident walls on their shared edge. Without merging, a door declared on\n * one room only cuts that room's wall and the neighbour's wall stays solid\n * behind it — the opening never passes through (and the walls z-fight in 3D).\n *\n * This collapses coincident, equal-thickness walls into one survivor and\n * re-points openings (re-projecting their offset) and room boundaries onto it,\n * so an interior door becomes a real passage between the rooms.\n */\nfunction mergeCoincidentWalls(floor: Floor): void {\n const key = (w: Wall): string => {\n const a: Vec2 = [round(w.start[0]), round(w.start[1])];\n const b: Vec2 = [round(w.end[0]), round(w.end[1])];\n // Order-insensitive so reversed walls share a key.\n const [p, q] = a[0] < b[0] || (a[0] === b[0] && a[1] <= b[1]) ? [a, b] : [b, a];\n return `${p[0]},${p[1]}|${q[0]},${q[1]}|${round(w.thickness)}`;\n };\n\n const groups = new Map<string, Wall[]>();\n for (const w of floor.walls) {\n const k = key(w);\n const g = groups.get(k);\n if (g) g.push(w);\n else groups.set(k, [w]);\n }\n\n const survivors: Wall[] = [];\n const survivorOf = new Map<string, Wall>(); // any wall id -> survivor wall\n for (const group of groups.values()) {\n const survivor = group[0]!;\n survivors.push(survivor);\n for (const w of group) survivorOf.set(w.id, survivor);\n }\n\n if (survivors.length === floor.walls.length) return; // nothing coincident\n\n const wallById = new Map(floor.walls.map((w) => [w.id, w]));\n for (const o of floor.openings) {\n const survivor = survivorOf.get(o.wallId);\n if (!survivor || survivor.id === o.wallId) continue;\n const orig = wallById.get(o.wallId);\n if (orig) {\n // World centre of the opening on its original wall.\n const od = normalize(sub(orig.end, orig.start));\n const cx = orig.start[0] + od[0] * o.offset;\n const cy = orig.start[1] + od[1] * o.offset;\n // Offset of that point along the survivor (handles reversed direction).\n const sd = normalize(sub(survivor.end, survivor.start));\n o.offset = (cx - survivor.start[0]) * sd[0] + (cy - survivor.start[1]) * sd[1];\n }\n o.wallId = survivor.id;\n }\n\n for (const r of floor.rooms) {\n if (r.boundaryWallIds) {\n r.boundaryWallIds = Array.from(\n new Set(r.boundaryWallIds.map((id) => survivorOf.get(id)?.id ?? id)),\n );\n }\n }\n\n floor.walls = survivors;\n}\n\n/**\n * Convert a rendered instance tree into the canonical BuildingDocument.\n * `fallbackName` is used when the <Building> has no `name` prop (e.g. the\n * registered composition name).\n */\nexport function convert(instances: Instance[], fallbackName = \"Untitled\"): BuildingDocument {\n const tops = flatten(instances);\n const materials: Material[] = [...DEFAULT_MATERIALS];\n for (const n of tops) if (n.tag === TAG.material) materials.push(toMaterial(n));\n\n const buildingNodes = tops.filter((n) => n.tag === TAG.building);\n const buildings: Building[] = [];\n let units: Units = \"metric\";\n let docName = fallbackName;\n\n const sources = buildingNodes.length > 0 ? buildingNodes : [{ tag: TAG.building, props: {}, children: tops }];\n\n for (const bn of sources) {\n const buildingId = str(bn.props, \"id\") ?? createId(\"bld\");\n const name = str(bn.props, \"name\") ?? fallbackName;\n if (str(bn.props, \"units\") === \"imperial\") units = \"imperial\";\n docName = name;\n const floors = flatten(bn.children)\n .filter((c) => c.tag === TAG.floor)\n .map((fn) => convertFloor(fn, buildingId, materials));\n // Keep floors ordered by elevation for stable stacking.\n floors.sort((a, b) => a.elevation - b.elevation);\n buildings.push({ id: buildingId, name, floors });\n }\n\n return {\n id: createId(\"doc\"),\n version: MODEL_VERSION,\n name: docName,\n units,\n buildings,\n materials,\n assets: [],\n metadata: { source: \"react\" },\n };\n}\n","import { createElement, useEffect, type ComponentType, type ReactElement } from \"react\";\nimport type { BuildingDocument } from \"@react-arch/core\";\nimport { renderToInstances } from \"./renderer.js\";\nimport { convert } from \"./convert.js\";\n\nexport interface BuildingComposition {\n id: string;\n name: string;\n component: ComponentType<Record<string, unknown>>;\n defaultProps?: Record<string, unknown>;\n}\n\n// --- module-level registry (Remotion-style) -------------------------------\n\nconst compositions = new Map<string, BuildingComposition>();\nconst listeners = new Set<() => void>();\nlet rootComponent: ComponentType | null = null;\n// Cached, referentially-stable snapshot for useSyncExternalStore consumers.\nlet snapshot: BuildingComposition[] = [];\nlet version = 0;\n\nfunction emit(): void {\n snapshot = [...compositions.values()];\n version += 1;\n for (const fn of listeners) fn();\n}\n\n/** Increments whenever the registry changes (incl. hot-reload re-registration). */\nexport function getCompositionsVersion(): number {\n return version;\n}\n\nexport function __registerComposition(c: BuildingComposition): void {\n compositions.set(c.id, c);\n emit();\n}\nexport function __unregisterComposition(id: string): void {\n compositions.delete(id);\n emit();\n}\n\nexport function getCompositions(): BuildingComposition[] {\n return snapshot;\n}\nexport function subscribeCompositions(fn: () => void): () => void {\n listeners.add(fn);\n return () => listeners.delete(fn);\n}\n\n/**\n * Register the root component (mirrors Remotion's registerRoot). The Studio\n * mounts this so its <Composition> children register themselves.\n */\nexport function registerRoot(component: ComponentType): void {\n rootComponent = component;\n emit();\n}\nexport function getRoot(): ComponentType | null {\n return rootComponent;\n}\n\n/**\n * Declares a building composition. Renders nothing visible; on mount it\n * registers itself into the module registry the Studio reads.\n */\nexport function Composition(props: BuildingComposition): null {\n const { id, name, component, defaultProps } = props;\n useEffect(() => {\n __registerComposition({ id, name, component, defaultProps });\n return () => __unregisterComposition(id);\n }, [id, name, component, defaultProps]);\n return null;\n}\n\n// --- rendering -------------------------------------------------------------\n\n/** Render any React Arch element tree to the canonical model. */\nexport function renderToDocument(element: ReactElement, fallbackName?: string): BuildingDocument {\n return convert(renderToInstances(element), fallbackName);\n}\n\n/** Render a registered composition (component + its default props) to a model. */\nexport function renderComposition(comp: BuildingComposition): BuildingDocument {\n const element = createElement(comp.component, comp.defaultProps ?? {});\n return renderToDocument(element, comp.name);\n}\n"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@react-arch/react",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"react-reconciler": "^0.29.2",
|
|
16
|
+
"@react-arch/core": "0.1.0",
|
|
17
|
+
"@react-arch/geometry": "0.1.0",
|
|
18
|
+
"@react-arch/shared": "0.1.0"
|
|
19
|
+
},
|
|
20
|
+
"peerDependencies": {
|
|
21
|
+
"react": "^18.3.0"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@types/react": "^18.3.12",
|
|
25
|
+
"@types/react-reconciler": "^0.28.9",
|
|
26
|
+
"react": "^18.3.1",
|
|
27
|
+
"typescript": "^5.7.2",
|
|
28
|
+
"vitest": "^2.1.8"
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"dist"
|
|
32
|
+
],
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public"
|
|
35
|
+
},
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "https://github.com/react-arch/react-arch.git",
|
|
39
|
+
"directory": "packages/react"
|
|
40
|
+
},
|
|
41
|
+
"license": "MIT",
|
|
42
|
+
"scripts": {
|
|
43
|
+
"typecheck": "tsc --noEmit",
|
|
44
|
+
"test": "vitest run --passWithNoTests",
|
|
45
|
+
"lint": "oxlint src",
|
|
46
|
+
"build": "tsdown"
|
|
47
|
+
}
|
|
48
|
+
}
|