@dcl/react-ecs 7.7.6 → 7.7.7-13655406288.commit-7b2a671
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 +1 -131
- package/dist/reconciler/index.js +28 -15
- package/dist/system.d.ts +0 -5
- package/dist/system.js +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,131 +1 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
React bindings for Decentraland's Entity Component System (ECS), providing a declarative way to build UIs in Decentraland scenes using React's component model and JSX syntax.
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- **Flexbox-based Layout**: Implements a subset of CSS Flexbox for powerful and intuitive UI layouts
|
|
8
|
-
- **React Components**: Familiar React-like component API for building UIs
|
|
9
|
-
- **Type Safety**: Full TypeScript support with proper type definitions
|
|
10
|
-
- **Event Handling**: Support for mouse events and user interactions
|
|
11
|
-
- **Performance**: Optimized reconciliation for minimal runtime overhead
|
|
12
|
-
- **Theme Support**: Built-in light and dark theme system with context-based switching
|
|
13
|
-
|
|
14
|
-
## Component Guidelines
|
|
15
|
-
|
|
16
|
-
All components in @dcl/react-ecs must:
|
|
17
|
-
|
|
18
|
-
- Return JSX.Elements for consistency and composability
|
|
19
|
-
- Support theme integration through context
|
|
20
|
-
- Be reusable and composable with other components
|
|
21
|
-
|
|
22
|
-
## Installation
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
npm install @dcl/react-ecs
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## Basic Usage
|
|
29
|
-
|
|
30
|
-
```tsx
|
|
31
|
-
import { ReactEcs, UiEntity, Label, Button } from '@dcl/react-ecs'
|
|
32
|
-
|
|
33
|
-
export function MyUI() {
|
|
34
|
-
return (
|
|
35
|
-
<UiEntity
|
|
36
|
-
uiTransform={{
|
|
37
|
-
width: 300,
|
|
38
|
-
height: 100,
|
|
39
|
-
display: 'flex',
|
|
40
|
-
justifyContent: 'center',
|
|
41
|
-
alignItems: 'center'
|
|
42
|
-
}}
|
|
43
|
-
>
|
|
44
|
-
<Label value="Hello Decentraland!" />
|
|
45
|
-
<Button value="Click Me!" onMouseDown={() => console.log('clicked!')} />
|
|
46
|
-
</UiEntity>
|
|
47
|
-
)
|
|
48
|
-
}
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
## Theme System
|
|
52
|
-
|
|
53
|
-
The package includes a theme system for consistent UI styling:
|
|
54
|
-
|
|
55
|
-
```tsx
|
|
56
|
-
import { ReactEcs, ThemeProvider, Button } from '@dcl/react-ecs'
|
|
57
|
-
|
|
58
|
-
// Wrap your UI with ThemeProvider
|
|
59
|
-
export function MyUI() {
|
|
60
|
-
return (
|
|
61
|
-
<ThemeProvider>
|
|
62
|
-
<Button value="Theme-Aware Button" />
|
|
63
|
-
</ThemeProvider>
|
|
64
|
-
)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Use themes in custom components
|
|
68
|
-
function CustomComponent() {
|
|
69
|
-
const { theme, toggleTheme } = React.useContext(ThemeContext)
|
|
70
|
-
|
|
71
|
-
return (
|
|
72
|
-
<UiEntity
|
|
73
|
-
uiBackground={{
|
|
74
|
-
color: theme === 'light' ? '#FFFFFF' : '#000000'
|
|
75
|
-
}}
|
|
76
|
-
onMouseDown={toggleTheme}
|
|
77
|
-
/>
|
|
78
|
-
)
|
|
79
|
-
}
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
## Components
|
|
83
|
-
|
|
84
|
-
### Core Components
|
|
85
|
-
|
|
86
|
-
- **UiEntity**: Base component for UI elements
|
|
87
|
-
- **Label**: Text display component
|
|
88
|
-
- **Button**: Interactive button component
|
|
89
|
-
- **Input**: Text input field
|
|
90
|
-
- **Dropdown**: Selection dropdown menu
|
|
91
|
-
|
|
92
|
-
### Layout System
|
|
93
|
-
|
|
94
|
-
The layout system is based on Flexbox and supports the following properties:
|
|
95
|
-
|
|
96
|
-
- `display: 'flex'`
|
|
97
|
-
- `flexDirection: 'row' | 'column'`
|
|
98
|
-
- `justifyContent: 'flex-start' | 'center' | 'flex-end' | 'space-between' | 'space-around'`
|
|
99
|
-
- `alignItems: 'flex-start' | 'center' | 'flex-end' | 'stretch'`
|
|
100
|
-
- `width`, `height`
|
|
101
|
-
- `margin`, `padding`
|
|
102
|
-
- `positionType: 'absolute' | 'relative'`
|
|
103
|
-
|
|
104
|
-
## Event Handling
|
|
105
|
-
|
|
106
|
-
Components support the following mouse events:
|
|
107
|
-
|
|
108
|
-
```tsx
|
|
109
|
-
<Button onMouseDown={() => {}} onMouseUp={() => {}} onMouseEnter={() => {}} onMouseLeave={() => {}} />
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
## Technical Details
|
|
113
|
-
|
|
114
|
-
The package implements a custom React reconciler that bridges React's component model with Decentraland's ECS. It:
|
|
115
|
-
|
|
116
|
-
1. Translates JSX into ECS entities and components
|
|
117
|
-
2. Manages component lifecycle and updates
|
|
118
|
-
3. Handles event delegation and bubbling
|
|
119
|
-
4. Provides a performant update mechanism
|
|
120
|
-
|
|
121
|
-
## Related Documentation
|
|
122
|
-
|
|
123
|
-
For more details about the UI system architecture and design decisions:
|
|
124
|
-
|
|
125
|
-
- [ADR-124: Implementing Flexbox-based UI](https://adr.decentraland.org/adr/ADR-124)
|
|
126
|
-
- [ADR-125: User Interface Components](https://adr.decentraland.org/adr/ADR-125)
|
|
127
|
-
- [ADR-237: SDK 7 Custom UI Components](https://adr.decentraland.org/adr/ADR-237)
|
|
128
|
-
|
|
129
|
-
## License
|
|
130
|
-
|
|
131
|
-
Apache 2.0
|
|
1
|
+
# React ECS
|
package/dist/reconciler/index.js
CHANGED
|
@@ -124,7 +124,6 @@ export function createReconciler(engine, pointerEvents) {
|
|
|
124
124
|
}
|
|
125
125
|
function removeChildEntity(instance) {
|
|
126
126
|
changeEvents.delete(instance.entity);
|
|
127
|
-
clickEvents.delete(instance.entity);
|
|
128
127
|
engine.removeEntity(instance.entity);
|
|
129
128
|
for (const child of instance._child) {
|
|
130
129
|
removeChildEntity(child);
|
|
@@ -171,23 +170,13 @@ export function createReconciler(engine, pointerEvents) {
|
|
|
171
170
|
removeChildEntity(child);
|
|
172
171
|
}
|
|
173
172
|
function updateOnChange(entity, componentId, state) {
|
|
174
|
-
const hasEvent = changeEvents.has(entity);
|
|
175
173
|
const event = changeEvents.get(entity) || changeEvents.set(entity, new Map()).get(entity);
|
|
174
|
+
const oldState = event.get(componentId);
|
|
176
175
|
const onChangeCallback = state?.onChangeCallback;
|
|
177
176
|
const onSubmitCallback = state?.onSubmitCallback;
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
const resultComponentId = componentId === UiDropdown.componentId ? UiDropdownResult.componentId : UiInputResult.componentId;
|
|
182
|
-
engine.getComponent(resultComponentId).onChange(entity, (value) => {
|
|
183
|
-
if (value?.isSubmit) {
|
|
184
|
-
const onSubmit = changeEvents.get(entity)?.get(componentId)?.onSubmitCallback;
|
|
185
|
-
onSubmit && onSubmit(value?.value);
|
|
186
|
-
}
|
|
187
|
-
const onChange = changeEvents.get(entity)?.get(componentId)?.onChangeCallback;
|
|
188
|
-
onChange && onChange(value?.value);
|
|
189
|
-
});
|
|
190
|
-
}
|
|
177
|
+
const value = state?.value ?? oldState?.value;
|
|
178
|
+
const isSubmit = state?.isSubmit ?? oldState?.isSubmit;
|
|
179
|
+
event.set(componentId, { onChangeCallback, onSubmitCallback, value, isSubmit });
|
|
191
180
|
}
|
|
192
181
|
const hostConfig = {
|
|
193
182
|
...noopConfig,
|
|
@@ -262,8 +251,32 @@ export function createReconciler(engine, pointerEvents) {
|
|
|
262
251
|
const root = reconciler.createContainer({}, 0, null, false, null, '',
|
|
263
252
|
/* istanbul ignore next */
|
|
264
253
|
function () { }, null);
|
|
254
|
+
// Maybe this could be something similar to Input system, but since we
|
|
255
|
+
// are going to use this only here, i prefer to scope it here.
|
|
256
|
+
function handleOnChange(componentId, resultComponent) {
|
|
257
|
+
for (const [entity, Result] of engine.getEntitiesWith(resultComponent)) {
|
|
258
|
+
const entityState = changeEvents.get(entity)?.get(componentId);
|
|
259
|
+
const isSubmit = !!Result.isSubmit;
|
|
260
|
+
if (entityState?.onChangeCallback && Result.value !== entityState.value) {
|
|
261
|
+
entityState.onChangeCallback(Result.value);
|
|
262
|
+
}
|
|
263
|
+
if (entityState?.onSubmitCallback && isSubmit && !entityState.isSubmit) {
|
|
264
|
+
entityState.onSubmitCallback(Result.value);
|
|
265
|
+
}
|
|
266
|
+
updateOnChange(entity, componentId, {
|
|
267
|
+
onChangeCallback: entityState?.onChangeCallback,
|
|
268
|
+
onSubmitCallback: entityState?.onSubmitCallback,
|
|
269
|
+
value: Result.value,
|
|
270
|
+
isSubmit
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
}
|
|
265
274
|
return {
|
|
266
275
|
update: function (component) {
|
|
276
|
+
if (changeEvents.size) {
|
|
277
|
+
handleOnChange(UiInput.componentId, UiInputResult);
|
|
278
|
+
handleOnChange(UiDropdown.componentId, UiDropdownResult);
|
|
279
|
+
}
|
|
267
280
|
return reconciler.updateContainer(component, root, null);
|
|
268
281
|
},
|
|
269
282
|
getEntities: () => Array.from(entities)
|
package/dist/system.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { IEngine, PointerEventsSystem } from '@dcl/ecs';
|
|
2
1
|
import type { ReactEcs } from './react-ecs';
|
|
3
2
|
/**
|
|
4
3
|
* @public
|
|
@@ -11,7 +10,3 @@ export interface ReactBasedUiSystem {
|
|
|
11
10
|
destroy(): void;
|
|
12
11
|
setUiRenderer(ui: UiComponent): void;
|
|
13
12
|
}
|
|
14
|
-
/**
|
|
15
|
-
* @public
|
|
16
|
-
*/
|
|
17
|
-
export declare function createReactBasedUiSystem(engine: IEngine, pointerSystem: PointerEventsSystem): ReactBasedUiSystem;
|
package/dist/system.js
CHANGED
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dcl/react-ecs",
|
|
3
3
|
"description": "Decentraland ECS",
|
|
4
|
-
"version": "7.7.
|
|
4
|
+
"version": "7.7.7-13655406288.commit-7b2a671",
|
|
5
5
|
"author": "DCL",
|
|
6
6
|
"bugs": "https://github.com/decentraland/js-sdk-toolchain/issues",
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@dcl/ecs": "7.7.
|
|
8
|
+
"@dcl/ecs": "7.7.7-13655406288.commit-7b2a671",
|
|
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": "7b2a6716919850a45b2f84abc9d05a1500ad6af3"
|
|
44
44
|
}
|