onejs-react 0.1.5 → 0.1.7
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/package.json +2 -2
- package/src/host-config.ts +35 -5
- package/src/style-parser.ts +38 -0
- package/src/types.ts +64 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "onejs-react",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "React 19 renderer for OneJS (Unity UI Toolkit)",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"types": "src/index.ts",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
],
|
|
18
18
|
"repository": {
|
|
19
19
|
"type": "git",
|
|
20
|
-
"url": "https://github.com/Singtaa/onejs-react"
|
|
20
|
+
"url": "git+https://github.com/Singtaa/onejs-react.git"
|
|
21
21
|
},
|
|
22
22
|
"author": "Singtaa",
|
|
23
23
|
"scripts": {
|
package/src/host-config.ts
CHANGED
|
@@ -12,6 +12,13 @@ declare function clearTimeout(id: number): void;
|
|
|
12
12
|
|
|
13
13
|
declare const console: { log: (...args: unknown[]) => void; error: (...args: unknown[]) => void };
|
|
14
14
|
|
|
15
|
+
// Native delegate callback helpers (from QuickJSBootstrap __csHelpers)
|
|
16
|
+
declare const __csHelpers: {
|
|
17
|
+
createDelegateCallback(fn: Function): number;
|
|
18
|
+
freeDelegateCallback(handle: number): void;
|
|
19
|
+
[key: string]: unknown;
|
|
20
|
+
};
|
|
21
|
+
|
|
15
22
|
// Priority constants from react-reconciler/constants
|
|
16
23
|
// These match React's internal lane priorities
|
|
17
24
|
const DiscreteEventPriority = 2;
|
|
@@ -149,6 +156,8 @@ export interface Instance {
|
|
|
149
156
|
hasMixedContent?: boolean;
|
|
150
157
|
// For vector drawing: track the current generateVisualContent callback
|
|
151
158
|
visualContentCallback?: GenerateVisualContentCallback;
|
|
159
|
+
// Native callback handle for the above (used to free slot on replacement)
|
|
160
|
+
visualContentCallbackHandle?: number;
|
|
152
161
|
}
|
|
153
162
|
|
|
154
163
|
export type TextInstance = Instance; // For Label elements with text content
|
|
@@ -435,6 +444,15 @@ function untrackParent(child: CSObject) {
|
|
|
435
444
|
}
|
|
436
445
|
}
|
|
437
446
|
|
|
447
|
+
// Free native callback handles tracked on an instance (prevents callback table leak)
|
|
448
|
+
function cleanupCallbackHandles(instance: Instance) {
|
|
449
|
+
if (instance.visualContentCallbackHandle !== undefined) {
|
|
450
|
+
__csHelpers.freeDelegateCallback(instance.visualContentCallbackHandle);
|
|
451
|
+
instance.visualContentCallbackHandle = undefined;
|
|
452
|
+
instance.visualContentCallback = undefined;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
438
456
|
// Apply event handlers
|
|
439
457
|
function applyEvents(instance: Instance, props: BaseProps) {
|
|
440
458
|
for (const [propName, eventType] of Object.entries(EVENT_PROPS)) {
|
|
@@ -468,17 +486,27 @@ function applyVisualContentCallback(instance: Instance, props: BaseProps) {
|
|
|
468
486
|
if (callback !== existingCallback) {
|
|
469
487
|
const element = instance.element as unknown as { generateVisualContent: GenerateVisualContentCallback | null };
|
|
470
488
|
|
|
471
|
-
//
|
|
489
|
+
// Free old native callback handle to prevent callback table leak
|
|
472
490
|
if (existingCallback) {
|
|
473
|
-
// Clear the delegate via C# interop
|
|
474
491
|
element.generateVisualContent = null;
|
|
492
|
+
if (instance.visualContentCallbackHandle !== undefined) {
|
|
493
|
+
__csHelpers.freeDelegateCallback(instance.visualContentCallbackHandle);
|
|
494
|
+
}
|
|
495
|
+
instance.visualContentCallbackHandle = undefined;
|
|
475
496
|
}
|
|
476
497
|
|
|
477
498
|
// Add new callback if provided
|
|
478
499
|
if (callback) {
|
|
479
|
-
//
|
|
480
|
-
|
|
481
|
-
|
|
500
|
+
// Register with argument wrapping and track the handle for cleanup
|
|
501
|
+
const handle = __csHelpers.createDelegateCallback(callback);
|
|
502
|
+
if (handle >= 0) {
|
|
503
|
+
instance.visualContentCallbackHandle = handle;
|
|
504
|
+
// Pass pre-resolved handle directly — bypasses __resolveValue's auto-registration
|
|
505
|
+
element.generateVisualContent = { __csCallbackHandle: handle } as any;
|
|
506
|
+
} else {
|
|
507
|
+
// WebGL path: no native callback table
|
|
508
|
+
element.generateVisualContent = callback;
|
|
509
|
+
}
|
|
482
510
|
instance.visualContentCallback = callback;
|
|
483
511
|
} else {
|
|
484
512
|
instance.visualContentCallback = undefined;
|
|
@@ -947,6 +975,7 @@ export const hostConfig = {
|
|
|
947
975
|
removeMergedTextChild(parentInstance, child);
|
|
948
976
|
} else {
|
|
949
977
|
__eventAPI.removeAllEventListeners(child.element);
|
|
978
|
+
cleanupCallbackHandles(child);
|
|
950
979
|
parentInstance.element.Remove(child.element);
|
|
951
980
|
}
|
|
952
981
|
untrackParent(child.element);
|
|
@@ -954,6 +983,7 @@ export const hostConfig = {
|
|
|
954
983
|
|
|
955
984
|
removeChildFromContainer(container: Container, child: Instance) {
|
|
956
985
|
__eventAPI.removeAllEventListeners(child.element);
|
|
986
|
+
cleanupCallbackHandles(child);
|
|
957
987
|
container.Remove(child.element);
|
|
958
988
|
untrackParent(child.element);
|
|
959
989
|
},
|
package/src/style-parser.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
declare const CS: {
|
|
10
10
|
UnityEngine: {
|
|
11
11
|
Color: new (r: number, g: number, b: number, a: number) => CSColor;
|
|
12
|
+
FontStyle: Record<string, number>;
|
|
12
13
|
UIElements: {
|
|
13
14
|
Length: new (value: number, unit?: number) => CSLength;
|
|
14
15
|
LengthUnit: { Pixel: number; Percent: number };
|
|
@@ -24,6 +25,9 @@ declare const CS: {
|
|
|
24
25
|
Visibility: Record<string, number>;
|
|
25
26
|
WhiteSpace: Record<string, number>;
|
|
26
27
|
TextAnchor: Record<string, number>;
|
|
28
|
+
TextOverflow: Record<string, number>;
|
|
29
|
+
TextOverflowPosition: Record<string, number>;
|
|
30
|
+
OverflowClipBox: Record<string, number>;
|
|
27
31
|
};
|
|
28
32
|
};
|
|
29
33
|
};
|
|
@@ -78,17 +82,20 @@ const LENGTH_PROPERTIES = new Set([
|
|
|
78
82
|
"borderWidth", "borderTopWidth", "borderRightWidth", "borderBottomWidth", "borderLeftWidth",
|
|
79
83
|
"borderRadius", "borderTopLeftRadius", "borderTopRightRadius", "borderBottomLeftRadius", "borderBottomRightRadius",
|
|
80
84
|
"fontSize",
|
|
85
|
+
"letterSpacing", "wordSpacing", "unityTextOutlineWidth", "unityParagraphSpacing",
|
|
81
86
|
])
|
|
82
87
|
|
|
83
88
|
// Style properties that expect color values
|
|
84
89
|
const COLOR_PROPERTIES = new Set([
|
|
85
90
|
"color", "backgroundColor",
|
|
86
91
|
"borderColor", "borderTopColor", "borderRightColor", "borderBottomColor", "borderLeftColor",
|
|
92
|
+
"unityTextOutlineColor", "unityBackgroundImageTintColor",
|
|
87
93
|
])
|
|
88
94
|
|
|
89
95
|
// Style properties that are plain numbers (no Length wrapper needed)
|
|
90
96
|
const NUMBER_PROPERTIES = new Set([
|
|
91
97
|
"flexGrow", "flexShrink", "opacity",
|
|
98
|
+
"unitySliceTop", "unitySliceRight", "unitySliceBottom", "unitySliceLeft", "unitySliceScale",
|
|
92
99
|
])
|
|
93
100
|
|
|
94
101
|
// Enum property mappings: React style value -> Unity enum value
|
|
@@ -186,6 +193,37 @@ const ENUM_MAPPINGS: Record<string, { enum: () => Record<string, number>, values
|
|
|
186
193
|
"nowrap": "NoWrap",
|
|
187
194
|
}
|
|
188
195
|
},
|
|
196
|
+
unityFontStyleAndWeight: {
|
|
197
|
+
enum: () => CS.UnityEngine.FontStyle,
|
|
198
|
+
values: {
|
|
199
|
+
"normal": "Normal",
|
|
200
|
+
"bold": "Bold",
|
|
201
|
+
"italic": "Italic",
|
|
202
|
+
"bold-and-italic": "BoldAndItalic",
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
textOverflow: {
|
|
206
|
+
enum: () => CS.UnityEngine.UIElements.TextOverflow,
|
|
207
|
+
values: {
|
|
208
|
+
"clip": "Clip",
|
|
209
|
+
"ellipsis": "Ellipsis",
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
unityTextOverflowPosition: {
|
|
213
|
+
enum: () => CS.UnityEngine.UIElements.TextOverflowPosition,
|
|
214
|
+
values: {
|
|
215
|
+
"end": "End",
|
|
216
|
+
"start": "Start",
|
|
217
|
+
"middle": "Middle",
|
|
218
|
+
}
|
|
219
|
+
},
|
|
220
|
+
unityOverflowClipBox: {
|
|
221
|
+
enum: () => CS.UnityEngine.UIElements.OverflowClipBox,
|
|
222
|
+
values: {
|
|
223
|
+
"padding-box": "PaddingBox",
|
|
224
|
+
"content-box": "ContentBox",
|
|
225
|
+
}
|
|
226
|
+
},
|
|
189
227
|
}
|
|
190
228
|
|
|
191
229
|
/**
|
package/src/types.ts
CHANGED
|
@@ -127,6 +127,70 @@ export interface ViewStyle {
|
|
|
127
127
|
/** Text alignment. Note: Use USS class or stylesheet for -unity-font-style (italic/bold) */
|
|
128
128
|
unityTextAlign?: 'upper-left' | 'upper-center' | 'upper-right' | 'middle-left' | 'middle-center' | 'middle-right' | 'lower-left' | 'lower-center' | 'lower-right';
|
|
129
129
|
whiteSpace?: 'normal' | 'nowrap';
|
|
130
|
+
|
|
131
|
+
// Typography
|
|
132
|
+
/** C# Font object */
|
|
133
|
+
unityFont?: any;
|
|
134
|
+
/** C# FontDefinition object */
|
|
135
|
+
unityFontDefinition?: any;
|
|
136
|
+
/** Font style and weight */
|
|
137
|
+
unityFontStyleAndWeight?: 'normal' | 'bold' | 'italic' | 'bold-and-italic';
|
|
138
|
+
/** Spacing between characters */
|
|
139
|
+
letterSpacing?: StyleLength;
|
|
140
|
+
/** Spacing between words */
|
|
141
|
+
wordSpacing?: StyleLength;
|
|
142
|
+
/** Spacing between paragraphs */
|
|
143
|
+
unityParagraphSpacing?: StyleLength;
|
|
144
|
+
/** Text outline color */
|
|
145
|
+
unityTextOutlineColor?: StyleColor;
|
|
146
|
+
/** Text outline width */
|
|
147
|
+
unityTextOutlineWidth?: StyleLength;
|
|
148
|
+
/** How overflowing text is handled */
|
|
149
|
+
textOverflow?: 'clip' | 'ellipsis';
|
|
150
|
+
/** Position of text overflow indicator */
|
|
151
|
+
unityTextOverflowPosition?: 'end' | 'start' | 'middle';
|
|
152
|
+
|
|
153
|
+
// Background (additional)
|
|
154
|
+
/** Tint color applied to the background image */
|
|
155
|
+
unityBackgroundImageTintColor?: StyleColor;
|
|
156
|
+
|
|
157
|
+
// Slicing
|
|
158
|
+
/** 9-slice top inset */
|
|
159
|
+
unitySliceTop?: number;
|
|
160
|
+
/** 9-slice right inset */
|
|
161
|
+
unitySliceRight?: number;
|
|
162
|
+
/** 9-slice bottom inset */
|
|
163
|
+
unitySliceBottom?: number;
|
|
164
|
+
/** 9-slice left inset */
|
|
165
|
+
unitySliceLeft?: number;
|
|
166
|
+
/** Scale applied to 9-slice borders */
|
|
167
|
+
unitySliceScale?: number;
|
|
168
|
+
|
|
169
|
+
// Transform
|
|
170
|
+
/** Rotation transform. Pass a C# Rotate struct. */
|
|
171
|
+
rotate?: any;
|
|
172
|
+
/** Scale transform. Pass a C# Scale struct. */
|
|
173
|
+
scale?: any;
|
|
174
|
+
/** Translation transform. Pass a C# Translate struct. */
|
|
175
|
+
translate?: any;
|
|
176
|
+
/** Transform origin point. Pass a C# TransformOrigin struct. */
|
|
177
|
+
transformOrigin?: any;
|
|
178
|
+
|
|
179
|
+
// Transition
|
|
180
|
+
/** Delay before transitions start. Pass a C# StyleList. */
|
|
181
|
+
transitionDelay?: any;
|
|
182
|
+
/** Duration of transitions. Pass a C# StyleList. */
|
|
183
|
+
transitionDuration?: any;
|
|
184
|
+
/** Properties to transition. Pass a C# StyleList. */
|
|
185
|
+
transitionProperty?: any;
|
|
186
|
+
/** Timing functions for transitions. Pass a C# StyleList. */
|
|
187
|
+
transitionTimingFunction?: any;
|
|
188
|
+
|
|
189
|
+
// Other
|
|
190
|
+
/** Overflow clipping box */
|
|
191
|
+
unityOverflowClipBox?: 'padding-box' | 'content-box';
|
|
192
|
+
/** Cursor style. Pass a C# Cursor struct. */
|
|
193
|
+
cursor?: any;
|
|
130
194
|
}
|
|
131
195
|
|
|
132
196
|
// Event types
|