onejs-react 0.1.12 → 0.1.15

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 CHANGED
@@ -258,6 +258,27 @@ type MeshGenerationContext = CS.UnityEngine.UIElements.MeshGenerationContext
258
258
  type GenerateVisualContentCallback = (context: MeshGenerationContext) => void
259
259
  ```
260
260
 
261
+ ## C# Interop Utilities
262
+
263
+ ### `toArray<T>(collection): T[]`
264
+
265
+ Converts C# collections (`List<T>`, arrays) to JavaScript arrays. C# collections exposed through the OneJS proxy have `.Count`/`.Length` and indexers but lack `.map()`, `.filter()`, and other array methods.
266
+
267
+ ```tsx
268
+ import { toArray } from "onejs-react"
269
+
270
+ // Convert a C# List for use in JSX
271
+ {toArray<Item>(inventory.Items).map(item => <ItemView key={item.Id} item={item} />)}
272
+
273
+ // Convert a C# array
274
+ const resolutions = toArray<Resolution>(Screen.resolutions)
275
+
276
+ // Safe with null — returns []
277
+ const npcs = toArray(currentPlace?.NPCs)
278
+ ```
279
+
280
+ Supports objects with `.Count` (List, IList) or `.Length` (C# arrays). Returns `[]` for null/undefined.
281
+
261
282
  ## Dependencies
262
283
 
263
284
  - `react-reconciler@0.31.x` (React 19 compatible)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "onejs-react",
3
- "version": "0.1.12",
3
+ "version": "0.1.15",
4
4
  "description": "React 19 renderer for OneJS (Unity UI Toolkit)",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -327,6 +327,7 @@ export function createMockCS() {
327
327
  GPU: {
328
328
  GPUBridge: {
329
329
  SetElementBackgroundImage: () => {},
330
+ SetElementBackgroundFromObject: () => {},
330
331
  ClearElementBackgroundImage: () => {},
331
332
  },
332
333
  },
@@ -271,9 +271,9 @@ describe("style-parser", () => {
271
271
  expect(result.value).toBe(8)
272
272
  })
273
273
 
274
- it("parses borderWidth", () => {
275
- const result = parseStyleValue("borderWidth", 1) as MockLength
276
- expect(result.value).toBe(1)
274
+ it("parses borderWidth as plain number (StyleFloat)", () => {
275
+ const result = parseStyleValue("borderWidth", 1)
276
+ expect(result).toBe(1)
277
277
  })
278
278
 
279
279
  it("parses fontSize", () => {
@@ -67,10 +67,6 @@ function _loadImageAsset(src: string): any | null {
67
67
  return result
68
68
  }
69
69
 
70
- function _isVectorImage(obj: any): boolean {
71
- return obj != null && obj.GetType?.().Name === "VectorImage"
72
- }
73
-
74
70
  /**
75
71
  * Clear the Image component's image cache.
76
72
  * Call this if you need to force-reload images (e.g., after replacing files on disk).
@@ -168,10 +164,6 @@ export const Image = forwardRef<ImageElement, ImageProps>(({ src, image, ...rest
168
164
  if (src) return _loadImageAsset(src)
169
165
  return image
170
166
  }, [src, image])
171
- const isVector = useMemo(() => _isVectorImage(resolved), [resolved])
172
- if (isVector) {
173
- return <ojs-image ref={ref} vectorImage={resolved} {...rest} />;
174
- }
175
167
  return <ojs-image ref={ref} image={resolved} {...rest} />;
176
168
  });
177
169
  Image.displayName = 'Image';
@@ -65,6 +65,7 @@ declare const CS: {
65
65
  GPU: {
66
66
  GPUBridge: {
67
67
  SetElementBackgroundImage: (element: CSObject, rtHandle: number) => void;
68
+ SetElementBackgroundFromObject: (element: CSObject, obj: CSObject) => void;
68
69
  ClearElementBackgroundImage: (element: CSObject) => void;
69
70
  };
70
71
  };
@@ -350,12 +351,18 @@ function applyStyle(element: CSObject, style: ViewStyle | undefined): Set<string
350
351
  s[prop] = parsed;
351
352
  appliedKeys.add(prop);
352
353
  }
353
- } else if (key === "backgroundImage" && isRenderTextureHandle(value)) {
354
- // Special handling for RenderTexture background images
355
- // Supports both direct RenderTexture objects and marker objects
356
- const handle = getRenderTextureHandle(value);
357
- if (handle >= 0) {
358
- CS.OneJS.GPU.GPUBridge.SetElementBackgroundImage(element, handle);
354
+ } else if (key === "backgroundImage") {
355
+ if (value == null) {
356
+ CS.OneJS.GPU.GPUBridge.ClearElementBackgroundImage(element);
357
+ } else if (isRenderTextureHandle(value)) {
358
+ // GPU compute RenderTexture handles (via rt.getUnityObject())
359
+ const handle = getRenderTextureHandle(value);
360
+ if (handle >= 0) {
361
+ CS.OneJS.GPU.GPUBridge.SetElementBackgroundImage(element, handle);
362
+ }
363
+ } else if (typeof value === "object" && "__csHandle" in value) {
364
+ // C# objects: Texture2D, Sprite, VectorImage, RenderTexture
365
+ CS.OneJS.GPU.GPUBridge.SetElementBackgroundFromObject(element, value);
359
366
  }
360
367
  appliedKeys.add(key);
361
368
  } else {
@@ -89,10 +89,9 @@ const LENGTH_PROPERTIES = new Set([
89
89
  "margin", "marginTop", "marginRight", "marginBottom", "marginLeft",
90
90
  "padding", "paddingTop", "paddingRight", "paddingBottom", "paddingLeft",
91
91
  "flexBasis",
92
- "borderWidth", "borderTopWidth", "borderRightWidth", "borderBottomWidth", "borderLeftWidth",
93
92
  "borderRadius", "borderTopLeftRadius", "borderTopRightRadius", "borderBottomLeftRadius", "borderBottomRightRadius",
94
93
  "fontSize",
95
- "letterSpacing", "wordSpacing", "unityTextOutlineWidth", "unityParagraphSpacing",
94
+ "letterSpacing", "wordSpacing", "unityParagraphSpacing",
96
95
  ])
97
96
 
98
97
  // Style properties that expect color values
@@ -106,6 +105,8 @@ const COLOR_PROPERTIES = new Set([
106
105
  const NUMBER_PROPERTIES = new Set([
107
106
  "flexGrow", "flexShrink", "opacity",
108
107
  "unitySliceTop", "unitySliceRight", "unitySliceBottom", "unitySliceLeft", "unitySliceScale",
108
+ "borderWidth", "borderTopWidth", "borderRightWidth", "borderBottomWidth", "borderLeftWidth",
109
+ "unityTextOutlineWidth",
109
110
  ])
110
111
 
111
112
  // Enum property mappings: React style value -> Unity enum value
package/src/types.ts CHANGED
@@ -82,10 +82,19 @@ export interface ViewStyle {
82
82
  /** Background color. Examples: "#3498db", "rgba(0,0,0,0.5)", "red" */
83
83
  backgroundColor?: StyleColor;
84
84
  /**
85
- * Background image - accepts a Texture2D, RenderTexture, or RenderTexture object from GPU compute.
85
+ * Background image - accepts Texture2D, Sprite, VectorImage, RenderTexture,
86
+ * or a GPU compute RenderTexture handle.
86
87
  *
87
- * For GPU compute RenderTextures, you can pass the RenderTexture object directly:
88
88
  * @example
89
+ * // Texture2D
90
+ * const tex = loadImage("images/card-bg.png")
91
+ * <View style={{ backgroundImage: tex }} />
92
+ *
93
+ * // Sprite from C#
94
+ * const sprite = getSpriteFromCSharp()
95
+ * <View style={{ backgroundImage: sprite }} />
96
+ *
97
+ * // GPU compute RenderTexture
89
98
  * const rt = compute.renderTexture({ width: 100, height: 100 })
90
99
  * <View style={{ backgroundImage: rt }} />
91
100
  */
@@ -99,12 +108,12 @@ export interface ViewStyle {
99
108
  borderBottomColor?: StyleColor;
100
109
  borderLeftColor?: StyleColor;
101
110
 
102
- /** Border width for all sides. Examples: 1, "1px" */
103
- borderWidth?: StyleLength;
104
- borderTopWidth?: StyleLength;
105
- borderRightWidth?: StyleLength;
106
- borderBottomWidth?: StyleLength;
107
- borderLeftWidth?: StyleLength;
111
+ /** Border width for all sides (StyleFloat). Examples: 1, 2 */
112
+ borderWidth?: number;
113
+ borderTopWidth?: number;
114
+ borderRightWidth?: number;
115
+ borderBottomWidth?: number;
116
+ borderLeftWidth?: number;
108
117
 
109
118
  /** Border radius for all corners. Examples: 8, "8px", "50%" */
110
119
  borderRadius?: StyleLength;
@@ -143,8 +152,8 @@ export interface ViewStyle {
143
152
  unityParagraphSpacing?: StyleLength;
144
153
  /** Text outline color */
145
154
  unityTextOutlineColor?: StyleColor;
146
- /** Text outline width */
147
- unityTextOutlineWidth?: StyleLength;
155
+ /** Text outline width (StyleFloat) */
156
+ unityTextOutlineWidth?: number;
148
157
  /** How overflowing text is handled */
149
158
  textOverflow?: 'clip' | 'ellipsis';
150
159
  /** Position of text overflow indicator */