onejs-react 0.1.15 → 0.1.17

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "onejs-react",
3
- "version": "0.1.15",
3
+ "version": "0.1.17",
4
4
  "description": "React 19 renderer for OneJS (Unity UI Toolkit)",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -1,5 +1,6 @@
1
- import { forwardRef, useMemo, type ReactElement, type Ref } from 'react';
1
+ import { forwardRef, createElement, useMemo, type ReactElement, type Ref } from 'react';
2
2
  import type {
3
+ BaseProps,
3
4
  ViewProps,
4
5
  TextProps,
5
6
  LabelProps,
@@ -10,6 +11,8 @@ import type {
10
11
  ScrollViewProps,
11
12
  ImageProps,
12
13
  ListViewProps,
14
+ FrostedGlassProps,
15
+ FrostedGlassIntrinsicProps,
13
16
  VisualElement,
14
17
  TextElement,
15
18
  LabelElement,
@@ -19,6 +22,7 @@ import type {
19
22
  SliderElement,
20
23
  ScrollViewElement,
21
24
  ImageElement,
25
+ FrostedGlassElement,
22
26
  } from './types';
23
27
 
24
28
  declare const CS: any
@@ -94,6 +98,7 @@ declare module 'react/jsx-runtime' {
94
98
  'ojs-scrollview': WithRef<ScrollViewProps, ScrollViewElement>;
95
99
  'ojs-image': WithRef<ImageProps, ImageElement>;
96
100
  'ojs-listview': WithRef<ListViewProps, VisualElement>;
101
+ 'ojs-frostedglass': WithRef<FrostedGlassIntrinsicProps, FrostedGlassElement>;
97
102
  }
98
103
  }
99
104
  }
@@ -112,6 +117,7 @@ declare module 'react' {
112
117
  'ojs-scrollview': WithRef<ScrollViewProps, ScrollViewElement>;
113
118
  'ojs-image': WithRef<ImageProps, ImageElement>;
114
119
  'ojs-listview': WithRef<ListViewProps, VisualElement>;
120
+ 'ojs-frostedglass': WithRef<FrostedGlassIntrinsicProps, FrostedGlassElement>;
115
121
  }
116
122
  }
117
123
  }
@@ -172,3 +178,50 @@ export const ListView = forwardRef<VisualElement, ListViewProps>((props, ref) =>
172
178
  return <ojs-listview ref={ref} {...props} />;
173
179
  });
174
180
  ListView.displayName = 'ListView';
181
+
182
+ export const FrostedGlass = forwardRef<FrostedGlassElement, FrostedGlassProps>(({ blur, tint, ...rest }, ref) => {
183
+ const parsedTint = useMemo(() => {
184
+ if (!tint) return new CS.UnityEngine.Color(1, 1, 1, 0.15)
185
+ const m = tint.match(/rgba?\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)\s*(?:,\s*([\d.]+))?\s*\)/)
186
+ if (m) return new CS.UnityEngine.Color(+m[1] / 255, +m[2] / 255, +m[3] / 255, m[4] != null ? +m[4] : 1)
187
+ return new CS.UnityEngine.Color(1, 1, 1, 0.15)
188
+ }, [tint])
189
+ return <ojs-frostedglass ref={ref} blurRadius={blur ?? 10} tintColor={parsedTint} {...rest} />;
190
+ });
191
+ FrostedGlass.displayName = 'FrostedGlass';
192
+
193
+ /**
194
+ * Create a typed React component for a registered custom element.
195
+ * Use with `registerElement()` to add custom C# VisualElement types to React.
196
+ *
197
+ * @param name - Element name matching what was passed to registerElement()
198
+ * @param displayName - Optional display name for React DevTools
199
+ *
200
+ * @example
201
+ * import { registerElement, createComponent } from "onejs-react"
202
+ * import { BaseProps, VisualElement } from "onejs-react"
203
+ *
204
+ * // Define props for your custom element
205
+ * interface RadialProgressProps extends BaseProps {
206
+ * progress?: number
207
+ * trackColor?: string
208
+ * }
209
+ *
210
+ * // Register and create the component
211
+ * registerElement("radial-progress", CS.MyGame.UI.RadialProgress)
212
+ * export const RadialProgress = createComponent<RadialProgressProps>("radial-progress")
213
+ *
214
+ * // Use in JSX like any React component
215
+ * <RadialProgress progress={0.75} trackColor="#333" style={{ width: 100, height: 100 }} />
216
+ */
217
+ export function createComponent<P extends BaseProps = BaseProps>(
218
+ name: string,
219
+ displayName?: string
220
+ ) {
221
+ const type = name.startsWith('ojs-') ? name : `ojs-${name}`;
222
+ const Component = forwardRef<VisualElement, P>((props, ref) => {
223
+ return createElement(type, { ...props, ref });
224
+ });
225
+ Component.displayName = displayName || name;
226
+ return Component;
227
+ }
@@ -60,6 +60,7 @@ declare const CS: {
60
60
  };
61
61
  ScaleMode: CSEnum;
62
62
  Rect: new (...args: any[]) => any;
63
+ Color: new (r: number, g: number, b: number, a: number) => any;
63
64
  };
64
65
  OneJS: {
65
66
  GPU: {
@@ -68,6 +69,7 @@ declare const CS: {
68
69
  SetElementBackgroundFromObject: (element: CSObject, obj: CSObject) => void;
69
70
  ClearElementBackgroundImage: (element: CSObject) => void;
70
71
  };
72
+ FrostedGlassElement: new () => CSObject;
71
73
  };
72
74
  };
73
75
  };
@@ -173,8 +175,38 @@ const TYPE_MAP: Record<string, () => CSObject> = {
173
175
  'ojs-scrollview': () => new CS.UnityEngine.UIElements.ScrollView(),
174
176
  'ojs-image': () => new CS.UnityEngine.UIElements.Image(),
175
177
  'ojs-listview': () => new CS.UnityEngine.UIElements.ListView(),
178
+ 'ojs-frostedglass': () => new CS.OneJS.GPU.FrostedGlassElement(),
176
179
  };
177
180
 
181
+ // Built-in types with specific prop handling in applyComponentProps
182
+ const BUILT_IN_TYPES = new Set(Object.keys(TYPE_MAP));
183
+
184
+ /**
185
+ * Register a custom VisualElement type for use in React JSX.
186
+ *
187
+ * @param name - Element name (with or without 'ojs-' prefix)
188
+ * @param constructor - C# constructor reference (e.g., CS.MyNamespace.MyWidget)
189
+ *
190
+ * @example
191
+ * import { registerElement, createComponent } from "onejs-react"
192
+ *
193
+ * // Register the custom element
194
+ * registerElement("radial-progress", CS.MyGame.UI.RadialProgress)
195
+ *
196
+ * // Create a typed React component for it
197
+ * const RadialProgress = createComponent<RadialProgressProps>("radial-progress")
198
+ *
199
+ * // Use in JSX
200
+ * <RadialProgress progress={0.75} />
201
+ */
202
+ export function registerElement(name: string, constructor: new (...args: any[]) => any): void {
203
+ const key = name.startsWith('ojs-') ? name : `ojs-${name}`;
204
+ if (TYPE_MAP[key]) {
205
+ console.error(`registerElement: "${name}" is already registered. Overwriting.`);
206
+ }
207
+ TYPE_MAP[key] = () => new constructor();
208
+ }
209
+
178
210
  // Event prop to event type mapping
179
211
  const EVENT_PROPS: Record<string, string> = {
180
212
  // Click
@@ -728,8 +760,29 @@ function applyListViewProps(element: CSListView, props: Record<string, unknown>)
728
760
  setEnumProp(element, 'showAlternatingRowBackgrounds', props, 'showAlternatingRowBackgrounds', UIE.AlternatingRowBackground);
729
761
  }
730
762
 
763
+ // Props handled by the reconciler infrastructure - not forwarded to C# elements
764
+ const RESERVED_PROPS = new Set([
765
+ 'children', 'key', 'ref', 'style', 'className', 'pickingMode',
766
+ 'onGenerateVisualContent',
767
+ ...Object.keys(EVENT_PROPS),
768
+ ]);
769
+
770
+ // Forward non-reserved props directly to C# element (for custom elements)
771
+ function applyCustomProps(element: CSObject, props: Record<string, unknown>) {
772
+ for (const [key, value] of Object.entries(props)) {
773
+ if (value === undefined || RESERVED_PROPS.has(key)) continue;
774
+ (element as any)[key] = value;
775
+ }
776
+ }
777
+
731
778
  // Apply component-specific props based on element type
732
779
  function applyComponentProps(element: CSObject, type: string, props: Record<string, unknown>) {
780
+ // Custom elements: forward all non-reserved props directly to C# element
781
+ if (!BUILT_IN_TYPES.has(type)) {
782
+ applyCustomProps(element, props);
783
+ return;
784
+ }
785
+
733
786
  // For Slider, apply range props (lowValue/highValue) BEFORE value
734
787
  // Unity's Slider clamps value to [lowValue, highValue], so range must be set first
735
788
  if (type === 'ojs-slider') {
@@ -750,6 +803,10 @@ function applyComponentProps(element: CSObject, type: string, props: Record<stri
750
803
  applyScrollViewProps(element as CSScrollView, props);
751
804
  } else if (type === 'ojs-listview') {
752
805
  applyListViewProps(element as CSListView, props);
806
+ } else if (type === 'ojs-frostedglass') {
807
+ const el = element as any;
808
+ if (props.blurRadius !== undefined) el.BlurRadius = props.blurRadius;
809
+ if (props.tintColor !== undefined) el.TintColor = props.tintColor;
753
810
  }
754
811
  }
755
812
 
package/src/index.ts CHANGED
@@ -10,9 +10,14 @@ export {
10
10
  ScrollView,
11
11
  Image,
12
12
  ListView,
13
+ FrostedGlass,
13
14
  clearImageCache,
15
+ createComponent,
14
16
  } from './components';
15
17
 
18
+ // Custom Element Registration
19
+ export { registerElement } from './host-config';
20
+
16
21
  // Renderer
17
22
  export { render, unmount, flushSync, batchedUpdates, getDebugInfo } from './renderer';
18
23
 
@@ -79,6 +84,7 @@ export type {
79
84
  ScrollViewProps,
80
85
  ImageProps,
81
86
  ListViewProps,
87
+ FrostedGlassProps,
82
88
  // Container type for render()
83
89
  RenderContainer,
84
90
  // Element types for refs
@@ -91,6 +97,7 @@ export type {
91
97
  SliderElement,
92
98
  ScrollViewElement,
93
99
  ImageElement,
100
+ FrostedGlassElement,
94
101
  // Vector drawing types
95
102
  Vector2,
96
103
  Color,
package/src/types.ts CHANGED
@@ -674,6 +674,24 @@ export interface ImageElement extends VisualElement {
674
674
 
675
675
  // ListView uses Unity's virtualization callbacks directly
676
676
  // This is intentionally imperative - ListView manages its own element recycling
677
+ export interface FrostedGlassProps extends BaseProps {
678
+ /** Blur radius in screen pixels. Higher = more blurry. Default: 10. */
679
+ blur?: number;
680
+ /** Tint color overlaid on the blurred background (CSS color string). */
681
+ tint?: string;
682
+ }
683
+
684
+ /** Internal props for the ojs-frostedglass intrinsic element */
685
+ export interface FrostedGlassIntrinsicProps extends BaseProps {
686
+ blurRadius?: number;
687
+ tintColor?: any;
688
+ }
689
+
690
+ export interface FrostedGlassElement extends VisualElement {
691
+ blurRadius: number;
692
+ tintColor: any;
693
+ }
694
+
677
695
  export interface ListViewProps extends BaseProps {
678
696
  // Data source - the array of items to display
679
697
  itemsSource: unknown[];