@dcl/react-ecs 7.29.1-35901015152.commit-d1b7b96 → 7.29.1-35978346337.commit-823107b
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/dist/components/Button/index.js +2 -2
- package/dist/components/Dropdown/index.js +2 -5
- package/dist/components/Input/index.js +2 -5
- package/dist/components/Label/index.js +2 -5
- package/dist/components/Label/types.d.ts +0 -2
- package/dist/components/listeners/types.d.ts +2 -10
- package/dist/components/listeners/types.js +1 -4
- package/dist/components/uiBackground/types.d.ts +1 -12
- package/dist/components/uiBackground/utils.js +0 -8
- package/dist/components/uiTransform/index.js +3 -5
- package/dist/components/uiTransform/types.d.ts +0 -12
- package/dist/components/uiTransform/utils.js +0 -21
- package/dist/react-ecs.d.ts +0 -3
- package/dist/reconciler/index.d.ts +1 -1
- package/dist/reconciler/index.js +53 -68
- package/dist/reconciler/utils.js +0 -3
- package/dist/system.d.ts +11 -14
- package/dist/system.js +44 -44
- package/package.json +3 -3
|
@@ -29,7 +29,7 @@ function getButtonProps(props) {
|
|
|
29
29
|
*/
|
|
30
30
|
/* @__PURE__ */
|
|
31
31
|
export function Button(props) {
|
|
32
|
-
const { uiTransform, uiBackground, onMouseDown, onMouseUp, onMouseEnter, onMouseLeave,
|
|
32
|
+
const { uiTransform, uiBackground, onMouseDown, onMouseUp, onMouseEnter, onMouseLeave, ...otherProps } = props;
|
|
33
33
|
const buttonProps = getButtonProps(props);
|
|
34
34
|
const uiBackgroundProps = parseUiBackground({
|
|
35
35
|
...buttonProps.uiBackground,
|
|
@@ -58,5 +58,5 @@ export function Button(props) {
|
|
|
58
58
|
uiBackgroundProps.color = { ...uiBackgroundProps.color, a: uiBackgroundProps.color.a / 2 };
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
|
-
return (ReactEcs.createElement("entity", { onMouseDown: !!props.disabled ? undefined : onMouseDown, onMouseUp: !!props.disabled ? undefined : onMouseUp, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave,
|
|
61
|
+
return (ReactEcs.createElement("entity", { onMouseDown: !!props.disabled ? undefined : onMouseDown, onMouseUp: !!props.disabled ? undefined : onMouseUp, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, uiTransform: uiTransformProps, uiText: textProps, uiBackground: uiBackgroundProps }));
|
|
62
62
|
}
|
|
@@ -34,7 +34,7 @@ function parseUiDropdown(props) {
|
|
|
34
34
|
*/
|
|
35
35
|
/* @__PURE__ */
|
|
36
36
|
export function Dropdown(props) {
|
|
37
|
-
const { uiTransform, uiBackground, onMouseDown, onMouseUp, onMouseEnter, onMouseLeave,
|
|
37
|
+
const { uiTransform, uiBackground, onMouseDown, onMouseUp, onMouseEnter, onMouseLeave, ...otherProps } = props;
|
|
38
38
|
const dropdownProps = parseUiDropdown(otherProps);
|
|
39
39
|
const commonProps = parseProps({
|
|
40
40
|
uiTransform,
|
|
@@ -42,10 +42,7 @@ export function Dropdown(props) {
|
|
|
42
42
|
onMouseDown,
|
|
43
43
|
onMouseUp,
|
|
44
44
|
onMouseEnter,
|
|
45
|
-
onMouseLeave
|
|
46
|
-
onMouseDrag,
|
|
47
|
-
onMouseDragLocked,
|
|
48
|
-
onMouseDragEnd
|
|
45
|
+
onMouseLeave
|
|
49
46
|
});
|
|
50
47
|
return ReactEcs.createElement("entity", { ...commonProps, uiDropdown: dropdownProps });
|
|
51
48
|
}
|
|
@@ -35,7 +35,7 @@ function parseUiInput(props) {
|
|
|
35
35
|
* @category Component
|
|
36
36
|
*/ /* @__PURE__ */
|
|
37
37
|
export function Input(props) {
|
|
38
|
-
const { uiTransform, uiBackground, onMouseDown, onMouseUp, onMouseEnter, onMouseLeave,
|
|
38
|
+
const { uiTransform, uiBackground, onMouseDown, onMouseUp, onMouseEnter, onMouseLeave, ...otherProps } = props;
|
|
39
39
|
const inputProps = parseUiInput(otherProps);
|
|
40
40
|
const commonProps = parseProps({
|
|
41
41
|
uiTransform,
|
|
@@ -43,10 +43,7 @@ export function Input(props) {
|
|
|
43
43
|
onMouseDown,
|
|
44
44
|
onMouseUp,
|
|
45
45
|
onMouseEnter,
|
|
46
|
-
onMouseLeave
|
|
47
|
-
onMouseDrag,
|
|
48
|
-
onMouseDragLocked,
|
|
49
|
-
onMouseDragEnd
|
|
46
|
+
onMouseLeave
|
|
50
47
|
});
|
|
51
48
|
return ReactEcs.createElement("entity", { ...commonProps, uiInput: inputProps });
|
|
52
49
|
}
|
|
@@ -16,17 +16,14 @@ export { scaleFontSize } from './utils';
|
|
|
16
16
|
*/
|
|
17
17
|
/* @__PURE__ */
|
|
18
18
|
export function Label(props) {
|
|
19
|
-
const { uiTransform, uiBackground, onMouseDown, onMouseUp, onMouseEnter, onMouseLeave,
|
|
19
|
+
const { uiTransform, uiBackground, onMouseDown, onMouseUp, onMouseEnter, onMouseLeave, ...uiTextProps } = props;
|
|
20
20
|
const commonProps = parseProps({
|
|
21
21
|
uiTransform,
|
|
22
22
|
uiBackground,
|
|
23
23
|
onMouseDown,
|
|
24
24
|
onMouseUp,
|
|
25
25
|
onMouseEnter,
|
|
26
|
-
onMouseLeave
|
|
27
|
-
onMouseDrag,
|
|
28
|
-
onMouseDragLocked,
|
|
29
|
-
onMouseDragEnd
|
|
26
|
+
onMouseLeave
|
|
30
27
|
});
|
|
31
28
|
const { font, textAlign, fontSize, textWrap, ...textProps } = uiTextProps;
|
|
32
29
|
const uiText = {
|
|
@@ -17,8 +17,6 @@ export interface UiLabelProps {
|
|
|
17
17
|
font?: UiFontType | undefined;
|
|
18
18
|
/** Behaviour when text reached. @defaultValue 'wrap' */
|
|
19
19
|
textWrap?: UiTextWrapType | undefined;
|
|
20
|
-
/** A font file in the scene, or a Google Fonts family name; `font` is the fallback. @defaultValue undefined */
|
|
21
|
-
fontSrc?: string | undefined;
|
|
22
20
|
}
|
|
23
21
|
/**
|
|
24
22
|
* @public
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import { PBPointerEventsResult } from '@dcl/ecs';
|
|
2
1
|
/**
|
|
3
|
-
* Callback function to be triggered on a specified event
|
|
4
|
-
* fired it (button, hit, and for drags the pointer delta), which handlers may ignore.
|
|
2
|
+
* Callback function to be triggered on a specified event
|
|
5
3
|
* @public
|
|
6
4
|
*/
|
|
7
|
-
export type Callback = (
|
|
5
|
+
export type Callback = () => void;
|
|
8
6
|
/**
|
|
9
7
|
* User key event Listeners
|
|
10
8
|
* @public
|
|
@@ -18,10 +16,4 @@ export type Listeners = {
|
|
|
18
16
|
onMouseEnter?: Callback;
|
|
19
17
|
/** triggered on mouse leave event */
|
|
20
18
|
onMouseLeave?: Callback;
|
|
21
|
-
/** triggered while the pointer is dragged after pressing on the element */
|
|
22
|
-
onMouseDrag?: Callback;
|
|
23
|
-
/** triggered while the pointer is dragged with the cursor locked in place */
|
|
24
|
-
onMouseDragLocked?: Callback;
|
|
25
|
-
/** triggered when a drag that started on the element ends */
|
|
26
|
-
onMouseDragEnd?: Callback;
|
|
27
19
|
};
|
|
@@ -2,10 +2,7 @@ const listeners = {
|
|
|
2
2
|
onMouseDown: undefined,
|
|
3
3
|
onMouseUp: undefined,
|
|
4
4
|
onMouseEnter: undefined,
|
|
5
|
-
onMouseLeave: undefined
|
|
6
|
-
onMouseDrag: undefined,
|
|
7
|
-
onMouseDragLocked: undefined,
|
|
8
|
-
onMouseDragEnd: undefined
|
|
5
|
+
onMouseLeave: undefined
|
|
9
6
|
};
|
|
10
7
|
const listenersKey = Object.keys(listeners);
|
|
11
8
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BorderRect
|
|
1
|
+
import { BorderRect } from '@dcl/ecs';
|
|
2
2
|
import { Color4 } from '@dcl/ecs/dist/components/generated/pb/decentraland/common/colors.gen';
|
|
3
3
|
/**
|
|
4
4
|
* @public
|
|
@@ -15,8 +15,6 @@ export interface UiBackgroundProps {
|
|
|
15
15
|
uvs?: number[];
|
|
16
16
|
/** AvatarTexture for the background */
|
|
17
17
|
avatarTexture?: UiAvatarTexture;
|
|
18
|
-
/** VideoTexture for the background: the frames of a VideoPlayer on another entity */
|
|
19
|
-
videoTexture?: UiVideoTexture;
|
|
20
18
|
/** Texture for the background */
|
|
21
19
|
texture?: UiTexture;
|
|
22
20
|
}
|
|
@@ -29,15 +27,6 @@ export interface UiAvatarTexture {
|
|
|
29
27
|
wrapMode?: TextureWrapType;
|
|
30
28
|
filterMode?: TextureFilterType;
|
|
31
29
|
}
|
|
32
|
-
/**
|
|
33
|
-
* Video Texture
|
|
34
|
-
* @public
|
|
35
|
-
*/
|
|
36
|
-
export interface UiVideoTexture {
|
|
37
|
-
videoPlayerEntity: Entity;
|
|
38
|
-
wrapMode?: TextureWrapType;
|
|
39
|
-
filterMode?: TextureFilterType;
|
|
40
|
-
}
|
|
41
30
|
/**
|
|
42
31
|
* Texture
|
|
43
32
|
* @public
|
|
@@ -30,14 +30,6 @@ export function getTexture(props) {
|
|
|
30
30
|
}
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
|
-
if (props.videoTexture) {
|
|
34
|
-
return {
|
|
35
|
-
tex: {
|
|
36
|
-
$case: 'videoTexture',
|
|
37
|
-
videoTexture: parseTexture(props.videoTexture)
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
33
|
return undefined;
|
|
42
34
|
}
|
|
43
35
|
function parseTexture(texture) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getAlign, getDisplay, getFlexDirection, getFlexWrap, getJustify, getOverflow, getPointerFilter, getPositionType,
|
|
1
|
+
import { getAlign, getDisplay, getFlexDirection, getFlexWrap, getJustify, getOverflow, getPointerFilter, getPositionType, parseBorderColor, parseBorderRadius, parseBorderWidth, parsePosition, parseSize } from './utils';
|
|
2
2
|
/**
|
|
3
3
|
* @internal
|
|
4
4
|
*/
|
|
@@ -60,7 +60,7 @@ const defaultUiTransform = {
|
|
|
60
60
|
*/
|
|
61
61
|
/* @__PURE__ */
|
|
62
62
|
export function parseUiTransform(props = {}) {
|
|
63
|
-
const { height, minHeight, maxHeight, width, minWidth, maxWidth, alignItems, alignContent, flexWrap, borderRadius, borderWidth, borderColor,
|
|
63
|
+
const { height, minHeight, maxHeight, width, minWidth, maxWidth, alignItems, alignContent, flexWrap, borderRadius, borderWidth, borderColor, ...otherProps } = props;
|
|
64
64
|
return {
|
|
65
65
|
...defaultUiTransform,
|
|
66
66
|
...otherProps,
|
|
@@ -86,8 +86,6 @@ export function parseUiTransform(props = {}) {
|
|
|
86
86
|
...(flexWrap && getFlexWrap(flexWrap)),
|
|
87
87
|
...(borderRadius && parseBorderRadius(borderRadius)),
|
|
88
88
|
...(borderWidth && parseBorderWidth(borderWidth)),
|
|
89
|
-
...(borderColor && parseBorderColor(borderColor))
|
|
90
|
-
...(scrollPosition && getScrollPosition(scrollPosition)),
|
|
91
|
-
...(scrollVisible && getScrollVisible(scrollVisible))
|
|
89
|
+
...(borderColor && parseBorderColor(borderColor))
|
|
92
90
|
};
|
|
93
91
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Color4 } from '@dcl/ecs/dist/components/generated/pb/decentraland/common/colors.gen';
|
|
2
|
-
import { Vector2 } from '@dcl/ecs/dist/components/generated/pb/decentraland/common/vectors.gen';
|
|
3
2
|
import { ScaleUnit } from '../types';
|
|
4
3
|
/**
|
|
5
4
|
* unit value specified. i.e. 1 || '100%' || '1px' || '10vw'
|
|
@@ -132,15 +131,4 @@ export interface UiTransformProps {
|
|
|
132
131
|
opacity?: number;
|
|
133
132
|
/** default 0 */
|
|
134
133
|
zIndex?: number;
|
|
135
|
-
/** A reference id for the element, e.g. as a scrollPosition target or for SetUiFocus. default empty */
|
|
136
|
-
elementId?: string;
|
|
137
|
-
/** Scroll offset when overflow is 'scroll': a position, or the elementId of a child to scroll to. default (0, 0) */
|
|
138
|
-
scrollPosition?: Vector2 | string;
|
|
139
|
-
/** Which scrollbars to show when overflow is 'scroll'. default 'both' */
|
|
140
|
-
scrollVisible?: ScrollVisibleType;
|
|
141
134
|
}
|
|
142
|
-
/**
|
|
143
|
-
* Which scrollbars are shown when the overflow is scrollable
|
|
144
|
-
* @public
|
|
145
|
-
*/
|
|
146
|
-
export type ScrollVisibleType = 'horizontal' | 'vertical' | 'both' | 'hidden';
|
|
@@ -244,24 +244,3 @@ const parsePointerFilter = {
|
|
|
244
244
|
none: 0 /* PointerFilterMode.PFM_NONE */,
|
|
245
245
|
block: 1 /* PointerFilterMode.PFM_BLOCK */
|
|
246
246
|
};
|
|
247
|
-
/**
|
|
248
|
-
* @internal
|
|
249
|
-
*/
|
|
250
|
-
export function getScrollPosition(scrollPosition) {
|
|
251
|
-
if (typeof scrollPosition === 'string') {
|
|
252
|
-
return { scrollPosition: { value: { $case: 'reference', reference: scrollPosition } } };
|
|
253
|
-
}
|
|
254
|
-
return { scrollPosition: { value: { $case: 'position', position: scrollPosition } } };
|
|
255
|
-
}
|
|
256
|
-
const parseScrollVisible = {
|
|
257
|
-
both: 0 /* ShowScrollBar.SSB_BOTH */,
|
|
258
|
-
hidden: 3 /* ShowScrollBar.SSB_HIDDEN */,
|
|
259
|
-
horizontal: 2 /* ShowScrollBar.SSB_ONLY_HORIZONTAL */,
|
|
260
|
-
vertical: 1 /* ShowScrollBar.SSB_ONLY_VERTICAL */
|
|
261
|
-
};
|
|
262
|
-
/**
|
|
263
|
-
* @internal
|
|
264
|
-
*/
|
|
265
|
-
export function getScrollVisible(scrollVisible) {
|
|
266
|
-
return { scrollVisible: parseScrollVisible[scrollVisible] };
|
|
267
|
-
}
|
package/dist/react-ecs.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Entity, IEngine, PointerEventsSystem } from '@dcl/ecs';
|
|
2
2
|
import { ReactEcs } from '../react-ecs';
|
|
3
|
-
export declare function createReconciler(engine: Pick<IEngine, 'getComponent' | 'addEntity' | 'removeEntity' | 'defineComponentFromSchema' | 'getEntitiesWith'>, pointerEvents: PointerEventsSystem
|
|
3
|
+
export declare function createReconciler(engine: Pick<IEngine, 'getComponent' | 'addEntity' | 'removeEntity' | 'defineComponentFromSchema' | 'getEntitiesWith'>, pointerEvents: PointerEventsSystem): {
|
|
4
4
|
update: (component: ReactEcs.JSX.ReactNode) => number;
|
|
5
5
|
getEntities: () => Entity[];
|
|
6
6
|
};
|
package/dist/reconciler/index.js
CHANGED
|
@@ -8,17 +8,11 @@ function getPointerEnum(pointerKey) {
|
|
|
8
8
|
onMouseDown: 1 /* PointerEventType.PET_DOWN */,
|
|
9
9
|
onMouseUp: 0 /* PointerEventType.PET_UP */,
|
|
10
10
|
onMouseEnter: 2 /* PointerEventType.PET_HOVER_ENTER */,
|
|
11
|
-
onMouseLeave: 3 /* PointerEventType.PET_HOVER_LEAVE
|
|
12
|
-
onMouseDrag: 7 /* PointerEventType.PET_DRAG */,
|
|
13
|
-
onMouseDragLocked: 6 /* PointerEventType.PET_DRAG_LOCKED */,
|
|
14
|
-
onMouseDragEnd: 8 /* PointerEventType.PET_DRAG_END */
|
|
11
|
+
onMouseLeave: 3 /* PointerEventType.PET_HOVER_LEAVE */
|
|
15
12
|
};
|
|
16
13
|
return pointers[pointerKey];
|
|
17
14
|
}
|
|
18
|
-
export function createReconciler(engine, pointerEvents
|
|
19
|
-
// When set, every entity this reconciler creates is parented to it -- a UiCanvas on the root
|
|
20
|
-
// entity then renders the tree to a texture instead of the screen.
|
|
21
|
-
rootEntity) {
|
|
15
|
+
export function createReconciler(engine, pointerEvents) {
|
|
22
16
|
// Store all the entities so when we destroy the UI we can also destroy them
|
|
23
17
|
const entities = new Set();
|
|
24
18
|
// Store the onChange callbacks to be runned every time a Result has changed
|
|
@@ -35,7 +29,6 @@ rootEntity) {
|
|
|
35
29
|
const UiInputResult = components.UiInputResult(engine);
|
|
36
30
|
const UiDropdown = components.UiDropdown(engine);
|
|
37
31
|
const UiDropdownResult = components.UiDropdownResult(engine);
|
|
38
|
-
const Transform = components.Transform(engine);
|
|
39
32
|
const UiInputBinding = components.UiInputBinding(engine);
|
|
40
33
|
// Component ID Helper
|
|
41
34
|
const getComponentId = {
|
|
@@ -46,14 +39,17 @@ rootEntity) {
|
|
|
46
39
|
uiDropdown: UiDropdown.componentId,
|
|
47
40
|
uiInputBinding: UiInputBinding.componentId
|
|
48
41
|
};
|
|
49
|
-
function pointerEventCallback(entity, pointerEvent
|
|
42
|
+
function pointerEventCallback(entity, pointerEvent) {
|
|
50
43
|
const callback = clickEvents.get(entity)?.get(pointerEvent);
|
|
51
44
|
if (callback)
|
|
52
|
-
callback(
|
|
45
|
+
callback();
|
|
53
46
|
return;
|
|
54
47
|
}
|
|
55
48
|
function updateTree(instance, props) {
|
|
56
|
-
|
|
49
|
+
// `rightOf` is a required int32 where 0 means "first sibling". A missing left
|
|
50
|
+
// neighbour is written as 0 so the first child of any parent (the canvas root
|
|
51
|
+
// included) serializes the same way as an explicit `rightOf: 0`.
|
|
52
|
+
upsertComponent(instance, { ...props, rightOf: props.rightOf ?? 0 }, 'uiTransform');
|
|
57
53
|
}
|
|
58
54
|
function upsertListener(instance, update) {
|
|
59
55
|
if (update.type === 'delete' || !update.props) {
|
|
@@ -70,15 +66,6 @@ rootEntity) {
|
|
|
70
66
|
else if (update.component === 'onMouseLeave') {
|
|
71
67
|
pointerEvents.removeOnPointerHoverLeave(instance.entity);
|
|
72
68
|
}
|
|
73
|
-
else if (update.component === 'onMouseDrag') {
|
|
74
|
-
pointerEvents.removeOnPointerDrag(instance.entity);
|
|
75
|
-
}
|
|
76
|
-
else if (update.component === 'onMouseDragLocked') {
|
|
77
|
-
pointerEvents.removeOnPointerDragLocked(instance.entity);
|
|
78
|
-
}
|
|
79
|
-
else if (update.component === 'onMouseDragEnd') {
|
|
80
|
-
pointerEvents.removeOnPointerDragEnd(instance.entity);
|
|
81
|
-
}
|
|
82
69
|
return;
|
|
83
70
|
}
|
|
84
71
|
if (update.props) {
|
|
@@ -94,13 +81,7 @@ rootEntity) {
|
|
|
94
81
|
? pointerEvents.onPointerUp
|
|
95
82
|
: update.component === 'onMouseEnter'
|
|
96
83
|
? pointerEvents.onPointerHoverEnter
|
|
97
|
-
: update.component === 'onMouseLeave'
|
|
98
|
-
? pointerEvents.onPointerHoverLeave
|
|
99
|
-
: update.component === 'onMouseDrag'
|
|
100
|
-
? pointerEvents.onPointerDrag
|
|
101
|
-
: update.component === 'onMouseDragLocked'
|
|
102
|
-
? pointerEvents.onPointerDragLocked
|
|
103
|
-
: update.component === 'onMouseDragEnd' && pointerEvents.onPointerDragEnd;
|
|
84
|
+
: update.component === 'onMouseLeave' && pointerEvents.onPointerHoverLeave;
|
|
104
85
|
if (pointerEventSystem) {
|
|
105
86
|
pointerEventSystem({
|
|
106
87
|
entity: instance.entity,
|
|
@@ -110,7 +91,7 @@ rootEntity) {
|
|
|
110
91
|
// This is needed for the renderer to know which entities are clickeables
|
|
111
92
|
showFeedback: true
|
|
112
93
|
}
|
|
113
|
-
}, (
|
|
94
|
+
}, () => pointerEventCallback(instance.entity, pointerEvent));
|
|
114
95
|
}
|
|
115
96
|
}
|
|
116
97
|
}
|
|
@@ -169,8 +150,6 @@ rootEntity) {
|
|
|
169
150
|
}
|
|
170
151
|
}
|
|
171
152
|
function appendChild(parent, child) {
|
|
172
|
-
if (!child || !Object.keys(parent).length)
|
|
173
|
-
return;
|
|
174
153
|
const isReorder = parent._child.find((c) => c.entity === child.entity);
|
|
175
154
|
// If its a reorder its seems that its a mutation of an array with key prop
|
|
176
155
|
// We need to move the child to the end of the array
|
|
@@ -213,6 +192,36 @@ rootEntity) {
|
|
|
213
192
|
}
|
|
214
193
|
removeChildEntity(child);
|
|
215
194
|
}
|
|
195
|
+
function insertBefore(parentInstance, child, beforeChild) {
|
|
196
|
+
// Handle reorder: if child already exists in this parent, remove it from its old position
|
|
197
|
+
// and fix up the old neighbor's rightOf before inserting at the new position.
|
|
198
|
+
const existingIndex = parentInstance._child.findIndex((c) => c.entity === child.entity);
|
|
199
|
+
if (existingIndex !== -1) {
|
|
200
|
+
// If beforeChild.rightOf already points to child, child is already in the correct
|
|
201
|
+
// position in the rightOf chain. Setting child.rightOf = beforeChild.rightOf would
|
|
202
|
+
// produce a self-cycle (child.rightOf = child.entity).
|
|
203
|
+
if (beforeChild.rightOf === child.entity) {
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
const oldNextSibling = parentInstance._child[existingIndex + 1];
|
|
207
|
+
if (oldNextSibling) {
|
|
208
|
+
oldNextSibling.rightOf = child.rightOf;
|
|
209
|
+
updateTree(oldNextSibling, { rightOf: oldNextSibling.rightOf });
|
|
210
|
+
}
|
|
211
|
+
parentInstance._child.splice(existingIndex, 1);
|
|
212
|
+
}
|
|
213
|
+
const beforeChildIndex = parentInstance._child.findIndex((c) => c.entity === beforeChild.entity);
|
|
214
|
+
parentInstance._child = [
|
|
215
|
+
...parentInstance._child.slice(0, beforeChildIndex),
|
|
216
|
+
child,
|
|
217
|
+
...parentInstance._child.slice(beforeChildIndex)
|
|
218
|
+
];
|
|
219
|
+
child.rightOf = beforeChild.rightOf;
|
|
220
|
+
beforeChild.rightOf = child.entity;
|
|
221
|
+
child.parent = parentInstance.entity;
|
|
222
|
+
updateTree(child, { rightOf: child.rightOf, parent: child.parent });
|
|
223
|
+
updateTree(beforeChild, { rightOf: beforeChild.rightOf });
|
|
224
|
+
}
|
|
216
225
|
function updateOnChange(entity, componentId, state) {
|
|
217
226
|
const hasEvent = changeEvents.has(entity);
|
|
218
227
|
const event = changeEvents.get(entity) || changeEvents.set(entity, new Map()).get(entity);
|
|
@@ -239,9 +248,6 @@ rootEntity) {
|
|
|
239
248
|
...noopConfig,
|
|
240
249
|
createInstance(type, props) {
|
|
241
250
|
const entity = engine.addEntity();
|
|
242
|
-
if (rootEntity !== undefined) {
|
|
243
|
-
Transform.createOrReplace(entity, { parent: rootEntity });
|
|
244
|
-
}
|
|
245
251
|
entities.add(entity);
|
|
246
252
|
const instance = {
|
|
247
253
|
entity,
|
|
@@ -270,6 +276,7 @@ rootEntity) {
|
|
|
270
276
|
appendChild,
|
|
271
277
|
appendChildToContainer: appendChild,
|
|
272
278
|
appendInitialChild: appendChild,
|
|
279
|
+
insertInContainerBefore: insertBefore,
|
|
273
280
|
removeChild: removeChild,
|
|
274
281
|
prepareUpdate(_instance, _type, oldProps, newProps) {
|
|
275
282
|
return componentKeys
|
|
@@ -290,42 +297,20 @@ rootEntity) {
|
|
|
290
297
|
}
|
|
291
298
|
}
|
|
292
299
|
},
|
|
293
|
-
insertBefore
|
|
294
|
-
|
|
295
|
-
// and fix up the old neighbor's rightOf before inserting at the new position.
|
|
296
|
-
const existingIndex = parentInstance._child.findIndex((c) => c.entity === child.entity);
|
|
297
|
-
if (existingIndex !== -1) {
|
|
298
|
-
// If beforeChild.rightOf already points to child, child is already in the correct
|
|
299
|
-
// position in the rightOf chain. Setting child.rightOf = beforeChild.rightOf would
|
|
300
|
-
// produce a self-cycle (child.rightOf = child.entity).
|
|
301
|
-
if (beforeChild.rightOf === child.entity) {
|
|
302
|
-
return;
|
|
303
|
-
}
|
|
304
|
-
const oldNextSibling = parentInstance._child[existingIndex + 1];
|
|
305
|
-
if (oldNextSibling) {
|
|
306
|
-
oldNextSibling.rightOf = child.rightOf;
|
|
307
|
-
updateTree(oldNextSibling, { rightOf: oldNextSibling.rightOf });
|
|
308
|
-
}
|
|
309
|
-
parentInstance._child.splice(existingIndex, 1);
|
|
310
|
-
}
|
|
311
|
-
const beforeChildIndex = parentInstance._child.findIndex((c) => c.entity === beforeChild.entity);
|
|
312
|
-
parentInstance._child = [
|
|
313
|
-
...parentInstance._child.slice(0, beforeChildIndex),
|
|
314
|
-
child,
|
|
315
|
-
...parentInstance._child.slice(beforeChildIndex)
|
|
316
|
-
];
|
|
317
|
-
child.rightOf = beforeChild.rightOf;
|
|
318
|
-
beforeChild.rightOf = child.entity;
|
|
319
|
-
child.parent = parentInstance.entity;
|
|
320
|
-
updateTree(child, { rightOf: child.rightOf, parent: child.parent });
|
|
321
|
-
updateTree(beforeChild, { rightOf: beforeChild.rightOf });
|
|
322
|
-
},
|
|
323
|
-
removeChildFromContainer(parenInstance, child) {
|
|
324
|
-
removeChildEntity(child);
|
|
325
|
-
}
|
|
300
|
+
insertBefore,
|
|
301
|
+
removeChildFromContainer: removeChild
|
|
326
302
|
};
|
|
327
303
|
const reconciler = Reconciler(hostConfig);
|
|
328
|
-
|
|
304
|
+
// The container is a real Instance standing in for the canvas root, so
|
|
305
|
+
// top-level elements get the same parent/rightOf bookkeeping as any other
|
|
306
|
+
// sibling group. It is never rendered itself.
|
|
307
|
+
const containerInstance = {
|
|
308
|
+
entity: CANVAS_ROOT_ENTITY,
|
|
309
|
+
_child: [],
|
|
310
|
+
parent: undefined,
|
|
311
|
+
rightOf: undefined
|
|
312
|
+
};
|
|
313
|
+
const root = reconciler.createContainer(containerInstance, 0, null, false, null, '',
|
|
329
314
|
/* istanbul ignore next */
|
|
330
315
|
function () { }, null);
|
|
331
316
|
return {
|
package/dist/reconciler/utils.js
CHANGED
|
@@ -49,9 +49,6 @@ const entityComponent = {
|
|
|
49
49
|
onMouseUp: undefined,
|
|
50
50
|
onMouseEnter: undefined,
|
|
51
51
|
onMouseLeave: undefined,
|
|
52
|
-
onMouseDrag: undefined,
|
|
53
|
-
onMouseDragLocked: undefined,
|
|
54
|
-
onMouseDragEnd: undefined,
|
|
55
52
|
uiInput: undefined,
|
|
56
53
|
uiDropdown: undefined,
|
|
57
54
|
uiInputBinding: undefined
|
package/dist/system.d.ts
CHANGED
|
@@ -27,6 +27,17 @@ export type UiRendererOptions = {
|
|
|
27
27
|
* can use different insets simultaneously.
|
|
28
28
|
*/
|
|
29
29
|
screenInset?: UiScreenInset;
|
|
30
|
+
/**
|
|
31
|
+
* Stacking order of this renderer's UI relative to the other renderers (the main
|
|
32
|
+
* one and every `addUiRenderer`). Higher values render in front. When omitted,
|
|
33
|
+
* renderers stack in the order they first render, later ones on top; among those
|
|
34
|
+
* first rendered in the same tick the main UI goes at the back.
|
|
35
|
+
*
|
|
36
|
+
* It is applied to the renderer's root container entity, so it only orders whole
|
|
37
|
+
* renderers against each other; a renderer zIndex of 0 is interpreted as "unset"
|
|
38
|
+
* (positional order); elements inside a renderer keep their own `zIndex`.
|
|
39
|
+
*/
|
|
40
|
+
zIndex?: number;
|
|
30
41
|
};
|
|
31
42
|
/**
|
|
32
43
|
* @public
|
|
@@ -74,20 +85,6 @@ export interface ReactBasedUiSystem {
|
|
|
74
85
|
* @param entity - The entity whose UI renderer should be removed
|
|
75
86
|
*/
|
|
76
87
|
removeUiRenderer(entity: Entity): void;
|
|
77
|
-
/**
|
|
78
|
-
* Render a UI tree to a texture. The tree is rooted at `entity`, which must carry a UiCanvas
|
|
79
|
-
* describing the texture; the result can be sampled through `TextureUnion.uiTexture`. Replaces
|
|
80
|
-
* any texture renderer already set on the entity, and is torn down when the entity is removed.
|
|
81
|
-
*
|
|
82
|
-
* @param entity - The UiCanvas entity the UI tree hangs from
|
|
83
|
-
* @param ui - The UI component to render
|
|
84
|
-
*/
|
|
85
|
-
setTextureRenderer(entity: Entity, ui: UiComponent): void;
|
|
86
|
-
/**
|
|
87
|
-
* Remove a texture renderer previously set with setTextureRenderer(), destroying its entities.
|
|
88
|
-
* @param entity - The UiCanvas entity the renderer was set on
|
|
89
|
-
*/
|
|
90
|
-
removeTextureRenderer(entity: Entity): void;
|
|
91
88
|
}
|
|
92
89
|
/**
|
|
93
90
|
* @public
|
package/dist/system.js
CHANGED
|
@@ -3,7 +3,7 @@ import * as ecsComponents from '@dcl/ecs/dist/components';
|
|
|
3
3
|
import React from 'react';
|
|
4
4
|
import { createReconciler } from './reconciler';
|
|
5
5
|
import { getUiScaleFactor, resetInteractableArea, resetScreenInsetArea, resetUiScaleFactor, setInteractableArea, setScreenInsetArea, setUiScaleFactor } from './components/utils';
|
|
6
|
-
import { InteractableArea, ScreenInsetArea } from './components';
|
|
6
|
+
import { InteractableArea, ScreenInsetArea, UiEntity } from './components';
|
|
7
7
|
import { isMobile } from './platform';
|
|
8
8
|
/**
|
|
9
9
|
* Default virtual screen size used on mobile platforms, and the size 16:9
|
|
@@ -47,18 +47,14 @@ export function createReactBasedUiSystem(engine, pointerSystem) {
|
|
|
47
47
|
let uiComponent = undefined;
|
|
48
48
|
let mainOptions = undefined;
|
|
49
49
|
const additionalRenderers = new Map();
|
|
50
|
-
//
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
for (const uiEntity of entry.renderer.getEntities()) {
|
|
59
|
-
engine.removeEntity(uiEntity);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
50
|
+
// Renderers are laid out in the order they first render, later ones on top, with
|
|
51
|
+
// the main UI first among those first rendered in the same tick. That is the order
|
|
52
|
+
// their entities were created in before the stacking was explicit, so scenes that
|
|
53
|
+
// set no zIndex keep the stacking they had. A renderer gets its sequence number the
|
|
54
|
+
// first time it renders and keeps it when replaced; the Map iterates in insertion
|
|
55
|
+
// order, so it is already sorted by `order` and only the main UI has to be slotted in.
|
|
56
|
+
let nextOrder = 0;
|
|
57
|
+
let mainOrder = undefined;
|
|
62
58
|
const UiCanvasInformation = ecsComponents.UiCanvasInformation(engine);
|
|
63
59
|
// Unique owner to prevent other UI systems resetting this scale factor.
|
|
64
60
|
const uiScaleFactorOwner = Symbol('react-ecs-ui-scale');
|
|
@@ -131,37 +127,58 @@ export function createReactBasedUiSystem(engine, pointerSystem) {
|
|
|
131
127
|
/**
|
|
132
128
|
* Wraps a renderer's component in a container positioned within the selected
|
|
133
129
|
* screen inset area. `'none'` adds no wrapper, leaving the UI on the whole
|
|
134
|
-
* screen
|
|
130
|
+
* screen, unless a `zIndex` needs a root entity to live on. Applied per
|
|
131
|
+
* renderer, so each renderer can use a different inset.
|
|
135
132
|
*/
|
|
136
|
-
function wrapWithScreenInset(ui,
|
|
133
|
+
function wrapWithScreenInset(ui, options, key) {
|
|
134
|
+
const zIndex = options?.zIndex;
|
|
135
|
+
// Only forward a provided zIndex: `{ zIndex: undefined }` would override the
|
|
136
|
+
// transform parser default and change what is written for every renderer.
|
|
137
|
+
const wrapperProps = zIndex === undefined ? { key } : { key, uiTransform: { zIndex } };
|
|
137
138
|
// An omitted inset is resolved to DEFAULT_SCREEN_INSET ('device') before the
|
|
138
139
|
// switch, so it lands on `case 'device'`. Only an explicit 'none' reaches the
|
|
139
140
|
// `default` clause below — the two are unrelated despite sharing a name.
|
|
140
|
-
switch (
|
|
141
|
+
switch (options?.screenInset ?? DEFAULT_SCREEN_INSET) {
|
|
141
142
|
case 'device':
|
|
142
|
-
return React.createElement(ScreenInsetArea,
|
|
143
|
+
return React.createElement(ScreenInsetArea, wrapperProps, React.createElement(ui));
|
|
143
144
|
case 'interactable':
|
|
144
|
-
return React.createElement(InteractableArea,
|
|
145
|
+
return React.createElement(InteractableArea, wrapperProps, React.createElement(ui));
|
|
145
146
|
// 'none' — the whole screen, no wrapper entity
|
|
146
147
|
default:
|
|
147
|
-
|
|
148
|
+
if (zIndex === undefined)
|
|
149
|
+
return React.createElement(ui, { key });
|
|
150
|
+
// A whole-screen container: absolutely positioned on every edge so it
|
|
151
|
+
// fills the canvas, with the zIndex the renderer is stacked by.
|
|
152
|
+
return React.createElement(UiEntity, {
|
|
153
|
+
key,
|
|
154
|
+
uiTransform: { positionType: 'absolute', position: { top: 0, left: 0, right: 0, bottom: 0 }, zIndex }
|
|
155
|
+
}, React.createElement(ui));
|
|
148
156
|
}
|
|
149
157
|
}
|
|
150
158
|
function ReactBasedUiSystem() {
|
|
151
159
|
const components = [];
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
}
|
|
160
|
+
if (uiComponent !== undefined && mainOrder === undefined)
|
|
161
|
+
mainOrder = nextOrder++;
|
|
162
|
+
let mainPushed = uiComponent === undefined;
|
|
156
163
|
const entitiesToRemove = [];
|
|
157
164
|
for (const [entity, entry] of additionalRenderers) {
|
|
158
165
|
// Check for entity-based cleanup
|
|
159
166
|
if (engine.getEntityState(entity) === EntityState.Removed) {
|
|
160
167
|
entitiesToRemove.push(entity);
|
|
168
|
+
continue;
|
|
161
169
|
}
|
|
162
|
-
|
|
163
|
-
|
|
170
|
+
if (entry.order === undefined)
|
|
171
|
+
entry.order = nextOrder++;
|
|
172
|
+
// The main UI goes right before the first renderer that rendered after it.
|
|
173
|
+
if (!mainPushed && mainOrder < entry.order) {
|
|
174
|
+
components.push(wrapWithScreenInset(uiComponent, mainOptions, '__main__'));
|
|
175
|
+
mainPushed = true;
|
|
164
176
|
}
|
|
177
|
+
components.push(wrapWithScreenInset(entry.ui, entry.options, `__entity_${entity}__`));
|
|
178
|
+
}
|
|
179
|
+
// Main UI first rendered after every other renderer (or alone): it goes on top.
|
|
180
|
+
if (!mainPushed) {
|
|
181
|
+
components.push(wrapWithScreenInset(uiComponent, mainOptions, '__main__'));
|
|
165
182
|
}
|
|
166
183
|
// Entity-based cleanup
|
|
167
184
|
for (const entity of entitiesToRemove) {
|
|
@@ -174,14 +191,6 @@ export function createReactBasedUiSystem(engine, pointerSystem) {
|
|
|
174
191
|
else {
|
|
175
192
|
renderer.update(null);
|
|
176
193
|
}
|
|
177
|
-
for (const [entity, entry] of textureRenderers) {
|
|
178
|
-
if (engine.getEntityState(entity) === EntityState.Removed) {
|
|
179
|
-
destroyTextureRenderer(entity);
|
|
180
|
-
}
|
|
181
|
-
else {
|
|
182
|
-
entry.renderer.update(React.createElement(entry.ui));
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
194
|
}
|
|
186
195
|
function UiScaleSystem() {
|
|
187
196
|
const canvasInfo = UiCanvasInformation.getOrNull(engine.RootEntity);
|
|
@@ -239,26 +248,17 @@ export function createReactBasedUiSystem(engine, pointerSystem) {
|
|
|
239
248
|
for (const entity of renderer.getEntities()) {
|
|
240
249
|
engine.removeEntity(entity);
|
|
241
250
|
}
|
|
242
|
-
for (const entity of textureRenderers.keys()) {
|
|
243
|
-
destroyTextureRenderer(entity);
|
|
244
|
-
}
|
|
245
251
|
},
|
|
246
252
|
setUiRenderer(ui, options) {
|
|
247
253
|
uiComponent = ui;
|
|
248
254
|
mainOptions = options;
|
|
249
255
|
},
|
|
250
256
|
addUiRenderer(entity, ui, options) {
|
|
251
|
-
|
|
257
|
+
// A replacement keeps its place in the stacking order.
|
|
258
|
+
additionalRenderers.set(entity, { ui, options, order: additionalRenderers.get(entity)?.order });
|
|
252
259
|
},
|
|
253
260
|
removeUiRenderer(entity) {
|
|
254
261
|
additionalRenderers.delete(entity);
|
|
255
|
-
},
|
|
256
|
-
setTextureRenderer(entity, ui) {
|
|
257
|
-
destroyTextureRenderer(entity);
|
|
258
|
-
textureRenderers.set(entity, { renderer: createReconciler(engine, pointerSystem, entity), ui });
|
|
259
|
-
},
|
|
260
|
-
removeTextureRenderer(entity) {
|
|
261
|
-
destroyTextureRenderer(entity);
|
|
262
262
|
}
|
|
263
263
|
};
|
|
264
264
|
}
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dcl/react-ecs",
|
|
3
3
|
"description": "Decentraland ECS",
|
|
4
|
-
"version": "7.29.1-
|
|
4
|
+
"version": "7.29.1-35978346337.commit-823107b",
|
|
5
5
|
"author": "DCL",
|
|
6
6
|
"bugs": "https://github.com/decentraland/js-sdk-toolchain/issues",
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@dcl/ecs": "7.29.1-
|
|
8
|
+
"@dcl/ecs": "7.29.1-35978346337.commit-823107b",
|
|
9
9
|
"react": "^18.2.0",
|
|
10
10
|
"react-reconciler": "^0.29.0"
|
|
11
11
|
},
|
|
@@ -40,5 +40,5 @@
|
|
|
40
40
|
"tsconfig": "./tsconfig.json"
|
|
41
41
|
},
|
|
42
42
|
"types": "./dist/index.d.ts",
|
|
43
|
-
"commit": "
|
|
43
|
+
"commit": "823107b9c97923a982ab4005453f7128e111aada"
|
|
44
44
|
}
|