react-three-game 0.0.65 → 0.0.67
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 +2 -660
- package/README.md +164 -91
- package/dist/index.d.ts +5 -3
- package/dist/index.js +3 -2
- package/dist/shared/GameCanvas.js +1 -1
- package/dist/tools/assetviewer/page.d.ts +13 -2
- package/dist/tools/assetviewer/page.js +61 -7
- package/dist/tools/dragdrop/index.d.ts +1 -1
- package/dist/tools/dragdrop/modelLoader.d.ts +2 -0
- package/dist/tools/prefabeditor/EditorContext.d.ts +2 -2
- package/dist/tools/prefabeditor/EditorTree.js +17 -3
- package/dist/tools/prefabeditor/EditorTreeMenus.d.ts +3 -1
- package/dist/tools/prefabeditor/EditorTreeMenus.js +7 -8
- package/dist/tools/prefabeditor/EditorUI.js +3 -7
- package/dist/tools/prefabeditor/GameEvents.d.ts +14 -1
- package/dist/tools/prefabeditor/GameEvents.js +2 -1
- package/dist/tools/prefabeditor/InstanceProvider.d.ts +4 -0
- package/dist/tools/prefabeditor/InstanceProvider.js +44 -12
- package/dist/tools/prefabeditor/PrefabEditor.js +77 -16
- package/dist/tools/prefabeditor/PrefabRoot.d.ts +9 -6
- package/dist/tools/prefabeditor/PrefabRoot.js +52 -126
- package/dist/tools/prefabeditor/components/CameraComponent.js +1 -1
- package/dist/tools/prefabeditor/components/ClickComponent.d.ts +3 -0
- package/dist/tools/prefabeditor/components/ClickComponent.js +45 -0
- package/dist/tools/prefabeditor/components/ComponentRegistry.js +0 -3
- package/dist/tools/prefabeditor/components/DirectionalLightComponent.js +3 -3
- package/dist/tools/prefabeditor/components/Input.d.ts +5 -2
- package/dist/tools/prefabeditor/components/Input.js +71 -38
- package/dist/tools/prefabeditor/components/MaterialComponent.js +4 -69
- package/dist/tools/prefabeditor/components/ModelComponent.js +5 -80
- package/dist/tools/prefabeditor/components/PhysicsComponent.d.ts +2 -0
- package/dist/tools/prefabeditor/components/PhysicsComponent.js +77 -10
- package/dist/tools/prefabeditor/components/SpotLightComponent.js +9 -7
- package/dist/tools/prefabeditor/components/index.js +2 -0
- package/dist/tools/prefabeditor/types.d.ts +1 -0
- package/dist/tools/prefabeditor/utils.d.ts +7 -1
- package/dist/tools/prefabeditor/utils.js +34 -1
- package/package.json +1 -1
|
@@ -8,25 +8,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
10
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
11
|
-
import {
|
|
12
|
-
import { forwardRef, useCallback,
|
|
13
|
-
import { BoxHelper, Euler, Matrix4, Quaternion,
|
|
14
|
-
import { getComponent, registerComponent
|
|
11
|
+
import { useHelper } from "@react-three/drei";
|
|
12
|
+
import { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
|
|
13
|
+
import { BoxHelper, Euler, Matrix4, Quaternion, Vector3, } from "three";
|
|
14
|
+
import { getComponent, registerComponent } from "./components/ComponentRegistry";
|
|
15
15
|
import components from "./components";
|
|
16
|
-
import { loadModel } from "../dragdrop";
|
|
16
|
+
import { loadModel, loadTexture } from "../dragdrop";
|
|
17
17
|
import { GameInstance, GameInstanceProvider, getRepeatAxesFromModelProperties, useInstanceCheck } from "./InstanceProvider";
|
|
18
|
-
import {
|
|
19
|
-
import { EditorContext } from "./EditorContext";
|
|
18
|
+
import { decompose } from "./utils";
|
|
20
19
|
components.forEach(registerComponent);
|
|
21
20
|
const IDENTITY = new Matrix4();
|
|
22
|
-
export const PrefabRoot = forwardRef(({ editMode, data,
|
|
23
|
-
var _a, _b, _c, _d;
|
|
24
|
-
// optional editor context
|
|
25
|
-
const editorContext = useContext(EditorContext);
|
|
26
|
-
const transformMode = (_a = editorContext === null || editorContext === void 0 ? void 0 : editorContext.transformMode) !== null && _a !== void 0 ? _a : "translate";
|
|
27
|
-
const snapResolution = (_b = editorContext === null || editorContext === void 0 ? void 0 : editorContext.snapResolution) !== null && _b !== void 0 ? _b : 0;
|
|
28
|
-
const positionSnap = (_c = editorContext === null || editorContext === void 0 ? void 0 : editorContext.positionSnap) !== null && _c !== void 0 ? _c : 0.5;
|
|
29
|
-
const rotationSnap = (_d = editorContext === null || editorContext === void 0 ? void 0 : editorContext.rotationSnap) !== null && _d !== void 0 ? _d : Math.PI / 4;
|
|
21
|
+
export const PrefabRoot = forwardRef(({ editMode, data, selectedId, onSelect, onClick, onSelectedObjectChange, onFocusNode, basePath = "", injectedModels = {}, injectedTextures = {} }, ref) => {
|
|
30
22
|
// prefab root state
|
|
31
23
|
const [models, setModels] = useState({});
|
|
32
24
|
const [textures, setTextures] = useState({});
|
|
@@ -34,28 +26,21 @@ export const PrefabRoot = forwardRef(({ editMode, data, onPrefabChange, selected
|
|
|
34
26
|
const failedTextures = useRef(new Set());
|
|
35
27
|
const objectRefs = useRef({});
|
|
36
28
|
const rigidBodyRefs = useRef(new Map());
|
|
37
|
-
const [selectedObject, setSelectedObject] = useState(null);
|
|
38
29
|
const rootRef = useRef(null);
|
|
39
|
-
const controlsRef = useRef(null);
|
|
40
30
|
const availableModels = useMemo(() => (Object.assign(Object.assign({}, models), injectedModels)), [models, injectedModels]);
|
|
41
31
|
const availableTextures = useMemo(() => (Object.assign(Object.assign({}, textures), injectedTextures)), [textures, injectedTextures]);
|
|
42
32
|
useImperativeHandle(ref, () => ({
|
|
43
33
|
root: rootRef.current,
|
|
44
34
|
rigidBodyRefs: rigidBodyRefs.current,
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const camera = controls === null || controls === void 0 ? void 0 : controls.object;
|
|
49
|
-
if (!object || !controls || !camera)
|
|
50
|
-
return;
|
|
51
|
-
focusCameraOnObject(object, camera, controls.target, () => { var _a; return (_a = controls.update) === null || _a === void 0 ? void 0 : _a.call(controls); });
|
|
52
|
-
}
|
|
53
|
-
}), []);
|
|
35
|
+
getObject: (nodeId) => { var _a; return (_a = objectRefs.current[nodeId]) !== null && _a !== void 0 ? _a : null; },
|
|
36
|
+
focusNode: (nodeId) => onFocusNode === null || onFocusNode === void 0 ? void 0 : onFocusNode(nodeId),
|
|
37
|
+
}), [onFocusNode]);
|
|
54
38
|
const registerRef = useCallback((id, obj) => {
|
|
55
39
|
objectRefs.current[id] = obj;
|
|
56
|
-
if (id === selectedId)
|
|
57
|
-
|
|
58
|
-
|
|
40
|
+
if (id === selectedId) {
|
|
41
|
+
onSelectedObjectChange === null || onSelectedObjectChange === void 0 ? void 0 : onSelectedObjectChange(obj);
|
|
42
|
+
}
|
|
43
|
+
}, [onSelectedObjectChange, selectedId]);
|
|
59
44
|
const registerRigidBodyRef = useCallback((id, rb) => {
|
|
60
45
|
rigidBodyRefs.current.set(id, rb);
|
|
61
46
|
}, []);
|
|
@@ -68,36 +53,26 @@ export const PrefabRoot = forwardRef(({ editMode, data, onPrefabChange, selected
|
|
|
68
53
|
};
|
|
69
54
|
return () => { console.error = originalError; };
|
|
70
55
|
}, []);
|
|
71
|
-
useEffect(() => {
|
|
72
|
-
var _a;
|
|
73
|
-
setSelectedObject(selectedId ? (_a = objectRefs.current[selectedId]) !== null && _a !== void 0 ? _a : null : null);
|
|
74
|
-
}, [selectedId]);
|
|
75
|
-
const onTransformChange = () => {
|
|
76
|
-
if (!selectedId || !onPrefabChange)
|
|
77
|
-
return;
|
|
78
|
-
const obj = objectRefs.current[selectedId];
|
|
79
|
-
if (!obj)
|
|
80
|
-
return;
|
|
81
|
-
const parentWorld = computeParentWorldMatrix(data.root, selectedId);
|
|
82
|
-
const local = parentWorld.clone().invert().multiply(obj.matrixWorld);
|
|
83
|
-
const { position, rotation, scale } = decompose(local);
|
|
84
|
-
const root = updateNode(data.root, selectedId, node => (Object.assign(Object.assign({}, node), { components: Object.assign(Object.assign({}, node.components), { transform: {
|
|
85
|
-
type: "Transform",
|
|
86
|
-
properties: { position, rotation, scale },
|
|
87
|
-
} }) })));
|
|
88
|
-
onPrefabChange(Object.assign(Object.assign({}, data), { root }));
|
|
89
|
-
};
|
|
90
56
|
useEffect(() => {
|
|
91
57
|
const modelsToLoad = new Set();
|
|
92
58
|
const texturesToLoad = new Set();
|
|
93
59
|
walk(data.root, node => {
|
|
94
|
-
var _a
|
|
95
|
-
((
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
60
|
+
var _a;
|
|
61
|
+
Object.values((_a = node.components) !== null && _a !== void 0 ? _a : {}).forEach(component => {
|
|
62
|
+
var _a, _b, _c, _d;
|
|
63
|
+
if (!(component === null || component === void 0 ? void 0 : component.type))
|
|
64
|
+
return;
|
|
65
|
+
if (component.type === 'Model' && ((_a = component.properties) === null || _a === void 0 ? void 0 : _a.filename)) {
|
|
66
|
+
modelsToLoad.add(component.properties.filename);
|
|
67
|
+
}
|
|
68
|
+
if (component.type === 'Material') {
|
|
69
|
+
((_b = component.properties) === null || _b === void 0 ? void 0 : _b.texture) && texturesToLoad.add(component.properties.texture);
|
|
70
|
+
((_c = component.properties) === null || _c === void 0 ? void 0 : _c.normalMapTexture) && texturesToLoad.add(component.properties.normalMapTexture);
|
|
71
|
+
}
|
|
72
|
+
if (component.type === 'SpotLight' && ((_d = component.properties) === null || _d === void 0 ? void 0 : _d.map)) {
|
|
73
|
+
texturesToLoad.add(component.properties.map);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
101
76
|
});
|
|
102
77
|
modelsToLoad.forEach((file) => __awaiter(void 0, void 0, void 0, function* () {
|
|
103
78
|
if (availableModels[file] || loading.current.has(file))
|
|
@@ -112,7 +87,6 @@ export const PrefabRoot = forwardRef(({ editMode, data, onPrefabChange, selected
|
|
|
112
87
|
setModels(m => (Object.assign(Object.assign({}, m), { [file]: model })));
|
|
113
88
|
}
|
|
114
89
|
}));
|
|
115
|
-
const loader = new TextureLoader();
|
|
116
90
|
texturesToLoad.forEach(file => {
|
|
117
91
|
if (availableTextures[file] || loading.current.has(file) || failedTextures.current.has(file))
|
|
118
92
|
return;
|
|
@@ -123,17 +97,18 @@ export const PrefabRoot = forwardRef(({ editMode, data, onPrefabChange, selected
|
|
|
123
97
|
: file.startsWith("/")
|
|
124
98
|
? `${basePath}${file}`
|
|
125
99
|
: `${basePath}/${file}`;
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
100
|
+
void loadTexture(path).then(result => {
|
|
101
|
+
if (result.success && result.texture) {
|
|
102
|
+
setTextures(t => (Object.assign(Object.assign({}, t), { [file]: result.texture })));
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
console.warn(`Failed to load texture: ${path}`, result.error);
|
|
131
106
|
loading.current.delete(file);
|
|
132
107
|
failedTextures.current.add(file);
|
|
133
108
|
});
|
|
134
109
|
});
|
|
135
110
|
}, [data, availableModels, availableTextures, basePath]);
|
|
136
|
-
return (
|
|
111
|
+
return (_jsx("group", { ref: rootRef, children: _jsx(GameInstanceProvider, { models: availableModels, selectedId: selectedId, editMode: editMode, onSelect: editMode ? onSelect : undefined, registerRef: registerRef, children: _jsx(GameObjectRenderer, { gameObject: data.root, selectedId: selectedId, onSelect: editMode ? onSelect : undefined, onClick: onClick, registerRef: registerRef, registerRigidBodyRef: registerRigidBodyRef, loadedModels: availableModels, loadedTextures: availableTextures, editMode: editMode, parentMatrix: IDENTITY }) }) }));
|
|
137
112
|
});
|
|
138
113
|
export function GameObjectRenderer(props) {
|
|
139
114
|
var _a, _b, _c;
|
|
@@ -162,12 +137,14 @@ function isPhysicsProps(v) {
|
|
|
162
137
|
return (v === null || v === void 0 ? void 0 : v.type) === "fixed" || (v === null || v === void 0 ? void 0 : v.type) === "dynamic" || (v === null || v === void 0 ? void 0 : v.type) === "kinematicPosition" || (v === null || v === void 0 ? void 0 : v.type) === "kinematicVelocity";
|
|
163
138
|
}
|
|
164
139
|
function InstancedNode({ gameObject, parentMatrix = IDENTITY, editMode, registerRef, selectedId: _selectedId, onSelect, onClick }) {
|
|
165
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
140
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
166
141
|
const localTransform = getNodeTransformProps(gameObject);
|
|
167
|
-
const
|
|
168
|
-
|
|
142
|
+
const isLocked = Boolean(gameObject.locked);
|
|
143
|
+
const clickable = Object.values((_a = gameObject.components) !== null && _a !== void 0 ? _a : {}).some(component => (component === null || component === void 0 ? void 0 : component.type) === 'Click');
|
|
144
|
+
const physicsProps = isPhysicsProps((_c = (_b = gameObject.components) === null || _b === void 0 ? void 0 : _b.physics) === null || _c === void 0 ? void 0 : _c.properties)
|
|
145
|
+
? (_e = (_d = gameObject.components) === null || _d === void 0 ? void 0 : _d.physics) === null || _e === void 0 ? void 0 : _e.properties
|
|
169
146
|
: undefined;
|
|
170
|
-
const modelUrl = (
|
|
147
|
+
const modelUrl = (_h = (_g = (_f = gameObject.components) === null || _f === void 0 ? void 0 : _f.model) === null || _g === void 0 ? void 0 : _g.properties) === null || _h === void 0 ? void 0 : _h.filename;
|
|
171
148
|
const instances = useMemo(() => buildRepeatedInstances(gameObject, parentMatrix, modelUrl, physicsProps), [gameObject, modelUrl, parentMatrix, physicsProps]);
|
|
172
149
|
const groupRef = useRef(null);
|
|
173
150
|
const clickValid = useRef(false);
|
|
@@ -178,22 +155,23 @@ function InstancedNode({ gameObject, parentMatrix = IDENTITY, editMode, register
|
|
|
178
155
|
}
|
|
179
156
|
}, [gameObject.id, registerRef, editMode]);
|
|
180
157
|
if (editMode) {
|
|
181
|
-
return (_jsxs(_Fragment, { children: [_jsx("group", { ref: groupRef, position: localTransform.position, rotation: localTransform.rotation, scale: localTransform.scale, onPointerDown: (e) => { e.stopPropagation(); clickValid.current = true; }, onPointerMove: () => { clickValid.current = false; }, onPointerUp: (e) => {
|
|
158
|
+
return (_jsxs(_Fragment, { children: [_jsx("group", { ref: groupRef, position: localTransform.position, rotation: localTransform.rotation, scale: localTransform.scale, onPointerDown: isLocked ? undefined : (e) => { e.stopPropagation(); clickValid.current = true; }, onPointerMove: isLocked ? undefined : () => { clickValid.current = false; }, onPointerUp: isLocked ? undefined : (e) => {
|
|
182
159
|
if (clickValid.current) {
|
|
183
160
|
e.stopPropagation();
|
|
184
161
|
onSelect === null || onSelect === void 0 ? void 0 : onSelect(gameObject.id);
|
|
185
162
|
onClick === null || onClick === void 0 ? void 0 : onClick(e, gameObject);
|
|
186
163
|
}
|
|
187
164
|
clickValid.current = false;
|
|
188
|
-
}, children: _jsx("mesh", { visible: false, children: _jsx("boxGeometry", { args: [0.01, 0.01, 0.01] }) }) }), instances.map(instance => (_jsx(GameInstance, { id: instance.id, sourceId: gameObject.id, modelUrl: instance.modelUrl, position: instance.position, rotation: instance.rotation, scale: instance.scale, physics: instance.physics }, instance.id)))] }));
|
|
165
|
+
}, children: _jsx("mesh", { visible: false, children: _jsx("boxGeometry", { args: [0.01, 0.01, 0.01] }) }) }), instances.map(instance => (_jsx(GameInstance, { id: instance.id, sourceId: gameObject.id, clickable: clickable, modelUrl: instance.modelUrl, position: instance.position, rotation: instance.rotation, scale: instance.scale, locked: isLocked, physics: instance.physics }, instance.id)))] }));
|
|
189
166
|
}
|
|
190
|
-
return (_jsx(_Fragment, { children: instances.map(instance => (_jsx(GameInstance, { id: instance.id, sourceId: gameObject.id, modelUrl: instance.modelUrl, position: instance.position, rotation: instance.rotation, scale: instance.scale, physics: instance.physics }, instance.id))) }));
|
|
167
|
+
return (_jsx(_Fragment, { children: instances.map(instance => (_jsx(GameInstance, { id: instance.id, sourceId: gameObject.id, clickable: clickable, modelUrl: instance.modelUrl, position: instance.position, rotation: instance.rotation, scale: instance.scale, locked: isLocked, physics: instance.physics }, instance.id))) }));
|
|
191
168
|
}
|
|
192
169
|
function StandardNode({ gameObject, selectedId, onSelect, onClick, registerRef, registerRigidBodyRef, loadedModels, loadedTextures, editMode, parentMatrix = IDENTITY, }) {
|
|
193
170
|
var _a, _b, _c, _d, _e;
|
|
194
171
|
const groupRef = useRef(null);
|
|
195
172
|
const helperRef = useRef(null);
|
|
196
173
|
const clickValid = useRef(false);
|
|
174
|
+
const isLocked = Boolean(gameObject.locked);
|
|
197
175
|
const isSelected = selectedId === gameObject.id;
|
|
198
176
|
const stillInstanced = useInstanceCheck(gameObject.id);
|
|
199
177
|
useHelper(editMode && isSelected ? helperRef : null, BoxHelper, "cyan");
|
|
@@ -235,26 +213,22 @@ function StandardNode({ gameObject, selectedId, onSelect, onClick, registerRef,
|
|
|
235
213
|
loadedTextures,
|
|
236
214
|
editMode,
|
|
237
215
|
});
|
|
238
|
-
const inner = (_jsx("group", { onPointerDown: editMode ? onDown : undefined, onPointerMove: editMode ? () => (clickValid.current = false) : undefined, onPointerUp: editMode ? onUp : undefined, children: renderCompositionNode(gameObject, renderCtx, parentMatrix, childNodes) }));
|
|
216
|
+
const inner = (_jsx("group", { onPointerDown: editMode && !isLocked ? onDown : undefined, onPointerMove: editMode && !isLocked ? () => (clickValid.current = false) : undefined, onPointerUp: editMode && !isLocked ? onUp : undefined, children: renderCompositionNode(gameObject, renderCtx, parentMatrix, childNodes) }));
|
|
239
217
|
if (editMode) {
|
|
240
218
|
return (_jsxs(_Fragment, { children: [_jsx("group", { ref: groupRef, position: transform.position, rotation: transform.rotation, scale: transform.scale, children: _jsx("mesh", { visible: false, children: _jsx("boxGeometry", { args: [0.01, 0.01, 0.01] }) }) }), _jsx("group", { ref: helperRef, position: transform.position, rotation: transform.rotation, scale: transform.scale, children: inner }), hasPhysics && (physicsDef === null || physicsDef === void 0 ? void 0 : physicsDef.View) ? (_jsx(physicsDef.View, { properties: physics.properties, position: transform.position, rotation: transform.rotation, scale: transform.scale, editMode: editMode, nodeId: gameObject.id, registerRigidBodyRef: registerRigidBodyRef, children: inner }, physicsKey)) : null] }));
|
|
241
219
|
}
|
|
242
220
|
if (hasPhysics && (physicsDef === null || physicsDef === void 0 ? void 0 : physicsDef.View)) {
|
|
243
221
|
return (_jsx(physicsDef.View, { properties: physics.properties, position: transform.position, rotation: transform.rotation, scale: transform.scale, editMode: editMode, nodeId: gameObject.id, registerRigidBodyRef: registerRigidBodyRef, children: inner }, physicsKey));
|
|
244
222
|
}
|
|
245
|
-
return (_jsx("group", { ref: groupRef, position: transform.position, rotation: transform.rotation, scale: transform.scale,
|
|
246
|
-
}
|
|
247
|
-
const CHILD_HOST_COMPONENT_TYPES = new Set(["Environment"]);
|
|
248
|
-
function isChildHostType(type) {
|
|
249
|
-
return CHILD_HOST_COMPONENT_TYPES.has(type);
|
|
223
|
+
return (_jsx("group", { ref: groupRef, position: transform.position, rotation: transform.rotation, scale: transform.scale, children: inner }));
|
|
250
224
|
}
|
|
251
225
|
function getChildHostComponents(gameObject) {
|
|
252
226
|
var _a;
|
|
253
227
|
return Object.entries((_a = gameObject.components) !== null && _a !== void 0 ? _a : {}).flatMap(([key, comp]) => {
|
|
254
|
-
if (!(comp === null || comp === void 0 ? void 0 : comp.type)
|
|
228
|
+
if (!(comp === null || comp === void 0 ? void 0 : comp.type))
|
|
255
229
|
return [];
|
|
256
230
|
const def = getComponent(comp.type);
|
|
257
|
-
if (!(def === null || def === void 0 ? void 0 : def.View))
|
|
231
|
+
if (!(def === null || def === void 0 ? void 0 : def.View) || def.nonComposable)
|
|
258
232
|
return [];
|
|
259
233
|
return { key, View: def.View, properties: comp.properties };
|
|
260
234
|
});
|
|
@@ -327,16 +301,6 @@ function buildRepeatedInstances(gameObject, parentMatrix, modelUrl, physics) {
|
|
|
327
301
|
}
|
|
328
302
|
return instances;
|
|
329
303
|
}
|
|
330
|
-
function decompose(m) {
|
|
331
|
-
const p = new Vector3(), q = new Quaternion(), s = new Vector3();
|
|
332
|
-
m.decompose(p, q, s);
|
|
333
|
-
const e = new Euler().setFromQuaternion(q);
|
|
334
|
-
return {
|
|
335
|
-
position: [p.x, p.y, p.z],
|
|
336
|
-
rotation: [e.x, e.y, e.z],
|
|
337
|
-
scale: [s.x, s.y, s.z],
|
|
338
|
-
};
|
|
339
|
-
}
|
|
340
304
|
function getNodeTransformProps(node) {
|
|
341
305
|
var _a, _b, _c, _d, _e;
|
|
342
306
|
const t = (_b = (_a = node === null || node === void 0 ? void 0 : node.components) === null || _a === void 0 ? void 0 : _a.transform) === null || _b === void 0 ? void 0 : _b.properties;
|
|
@@ -346,20 +310,6 @@ function getNodeTransformProps(node) {
|
|
|
346
310
|
scale: (_e = t === null || t === void 0 ? void 0 : t.scale) !== null && _e !== void 0 ? _e : [1, 1, 1],
|
|
347
311
|
};
|
|
348
312
|
}
|
|
349
|
-
function computeParentWorldMatrix(root, targetId) {
|
|
350
|
-
let result = null;
|
|
351
|
-
const visit = (node, parent) => {
|
|
352
|
-
var _a;
|
|
353
|
-
if (node.id === targetId) {
|
|
354
|
-
result = parent.clone();
|
|
355
|
-
return;
|
|
356
|
-
}
|
|
357
|
-
const world = parent.clone().multiply(compose(node));
|
|
358
|
-
(_a = node.children) === null || _a === void 0 ? void 0 : _a.forEach(c => !result && visit(c, world));
|
|
359
|
-
};
|
|
360
|
-
visit(root, IDENTITY);
|
|
361
|
-
return result !== null && result !== void 0 ? result : IDENTITY;
|
|
362
|
-
}
|
|
363
313
|
function renderCompositionSubtree(gameObject, ctx, parentMatrix = IDENTITY) {
|
|
364
314
|
if (!gameObject || gameObject.disabled)
|
|
365
315
|
return null;
|
|
@@ -374,9 +324,7 @@ function renderHostedChildren(gameObject, ctx, parentMatrix) {
|
|
|
374
324
|
}
|
|
375
325
|
function renderCompositionNode(gameObject, ctx, parentMatrix, childNodes) {
|
|
376
326
|
const ownContent = renderNodeOwnContent(gameObject, ctx, parentMatrix);
|
|
377
|
-
|
|
378
|
-
const subtree = _jsxs(_Fragment, { children: [ownContent, siblingContent, childNodes] });
|
|
379
|
-
return wrapWithChildHosts(gameObject, ctx, parentMatrix, subtree);
|
|
327
|
+
return wrapWithChildHosts(gameObject, ctx, parentMatrix, _jsxs(_Fragment, { children: [ownContent, childNodes] }));
|
|
380
328
|
}
|
|
381
329
|
function renderNodeOwnContent(gameObject, ctx, parentMatrix) {
|
|
382
330
|
var _a, _b, _c, _d;
|
|
@@ -412,28 +360,6 @@ function renderNodeOwnContent(gameObject, ctx, parentMatrix) {
|
|
|
412
360
|
}
|
|
413
361
|
return core;
|
|
414
362
|
}
|
|
415
|
-
function renderNodeSiblingComponents(gameObject, ctx, parentMatrix) {
|
|
416
|
-
var _a;
|
|
417
|
-
const contextProps = {
|
|
418
|
-
loadedModels: ctx.loadedModels,
|
|
419
|
-
loadedTextures: ctx.loadedTextures,
|
|
420
|
-
editMode: ctx.editMode,
|
|
421
|
-
isSelected: ctx.selectedId === gameObject.id,
|
|
422
|
-
nodeId: gameObject.id,
|
|
423
|
-
parentMatrix,
|
|
424
|
-
registerRef: ctx.registerRef,
|
|
425
|
-
};
|
|
426
|
-
return Object.entries((_a = gameObject.components) !== null && _a !== void 0 ? _a : {})
|
|
427
|
-
.filter(([key]) => !getNonComposableKeys().includes(key))
|
|
428
|
-
.flatMap(([key, comp]) => {
|
|
429
|
-
if (!(comp === null || comp === void 0 ? void 0 : comp.type) || isChildHostType(comp.type))
|
|
430
|
-
return [];
|
|
431
|
-
const def = getComponent(comp.type);
|
|
432
|
-
if (!(def === null || def === void 0 ? void 0 : def.View))
|
|
433
|
-
return [];
|
|
434
|
-
return _jsx(def.View, Object.assign({ properties: comp.properties }, contextProps), key);
|
|
435
|
-
});
|
|
436
|
-
}
|
|
437
363
|
function wrapWithChildHosts(gameObject, ctx, parentMatrix, subtree) {
|
|
438
364
|
const contextProps = {
|
|
439
365
|
loadedModels: ctx.loadedModels,
|
|
@@ -34,7 +34,7 @@ function CameraComponentView({ properties, editMode, isSelected }) {
|
|
|
34
34
|
cameraHelper.update();
|
|
35
35
|
}
|
|
36
36
|
});
|
|
37
|
-
return (_jsxs(_Fragment, { children: [_jsx(PerspectiveCamera, { ref: (instance) => setCamera(instance), makeDefault: !editMode, fov: fov, near: near, zoom: zoom, far: far }), editMode && isSelected && cameraHelper && (_jsx("primitive", { object: cameraHelper })), editMode
|
|
37
|
+
return (_jsxs(_Fragment, { children: [_jsx(PerspectiveCamera, { ref: (instance) => setCamera(instance), makeDefault: !editMode, fov: fov, near: near, zoom: zoom, far: far }), editMode && isSelected && cameraHelper && (_jsx("primitive", { object: cameraHelper })), editMode ? (_jsxs("group", { children: [_jsxs("mesh", { children: [_jsx("boxGeometry", { args: [0.3, 0.3, 0.5] }), _jsx("meshBasicMaterial", { color: '#22d3ee', wireframe: true })] }), _jsxs("mesh", { position: [0, 0, -0.25], rotation: [Math.PI / 2, 0, 0], children: [_jsx("coneGeometry", { args: [0.08, 0.16, 16] }), _jsx("meshBasicMaterial", { color: '#22d3ee', wireframe: true })] })] })) : null] }));
|
|
38
38
|
}
|
|
39
39
|
const CameraComponent = {
|
|
40
40
|
name: 'Camera',
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useRef } from 'react';
|
|
3
|
+
import { gameEvents } from '../GameEvents';
|
|
4
|
+
import { FieldGroup } from './Input';
|
|
5
|
+
function ClickComponentEditor() {
|
|
6
|
+
return (_jsx(FieldGroup, { children: _jsx("div", { style: { fontSize: 12, opacity: 0.8 }, children: "Emits a click game event in play mode when this entity is clicked." }) }));
|
|
7
|
+
}
|
|
8
|
+
function ClickComponentView({ children, editMode, nodeId }) {
|
|
9
|
+
const clickValid = useRef(false);
|
|
10
|
+
const emitClick = (event) => {
|
|
11
|
+
if (!nodeId)
|
|
12
|
+
return;
|
|
13
|
+
gameEvents.emit('click', {
|
|
14
|
+
sourceEntityId: nodeId,
|
|
15
|
+
point: [event.point.x, event.point.y, event.point.z],
|
|
16
|
+
button: event.button,
|
|
17
|
+
altKey: event.nativeEvent.altKey,
|
|
18
|
+
ctrlKey: event.nativeEvent.ctrlKey,
|
|
19
|
+
metaKey: event.nativeEvent.metaKey,
|
|
20
|
+
shiftKey: event.nativeEvent.shiftKey,
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
if (editMode) {
|
|
24
|
+
return _jsx(_Fragment, { children: children });
|
|
25
|
+
}
|
|
26
|
+
return (_jsx("group", { onPointerDown: (event) => {
|
|
27
|
+
event.stopPropagation();
|
|
28
|
+
clickValid.current = true;
|
|
29
|
+
}, onPointerMove: () => {
|
|
30
|
+
clickValid.current = false;
|
|
31
|
+
}, onPointerUp: (event) => {
|
|
32
|
+
if (!clickValid.current)
|
|
33
|
+
return;
|
|
34
|
+
event.stopPropagation();
|
|
35
|
+
emitClick(event);
|
|
36
|
+
clickValid.current = false;
|
|
37
|
+
}, children: children }));
|
|
38
|
+
}
|
|
39
|
+
const ClickComponent = {
|
|
40
|
+
name: 'Click',
|
|
41
|
+
Editor: ClickComponentEditor,
|
|
42
|
+
View: ClickComponentView,
|
|
43
|
+
defaultProperties: {},
|
|
44
|
+
};
|
|
45
|
+
export default ClickComponent;
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
const REGISTRY = {};
|
|
2
2
|
export function registerComponent(component) {
|
|
3
|
-
if (REGISTRY[component.name]) {
|
|
4
|
-
throw new Error(`Component with name ${component.name} already registered.`);
|
|
5
|
-
}
|
|
6
3
|
REGISTRY[component.name] = component;
|
|
7
4
|
}
|
|
8
5
|
export function getComponent(name) {
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
2
2
|
import { useRef, useEffect, useMemo, useState } from "react";
|
|
3
3
|
import { useFrame } from "@react-three/fiber";
|
|
4
4
|
import { CameraHelper, Vector3 } from "three";
|
|
5
|
-
import { FieldRenderer,
|
|
5
|
+
import { FieldRenderer, NumberInput } from "./Input";
|
|
6
6
|
const smallLabel = { display: 'block', fontSize: '8px', color: 'rgba(34, 211, 238, 0.5)', marginBottom: 2 };
|
|
7
7
|
const directionalLightDefaults = {
|
|
8
8
|
color: '#ffffff',
|
|
@@ -28,7 +28,7 @@ const directionalLightFields = [
|
|
|
28
28
|
label: 'Shadow Camera',
|
|
29
29
|
render: ({ values, onChangeMultiple }) => {
|
|
30
30
|
var _a, _b, _c, _d, _e, _f;
|
|
31
|
-
return (_jsxs("div", { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 4 }, children: [_jsxs("div", { children: [_jsx("label", { style: smallLabel, children: "Near" }), _jsx(
|
|
31
|
+
return (_jsxs("div", { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 4 }, children: [_jsxs("div", { children: [_jsx("label", { style: smallLabel, children: "Near" }), _jsx(NumberInput, { step: 0.1, value: (_a = values.shadowCameraNear) !== null && _a !== void 0 ? _a : 0.1, onChange: v => onChangeMultiple({ shadowCameraNear: v }) })] }), _jsxs("div", { children: [_jsx("label", { style: smallLabel, children: "Far" }), _jsx(NumberInput, { step: 1, value: (_b = values.shadowCameraFar) !== null && _b !== void 0 ? _b : 100, onChange: v => onChangeMultiple({ shadowCameraFar: v }) })] }), _jsxs("div", { children: [_jsx("label", { style: smallLabel, children: "Top" }), _jsx(NumberInput, { step: 1, value: (_c = values.shadowCameraTop) !== null && _c !== void 0 ? _c : 30, onChange: v => onChangeMultiple({ shadowCameraTop: v }) })] }), _jsxs("div", { children: [_jsx("label", { style: smallLabel, children: "Bottom" }), _jsx(NumberInput, { step: 1, value: (_d = values.shadowCameraBottom) !== null && _d !== void 0 ? _d : -30, onChange: v => onChangeMultiple({ shadowCameraBottom: v }) })] }), _jsxs("div", { children: [_jsx("label", { style: smallLabel, children: "Left" }), _jsx(NumberInput, { step: 1, value: (_e = values.shadowCameraLeft) !== null && _e !== void 0 ? _e : -30, onChange: v => onChangeMultiple({ shadowCameraLeft: v }) })] }), _jsxs("div", { children: [_jsx("label", { style: smallLabel, children: "Right" }), _jsx(NumberInput, { step: 1, value: (_f = values.shadowCameraRight) !== null && _f !== void 0 ? _f : 30, onChange: v => onChangeMultiple({ shadowCameraRight: v }) })] })] }));
|
|
32
32
|
},
|
|
33
33
|
},
|
|
34
34
|
{
|
|
@@ -37,7 +37,7 @@ const directionalLightFields = [
|
|
|
37
37
|
label: 'Target Offset',
|
|
38
38
|
render: ({ value, onChange }) => {
|
|
39
39
|
const offset = value !== null && value !== void 0 ? value : [0, -5, 0];
|
|
40
|
-
return (_jsxs("div", { style: { display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 4 }, children: [_jsxs("div", { children: [_jsx("label", { style: smallLabel, children: "X" }), _jsx(
|
|
40
|
+
return (_jsxs("div", { style: { display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 4 }, children: [_jsxs("div", { children: [_jsx("label", { style: smallLabel, children: "X" }), _jsx(NumberInput, { step: 0.5, value: offset[0], onChange: v => onChange([v, offset[1], offset[2]]) })] }), _jsxs("div", { children: [_jsx("label", { style: smallLabel, children: "Y" }), _jsx(NumberInput, { step: 0.5, value: offset[1], onChange: v => onChange([offset[0], v, offset[2]]) })] }), _jsxs("div", { children: [_jsx("label", { style: smallLabel, children: "Z" }), _jsx(NumberInput, { step: 0.5, value: offset[2], onChange: v => onChange([offset[0], offset[1], v]) })] })] }));
|
|
41
41
|
},
|
|
42
42
|
},
|
|
43
43
|
];
|
|
@@ -52,12 +52,15 @@ interface InputProps {
|
|
|
52
52
|
min?: number;
|
|
53
53
|
max?: number;
|
|
54
54
|
style?: React.CSSProperties;
|
|
55
|
-
label?: string;
|
|
56
55
|
}
|
|
57
|
-
export declare function
|
|
56
|
+
export declare function NumberInput({ value, onChange, step, min, max, style }: InputProps): import("react/jsx-runtime").JSX.Element;
|
|
58
57
|
export declare function Label({ children }: {
|
|
59
58
|
children: React.ReactNode;
|
|
60
59
|
}): import("react/jsx-runtime").JSX.Element;
|
|
60
|
+
export declare function FieldRow({ label, children, }: {
|
|
61
|
+
label: string;
|
|
62
|
+
children: React.ReactNode;
|
|
63
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
61
64
|
export declare function Vector3Input({ label, value, onChange, snap, labelExtra }: {
|
|
62
65
|
label: string;
|
|
63
66
|
value: [number, number, number];
|
|
@@ -49,23 +49,59 @@ function getStepPrecision(step) {
|
|
|
49
49
|
const decimal = stepString.split('.')[1];
|
|
50
50
|
return (_a = decimal === null || decimal === void 0 ? void 0 : decimal.length) !== null && _a !== void 0 ? _a : 0;
|
|
51
51
|
}
|
|
52
|
-
|
|
52
|
+
function clampNumber(value, min, max) {
|
|
53
|
+
if (min !== undefined && value < min)
|
|
54
|
+
return min;
|
|
55
|
+
if (max !== undefined && value > max)
|
|
56
|
+
return max;
|
|
57
|
+
return value;
|
|
58
|
+
}
|
|
59
|
+
function normalizeNumber(value, step, min, max) {
|
|
60
|
+
const clampedValue = clampNumber(value, min, max);
|
|
61
|
+
const normalizedStep = getNumericStep(step, 0);
|
|
62
|
+
if (!Number.isFinite(normalizedStep) || normalizedStep <= 0)
|
|
63
|
+
return clampedValue;
|
|
64
|
+
const precision = getStepPrecision(normalizedStep);
|
|
65
|
+
const stepBase = min !== null && min !== void 0 ? min : 0;
|
|
66
|
+
const steppedValue = stepBase + Math.round((clampedValue - stepBase) / normalizedStep) * normalizedStep;
|
|
67
|
+
return Number(steppedValue.toFixed(precision));
|
|
68
|
+
}
|
|
69
|
+
function isIncompleteNumber(value) {
|
|
70
|
+
return value === '' || value === '-' || value === '.' || value === '-.';
|
|
71
|
+
}
|
|
72
|
+
export function NumberInput({ value, onChange, step, min, max, style }) {
|
|
53
73
|
const [draft, setDraft] = useState(() => value.toString());
|
|
74
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
54
75
|
useEffect(() => {
|
|
55
|
-
|
|
56
|
-
|
|
76
|
+
if (!isFocused) {
|
|
77
|
+
setDraft(value.toString());
|
|
78
|
+
}
|
|
79
|
+
}, [value, isFocused]);
|
|
57
80
|
const handleChange = (e) => {
|
|
58
81
|
const inputValue = e.target.value;
|
|
59
82
|
setDraft(inputValue);
|
|
60
|
-
|
|
83
|
+
if (isIncompleteNumber(inputValue))
|
|
84
|
+
return;
|
|
85
|
+
const num = Number(inputValue);
|
|
61
86
|
if (Number.isFinite(num)) {
|
|
62
|
-
onChange(num);
|
|
87
|
+
onChange(clampNumber(num, min, max));
|
|
63
88
|
}
|
|
64
89
|
};
|
|
65
90
|
const handleBlur = () => {
|
|
66
|
-
|
|
91
|
+
setIsFocused(false);
|
|
92
|
+
if (isIncompleteNumber(draft)) {
|
|
93
|
+
setDraft(value.toString());
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const num = Number(draft);
|
|
67
97
|
if (!Number.isFinite(num)) {
|
|
68
98
|
setDraft(value.toString());
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const normalized = normalizeNumber(num, step, min, max);
|
|
102
|
+
setDraft(normalized.toString());
|
|
103
|
+
if (normalized !== value) {
|
|
104
|
+
onChange(normalized);
|
|
69
105
|
}
|
|
70
106
|
};
|
|
71
107
|
const dragState = useRef(null);
|
|
@@ -88,15 +124,10 @@ export function Input({ value, onChange, step, min, max, style, label }) {
|
|
|
88
124
|
scrubStep /= 10;
|
|
89
125
|
if (e.altKey)
|
|
90
126
|
scrubStep *= 10;
|
|
91
|
-
const precision = getStepPrecision(scrubStep);
|
|
92
127
|
const deltaSteps = Math.round(dx / 8);
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
nextValue = min;
|
|
97
|
-
if (max !== undefined && nextValue > max)
|
|
98
|
-
nextValue = max;
|
|
99
|
-
setDraft(nextValue.toFixed(precision));
|
|
128
|
+
const rawValue = startValue + deltaSteps * scrubStep;
|
|
129
|
+
const nextValue = normalizeNumber(rawValue, scrubStep, min, max);
|
|
130
|
+
setDraft(nextValue.toString());
|
|
100
131
|
onChange(nextValue);
|
|
101
132
|
};
|
|
102
133
|
const endScrub = (e) => {
|
|
@@ -106,26 +137,23 @@ export function Input({ value, onChange, step, min, max, style, label }) {
|
|
|
106
137
|
document.body.style.cursor = "";
|
|
107
138
|
e.currentTarget.releasePointerCapture(e.pointerId);
|
|
108
139
|
};
|
|
109
|
-
|
|
110
|
-
return (_jsxs("div", { style: {
|
|
111
|
-
display: 'flex',
|
|
112
|
-
alignItems: 'center',
|
|
113
|
-
justifyContent: 'space-between',
|
|
114
|
-
}, children: [_jsx("span", { style: Object.assign(Object.assign({}, styles.label), { marginBottom: 0, userSelect: 'none', flex: '0 0 auto', minWidth: 20 }), children: label }), _jsx("input", { type: "text", value: draft, onChange: handleChange, onBlur: handleBlur, onKeyDown: e => {
|
|
115
|
-
if (e.key === 'Enter') {
|
|
116
|
-
e.target.blur();
|
|
117
|
-
}
|
|
118
|
-
}, step: step, min: min, max: max, style: Object.assign(Object.assign(Object.assign({}, styles.input), { cursor: 'ew-resize' }), style), onPointerDown: startScrub, onPointerMove: onScrubMove, onPointerUp: endScrub })] }));
|
|
119
|
-
}
|
|
120
|
-
return (_jsx("input", { type: "text", value: draft, onChange: handleChange, onBlur: handleBlur, onKeyDown: e => {
|
|
140
|
+
return (_jsx("input", { type: "number", inputMode: "decimal", value: draft, onChange: handleChange, onFocus: () => setIsFocused(true), onBlur: handleBlur, onKeyDown: e => {
|
|
121
141
|
if (e.key === 'Enter') {
|
|
122
142
|
e.target.blur();
|
|
123
143
|
}
|
|
124
|
-
}, step: step, min: min, max: max, style: Object.assign(Object.assign(Object.assign({}, styles.input), { cursor: 'ew-resize' }), style), onPointerDown: startScrub, onPointerMove: onScrubMove, onPointerUp: endScrub }));
|
|
144
|
+
}, step: step !== null && step !== void 0 ? step : 'any', min: min, max: max, style: Object.assign(Object.assign(Object.assign({}, styles.input), { cursor: 'ew-resize' }), style), onPointerDown: startScrub, onPointerMove: onScrubMove, onPointerUp: endScrub }));
|
|
125
145
|
}
|
|
126
146
|
export function Label({ children }) {
|
|
127
147
|
return _jsx("label", { style: styles.label, children: children });
|
|
128
148
|
}
|
|
149
|
+
export function FieldRow({ label, children, }) {
|
|
150
|
+
return (_jsxs("div", { style: {
|
|
151
|
+
display: 'flex',
|
|
152
|
+
alignItems: 'center',
|
|
153
|
+
justifyContent: 'space-between',
|
|
154
|
+
gap: 8,
|
|
155
|
+
}, children: [_jsx("span", { style: Object.assign(Object.assign({}, styles.label), { marginBottom: 0, userSelect: 'none', flex: '0 0 auto', minWidth: 20 }), children: label }), children] }));
|
|
156
|
+
}
|
|
129
157
|
export function Vector3Input({ label, value, onChange, snap, labelExtra }) {
|
|
130
158
|
const snapValue = (num) => {
|
|
131
159
|
if (!snap)
|
|
@@ -133,18 +161,23 @@ export function Vector3Input({ label, value, onChange, snap, labelExtra }) {
|
|
|
133
161
|
return Math.round(num / snap) * snap;
|
|
134
162
|
};
|
|
135
163
|
const [draft, setDraft] = useState(() => value.map(v => v.toString()));
|
|
136
|
-
// Sync external changes (gizmo, undo, etc.)
|
|
137
164
|
useEffect(() => {
|
|
138
165
|
setDraft(value.map(v => v.toString()));
|
|
139
|
-
}, [value
|
|
166
|
+
}, [value]);
|
|
140
167
|
const dragState = useRef(null);
|
|
141
168
|
const commit = (index) => {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
next[index] = snapValue(num);
|
|
146
|
-
onChange(next);
|
|
169
|
+
if (isIncompleteNumber(draft[index])) {
|
|
170
|
+
setDraft(value.map(v => v.toString()));
|
|
171
|
+
return;
|
|
147
172
|
}
|
|
173
|
+
const num = Number(draft[index]);
|
|
174
|
+
if (!Number.isFinite(num)) {
|
|
175
|
+
setDraft(value.map(v => v.toString()));
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
const next = [...value];
|
|
179
|
+
next[index] = snapValue(num);
|
|
180
|
+
onChange(next);
|
|
148
181
|
};
|
|
149
182
|
const startScrub = (e, index) => {
|
|
150
183
|
dragState.current = {
|
|
@@ -171,7 +204,7 @@ export function Vector3Input({ label, value, onChange, snap, labelExtra }) {
|
|
|
171
204
|
next[index] = nextValue;
|
|
172
205
|
setDraft(d => {
|
|
173
206
|
const copy = [...d];
|
|
174
|
-
copy[index] = nextValue.
|
|
207
|
+
copy[index] = nextValue.toString();
|
|
175
208
|
return copy;
|
|
176
209
|
});
|
|
177
210
|
onChange(next);
|
|
@@ -216,7 +249,7 @@ export function Vector3Input({ label, value, onChange, snap, labelExtra }) {
|
|
|
216
249
|
width: '100%',
|
|
217
250
|
minWidth: 0,
|
|
218
251
|
cursor: 'inherit',
|
|
219
|
-
}, type: "
|
|
252
|
+
}, type: "number", inputMode: "decimal", step: snap !== null && snap !== void 0 ? snap : 'any', value: draft[index], onChange: e => {
|
|
220
253
|
const next = [...draft];
|
|
221
254
|
next[index] = e.target.value;
|
|
222
255
|
setDraft(next);
|
|
@@ -263,7 +296,7 @@ export function FieldGroup({ children }) {
|
|
|
263
296
|
}
|
|
264
297
|
export function NumberField({ name, label, values, onChange, fallback = 0, step, min, max, style, }) {
|
|
265
298
|
var _a;
|
|
266
|
-
return (_jsx(
|
|
299
|
+
return (_jsx(FieldRow, { label: label, children: _jsx(NumberInput, { value: (_a = values[name]) !== null && _a !== void 0 ? _a : fallback, onChange: bindFieldChange(name, onChange), step: step, min: min, max: max, style: style }) }));
|
|
267
300
|
}
|
|
268
301
|
export function StringField({ name, label, values, onChange, fallback = '', placeholder, }) {
|
|
269
302
|
var _a;
|
|
@@ -296,7 +329,7 @@ export function FieldRenderer({ fields, values, onChange }) {
|
|
|
296
329
|
case 'vector3':
|
|
297
330
|
return (_jsx(Vector3Input, { label: field.label, value: value !== null && value !== void 0 ? value : [0, 0, 0], onChange: v => updateField(field.name, v), snap: field.snap }, field.name));
|
|
298
331
|
case 'number':
|
|
299
|
-
return (_jsx(
|
|
332
|
+
return (_jsx(FieldRow, { label: field.label, children: _jsx(NumberInput, { value: value !== null && value !== void 0 ? value : 0, onChange: v => updateField(field.name, v), min: field.min, max: field.max, step: field.step }) }, field.name));
|
|
300
333
|
case 'string':
|
|
301
334
|
return (_jsx(StringInput, { label: field.label, value: value !== null && value !== void 0 ? value : '', onChange: v => updateField(field.name, v), placeholder: field.placeholder }, field.name));
|
|
302
335
|
case 'color':
|