onejs-react 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +265 -0
- package/package.json +3 -1
- package/src/__tests__/components.test.tsx +36 -0
- package/src/__tests__/host-config.test.ts +141 -99
- package/src/__tests__/mocks.ts +17 -1
- package/src/__tests__/setup.ts +23 -11
- package/src/components.tsx +77 -48
- package/src/error-boundary.tsx +175 -0
- package/src/host-config.ts +503 -162
- package/src/index.ts +46 -2
- package/src/renderer.ts +50 -23
- package/src/screen.tsx +1 -1
- package/src/style-parser.ts +171 -79
- package/src/types.ts +326 -8
- package/src/vector.ts +312 -0
package/src/host-config.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type {HostConfig} from 'react-reconciler';
|
|
2
|
-
import type {BaseProps, ViewStyle} from './types';
|
|
3
|
-
import {parseStyleValue} from './style-parser';
|
|
2
|
+
import type {BaseProps, ViewStyle, VisualElement, GenerateVisualContentCallback} from './types';
|
|
3
|
+
import {parseStyleValue, parseColor} from './style-parser';
|
|
4
|
+
|
|
5
|
+
// CSObject is an alias for VisualElement - they represent the same C# objects
|
|
6
|
+
type CSObject = VisualElement;
|
|
4
7
|
|
|
5
8
|
// Global declarations for QuickJS environment
|
|
6
9
|
declare function setTimeout(callback: () => void, ms?: number): number;
|
|
@@ -32,6 +35,7 @@ declare const CS: {
|
|
|
32
35
|
UnityEngine: {
|
|
33
36
|
UIElements: {
|
|
34
37
|
VisualElement: new () => CSObject;
|
|
38
|
+
TextElement: new () => CSObject;
|
|
35
39
|
Label: new () => CSObject;
|
|
36
40
|
Button: new () => CSObject;
|
|
37
41
|
TextField: new () => CSObject;
|
|
@@ -49,6 +53,15 @@ declare const CS: {
|
|
|
49
53
|
ListViewReorderMode: CSEnum;
|
|
50
54
|
AlternatingRowBackground: CSEnum;
|
|
51
55
|
CollectionVirtualizationMethod: CSEnum;
|
|
56
|
+
DisplayStyle: CSEnum;
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
OneJS: {
|
|
60
|
+
GPU: {
|
|
61
|
+
GPUBridge: {
|
|
62
|
+
SetElementBackgroundImage: (element: CSObject, rtHandle: number) => void;
|
|
63
|
+
ClearElementBackgroundImage: (element: CSObject) => void;
|
|
64
|
+
};
|
|
52
65
|
};
|
|
53
66
|
};
|
|
54
67
|
};
|
|
@@ -59,24 +72,6 @@ declare const __eventAPI: {
|
|
|
59
72
|
removeAllEventListeners: (element: CSObject) => void;
|
|
60
73
|
};
|
|
61
74
|
|
|
62
|
-
interface CSObject {
|
|
63
|
-
__csHandle: number;
|
|
64
|
-
__csType: string;
|
|
65
|
-
Add: (child: CSObject) => void;
|
|
66
|
-
Insert: (index: number, child: CSObject) => void;
|
|
67
|
-
Remove: (child: CSObject) => void;
|
|
68
|
-
RemoveAt: (index: number) => void;
|
|
69
|
-
IndexOf: (child: CSObject) => number;
|
|
70
|
-
Clear: () => void;
|
|
71
|
-
style: CSStyle;
|
|
72
|
-
text?: string;
|
|
73
|
-
value?: unknown;
|
|
74
|
-
label?: string;
|
|
75
|
-
AddToClassList: (className: string) => void;
|
|
76
|
-
RemoveFromClassList: (className: string) => void;
|
|
77
|
-
ClearClassList: () => void;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
75
|
interface CSStyle {
|
|
81
76
|
[key: string]: unknown;
|
|
82
77
|
}
|
|
@@ -132,6 +127,10 @@ interface CSListView extends CSObject {
|
|
|
132
127
|
Rebuild: () => void;
|
|
133
128
|
}
|
|
134
129
|
|
|
130
|
+
// Elements that merge text children into their text property instead of adding as visual children
|
|
131
|
+
// This enables <Label>Hello {"World"}</Label> to render as single line, matching React Native behavior
|
|
132
|
+
const TEXT_MERGE_TYPES = new Set(['ojs-label', 'ojs-text', 'ojs-button']);
|
|
133
|
+
|
|
135
134
|
// Instance type used by the reconciler
|
|
136
135
|
export interface Instance {
|
|
137
136
|
element: CSObject;
|
|
@@ -139,6 +138,14 @@ export interface Instance {
|
|
|
139
138
|
props: BaseProps;
|
|
140
139
|
eventHandlers: Map<string, Function>;
|
|
141
140
|
appliedStyleKeys: Set<string>; // Track which style properties are currently applied
|
|
141
|
+
// For text-merging parents: ordered list of merged text children
|
|
142
|
+
mergedTextChildren?: Instance[];
|
|
143
|
+
// For merged text children: reference to parent they're merged into
|
|
144
|
+
mergedInto?: Instance;
|
|
145
|
+
// Set to true when a non-text child is added, disabling further text merging
|
|
146
|
+
hasMixedContent?: boolean;
|
|
147
|
+
// For vector drawing: track the current generateVisualContent callback
|
|
148
|
+
visualContentCallback?: GenerateVisualContentCallback;
|
|
142
149
|
}
|
|
143
150
|
|
|
144
151
|
export type TextInstance = Instance; // For Label elements with text content
|
|
@@ -149,6 +156,7 @@ export type ChildSet = never; // Not using persistent mode
|
|
|
149
156
|
// Element types use 'ojs-' prefix to avoid conflicts with HTML/SVG in @types/react
|
|
150
157
|
const TYPE_MAP: Record<string, () => CSObject> = {
|
|
151
158
|
'ojs-view': () => new CS.UnityEngine.UIElements.VisualElement(),
|
|
159
|
+
'ojs-text': () => new CS.UnityEngine.UIElements.TextElement(),
|
|
152
160
|
'ojs-label': () => new CS.UnityEngine.UIElements.Label(),
|
|
153
161
|
'ojs-button': () => new CS.UnityEngine.UIElements.Button(),
|
|
154
162
|
'ojs-textfield': () => new CS.UnityEngine.UIElements.TextField(),
|
|
@@ -161,17 +169,68 @@ const TYPE_MAP: Record<string, () => CSObject> = {
|
|
|
161
169
|
|
|
162
170
|
// Event prop to event type mapping
|
|
163
171
|
const EVENT_PROPS: Record<string, string> = {
|
|
172
|
+
// Click
|
|
164
173
|
onClick: 'click',
|
|
174
|
+
|
|
175
|
+
// Pointer events
|
|
165
176
|
onPointerDown: 'pointerdown',
|
|
166
177
|
onPointerUp: 'pointerup',
|
|
167
178
|
onPointerMove: 'pointermove',
|
|
168
179
|
onPointerEnter: 'pointerenter',
|
|
169
180
|
onPointerLeave: 'pointerleave',
|
|
181
|
+
onPointerCancel: 'pointercancel',
|
|
182
|
+
onPointerCapture: 'pointercapture',
|
|
183
|
+
onPointerCaptureOut: 'pointercaptureout',
|
|
184
|
+
onPointerStationary: 'pointerstationary',
|
|
185
|
+
|
|
186
|
+
// Mouse events
|
|
187
|
+
onMouseDown: 'mousedown',
|
|
188
|
+
onMouseUp: 'mouseup',
|
|
189
|
+
onMouseMove: 'mousemove',
|
|
190
|
+
onMouseEnter: 'mouseenter',
|
|
191
|
+
onMouseLeave: 'mouseleave',
|
|
192
|
+
onMouseOver: 'mouseover',
|
|
193
|
+
onMouseOut: 'mouseout',
|
|
194
|
+
onWheel: 'wheel',
|
|
195
|
+
onContextClick: 'contextclick',
|
|
196
|
+
|
|
197
|
+
// Focus events
|
|
170
198
|
onFocus: 'focus',
|
|
171
199
|
onBlur: 'blur',
|
|
200
|
+
onFocusIn: 'focusin',
|
|
201
|
+
onFocusOut: 'focusout',
|
|
202
|
+
|
|
203
|
+
// Keyboard events
|
|
172
204
|
onKeyDown: 'keydown',
|
|
173
205
|
onKeyUp: 'keyup',
|
|
206
|
+
|
|
207
|
+
// Input events
|
|
174
208
|
onChange: 'change',
|
|
209
|
+
onInput: 'input',
|
|
210
|
+
|
|
211
|
+
// Drag events
|
|
212
|
+
onDragEnter: 'dragenter',
|
|
213
|
+
onDragLeave: 'dragleave',
|
|
214
|
+
onDragUpdated: 'dragupdated',
|
|
215
|
+
onDragPerform: 'dragperform',
|
|
216
|
+
onDragExited: 'dragexited',
|
|
217
|
+
|
|
218
|
+
// Geometry events
|
|
219
|
+
onGeometryChanged: 'geometrychanged',
|
|
220
|
+
|
|
221
|
+
// Navigation events
|
|
222
|
+
onNavigationMove: 'navigationmove',
|
|
223
|
+
onNavigationSubmit: 'navigationsubmit',
|
|
224
|
+
onNavigationCancel: 'navigationcancel',
|
|
225
|
+
|
|
226
|
+
// Tooltip
|
|
227
|
+
onTooltip: 'tooltip',
|
|
228
|
+
|
|
229
|
+
// Transition events
|
|
230
|
+
onTransitionRun: 'transitionrun',
|
|
231
|
+
onTransitionStart: 'transitionstart',
|
|
232
|
+
onTransitionEnd: 'transitionend',
|
|
233
|
+
onTransitionCancel: 'transitioncancel',
|
|
175
234
|
};
|
|
176
235
|
|
|
177
236
|
// Shorthand style properties that expand to multiple properties
|
|
@@ -237,6 +296,35 @@ function getExpandedStyleKeys(style: ViewStyle | undefined): Set<string> {
|
|
|
237
296
|
return keys;
|
|
238
297
|
}
|
|
239
298
|
|
|
299
|
+
/**
|
|
300
|
+
* RenderTexture-like object for backgroundImage style property.
|
|
301
|
+
* Can be either:
|
|
302
|
+
* - A marker object with __rtHandle (from rt.getUnityObject())
|
|
303
|
+
* - A RenderTexture object directly (has __handle property)
|
|
304
|
+
*/
|
|
305
|
+
interface RenderTextureRef {
|
|
306
|
+
__rtHandle?: number;
|
|
307
|
+
__handle?: number;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Check if a value is a RenderTexture or RenderTexture handle marker.
|
|
312
|
+
* Supports both:
|
|
313
|
+
* - Direct RenderTexture objects (have __handle)
|
|
314
|
+
* - Marker objects from getUnityObject() (have __rtHandle)
|
|
315
|
+
*/
|
|
316
|
+
function isRenderTextureHandle(value: unknown): value is RenderTextureRef {
|
|
317
|
+
if (typeof value !== "object" || value === null) return false;
|
|
318
|
+
return "__rtHandle" in value || "__handle" in value;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Get the RT handle from a RenderTexture-like object.
|
|
323
|
+
*/
|
|
324
|
+
function getRenderTextureHandle(value: RenderTextureRef): number {
|
|
325
|
+
return value.__rtHandle ?? value.__handle ?? -1;
|
|
326
|
+
}
|
|
327
|
+
|
|
240
328
|
// Apply style properties to element, returns the set of applied keys
|
|
241
329
|
function applyStyle(element: CSObject, style: ViewStyle | undefined): Set<string> {
|
|
242
330
|
const appliedKeys = new Set<string>();
|
|
@@ -255,6 +343,14 @@ function applyStyle(element: CSObject, style: ViewStyle | undefined): Set<string
|
|
|
255
343
|
s[prop] = parsed;
|
|
256
344
|
appliedKeys.add(prop);
|
|
257
345
|
}
|
|
346
|
+
} else if (key === "backgroundImage" && isRenderTextureHandle(value)) {
|
|
347
|
+
// Special handling for RenderTexture background images
|
|
348
|
+
// Supports both direct RenderTexture objects and marker objects
|
|
349
|
+
const handle = getRenderTextureHandle(value);
|
|
350
|
+
if (handle >= 0) {
|
|
351
|
+
CS.OneJS.GPU.GPUBridge.SetElementBackgroundImage(element, handle);
|
|
352
|
+
}
|
|
353
|
+
appliedKeys.add(key);
|
|
258
354
|
} else {
|
|
259
355
|
// Parse and apply individual property
|
|
260
356
|
s[key] = parseStyleValue(key, value);
|
|
@@ -269,8 +365,13 @@ function clearRemovedStyles(element: CSObject, oldKeys: Set<string>, newKeys: Se
|
|
|
269
365
|
const s = element.style;
|
|
270
366
|
for (const key of oldKeys) {
|
|
271
367
|
if (!newKeys.has(key)) {
|
|
272
|
-
|
|
273
|
-
|
|
368
|
+
if (key === "backgroundImage") {
|
|
369
|
+
// Special handling for backgroundImage - use GPUBridge to clear
|
|
370
|
+
CS.OneJS.GPU.GPUBridge.ClearElementBackgroundImage(element);
|
|
371
|
+
} else {
|
|
372
|
+
// Setting to undefined clears the inline style, falling back to USS
|
|
373
|
+
s[key] = undefined;
|
|
374
|
+
}
|
|
274
375
|
}
|
|
275
376
|
}
|
|
276
377
|
}
|
|
@@ -334,126 +435,325 @@ function applyEvents(instance: Instance, props: BaseProps) {
|
|
|
334
435
|
}
|
|
335
436
|
}
|
|
336
437
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
438
|
+
/**
|
|
439
|
+
* Apply generateVisualContent callback for vector drawing.
|
|
440
|
+
* Uses Unity's generateVisualContent delegate on VisualElement.
|
|
441
|
+
*
|
|
442
|
+
* This follows the same pattern as ListView's makeItem/bindItem callbacks -
|
|
443
|
+
* we assign JS functions directly to C# delegate properties via the interop layer.
|
|
444
|
+
*/
|
|
445
|
+
function applyVisualContentCallback(instance: Instance, props: BaseProps) {
|
|
446
|
+
const callback = props.onGenerateVisualContent;
|
|
447
|
+
const existingCallback = instance.visualContentCallback;
|
|
448
|
+
|
|
449
|
+
if (callback !== existingCallback) {
|
|
450
|
+
const element = instance.element as unknown as { generateVisualContent: GenerateVisualContentCallback | null };
|
|
451
|
+
|
|
452
|
+
// Remove old callback if exists
|
|
453
|
+
if (existingCallback) {
|
|
454
|
+
// Clear the delegate via C# interop
|
|
455
|
+
element.generateVisualContent = null;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// Add new callback if provided
|
|
459
|
+
if (callback) {
|
|
460
|
+
// Assign callback to generateVisualContent property
|
|
461
|
+
// The C# interop layer handles the delegate conversion
|
|
462
|
+
element.generateVisualContent = callback;
|
|
463
|
+
instance.visualContentCallback = callback;
|
|
464
|
+
} else {
|
|
465
|
+
instance.visualContentCallback = undefined;
|
|
466
|
+
}
|
|
342
467
|
}
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// MARK: Text Merging
|
|
471
|
+
// Rebuild concatenated text from merged text children
|
|
472
|
+
function rebuildMergedText(instance: Instance) {
|
|
473
|
+
const children = instance.mergedTextChildren;
|
|
474
|
+
if (!children || children.length === 0) {
|
|
475
|
+
// No merged children - clear text (or keep prop-based text?)
|
|
476
|
+
// For now, set to empty - if user wants text, they should use children
|
|
477
|
+
instance.element.text = '';
|
|
478
|
+
return;
|
|
346
479
|
}
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
480
|
+
instance.element.text = children.map(c => c.element.text || '').join('');
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// Check if a child should be merged into parent's text property
|
|
484
|
+
function shouldMergeText(parentInstance: Instance, child: Instance): boolean {
|
|
485
|
+
// Don't merge if parent has mixed content (non-text children were added)
|
|
486
|
+
if (parentInstance.hasMixedContent) return false;
|
|
487
|
+
return TEXT_MERGE_TYPES.has(parentInstance.type) && child.type === 'text';
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// "Unmerge" all text children - add them as actual visual children
|
|
491
|
+
// Called when a non-text child is added, breaking the pure-text assumption
|
|
492
|
+
function unmergTextChildren(parentInstance: Instance) {
|
|
493
|
+
const children = parentInstance.mergedTextChildren;
|
|
494
|
+
if (!children || children.length === 0) return;
|
|
495
|
+
|
|
496
|
+
// Clear parent's merged text
|
|
497
|
+
parentInstance.element.text = '';
|
|
498
|
+
|
|
499
|
+
// Add each merged text child as an actual visual child
|
|
500
|
+
for (const child of children) {
|
|
501
|
+
child.mergedInto = undefined;
|
|
502
|
+
parentInstance.element.Add(child.element);
|
|
350
503
|
}
|
|
351
504
|
|
|
352
|
-
//
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
sv.verticalScrollerVisibility = CS.UnityEngine.UIElements.ScrollerVisibility[props.verticalScrollerVisibility as string];
|
|
363
|
-
}
|
|
364
|
-
if (props.elasticity !== undefined) {
|
|
365
|
-
sv.elasticity = props.elasticity as number;
|
|
366
|
-
}
|
|
367
|
-
if (props.elasticAnimationIntervalMs !== undefined) {
|
|
368
|
-
sv.elasticAnimationIntervalMs = props.elasticAnimationIntervalMs as number;
|
|
369
|
-
}
|
|
370
|
-
if (props.scrollDecelerationRate !== undefined) {
|
|
371
|
-
sv.scrollDecelerationRate = props.scrollDecelerationRate as number;
|
|
372
|
-
}
|
|
373
|
-
if (props.mouseWheelScrollSize !== undefined) {
|
|
374
|
-
sv.mouseWheelScrollSize = props.mouseWheelScrollSize as number;
|
|
375
|
-
}
|
|
376
|
-
if (props.horizontalPageSize !== undefined) {
|
|
377
|
-
sv.horizontalPageSize = props.horizontalPageSize as number;
|
|
378
|
-
}
|
|
379
|
-
if (props.verticalPageSize !== undefined) {
|
|
380
|
-
sv.verticalPageSize = props.verticalPageSize as number;
|
|
381
|
-
}
|
|
382
|
-
if (props.touchScrollBehavior !== undefined) {
|
|
383
|
-
sv.touchScrollBehavior = CS.UnityEngine.UIElements.TouchScrollBehavior[props.touchScrollBehavior as string];
|
|
384
|
-
}
|
|
385
|
-
if (props.nestedInteractionKind !== undefined) {
|
|
386
|
-
sv.nestedInteractionKind = CS.UnityEngine.UIElements.NestedInteractionKind[props.nestedInteractionKind as string];
|
|
387
|
-
}
|
|
505
|
+
// Clear the merged children list
|
|
506
|
+
parentInstance.mergedTextChildren = undefined;
|
|
507
|
+
parentInstance.hasMixedContent = true;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// Handle adding a non-text child to a text-merge parent
|
|
511
|
+
// This triggers unmerging of any previously merged text
|
|
512
|
+
function handleNonTextChild(parentInstance: Instance) {
|
|
513
|
+
if (TEXT_MERGE_TYPES.has(parentInstance.type) && !parentInstance.hasMixedContent) {
|
|
514
|
+
unmergTextChildren(parentInstance);
|
|
388
515
|
}
|
|
516
|
+
}
|
|
389
517
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
518
|
+
// Append a text child to a text-merging parent
|
|
519
|
+
function appendMergedTextChild(parentInstance: Instance, child: Instance) {
|
|
520
|
+
if (!parentInstance.mergedTextChildren) {
|
|
521
|
+
parentInstance.mergedTextChildren = [];
|
|
522
|
+
}
|
|
523
|
+
parentInstance.mergedTextChildren.push(child);
|
|
524
|
+
child.mergedInto = parentInstance;
|
|
525
|
+
rebuildMergedText(parentInstance);
|
|
526
|
+
}
|
|
393
527
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
lv.destroyItem = props.destroyItem as (element: CSObject) => void;
|
|
409
|
-
}
|
|
528
|
+
// Insert a text child before another in a text-merging parent
|
|
529
|
+
function insertMergedTextChild(parentInstance: Instance, child: Instance, beforeChild: Instance) {
|
|
530
|
+
if (!parentInstance.mergedTextChildren) {
|
|
531
|
+
parentInstance.mergedTextChildren = [];
|
|
532
|
+
}
|
|
533
|
+
const index = parentInstance.mergedTextChildren.indexOf(beforeChild);
|
|
534
|
+
if (index >= 0) {
|
|
535
|
+
parentInstance.mergedTextChildren.splice(index, 0, child);
|
|
536
|
+
} else {
|
|
537
|
+
parentInstance.mergedTextChildren.push(child);
|
|
538
|
+
}
|
|
539
|
+
child.mergedInto = parentInstance;
|
|
540
|
+
rebuildMergedText(parentInstance);
|
|
541
|
+
}
|
|
410
542
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
543
|
+
// Remove a text child from a text-merging parent
|
|
544
|
+
function removeMergedTextChild(parentInstance: Instance, child: Instance) {
|
|
545
|
+
const children = parentInstance.mergedTextChildren;
|
|
546
|
+
if (children) {
|
|
547
|
+
const index = children.indexOf(child);
|
|
548
|
+
if (index >= 0) {
|
|
549
|
+
children.splice(index, 1);
|
|
417
550
|
}
|
|
551
|
+
}
|
|
552
|
+
child.mergedInto = undefined;
|
|
553
|
+
rebuildMergedText(parentInstance);
|
|
554
|
+
}
|
|
418
555
|
|
|
419
|
-
|
|
420
|
-
if (props.selectionType !== undefined) {
|
|
421
|
-
lv.selectionType = CS.UnityEngine.UIElements.SelectionType[props.selectionType as string];
|
|
422
|
-
}
|
|
423
|
-
if (props.selectedIndex !== undefined) {
|
|
424
|
-
lv.selectedIndex = props.selectedIndex as number;
|
|
425
|
-
}
|
|
426
|
-
if (props.selectedIndices !== undefined) {
|
|
427
|
-
lv.selectedIndices = props.selectedIndices as number[];
|
|
428
|
-
}
|
|
556
|
+
// MARK: Component-specific prop handlers
|
|
429
557
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
}
|
|
558
|
+
// Apply common props (text, value, label)
|
|
559
|
+
function applyCommonProps(element: CSObject, props: Record<string, unknown>) {
|
|
560
|
+
if (props.text !== undefined) (element as { text: string }).text = props.text as string;
|
|
561
|
+
if (props.value !== undefined) (element as { value: unknown }).value = props.value;
|
|
562
|
+
if (props.label !== undefined) (element as { label: string }).label = props.label as string;
|
|
563
|
+
}
|
|
437
564
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
}
|
|
445
|
-
if (props.showAddRemoveFooter !== undefined) {
|
|
446
|
-
lv.showAddRemoveFooter = props.showAddRemoveFooter as boolean;
|
|
447
|
-
}
|
|
565
|
+
// Helper to set enum prop if defined
|
|
566
|
+
function setEnumProp<T>(target: T, key: keyof T, props: Record<string, unknown>, propKey: string, enumType: CSEnum) {
|
|
567
|
+
if (props[propKey] !== undefined) {
|
|
568
|
+
(target as Record<string, unknown>)[key as string] = enumType[props[propKey] as string];
|
|
569
|
+
}
|
|
570
|
+
}
|
|
448
571
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
572
|
+
// Helper to set value prop if defined
|
|
573
|
+
function setValueProp<T>(target: T, key: keyof T, props: Record<string, unknown>, propKey: string) {
|
|
574
|
+
if (props[propKey] !== undefined) {
|
|
575
|
+
(target as Record<string, unknown>)[key as string] = props[propKey];
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
// Apply TextField-specific properties
|
|
580
|
+
function applyTextFieldProps(element: CSObject, props: Record<string, unknown>) {
|
|
581
|
+
// Map readOnly prop to isReadOnly property
|
|
582
|
+
if (props.readOnly !== undefined) {
|
|
583
|
+
(element as { isReadOnly: boolean }).isReadOnly = props.readOnly as boolean;
|
|
584
|
+
}
|
|
585
|
+
if (props.multiline !== undefined) {
|
|
586
|
+
(element as { multiline: boolean }).multiline = props.multiline as boolean;
|
|
587
|
+
}
|
|
588
|
+
if (props.maxLength !== undefined) {
|
|
589
|
+
(element as { maxLength: number }).maxLength = props.maxLength as number;
|
|
590
|
+
}
|
|
591
|
+
if (props.isPasswordField !== undefined) {
|
|
592
|
+
(element as { isPasswordField: boolean }).isPasswordField = props.isPasswordField as boolean;
|
|
593
|
+
}
|
|
594
|
+
if (props.maskChar !== undefined) {
|
|
595
|
+
(element as { maskChar: string }).maskChar = (props.maskChar as string).charAt(0);
|
|
596
|
+
}
|
|
597
|
+
if (props.isDelayed !== undefined) {
|
|
598
|
+
(element as { isDelayed: boolean }).isDelayed = props.isDelayed as boolean;
|
|
599
|
+
}
|
|
600
|
+
if (props.selectAllOnFocus !== undefined) {
|
|
601
|
+
(element as { selectAllOnFocus: boolean }).selectAllOnFocus = props.selectAllOnFocus as boolean;
|
|
602
|
+
}
|
|
603
|
+
if (props.selectAllOnMouseUp !== undefined) {
|
|
604
|
+
(element as { selectAllOnMouseUp: boolean }).selectAllOnMouseUp = props.selectAllOnMouseUp as boolean;
|
|
605
|
+
}
|
|
606
|
+
if (props.hideMobileInput !== undefined) {
|
|
607
|
+
(element as { hideMobileInput: boolean }).hideMobileInput = props.hideMobileInput as boolean;
|
|
608
|
+
}
|
|
609
|
+
if (props.autoCorrection !== undefined) {
|
|
610
|
+
(element as { autoCorrection: boolean }).autoCorrection = props.autoCorrection as boolean;
|
|
611
|
+
}
|
|
612
|
+
// Note: placeholder is handled differently in Unity - it's set via the textEdition interface
|
|
613
|
+
// For now we skip it as it requires more complex handling
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
// Apply Slider-specific properties
|
|
617
|
+
function applySliderProps(element: CSObject, props: Record<string, unknown>) {
|
|
618
|
+
if (props.lowValue !== undefined) {
|
|
619
|
+
(element as { lowValue: number }).lowValue = props.lowValue as number;
|
|
620
|
+
}
|
|
621
|
+
if (props.highValue !== undefined) {
|
|
622
|
+
(element as { highValue: number }).highValue = props.highValue as number;
|
|
623
|
+
}
|
|
624
|
+
if (props.showInputField !== undefined) {
|
|
625
|
+
(element as { showInputField: boolean }).showInputField = props.showInputField as boolean;
|
|
626
|
+
}
|
|
627
|
+
if (props.inverted !== undefined) {
|
|
628
|
+
(element as { inverted: boolean }).inverted = props.inverted as boolean;
|
|
629
|
+
}
|
|
630
|
+
if (props.pageSize !== undefined) {
|
|
631
|
+
(element as { pageSize: number }).pageSize = props.pageSize as number;
|
|
632
|
+
}
|
|
633
|
+
if (props.fill !== undefined) {
|
|
634
|
+
(element as { fill: boolean }).fill = props.fill as boolean;
|
|
635
|
+
}
|
|
636
|
+
if (props.direction !== undefined) {
|
|
637
|
+
const UIE = CS.UnityEngine.UIElements;
|
|
638
|
+
(element as { direction: unknown }).direction = UIE.SliderDirection[props.direction as string];
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
// Apply Toggle-specific properties
|
|
643
|
+
function applyToggleProps(element: CSObject, props: Record<string, unknown>) {
|
|
644
|
+
if (props.text !== undefined) {
|
|
645
|
+
(element as { text: string }).text = props.text as string;
|
|
646
|
+
}
|
|
647
|
+
if (props.toggleOnLabelClick !== undefined) {
|
|
648
|
+
(element as { toggleOnLabelClick: boolean }).toggleOnLabelClick = props.toggleOnLabelClick as boolean;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
// Apply Image-specific properties
|
|
653
|
+
function applyImageProps(element: CSObject, props: Record<string, unknown>) {
|
|
654
|
+
if (props.image !== undefined) {
|
|
655
|
+
(element as { image: unknown }).image = props.image;
|
|
656
|
+
}
|
|
657
|
+
if (props.sprite !== undefined) {
|
|
658
|
+
(element as { sprite: unknown }).sprite = props.sprite;
|
|
659
|
+
}
|
|
660
|
+
if (props.vectorImage !== undefined) {
|
|
661
|
+
(element as { vectorImage: unknown }).vectorImage = props.vectorImage;
|
|
662
|
+
}
|
|
663
|
+
if (props.scaleMode !== undefined) {
|
|
664
|
+
const scaleMode = CS.UnityEngine.ScaleMode[props.scaleMode as string];
|
|
665
|
+
(element as { scaleMode: unknown }).scaleMode = scaleMode;
|
|
666
|
+
}
|
|
667
|
+
if (props.tintColor !== undefined) {
|
|
668
|
+
// Parse color string to Unity Color
|
|
669
|
+
const color = parseColor(props.tintColor as string);
|
|
670
|
+
if (color) {
|
|
671
|
+
(element as { tintColor: unknown }).tintColor = color;
|
|
455
672
|
}
|
|
456
673
|
}
|
|
674
|
+
if (props.sourceRect !== undefined) {
|
|
675
|
+
const rect = props.sourceRect as { x: number; y: number; width: number; height: number };
|
|
676
|
+
(element as { sourceRect: unknown }).sourceRect = new CS.UnityEngine.Rect(rect.x, rect.y, rect.width, rect.height);
|
|
677
|
+
}
|
|
678
|
+
if (props.uv !== undefined) {
|
|
679
|
+
const rect = props.uv as { x: number; y: number; width: number; height: number };
|
|
680
|
+
(element as { uv: unknown }).uv = new CS.UnityEngine.Rect(rect.x, rect.y, rect.width, rect.height);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
// Apply ScrollView-specific properties
|
|
685
|
+
function applyScrollViewProps(element: CSScrollView, props: Record<string, unknown>) {
|
|
686
|
+
const UIE = CS.UnityEngine.UIElements;
|
|
687
|
+
setEnumProp(element, 'mode', props, 'mode', UIE.ScrollViewMode);
|
|
688
|
+
setEnumProp(element, 'horizontalScrollerVisibility', props, 'horizontalScrollerVisibility', UIE.ScrollerVisibility);
|
|
689
|
+
setEnumProp(element, 'verticalScrollerVisibility', props, 'verticalScrollerVisibility', UIE.ScrollerVisibility);
|
|
690
|
+
setEnumProp(element, 'touchScrollBehavior', props, 'touchScrollBehavior', UIE.TouchScrollBehavior);
|
|
691
|
+
setEnumProp(element, 'nestedInteractionKind', props, 'nestedInteractionKind', UIE.NestedInteractionKind);
|
|
692
|
+
setValueProp(element, 'elasticity', props, 'elasticity');
|
|
693
|
+
setValueProp(element, 'elasticAnimationIntervalMs', props, 'elasticAnimationIntervalMs');
|
|
694
|
+
setValueProp(element, 'scrollDecelerationRate', props, 'scrollDecelerationRate');
|
|
695
|
+
setValueProp(element, 'mouseWheelScrollSize', props, 'mouseWheelScrollSize');
|
|
696
|
+
setValueProp(element, 'horizontalPageSize', props, 'horizontalPageSize');
|
|
697
|
+
setValueProp(element, 'verticalPageSize', props, 'verticalPageSize');
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
// Apply ListView-specific properties
|
|
701
|
+
function applyListViewProps(element: CSListView, props: Record<string, unknown>) {
|
|
702
|
+
const UIE = CS.UnityEngine.UIElements;
|
|
703
|
+
|
|
704
|
+
// Data binding callbacks
|
|
705
|
+
setValueProp(element, 'itemsSource', props, 'itemsSource');
|
|
706
|
+
setValueProp(element, 'makeItem', props, 'makeItem');
|
|
707
|
+
setValueProp(element, 'bindItem', props, 'bindItem');
|
|
708
|
+
setValueProp(element, 'unbindItem', props, 'unbindItem');
|
|
709
|
+
setValueProp(element, 'destroyItem', props, 'destroyItem');
|
|
710
|
+
|
|
711
|
+
// Virtualization
|
|
712
|
+
setValueProp(element, 'fixedItemHeight', props, 'fixedItemHeight');
|
|
713
|
+
setEnumProp(element, 'virtualizationMethod', props, 'virtualizationMethod', UIE.CollectionVirtualizationMethod);
|
|
714
|
+
|
|
715
|
+
// Selection
|
|
716
|
+
setEnumProp(element, 'selectionType', props, 'selectionType', UIE.SelectionType);
|
|
717
|
+
setValueProp(element, 'selectedIndex', props, 'selectedIndex');
|
|
718
|
+
setValueProp(element, 'selectedIndices', props, 'selectedIndices');
|
|
719
|
+
|
|
720
|
+
// Reordering
|
|
721
|
+
setValueProp(element, 'reorderable', props, 'reorderable');
|
|
722
|
+
setEnumProp(element, 'reorderMode', props, 'reorderMode', UIE.ListViewReorderMode);
|
|
723
|
+
|
|
724
|
+
// Header/Footer
|
|
725
|
+
setValueProp(element, 'showFoldoutHeader', props, 'showFoldoutHeader');
|
|
726
|
+
setValueProp(element, 'headerTitle', props, 'headerTitle');
|
|
727
|
+
setValueProp(element, 'showAddRemoveFooter', props, 'showAddRemoveFooter');
|
|
728
|
+
|
|
729
|
+
// Appearance
|
|
730
|
+
setValueProp(element, 'showBorder', props, 'showBorder');
|
|
731
|
+
setEnumProp(element, 'showAlternatingRowBackgrounds', props, 'showAlternatingRowBackgrounds', UIE.AlternatingRowBackground);
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
// Apply component-specific props based on element type
|
|
735
|
+
function applyComponentProps(element: CSObject, type: string, props: Record<string, unknown>) {
|
|
736
|
+
// For Slider, apply range props (lowValue/highValue) BEFORE value
|
|
737
|
+
// Unity's Slider clamps value to [lowValue, highValue], so range must be set first
|
|
738
|
+
if (type === 'ojs-slider') {
|
|
739
|
+
applySliderProps(element, props);
|
|
740
|
+
applyCommonProps(element, props);
|
|
741
|
+
return;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
applyCommonProps(element, props);
|
|
745
|
+
|
|
746
|
+
if (type === 'ojs-textfield') {
|
|
747
|
+
applyTextFieldProps(element, props);
|
|
748
|
+
} else if (type === 'ojs-toggle') {
|
|
749
|
+
applyToggleProps(element, props);
|
|
750
|
+
} else if (type === 'ojs-image') {
|
|
751
|
+
applyImageProps(element, props);
|
|
752
|
+
} else if (type === 'ojs-scrollview') {
|
|
753
|
+
applyScrollViewProps(element as CSScrollView, props);
|
|
754
|
+
} else if (type === 'ojs-listview') {
|
|
755
|
+
applyListViewProps(element as CSListView, props);
|
|
756
|
+
}
|
|
457
757
|
}
|
|
458
758
|
|
|
459
759
|
// Create an instance
|
|
@@ -475,6 +775,7 @@ function createInstance(type: string, props: BaseProps): Instance {
|
|
|
475
775
|
|
|
476
776
|
applyClassName(element, props.className);
|
|
477
777
|
applyEvents(instance, props);
|
|
778
|
+
applyVisualContentCallback(instance, props);
|
|
478
779
|
applyComponentProps(element, type, props as Record<string, unknown>);
|
|
479
780
|
|
|
480
781
|
return instance;
|
|
@@ -499,14 +800,20 @@ function updateInstance(instance: Instance, oldProps: BaseProps, newProps: BaseP
|
|
|
499
800
|
// Update events
|
|
500
801
|
applyEvents(instance, newProps);
|
|
501
802
|
|
|
803
|
+
// Update vector drawing callback
|
|
804
|
+
applyVisualContentCallback(instance, newProps);
|
|
805
|
+
|
|
502
806
|
// Update component-specific props
|
|
503
807
|
applyComponentProps(element, instance.type, newProps as Record<string, unknown>);
|
|
504
808
|
|
|
505
809
|
instance.props = newProps;
|
|
506
810
|
}
|
|
507
811
|
|
|
508
|
-
//
|
|
509
|
-
|
|
812
|
+
// NOTE: We use a type assertion because @types/react-reconciler (0.28.x) is outdated
|
|
813
|
+
// and doesn't match react-reconciler 0.31.x (React 19). The HostConfig interface
|
|
814
|
+
// has changed significantly - notably commitUpdate no longer receives updatePayload.
|
|
815
|
+
// Once @types/react-reconciler is updated for React 19, we can use proper typing.
|
|
816
|
+
type OurHostConfig = HostConfig<
|
|
510
817
|
string, // Type
|
|
511
818
|
BaseProps, // Props
|
|
512
819
|
Container, // Container
|
|
@@ -514,13 +821,16 @@ export const hostConfig: HostConfig<
|
|
|
514
821
|
TextInstance, // TextInstance
|
|
515
822
|
never, // SuspenseInstance
|
|
516
823
|
never, // HydratableInstance
|
|
517
|
-
|
|
824
|
+
CSObject, // PublicInstance - refs point to the actual UI Toolkit element
|
|
518
825
|
{}, // HostContext
|
|
519
826
|
true, // UpdatePayload (true = needs update)
|
|
520
827
|
ChildSet, // ChildSet
|
|
521
828
|
number, // TimeoutHandle
|
|
522
829
|
number // NoTimeout
|
|
523
|
-
|
|
830
|
+
>;
|
|
831
|
+
|
|
832
|
+
// The host config for react-reconciler
|
|
833
|
+
export const hostConfig = {
|
|
524
834
|
supportsMutation: true,
|
|
525
835
|
supportsPersistence: false,
|
|
526
836
|
supportsHydration: false,
|
|
@@ -528,13 +838,16 @@ export const hostConfig: HostConfig<
|
|
|
528
838
|
isPrimaryRenderer: true,
|
|
529
839
|
noTimeout: -1,
|
|
530
840
|
|
|
531
|
-
createInstance(type, props) {
|
|
841
|
+
createInstance(type: string, props: BaseProps) {
|
|
532
842
|
return createInstance(type, props);
|
|
533
843
|
},
|
|
534
844
|
|
|
535
|
-
createTextInstance(text) {
|
|
536
|
-
// Create a
|
|
537
|
-
|
|
845
|
+
createTextInstance(text: string) {
|
|
846
|
+
// Create a TextElement for implicit text content
|
|
847
|
+
// Using TextElement (not Label) for semantic clarity:
|
|
848
|
+
// - TextElement = raw text content in JSX
|
|
849
|
+
// - Label = explicit <Label> component
|
|
850
|
+
const element = new CS.UnityEngine.UIElements.TextElement();
|
|
538
851
|
element.text = text;
|
|
539
852
|
return {
|
|
540
853
|
element,
|
|
@@ -545,28 +858,46 @@ export const hostConfig: HostConfig<
|
|
|
545
858
|
};
|
|
546
859
|
},
|
|
547
860
|
|
|
548
|
-
appendInitialChild(parentInstance, child) {
|
|
549
|
-
parentInstance
|
|
861
|
+
appendInitialChild(parentInstance: Instance, child: Instance) {
|
|
862
|
+
if (shouldMergeText(parentInstance, child)) {
|
|
863
|
+
appendMergedTextChild(parentInstance, child);
|
|
864
|
+
} else {
|
|
865
|
+
// Non-text child - unmerge any previously merged text first
|
|
866
|
+
handleNonTextChild(parentInstance);
|
|
867
|
+
parentInstance.element.Add(child.element);
|
|
868
|
+
}
|
|
550
869
|
},
|
|
551
870
|
|
|
552
|
-
appendChild(parentInstance, child) {
|
|
553
|
-
parentInstance
|
|
871
|
+
appendChild(parentInstance: Instance, child: Instance) {
|
|
872
|
+
if (shouldMergeText(parentInstance, child)) {
|
|
873
|
+
appendMergedTextChild(parentInstance, child);
|
|
874
|
+
} else {
|
|
875
|
+
// Non-text child - unmerge any previously merged text first
|
|
876
|
+
handleNonTextChild(parentInstance);
|
|
877
|
+
parentInstance.element.Add(child.element);
|
|
878
|
+
}
|
|
554
879
|
},
|
|
555
880
|
|
|
556
|
-
appendChildToContainer(container, child) {
|
|
881
|
+
appendChildToContainer(container: Container, child: Instance) {
|
|
557
882
|
container.Add(child.element);
|
|
558
883
|
},
|
|
559
884
|
|
|
560
|
-
insertBefore(parentInstance, child, beforeChild) {
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
parentInstance.element.Insert(index, child.element);
|
|
885
|
+
insertBefore(parentInstance: Instance, child: Instance, beforeChild: Instance) {
|
|
886
|
+
if (shouldMergeText(parentInstance, child)) {
|
|
887
|
+
insertMergedTextChild(parentInstance, child, beforeChild);
|
|
564
888
|
} else {
|
|
565
|
-
|
|
889
|
+
// Non-text child - unmerge any previously merged text first
|
|
890
|
+
handleNonTextChild(parentInstance);
|
|
891
|
+
const index = parentInstance.element.IndexOf(beforeChild.element);
|
|
892
|
+
if (index >= 0) {
|
|
893
|
+
parentInstance.element.Insert(index, child.element);
|
|
894
|
+
} else {
|
|
895
|
+
parentInstance.element.Add(child.element);
|
|
896
|
+
}
|
|
566
897
|
}
|
|
567
898
|
},
|
|
568
899
|
|
|
569
|
-
insertInContainerBefore(container, child, beforeChild) {
|
|
900
|
+
insertInContainerBefore(container: Container, child: Instance, beforeChild: Instance) {
|
|
570
901
|
const index = container.IndexOf(beforeChild.element);
|
|
571
902
|
if (index >= 0) {
|
|
572
903
|
container.Insert(index, child.element);
|
|
@@ -575,37 +906,47 @@ export const hostConfig: HostConfig<
|
|
|
575
906
|
}
|
|
576
907
|
},
|
|
577
908
|
|
|
578
|
-
removeChild(parentInstance, child) {
|
|
579
|
-
|
|
580
|
-
|
|
909
|
+
removeChild(parentInstance: Instance, child: Instance) {
|
|
910
|
+
if (child.mergedInto === parentInstance) {
|
|
911
|
+
// Child was merged into parent's text - remove from merged children
|
|
912
|
+
removeMergedTextChild(parentInstance, child);
|
|
913
|
+
} else {
|
|
914
|
+
__eventAPI.removeAllEventListeners(child.element);
|
|
915
|
+
parentInstance.element.Remove(child.element);
|
|
916
|
+
}
|
|
581
917
|
},
|
|
582
918
|
|
|
583
|
-
removeChildFromContainer(container, child) {
|
|
919
|
+
removeChildFromContainer(container: Container, child: Instance) {
|
|
584
920
|
__eventAPI.removeAllEventListeners(child.element);
|
|
585
921
|
container.Remove(child.element);
|
|
586
922
|
},
|
|
587
923
|
|
|
588
|
-
prepareUpdate(_instance, _type, oldProps, newProps) {
|
|
924
|
+
prepareUpdate(_instance: Instance, _type: string, oldProps: BaseProps, newProps: BaseProps) {
|
|
589
925
|
// Return true if we need to update, null if no update needed
|
|
590
926
|
return oldProps !== newProps ? true : null;
|
|
591
927
|
},
|
|
592
928
|
|
|
593
929
|
// React 19 changed the signature: (instance, type, oldProps, newProps, fiber)
|
|
594
930
|
// The updatePayload parameter was removed!
|
|
595
|
-
commitUpdate(instance, _type, oldProps, newProps, _fiber) {
|
|
931
|
+
commitUpdate(instance: Instance, _type: string, oldProps: BaseProps, newProps: BaseProps, _fiber: unknown) {
|
|
596
932
|
updateInstance(instance, oldProps, newProps);
|
|
597
933
|
},
|
|
598
934
|
|
|
599
|
-
commitTextUpdate(textInstance, _oldText, newText) {
|
|
935
|
+
commitTextUpdate(textInstance: Instance, _oldText: string, newText: string) {
|
|
600
936
|
textInstance.element.text = newText;
|
|
937
|
+
// If this text is merged into a parent, rebuild the parent's concatenated text
|
|
938
|
+
if (textInstance.mergedInto) {
|
|
939
|
+
rebuildMergedText(textInstance.mergedInto);
|
|
940
|
+
}
|
|
601
941
|
},
|
|
602
942
|
|
|
603
943
|
finalizeInitialChildren() {
|
|
604
944
|
return false;
|
|
605
945
|
},
|
|
606
946
|
|
|
607
|
-
getPublicInstance(instance) {
|
|
608
|
-
|
|
947
|
+
getPublicInstance(instance: Instance) {
|
|
948
|
+
// Return the actual UI Toolkit element so refs point to it
|
|
949
|
+
return instance.element;
|
|
609
950
|
},
|
|
610
951
|
|
|
611
952
|
prepareForCommit() {
|
|
@@ -624,7 +965,7 @@ export const hostConfig: HostConfig<
|
|
|
624
965
|
return {};
|
|
625
966
|
},
|
|
626
967
|
|
|
627
|
-
getChildHostContext(parentHostContext) {
|
|
968
|
+
getChildHostContext(parentHostContext: {}) {
|
|
628
969
|
return parentHostContext;
|
|
629
970
|
},
|
|
630
971
|
|
|
@@ -632,7 +973,7 @@ export const hostConfig: HostConfig<
|
|
|
632
973
|
return false;
|
|
633
974
|
},
|
|
634
975
|
|
|
635
|
-
clearContainer(container) {
|
|
976
|
+
clearContainer(container: Container) {
|
|
636
977
|
container.Clear();
|
|
637
978
|
},
|
|
638
979
|
|
|
@@ -704,16 +1045,16 @@ export const hostConfig: HostConfig<
|
|
|
704
1045
|
|
|
705
1046
|
// Visibility support
|
|
706
1047
|
hideInstance(instance: Instance) {
|
|
707
|
-
instance.element.style.display =
|
|
1048
|
+
instance.element.style.display = CS.UnityEngine.UIElements.DisplayStyle.None;
|
|
708
1049
|
},
|
|
709
1050
|
hideTextInstance(textInstance: TextInstance) {
|
|
710
|
-
textInstance.element.style.display =
|
|
1051
|
+
textInstance.element.style.display = CS.UnityEngine.UIElements.DisplayStyle.None;
|
|
711
1052
|
},
|
|
712
1053
|
unhideInstance(instance: Instance, _props: BaseProps) {
|
|
713
|
-
instance.element.style.display =
|
|
1054
|
+
instance.element.style.display = CS.UnityEngine.UIElements.DisplayStyle.Flex;
|
|
714
1055
|
},
|
|
715
1056
|
unhideTextInstance(textInstance: TextInstance, _text: string) {
|
|
716
|
-
textInstance.element.style.display =
|
|
1057
|
+
textInstance.element.style.display = CS.UnityEngine.UIElements.DisplayStyle.Flex;
|
|
717
1058
|
},
|
|
718
1059
|
|
|
719
1060
|
// Text content
|
|
@@ -746,4 +1087,4 @@ export const hostConfig: HostConfig<
|
|
|
746
1087
|
bindToConsole(methodName: string, args: unknown[], _badgeName: string) {
|
|
747
1088
|
return (console as Record<string, Function>)[methodName]?.bind(console, ...args);
|
|
748
1089
|
},
|
|
749
|
-
};
|
|
1090
|
+
} as unknown as OurHostConfig;
|