onejs-react 0.1.0
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 +43 -0
- package/src/__tests__/components.test.tsx +388 -0
- package/src/__tests__/host-config.test.ts +674 -0
- package/src/__tests__/mocks.ts +311 -0
- package/src/__tests__/renderer.test.tsx +387 -0
- package/src/__tests__/setup.ts +52 -0
- package/src/__tests__/style-parser.test.ts +321 -0
- package/src/components.tsx +87 -0
- package/src/host-config.ts +749 -0
- package/src/index.ts +54 -0
- package/src/renderer.ts +73 -0
- package/src/screen.tsx +242 -0
- package/src/style-parser.ts +288 -0
- package/src/types.ts +295 -0
package/src/types.ts
ADDED
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Length value - can be a number (pixels) or string with unit
|
|
5
|
+
* @example
|
|
6
|
+
* 100 // 100px
|
|
7
|
+
* "100px" // 100px
|
|
8
|
+
* "50%" // 50 percent
|
|
9
|
+
* "auto" // auto keyword
|
|
10
|
+
*/
|
|
11
|
+
export type StyleLength = number | string;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Color value - supports multiple formats
|
|
15
|
+
* @example
|
|
16
|
+
* "#fff" // Short hex
|
|
17
|
+
* "#ffffff" // Full hex
|
|
18
|
+
* "#ffffff80" // Hex with alpha
|
|
19
|
+
* "rgb(255, 0, 0)" // RGB
|
|
20
|
+
* "rgba(255, 0, 0, 0.5)" // RGBA
|
|
21
|
+
* "red" // Named color
|
|
22
|
+
*/
|
|
23
|
+
export type StyleColor = string;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Style properties for UI elements (subset of UI Toolkit USS properties)
|
|
27
|
+
*
|
|
28
|
+
* Length values accept:
|
|
29
|
+
* - Numbers: treated as pixels (e.g., `100` = 100px)
|
|
30
|
+
* - Strings: "100px", "50%", "auto"
|
|
31
|
+
*
|
|
32
|
+
* Color values accept:
|
|
33
|
+
* - Hex: "#fff", "#ffffff", "#ffffffff" (with alpha)
|
|
34
|
+
* - RGB: "rgb(255, 0, 0)", "rgba(255, 0, 0, 0.5)"
|
|
35
|
+
* - Named: "red", "blue", "transparent", etc.
|
|
36
|
+
*/
|
|
37
|
+
export interface ViewStyle {
|
|
38
|
+
// Layout - dimensions
|
|
39
|
+
/** Width in pixels or percentage. Examples: 100, "100px", "50%", "auto" */
|
|
40
|
+
width?: StyleLength;
|
|
41
|
+
/** Height in pixels or percentage. Examples: 100, "100px", "50%", "auto" */
|
|
42
|
+
height?: StyleLength;
|
|
43
|
+
minWidth?: StyleLength;
|
|
44
|
+
minHeight?: StyleLength;
|
|
45
|
+
maxWidth?: StyleLength;
|
|
46
|
+
maxHeight?: StyleLength;
|
|
47
|
+
|
|
48
|
+
// Flexbox
|
|
49
|
+
flexGrow?: number;
|
|
50
|
+
flexShrink?: number;
|
|
51
|
+
flexBasis?: StyleLength;
|
|
52
|
+
flexDirection?: 'row' | 'row-reverse' | 'column' | 'column-reverse';
|
|
53
|
+
flexWrap?: 'nowrap' | 'wrap' | 'wrap-reverse';
|
|
54
|
+
alignItems?: 'flex-start' | 'flex-end' | 'center' | 'stretch';
|
|
55
|
+
alignSelf?: 'auto' | 'flex-start' | 'flex-end' | 'center' | 'stretch';
|
|
56
|
+
alignContent?: 'flex-start' | 'flex-end' | 'center' | 'stretch';
|
|
57
|
+
justifyContent?: 'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around';
|
|
58
|
+
|
|
59
|
+
// Positioning
|
|
60
|
+
position?: 'relative' | 'absolute';
|
|
61
|
+
top?: StyleLength;
|
|
62
|
+
right?: StyleLength;
|
|
63
|
+
bottom?: StyleLength;
|
|
64
|
+
left?: StyleLength;
|
|
65
|
+
|
|
66
|
+
// Margin & Padding (shorthand applies to all sides)
|
|
67
|
+
/** Margin for all sides. Examples: 16, "16px", "5%" */
|
|
68
|
+
margin?: StyleLength;
|
|
69
|
+
marginTop?: StyleLength;
|
|
70
|
+
marginRight?: StyleLength;
|
|
71
|
+
marginBottom?: StyleLength;
|
|
72
|
+
marginLeft?: StyleLength;
|
|
73
|
+
|
|
74
|
+
/** Padding for all sides. Examples: 16, "16px", "5%" */
|
|
75
|
+
padding?: StyleLength;
|
|
76
|
+
paddingTop?: StyleLength;
|
|
77
|
+
paddingRight?: StyleLength;
|
|
78
|
+
paddingBottom?: StyleLength;
|
|
79
|
+
paddingLeft?: StyleLength;
|
|
80
|
+
|
|
81
|
+
// Background
|
|
82
|
+
/** Background color. Examples: "#3498db", "rgba(0,0,0,0.5)", "red" */
|
|
83
|
+
backgroundColor?: StyleColor;
|
|
84
|
+
|
|
85
|
+
// Border
|
|
86
|
+
/** Border color for all sides. Examples: "#ccc", "rgba(0,0,0,0.1)" */
|
|
87
|
+
borderColor?: StyleColor;
|
|
88
|
+
borderTopColor?: StyleColor;
|
|
89
|
+
borderRightColor?: StyleColor;
|
|
90
|
+
borderBottomColor?: StyleColor;
|
|
91
|
+
borderLeftColor?: StyleColor;
|
|
92
|
+
|
|
93
|
+
/** Border width for all sides. Examples: 1, "1px" */
|
|
94
|
+
borderWidth?: StyleLength;
|
|
95
|
+
borderTopWidth?: StyleLength;
|
|
96
|
+
borderRightWidth?: StyleLength;
|
|
97
|
+
borderBottomWidth?: StyleLength;
|
|
98
|
+
borderLeftWidth?: StyleLength;
|
|
99
|
+
|
|
100
|
+
/** Border radius for all corners. Examples: 8, "8px", "50%" */
|
|
101
|
+
borderRadius?: StyleLength;
|
|
102
|
+
borderTopLeftRadius?: StyleLength;
|
|
103
|
+
borderTopRightRadius?: StyleLength;
|
|
104
|
+
borderBottomLeftRadius?: StyleLength;
|
|
105
|
+
borderBottomRightRadius?: StyleLength;
|
|
106
|
+
|
|
107
|
+
// Display
|
|
108
|
+
opacity?: number;
|
|
109
|
+
overflow?: 'visible' | 'hidden';
|
|
110
|
+
display?: 'flex' | 'none';
|
|
111
|
+
visibility?: 'visible' | 'hidden';
|
|
112
|
+
|
|
113
|
+
// Text
|
|
114
|
+
/** Text color. Examples: "#333", "white" */
|
|
115
|
+
color?: StyleColor;
|
|
116
|
+
/** Font size in pixels. Examples: 16, "16px" */
|
|
117
|
+
fontSize?: StyleLength;
|
|
118
|
+
fontStyle?: 'normal' | 'italic' | 'bold' | 'bold-and-italic';
|
|
119
|
+
unityTextAlign?: 'upper-left' | 'upper-center' | 'upper-right' | 'middle-left' | 'middle-center' | 'middle-right' | 'lower-left' | 'lower-center' | 'lower-right';
|
|
120
|
+
whiteSpace?: 'normal' | 'nowrap';
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Event types
|
|
124
|
+
export interface PointerEventData {
|
|
125
|
+
type: string;
|
|
126
|
+
x: number;
|
|
127
|
+
y: number;
|
|
128
|
+
button: number;
|
|
129
|
+
pointerId: number;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export interface KeyEventData {
|
|
133
|
+
type: string;
|
|
134
|
+
keyCode: number;
|
|
135
|
+
key: string;
|
|
136
|
+
char: string;
|
|
137
|
+
shift: boolean;
|
|
138
|
+
ctrl: boolean;
|
|
139
|
+
alt: boolean;
|
|
140
|
+
meta: boolean;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export interface ChangeEventData<T = unknown> {
|
|
144
|
+
type: string;
|
|
145
|
+
value: T;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export type PointerEventHandler = (event: PointerEventData) => void;
|
|
149
|
+
export type KeyEventHandler = (event: KeyEventData) => void;
|
|
150
|
+
export type ChangeEventHandler<T = unknown> = (event: ChangeEventData<T>) => void;
|
|
151
|
+
export type FocusEventHandler = () => void;
|
|
152
|
+
|
|
153
|
+
// Base props for all components
|
|
154
|
+
export interface BaseProps {
|
|
155
|
+
key?: string | number;
|
|
156
|
+
children?: ReactNode;
|
|
157
|
+
style?: ViewStyle;
|
|
158
|
+
className?: string;
|
|
159
|
+
|
|
160
|
+
// Pointer events
|
|
161
|
+
onClick?: PointerEventHandler;
|
|
162
|
+
onPointerDown?: PointerEventHandler;
|
|
163
|
+
onPointerUp?: PointerEventHandler;
|
|
164
|
+
onPointerMove?: PointerEventHandler;
|
|
165
|
+
onPointerEnter?: PointerEventHandler;
|
|
166
|
+
onPointerLeave?: PointerEventHandler;
|
|
167
|
+
|
|
168
|
+
// Focus events
|
|
169
|
+
onFocus?: FocusEventHandler;
|
|
170
|
+
onBlur?: FocusEventHandler;
|
|
171
|
+
|
|
172
|
+
// Keyboard events
|
|
173
|
+
onKeyDown?: KeyEventHandler;
|
|
174
|
+
onKeyUp?: KeyEventHandler;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Component-specific props
|
|
178
|
+
export interface ViewProps extends BaseProps {}
|
|
179
|
+
|
|
180
|
+
export interface LabelProps extends BaseProps {
|
|
181
|
+
text?: string;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export interface ButtonProps extends BaseProps {
|
|
185
|
+
text?: string;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export interface TextFieldProps extends BaseProps {
|
|
189
|
+
value?: string;
|
|
190
|
+
placeholder?: string;
|
|
191
|
+
multiline?: boolean;
|
|
192
|
+
readOnly?: boolean;
|
|
193
|
+
maxLength?: number;
|
|
194
|
+
onChange?: ChangeEventHandler<string>;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export interface ToggleProps extends BaseProps {
|
|
198
|
+
value?: boolean;
|
|
199
|
+
label?: string;
|
|
200
|
+
onChange?: ChangeEventHandler<boolean>;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export interface SliderProps extends BaseProps {
|
|
204
|
+
value?: number;
|
|
205
|
+
lowValue?: number;
|
|
206
|
+
highValue?: number;
|
|
207
|
+
onChange?: ChangeEventHandler<number>;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export interface ScrollViewProps extends BaseProps {
|
|
211
|
+
// Scroll direction
|
|
212
|
+
mode?: 'Vertical' | 'Horizontal' | 'VerticalAndHorizontal';
|
|
213
|
+
|
|
214
|
+
// Scrollbar visibility
|
|
215
|
+
horizontalScrollerVisibility?: 'Auto' | 'AlwaysVisible' | 'Hidden';
|
|
216
|
+
verticalScrollerVisibility?: 'Auto' | 'AlwaysVisible' | 'Hidden';
|
|
217
|
+
|
|
218
|
+
// Scroll behavior
|
|
219
|
+
elasticity?: number;
|
|
220
|
+
elasticAnimationIntervalMs?: number;
|
|
221
|
+
scrollDecelerationRate?: number;
|
|
222
|
+
mouseWheelScrollSize?: number;
|
|
223
|
+
horizontalPageSize?: number;
|
|
224
|
+
verticalPageSize?: number;
|
|
225
|
+
|
|
226
|
+
// Touch behavior
|
|
227
|
+
touchScrollBehavior?: 'Unrestricted' | 'Elastic' | 'Clamped';
|
|
228
|
+
|
|
229
|
+
// Nested scroll handling
|
|
230
|
+
nestedInteractionKind?: 'Default' | 'StopScrolling' | 'ForwardScrolling';
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export interface ImageProps extends BaseProps {
|
|
234
|
+
src?: string;
|
|
235
|
+
scaleMode?: 'stretch-to-fill' | 'scale-and-crop' | 'scale-to-fit';
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// VisualElement type for ListView callbacks
|
|
239
|
+
// This is the C# VisualElement exposed to JS
|
|
240
|
+
export interface VisualElement {
|
|
241
|
+
__csHandle: number;
|
|
242
|
+
__csType: string;
|
|
243
|
+
style: Record<string, unknown>;
|
|
244
|
+
text?: string;
|
|
245
|
+
value?: unknown;
|
|
246
|
+
Add: (child: VisualElement) => void;
|
|
247
|
+
Remove: (child: VisualElement) => void;
|
|
248
|
+
AddToClassList: (className: string) => void;
|
|
249
|
+
RemoveFromClassList: (className: string) => void;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// ListView uses Unity's virtualization callbacks directly
|
|
253
|
+
// This is intentionally imperative - ListView manages its own element recycling
|
|
254
|
+
export interface ListViewProps extends BaseProps {
|
|
255
|
+
// Data source - the array of items to display
|
|
256
|
+
itemsSource: unknown[];
|
|
257
|
+
|
|
258
|
+
// Element creation callback - called when ListView needs a new visual element
|
|
259
|
+
// Return a VisualElement (e.g., new CS.UnityEngine.UIElements.Label())
|
|
260
|
+
makeItem: () => VisualElement;
|
|
261
|
+
|
|
262
|
+
// Bind callback - called to populate an element with data at the given index
|
|
263
|
+
// The element is recycled, so clear/set all relevant properties
|
|
264
|
+
bindItem: (element: VisualElement, index: number) => void;
|
|
265
|
+
|
|
266
|
+
// Optional: called when an element is about to be recycled
|
|
267
|
+
unbindItem?: (element: VisualElement, index: number) => void;
|
|
268
|
+
|
|
269
|
+
// Optional: called when an element is being destroyed
|
|
270
|
+
destroyItem?: (element: VisualElement) => void;
|
|
271
|
+
|
|
272
|
+
// Virtualization settings
|
|
273
|
+
fixedItemHeight?: number;
|
|
274
|
+
virtualizationMethod?: 'FixedHeight' | 'DynamicHeight';
|
|
275
|
+
|
|
276
|
+
// Selection
|
|
277
|
+
selectionType?: 'None' | 'Single' | 'Multiple';
|
|
278
|
+
selectedIndex?: number;
|
|
279
|
+
selectedIndices?: number[];
|
|
280
|
+
onSelectionChange?: (selectedIndices: number[]) => void;
|
|
281
|
+
onItemsChosen?: (chosenItems: unknown[]) => void;
|
|
282
|
+
|
|
283
|
+
// Reordering
|
|
284
|
+
reorderable?: boolean;
|
|
285
|
+
reorderMode?: 'Simple' | 'Animated';
|
|
286
|
+
|
|
287
|
+
// Header/Footer
|
|
288
|
+
showFoldoutHeader?: boolean;
|
|
289
|
+
headerTitle?: string;
|
|
290
|
+
showAddRemoveFooter?: boolean;
|
|
291
|
+
|
|
292
|
+
// Appearance
|
|
293
|
+
showBorder?: boolean;
|
|
294
|
+
showAlternatingRowBackgrounds?: 'None' | 'ContentOnly' | 'All';
|
|
295
|
+
}
|