@@ -41,7 +41,8 @@
|
||||
"@types/react-reconciler": "~0.32.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"react-reconciler": "~0.32.0"
|
||||
"react-reconciler": "~0.32.0",
|
||||
"type-fest": "^5.3.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^19.2.0",
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { Predicate, String } from "effect"
|
||||
import { ClassDB, Node } from "godot"
|
||||
import { ClassDB, Node, type NodePathMap } from "godot"
|
||||
import ReactReconciler from "react-reconciler"
|
||||
import { DefaultEventPriority } from "react-reconciler/constants"
|
||||
import { camelToSnake, hasProperty, snakeToPascal } from "./utils.js"
|
||||
|
||||
|
||||
const DefaultEventPriority = 32
|
||||
|
||||
|
||||
export const make = () => {
|
||||
@@ -11,13 +13,13 @@ export const make = () => {
|
||||
return ReactReconciler<
|
||||
string,
|
||||
Record<string, unknown>,
|
||||
Node,
|
||||
Node,
|
||||
Node,
|
||||
Node,
|
||||
Node,
|
||||
Node,
|
||||
Node,
|
||||
Node<NodePathMap>,
|
||||
Node<NodePathMap>,
|
||||
Node<NodePathMap>,
|
||||
Node<NodePathMap>,
|
||||
Node<NodePathMap>,
|
||||
Node<NodePathMap>,
|
||||
Node<NodePathMap>,
|
||||
unknown,
|
||||
unknown,
|
||||
unknown,
|
||||
@@ -29,12 +31,12 @@ export const make = () => {
|
||||
createInstance(type, props) {
|
||||
let instance: Node
|
||||
if (type === "custom") {
|
||||
if (!Predicate.hasProperty(props, "class"))
|
||||
if (!hasProperty(props, "class"))
|
||||
throw new Error("Property 'class' required when using the 'custom' intrinsic type")
|
||||
instance = new (props.class as any)()
|
||||
}
|
||||
else {
|
||||
const className = String.capitalize(type)
|
||||
const className = snakeToPascal(camelToSnake(type))
|
||||
if (!ClassDB.class_exists(className))
|
||||
throw new Error(`Class is invalid: '${className}' (declared as '${type}') is not a valid engine or GDExtension class`)
|
||||
instance = ClassDB.instantiate(className)
|
||||
@@ -79,14 +81,14 @@ export const make = () => {
|
||||
return false
|
||||
},
|
||||
|
||||
prepareForCommit() {},
|
||||
prepareForCommit() { return null },
|
||||
resetAfterCommit() {},
|
||||
|
||||
getRootHostContext() {
|
||||
return {};
|
||||
},
|
||||
|
||||
getChildHostContext(parentHostContext, type, rootContainer) {
|
||||
getChildHostContext(parentHostContext, _type, _rootContainer) {
|
||||
return parentHostContext
|
||||
},
|
||||
|
||||
@@ -103,7 +105,7 @@ export const make = () => {
|
||||
},
|
||||
|
||||
getPublicInstance(instance) {
|
||||
return instance;
|
||||
return instance
|
||||
},
|
||||
|
||||
resolveUpdatePriority() {
|
||||
@@ -142,12 +144,12 @@ export const make = () => {
|
||||
})
|
||||
}
|
||||
|
||||
const applyNextProps = (instance: Node, nextProps: Record<string, unknown>) => {
|
||||
const applyNextProps = (instance: Node<NodePathMap>, nextProps: Record<string, unknown>) => {
|
||||
Object.keys(nextProps).forEach(name => {
|
||||
(instance as any)[name] = nextProps[name]
|
||||
})
|
||||
|
||||
if (Predicate.hasProperty(nextProps, "name")) {
|
||||
if (hasProperty(nextProps, "name")) {
|
||||
if (typeof nextProps.name !== "string")
|
||||
throw new Error("Prop 'name' should be a string")
|
||||
instance.set_name(nextProps.name)
|
||||
|
||||
16
packages/react-godot-renderer/src/utils.ts
Normal file
16
packages/react-godot-renderer/src/utils.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
export const isRecordOrArray = (input: unknown): input is { [x: PropertyKey]: unknown } =>
|
||||
typeof input === "object" && input !== null
|
||||
// biome-ignore lint/complexity/noBannedTypes: it's completely fine
|
||||
export const isFunction = (input: unknown): input is Function => typeof input === "function"
|
||||
export const isObject = (input: unknown): input is object => isRecordOrArray(input) || isFunction(input)
|
||||
export const hasProperty = <P extends PropertyKey>(self: unknown, property: P): self is { [K in P]: unknown } =>
|
||||
isObject(self) && (property in self)
|
||||
|
||||
export const camelToSnake = (self: string): string => self.replace(/([A-Z])/g, "_$1").toLowerCase()
|
||||
export const snakeToPascal = (self: string): string => {
|
||||
let str = self[0].toUpperCase()
|
||||
for (let i = 1; i < self.length; i++) {
|
||||
str += self[i] === "_" ? self[++i].toUpperCase() : self[i]
|
||||
}
|
||||
return str
|
||||
}
|
||||
Reference in New Issue
Block a user