@ringozz/react-godot 4.7.2-612 → 4.7.2-616

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.
@@ -1,315 +1,331 @@
1
- /**********************************************************************
2
- Copyright (c) Vladimir Davidovich. All rights reserved.
3
- ***********************************************************************/
4
-
5
- import { ClassDB } from '@ringozz/godot/ClassDB';
6
- import { Node } from '@ringozz/godot/Node';
7
- import { Object as Instance } from '@ringozz/godot/Object';
8
- import { PackedScene } from '@ringozz/godot/PackedScene';
9
- import { RefCounted } from '@ringozz/godot/RefCounted';
10
- import type Reconciler from 'react-reconciler';
11
- import Constants from 'react-reconciler/constants.js';
12
- import pkg from '../package.json' with { type: 'json' };
13
- import type { InstanceProps } from './react-types.ts';
14
-
15
- /* eslint-disable @typescript-eslint/no-unused-vars */
16
-
17
- export const rendererPackageName = pkg.name;
18
- export const rendererVersion = pkg.version;
19
- export const supportsMutation = true;
20
- export const supportsPersistence = false;
21
- export const supportsHydration = false;
22
- export const isPrimaryRenderer = true;
23
-
24
- type Type = string;
25
- type Props = InstanceProps & Record<string, unknown>;
26
- type Container = Instance;
27
- type TextInstance = Instance;
28
- type SuspenseInstance = Instance;
29
- type PublicInstance = Instance;
30
- type HostContext = unknown;
31
-
32
- const EMPTY = Object.freeze({});
33
- const attachments = new WeakMap<Instance, string>();
34
-
35
- export function createInstance<T extends Instance>(type: Type, props: Props, root: Container, hostContext: HostContext, internalHandle: Reconciler.OpaqueHandle): T {
36
- let { attach, object, ...rest } = props;
37
- if (object instanceof PackedScene)
38
- object = object.instantiate();
39
- else if (object instanceof RefCounted)
40
- object.reference();
41
-
42
- const instance = (object ?? ClassDB.instantiate(type)) as T;
43
- if (attach)
44
- attachments.set(instance, attach);
45
-
46
- commitUpdate(instance, type, EMPTY, rest, internalHandle);
47
- return instance;
48
- }
49
-
50
- export function createTextInstance(text: string, root: Container, hostContext: HostContext, internalHandle: Reconciler.OpaqueHandle): TextInstance {
51
- throw new Error('Text nodes are not supported: use a text prop, or a single string/all-string children (they are flattened into the node\'s `text` property).');
52
- }
53
-
54
- export const appendInitialChild = appendChild;
55
-
56
- export function finalizeInitialChildren(instance: Instance, type: Type, props: Props, root: Container, hostContext: HostContext): boolean {
57
- return false;
58
- }
59
-
60
- export function shouldSetTextContent(type: Type, props: Props): boolean {
61
- const c = props.children;
62
- if (typeof c === 'string' || typeof c === 'number')
63
- return true;
64
- return Array.isArray(c) && c.every((v) => typeof v === 'string' || typeof v === 'number');
65
- }
66
-
67
- export function getRootHostContext(root: Container): HostContext | null {
68
- return EMPTY;
69
- }
70
-
71
- export function getChildHostContext(parentHostContext: HostContext, type: Type, root: Container): HostContext {
72
- return parentHostContext;
73
- }
74
-
75
- export function getPublicInstance(instance: Instance | TextInstance): PublicInstance {
76
- return instance;
77
- }
78
-
79
- export function prepareForCommit(containerInfo: Container): Props | null {
80
- return null;
81
- }
82
-
83
- export function resetAfterCommit(containerInfo: Container): void {
84
- }
85
-
86
- export function preparePortalMount(containerInfo: Container): void {
87
- // No-op: portal children attach to their target Node via appendChildToContainer.
88
- // Mirrors ReactDOM's empty implementation.
89
- }
90
-
91
- export const noTimeout = -1;
92
- export const scheduleTimeout = setTimeout;
93
- export const cancelTimeout = clearTimeout;
94
- export const supportsMicrotasks = true;
95
- export const scheduleMicrotask = queueMicrotask;
96
-
97
- let currentUpdatePriority = Constants.NoEventPriority;
98
- export function setCurrentUpdatePriority(newPriority: Reconciler.EventPriority) {
99
- currentUpdatePriority = newPriority;
100
- }
101
-
102
- export function getCurrentUpdatePriority(): Reconciler.EventPriority {
103
- return currentUpdatePriority;
104
- }
105
-
106
- const currentEvent = () => globalThis.window?.event;
107
-
108
- export function resolveUpdatePriority(): Reconciler.EventPriority {
109
- if (currentUpdatePriority)
110
- return currentUpdatePriority;
111
- const event = currentEvent();
112
- switch (event?.type) {
113
- case 'click':
114
- case 'contextmenu':
115
- case 'keydown':
116
- case 'keypress':
117
- case 'keyup':
118
- case 'pointercancel':
119
- case 'pointerdown':
120
- case 'pointerup':
121
- return Constants.DiscreteEventPriority;
122
- case 'pointerenter':
123
- case 'pointerleave':
124
- case 'pointermove':
125
- case 'pointerout':
126
- case 'pointerover':
127
- case 'resize':
128
- case 'wheel':
129
- return Constants.ContinuousEventPriority;
130
- default:
131
- return Constants.DefaultEventPriority;
132
- }
133
- }
134
-
135
- let schedulerEvent: Event | undefined = undefined;
136
- export function trackSchedulerEvent() {
137
- schedulerEvent = currentEvent();
138
- }
139
-
140
- export function resolveEventType(): null | string {
141
- const event = currentEvent();
142
- return event && event !== schedulerEvent ? event.type : null;
143
- }
144
-
145
- export function resolveEventTimeStamp(): number {
146
- const event = currentEvent();
147
- return event && event !== schedulerEvent ? event.timeStamp : -1.1;
148
- }
149
-
150
- export function requestPostPaintCallback() {
151
- }
152
-
153
- export function resetFormInstance() {
154
- }
155
-
156
- export const NotPendingTransition = null;
157
- export const HostTransitionContext = null as never;
158
-
159
- export function shouldAttemptEagerTransition() {
160
- return false;
161
- }
162
-
163
- export function getInstanceFromNode(node: unknown): Reconciler.Fiber | null | undefined {
164
- return null;
165
- }
166
-
167
- export function beforeActiveInstanceBlur(): void {
168
- }
169
-
170
- export function afterActiveInstanceBlur(): void {
171
- }
172
-
173
- export function prepareScopeUpdate(scopeInstance: unknown, instance: unknown): void {
174
- }
175
-
176
- export function getInstanceFromScope(scopeInstance: unknown): Instance | null {
177
- return null;
178
- }
179
-
180
- export function detachDeletedInstance(node: Instance): void {
181
- if (node instanceof Node)
182
- node.queueFree();
183
- else
184
- node.free();
185
- }
186
-
187
- export function maySuspendCommit(type: Type, props: Props) {
188
- return false;
189
- }
190
-
191
- export function preloadInstance(type: Type, props: Props) {
192
- return true; // Return true to indicate it's already loaded
193
- }
194
-
195
- export function startSuspendingCommit() {
196
- }
197
-
198
- export function suspendInstance(type: Type, props: Props) {
199
- }
200
-
201
- export function waitForCommitToBeReady() {
202
- return null;
203
- }
204
-
205
- export function appendChild(parentInstance: Instance, child: Instance | TextInstance): void {
206
- const attached = attachments.get(child);
207
- if (attached) {
208
- Instance.assign(parentInstance, { [attached]: child });
209
- return;
210
- }
211
- (parentInstance as Node).addChild(child as Node);
212
- }
213
-
214
- export function appendChildToContainer(container: Container, child: Instance | TextInstance): void {
215
- appendChild(container, child);
216
- }
217
-
218
- export function insertBefore(parentInstance: Instance, child: Instance | TextInstance, beforeChild: Instance | TextInstance | SuspenseInstance): void {
219
- const attached = attachments.get(child);
220
- if (attached) {
221
- Instance.assign(parentInstance, { [attached]: child });
222
- return;
223
- }
224
- if ((child as Node).getParent() !== null) {
225
- (parentInstance as Node).removeChild(child as Node);
226
- }
227
- (parentInstance as Node).addChild(child as Node);
228
- (parentInstance as Node).moveChild(child as Node, (beforeChild as Node).getIndex());
229
- }
230
-
231
- export function insertInContainerBefore(container: Container, child: Instance | TextInstance, beforeChild: Instance | TextInstance | SuspenseInstance): void {
232
- insertBefore(container, child, beforeChild);
233
- }
234
-
235
- export function removeChild(parentInstance: Instance, child: Instance | TextInstance | SuspenseInstance): void {
236
- const attached = attachments.get(child);
237
- if (attached) {
238
- Instance.assign(parentInstance, { [attached]: undefined });
239
- return;
240
- }
241
- (parentInstance as Node).removeChild(child as Node);
242
- }
243
-
244
- export function removeChildFromContainer(container: Container, child: Instance | TextInstance | SuspenseInstance): void {
245
- removeChild(container, child);
246
- }
247
-
248
- export function resetTextContent(instance: Instance): void {
249
- instance.set('text', undefined);
250
- }
251
-
252
- export function commitTextUpdate(instance: TextInstance, oldText: string, newText: string): void {
253
- instance.set('text', newText);
254
- }
255
-
256
- export function commitMount(instance: Instance, type: Type, props: Props, internalInstanceHandle: Reconciler.OpaqueHandle): void {
257
- }
258
-
259
- function isEqual(a: unknown, b: unknown) {
260
- if (a === b) return true;
261
-
262
- const i1 = (a as Iterable<unknown> | undefined)?.[Symbol.iterator]?.();
263
- const i2 = (b as Iterable<unknown> | undefined)?.[Symbol.iterator]?.();
264
- while (i1 && i2) {
265
- const n1 = i1.next();
266
- const n2 = i2.next();
267
- if (n1.done !== n2.done) return false; // Different lengths
268
- if (n1.done) return true; // Both finished
269
- if (n1.value !== n2.value) return false; // Values mismatch
270
- }
271
- }
272
-
273
- export function commitUpdate(instance: Instance, type: Type, prevProps: Props, nextProps: Props, internalHandle: Reconciler.OpaqueHandle): void {
274
- const { attach: attachOld, object: objectOld, ref: refOld, children: childrenOld, ...restOld } = prevProps;
275
- const { attach: attachNew, object: objectNew, ref: refNew, children: childrenNew, ...restNew } = nextProps;
276
- if (attachOld !== attachNew)
277
- throw new Error(`Cannot change attachment ${attachOld} to ${attachNew}`);
278
- if (objectOld !== objectNew)
279
- throw new Error(`Cannot change the \`object\` of a mounted instance (${objectOld} -> ${objectNew}); remount with a new key`);
280
-
281
- const toText = (c: unknown) => Array.isArray(c) ? c.join('') : c as string;
282
- if (shouldSetTextContent(type, prevProps)) restOld['text'] = toText(childrenOld);
283
- if (shouldSetTextContent(type, nextProps)) restNew['text'] = toText(childrenNew);
284
-
285
- for (const [key, oldVal] of Object.entries(restOld)) {
286
- const newVal = restNew[key];
287
- if (isEqual(oldVal, newVal))
288
- delete restNew[key];
289
- else if (newVal === undefined)
290
- restNew[key] = undefined;
291
- }
292
-
293
- Instance.assign(instance, restNew);
294
- }
295
-
296
- export function hideInstance(instance: Instance | TextInstance): void {
297
- instance.set('visible', false);
298
- }
299
-
300
- export const hideTextInstance = hideInstance;
301
-
302
- export function unhideInstance(instance: Instance | TextInstance): void {
303
- instance.set('visible', true);
304
- }
305
-
306
- export const unhideTextInstance = unhideInstance;
307
-
308
- export function clearContainer(container: Container): void {
309
- // No-op: Godot containers (e.g. the SceneTree root) can hold non-React
310
- // children such as portal targets. The reconciler calls this on every
311
- // initial mount; queue-freeing the container's children here would destroy
312
- // those foreign nodes and leave React fibers referencing freed instances.
313
- // React-managed children are removed by the reconciler's deletion path.
314
- }
315
-
1
+ /**********************************************************************
2
+ Copyright (c) Vladimir Davidovich. All rights reserved.
3
+ ***********************************************************************/
4
+
5
+ import { ClassDB } from '@ringozz/godot/ClassDB';
6
+ import { Node } from '@ringozz/godot/Node';
7
+ import { Object as Instance } from '@ringozz/godot/Object';
8
+ import { PackedScene } from '@ringozz/godot/PackedScene';
9
+ import { RefCounted } from '@ringozz/godot/RefCounted';
10
+ import type Reconciler from 'react-reconciler';
11
+ import Constants from 'react-reconciler/constants.js';
12
+ import pkg from '../package.json' with { type: 'json' };
13
+ import type { InstanceProps } from './react-types.ts';
14
+
15
+ /* eslint-disable @typescript-eslint/no-unused-vars */
16
+
17
+ export const rendererPackageName = pkg.name;
18
+ export const rendererVersion = pkg.version;
19
+ export const supportsMutation = true;
20
+ export const supportsPersistence = false;
21
+ export const supportsHydration = false;
22
+ export const isPrimaryRenderer = true;
23
+
24
+ type Type = string;
25
+ type Props = InstanceProps & Record<string, unknown>;
26
+ type Container = Instance;
27
+ type TextInstance = Instance;
28
+ type SuspenseInstance = Instance;
29
+ type PublicInstance = Instance;
30
+ type HostContext = unknown;
31
+
32
+ const EMPTY = Object.freeze({});
33
+ const attachments = new WeakMap<Instance, string>();
34
+
35
+ export function createInstance<T extends Instance>(type: Type, props: Props, root: Container, hostContext: HostContext, internalHandle: Reconciler.OpaqueHandle): T {
36
+ let { attach, object, script, ...rest } = props;
37
+ if (object instanceof PackedScene)
38
+ object = object.instantiate();
39
+ else if (object instanceof RefCounted)
40
+ object.reference();
41
+
42
+ const instance = (object ?? ClassDB.instantiate(type)) as T;
43
+ if (attach)
44
+ attachments.set(instance, attach);
45
+
46
+ if (script)
47
+ instance.setScript(script);
48
+
49
+ commitUpdate(instance, type, EMPTY, rest, internalHandle);
50
+ return instance;
51
+ }
52
+
53
+ export function createTextInstance(text: string, root: Container, hostContext: HostContext, internalHandle: Reconciler.OpaqueHandle): TextInstance {
54
+ throw new Error('Text nodes are not supported: use a text prop, or a single string/all-string children (they are flattened into the node\'s `text` property).');
55
+ }
56
+
57
+ export const appendInitialChild = appendChild;
58
+
59
+ export function finalizeInitialChildren(instance: Instance, type: Type, props: Props, root: Container, hostContext: HostContext): boolean {
60
+ return false;
61
+ }
62
+
63
+ export function shouldSetTextContent(type: Type, props: Props): boolean {
64
+ const c = props.children;
65
+ if (typeof c === 'string' || typeof c === 'number')
66
+ return true;
67
+ return Array.isArray(c) && c.every((v) => typeof v === 'string' || typeof v === 'number');
68
+ }
69
+
70
+ export function getRootHostContext(root: Container): HostContext | null {
71
+ return EMPTY;
72
+ }
73
+
74
+ export function getChildHostContext(parentHostContext: HostContext, type: Type, root: Container): HostContext {
75
+ return parentHostContext;
76
+ }
77
+
78
+ export function getPublicInstance(instance: Instance | TextInstance): PublicInstance {
79
+ return instance;
80
+ }
81
+
82
+ export function prepareForCommit(containerInfo: Container): Props | null {
83
+ return null;
84
+ }
85
+
86
+ export function resetAfterCommit(containerInfo: Container): void {
87
+ }
88
+
89
+ export function preparePortalMount(containerInfo: Container): void {
90
+ // No-op: portal children attach to their target Node via appendChildToContainer.
91
+ // Mirrors ReactDOM's empty implementation.
92
+ }
93
+
94
+ export const noTimeout = -1;
95
+ export const scheduleTimeout = setTimeout;
96
+ export const cancelTimeout = clearTimeout;
97
+ export const supportsMicrotasks = true;
98
+ export const scheduleMicrotask = queueMicrotask;
99
+
100
+ let currentUpdatePriority = Constants.NoEventPriority;
101
+ export function setCurrentUpdatePriority(newPriority: Reconciler.EventPriority) {
102
+ currentUpdatePriority = newPriority;
103
+ }
104
+
105
+ export function getCurrentUpdatePriority(): Reconciler.EventPriority {
106
+ return currentUpdatePriority;
107
+ }
108
+
109
+ const currentEvent = () => globalThis.window?.event;
110
+
111
+ export function resolveUpdatePriority(): Reconciler.EventPriority {
112
+ if (currentUpdatePriority)
113
+ return currentUpdatePriority;
114
+ const event = currentEvent();
115
+ switch (event?.type) {
116
+ case 'click':
117
+ case 'contextmenu':
118
+ case 'keydown':
119
+ case 'keypress':
120
+ case 'keyup':
121
+ case 'pointercancel':
122
+ case 'pointerdown':
123
+ case 'pointerup':
124
+ return Constants.DiscreteEventPriority;
125
+ case 'pointerenter':
126
+ case 'pointerleave':
127
+ case 'pointermove':
128
+ case 'pointerout':
129
+ case 'pointerover':
130
+ case 'resize':
131
+ case 'wheel':
132
+ return Constants.ContinuousEventPriority;
133
+ default:
134
+ return Constants.DefaultEventPriority;
135
+ }
136
+ }
137
+
138
+ let schedulerEvent: Event | undefined = undefined;
139
+ export function trackSchedulerEvent() {
140
+ schedulerEvent = currentEvent();
141
+ }
142
+
143
+ export function resolveEventType(): null | string {
144
+ const event = currentEvent();
145
+ return event && event !== schedulerEvent ? event.type : null;
146
+ }
147
+
148
+ export function resolveEventTimeStamp(): number {
149
+ const event = currentEvent();
150
+ return event && event !== schedulerEvent ? event.timeStamp : -1.1;
151
+ }
152
+
153
+ export function requestPostPaintCallback() {
154
+ }
155
+
156
+ export function resetFormInstance() {
157
+ }
158
+
159
+ export const NotPendingTransition = null;
160
+ export const HostTransitionContext = null as never;
161
+
162
+ export function shouldAttemptEagerTransition() {
163
+ return false;
164
+ }
165
+
166
+ export function getInstanceFromNode(node: unknown): Reconciler.Fiber | null | undefined {
167
+ return null;
168
+ }
169
+
170
+ export function beforeActiveInstanceBlur(): void {
171
+ }
172
+
173
+ export function afterActiveInstanceBlur(): void {
174
+ }
175
+
176
+ export function prepareScopeUpdate(scopeInstance: unknown, instance: unknown): void {
177
+ }
178
+
179
+ export function getInstanceFromScope(scopeInstance: unknown): Instance | null {
180
+ return null;
181
+ }
182
+
183
+ export function detachDeletedInstance(node: Instance): void {
184
+ if (node instanceof Node)
185
+ node.queueFree();
186
+ else
187
+ node.free();
188
+ }
189
+
190
+ export function maySuspendCommit(type: Type, props: Props) {
191
+ return false;
192
+ }
193
+
194
+ export function preloadInstance(type: Type, props: Props) {
195
+ return true; // Return true to indicate it's already loaded
196
+ }
197
+
198
+ export function startSuspendingCommit() {
199
+ }
200
+
201
+ export function suspendInstance(type: Type, props: Props) {
202
+ }
203
+
204
+ export function suspendOnActiveViewTransition() {
205
+ }
206
+
207
+ export function waitForCommitToBeReady() {
208
+ return null;
209
+ }
210
+
211
+ export function appendChild(parentInstance: Instance, child: Instance | TextInstance): void {
212
+ insertBefore(parentInstance, child, null);
213
+ }
214
+
215
+ export function appendChildToContainer(container: Container, child: Instance | TextInstance): void {
216
+ appendChild(container, child);
217
+ }
218
+
219
+ export function insertBefore(parentInstance: Instance, child: Instance | TextInstance, beforeChild: Instance | TextInstance | SuspenseInstance | null): void {
220
+ const attached = attachments.get(child);
221
+ if (attached) {
222
+ Instance.assign(parentInstance, { [attached]: child });
223
+ return;
224
+ }
225
+ const parent = parentInstance as Node;
226
+ const node = child as Node;
227
+ const oldParent = node.getParent();
228
+ if (oldParent != parent) {
229
+ oldParent?.removeChild(node);
230
+ parent.addChild(node);
231
+ }
232
+ // A negative index counts from the end, so -1 is the append case — one native
233
+ // call, no anchor to look up.
234
+ if (!beforeChild) {
235
+ parent.moveChild(node, -1);
236
+ return;
237
+ }
238
+ // move_child() inserts into the list *after* removing the node, so an anchor
239
+ // sitting after the node shifts down by one.
240
+ const from = node.getIndex();
241
+ const to = (beforeChild as Node).getIndex();
242
+ parent.moveChild(node, to > from ? to - 1 : to);
243
+ }
244
+
245
+ export function insertInContainerBefore(container: Container, child: Instance | TextInstance, beforeChild: Instance | TextInstance | SuspenseInstance): void {
246
+ insertBefore(container, child, beforeChild);
247
+ }
248
+
249
+ export function removeChild(parentInstance: Instance, child: Instance | TextInstance | SuspenseInstance): void {
250
+ const attached = attachments.get(child);
251
+ if (attached) {
252
+ Instance.assign(parentInstance, { [attached]: undefined });
253
+ return;
254
+ }
255
+ (parentInstance as Node).removeChild(child as Node);
256
+ }
257
+
258
+ export function removeChildFromContainer(container: Container, child: Instance | TextInstance | SuspenseInstance): void {
259
+ removeChild(container, child);
260
+ }
261
+
262
+ export function resetTextContent(instance: Instance): void {
263
+ instance.set('text', undefined);
264
+ }
265
+
266
+ export function commitTextUpdate(instance: TextInstance, oldText: string, newText: string): void {
267
+ instance.set('text', newText);
268
+ }
269
+
270
+ export function commitMount(instance: Instance, type: Type, props: Props, internalInstanceHandle: Reconciler.OpaqueHandle): void {
271
+ }
272
+
273
+ function isEqual(a: unknown, b: unknown) {
274
+ if (a === b) return true;
275
+
276
+ const i1 = (a as Iterable<unknown> | undefined)?.[Symbol.iterator]?.();
277
+ const i2 = (b as Iterable<unknown> | undefined)?.[Symbol.iterator]?.();
278
+ while (i1 && i2) {
279
+ const n1 = i1.next();
280
+ const n2 = i2.next();
281
+ if (n1.done !== n2.done) return false; // Different lengths
282
+ if (n1.done) return true; // Both finished
283
+ if (n1.value !== n2.value) return false; // Values mismatch
284
+ }
285
+ }
286
+
287
+ export function commitUpdate(instance: Instance, type: Type, prevProps: Props, nextProps: Props, internalHandle: Reconciler.OpaqueHandle): void {
288
+ const { attach: attachOld, object: objectOld, script: scriptOld, ref: refOld, children: childrenOld, ...restOld } = prevProps;
289
+ const { attach: attachNew, object: objectNew, script: scriptNew, ref: refNew, children: childrenNew, ...restNew } = nextProps;
290
+ if (attachOld !== attachNew)
291
+ throw new Error(`Cannot change attachment ${attachOld} to ${attachNew}`);
292
+ if (objectOld !== objectNew)
293
+ throw new Error(`Cannot change the \`object\` of a mounted instance (${objectOld} -> ${objectNew}); remount with a new key`);
294
+ if (scriptOld !== scriptNew)
295
+ throw new Error(`Cannot change the \`script\` of a mounted instance (${scriptOld} -> ${scriptNew}); remount with a new key`);
296
+
297
+ const toText = (c: unknown) => Array.isArray(c) ? c.join('') : c as string;
298
+ if (shouldSetTextContent(type, prevProps)) restOld['text'] = toText(childrenOld);
299
+ if (shouldSetTextContent(type, nextProps)) restNew['text'] = toText(childrenNew);
300
+
301
+ for (const [key, oldVal] of Object.entries(restOld)) {
302
+ const newVal = restNew[key];
303
+ if (isEqual(oldVal, newVal))
304
+ delete restNew[key];
305
+ else if (newVal === undefined)
306
+ restNew[key] = undefined;
307
+ }
308
+
309
+ Instance.assign(instance, restNew);
310
+ }
311
+
312
+ export function hideInstance(instance: Instance | TextInstance): void {
313
+ instance.set('visible', false);
314
+ }
315
+
316
+ export const hideTextInstance = hideInstance;
317
+
318
+ export function unhideInstance(instance: Instance | TextInstance): void {
319
+ instance.set('visible', true);
320
+ }
321
+
322
+ export const unhideTextInstance = unhideInstance;
323
+
324
+ export function clearContainer(container: Container): void {
325
+ // No-op: Godot containers (e.g. the SceneTree root) can hold non-React
326
+ // children such as portal targets. The reconciler calls this on every
327
+ // initial mount; queue-freeing the container's children here would destroy
328
+ // those foreign nodes and leave React fibers referencing freed instances.
329
+ // React-managed children are removed by the reconciler's deletion path.
330
+ }
331
+