@dcl/react-ecs 0.0.1-3548419522.commit-ddcf4b7 → 7.0.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.
@@ -0,0 +1,29 @@
1
+ import { EventSystemCallback } from '@dcl/ecs';
2
+ import { PBUiBackground, PBUiText, PBUiTransform } from '@dcl/ecs/dist/components';
3
+ import { CommonProps } from './components/types';
4
+ export declare type EcsElements = {
5
+ entity: Partial<Omit<EntityComponents, 'onClick'> & CommonProps>;
6
+ };
7
+ export declare type EntityComponents = {
8
+ uiTransform: PBUiTransform;
9
+ uiText: PBUiText;
10
+ uiBackground: PBUiBackground;
11
+ onClick: EventSystemCallback;
12
+ };
13
+ export declare namespace JSX {
14
+ interface Element {
15
+ }
16
+ type IntrinsicElements = EcsElements;
17
+ interface Component {
18
+ }
19
+ }
20
+ export declare namespace ReactEcs {
21
+ namespace JSX {
22
+ interface Element {
23
+ }
24
+ type IntrinsicElements = EcsElements;
25
+ interface Component {
26
+ }
27
+ }
28
+ const createElement: any;
29
+ }
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+ export var ReactEcs;
3
+ (function (ReactEcs) {
4
+ ReactEcs.createElement = React.createElement;
5
+ })(ReactEcs || (ReactEcs = {}));
@@ -0,0 +1,6 @@
1
+ import { IEngine, PointerEventsSystem } from '@dcl/ecs';
2
+ import { JSX } from '../react-ecs';
3
+ export declare function createReconciler(engine: Pick<IEngine, 'getComponent' | 'addEntity' | 'removeEntity' | 'defineComponentFromSchema'>, pointerEvents: PointerEventsSystem): {
4
+ update: (component: JSX.Element) => number;
5
+ getEntities: () => unknown[];
6
+ };
@@ -0,0 +1,198 @@
1
+ import * as components from '@dcl/ecs/dist/components';
2
+ import Reconciler from 'react-reconciler';
3
+ import { isListener } from '../components';
4
+ import { CANVAS_ROOT_ENTITY } from '../components/uiTransform';
5
+ import { componentKeys, isEqual, isNotUndefined, noopConfig } from './utils';
6
+ // TODO: export InputAction types.
7
+ const IA_POINTER = 0;
8
+ function propsChanged(component, prevProps, nextProps) {
9
+ if (prevProps && !nextProps) {
10
+ return { type: 'delete', component };
11
+ }
12
+ if (!nextProps) {
13
+ return;
14
+ }
15
+ if (!prevProps && nextProps) {
16
+ return { type: 'add', props: nextProps, component };
17
+ }
18
+ if (isListener(component)) {
19
+ if (!isEqual(prevProps, nextProps)) {
20
+ return { type: 'put', component, props: nextProps };
21
+ }
22
+ }
23
+ const changes = {};
24
+ // TODO: array and object types. For now only primitives
25
+ for (const k in prevProps) {
26
+ const propKey = k;
27
+ if (!isEqual(prevProps[propKey], nextProps[propKey])) {
28
+ changes[propKey] = nextProps[propKey];
29
+ }
30
+ }
31
+ if (!Object.keys(changes).length) {
32
+ return;
33
+ }
34
+ return { type: 'put', props: changes, component };
35
+ }
36
+ export function createReconciler(engine, pointerEvents) {
37
+ const entities = new Set();
38
+ const UiTransform = components.UiTransform(engine);
39
+ const UiText = components.UiText(engine);
40
+ const UiBackground = components.UiBackground(engine);
41
+ const getComponentId = {
42
+ uiTransform: UiTransform._id,
43
+ uiText: UiText._id,
44
+ uiBackground: UiBackground._id
45
+ };
46
+ function updateTree(instance, props) {
47
+ upsertComponent(instance, props, 'uiTransform');
48
+ }
49
+ function upsertListener(instance, update) {
50
+ // TODO: This handles only onClick listener for the moment
51
+ if (update.type === 'delete' || !update.props) {
52
+ pointerEvents.removeOnPointerDown(instance.entity);
53
+ return;
54
+ }
55
+ if (update.props) {
56
+ pointerEvents.onPointerDown(instance.entity, update.props, {
57
+ button: IA_POINTER,
58
+ hoverText: ''
59
+ });
60
+ }
61
+ }
62
+ function removeComponent(instance, component) {
63
+ const Component = engine.getComponent(getComponentId[component]);
64
+ Component.deleteFrom(instance.entity);
65
+ }
66
+ function upsertComponent(instance, props, componentName) {
67
+ const componentId = getComponentId[componentName];
68
+ const Component = engine.getComponent(componentId);
69
+ const component = Component.getMutableOrNull(instance.entity) ||
70
+ Component.create(instance.entity);
71
+ for (const key in props) {
72
+ const keyProp = key;
73
+ component[keyProp] = props[keyProp];
74
+ }
75
+ }
76
+ function removeChildEntity(instance) {
77
+ engine.removeEntity(instance.entity);
78
+ for (const child of instance._child) {
79
+ removeChildEntity(child);
80
+ }
81
+ }
82
+ function appendChild(parent, child) {
83
+ if (!child || !Object.keys(parent).length)
84
+ return;
85
+ const isReorder = parent._child.find((c) => c.entity === child.entity);
86
+ // If its a reorder its seems that its a mutation of an array with key prop
87
+ // We need to move the child to the end of the array
88
+ // And update the order of the parent_.child array
89
+ // child.rightOf => Latest entity of the array
90
+ // childThatWasAtRightOfEntity = childEntity.rightOf
91
+ if (isReorder) {
92
+ const rightOfChild = parent._child.find((c) => c.rightOf === child.entity);
93
+ if (rightOfChild) {
94
+ rightOfChild.rightOf = child.rightOf;
95
+ // Re-order parent._child array
96
+ parent._child = parent._child.filter((c) => c.entity !== child.entity);
97
+ parent._child.push(child);
98
+ updateTree(rightOfChild, { rightOf: rightOfChild.rightOf });
99
+ }
100
+ // Its a re-order. We are the last element, so we need to fetch the element before us.
101
+ child.rightOf = parent._child[parent._child.length - 2]?.entity;
102
+ }
103
+ else {
104
+ // Its an append. Put it at the end
105
+ child.rightOf = parent._child[parent._child.length - 1]?.entity;
106
+ parent._child.push(child);
107
+ }
108
+ child.parent = parent.entity;
109
+ updateTree(child, { rightOf: child.rightOf, parent: parent.entity });
110
+ }
111
+ function removeChild(parentInstance, child) {
112
+ const childIndex = parentInstance._child.findIndex((c) => c.entity === child.entity);
113
+ const childToModify = parentInstance._child[childIndex + 1];
114
+ if (childToModify) {
115
+ childToModify.rightOf = child.rightOf;
116
+ updateTree(childToModify, { rightOf: child.rightOf });
117
+ }
118
+ // Mutate 💀
119
+ parentInstance._child.splice(childIndex, 1);
120
+ removeChildEntity(child);
121
+ }
122
+ const hostConfig = {
123
+ ...noopConfig,
124
+ createInstance(type, props) {
125
+ const entity = engine.addEntity();
126
+ entities.add(entity);
127
+ const instance = {
128
+ entity,
129
+ _child: [],
130
+ parent: CANVAS_ROOT_ENTITY,
131
+ rightOf: undefined
132
+ };
133
+ for (const key in props) {
134
+ const keyTyped = key;
135
+ if (keyTyped === 'children' || keyTyped === 'key') {
136
+ continue;
137
+ }
138
+ if (isListener(keyTyped)) {
139
+ upsertListener(instance, {
140
+ type: 'add',
141
+ props: props[keyTyped],
142
+ component: keyTyped
143
+ });
144
+ }
145
+ else {
146
+ upsertComponent(instance, props[keyTyped], keyTyped);
147
+ }
148
+ }
149
+ return instance;
150
+ },
151
+ appendChild,
152
+ appendChildToContainer: appendChild,
153
+ appendInitialChild: appendChild,
154
+ removeChild: removeChild,
155
+ prepareUpdate(_instance, _type, oldProps, newProps) {
156
+ return componentKeys
157
+ .map((component) => propsChanged(component, oldProps[component], newProps[component]))
158
+ .filter(isNotUndefined);
159
+ },
160
+ commitUpdate(instance, updatePayload, _type, _prevPropsProps, _nextProps, _internalHandle) {
161
+ for (const update of updatePayload) {
162
+ if (isListener(update.component)) {
163
+ upsertListener(instance, update);
164
+ continue;
165
+ }
166
+ if (update.type === 'delete') {
167
+ removeComponent(instance, update.component);
168
+ }
169
+ else {
170
+ upsertComponent(instance, update.props, update.component);
171
+ }
172
+ }
173
+ },
174
+ insertBefore(parentInstance, child, beforeChild) {
175
+ const beforeChildIndex = parentInstance._child.findIndex((c) => c.entity === beforeChild.entity);
176
+ parentInstance._child = [
177
+ ...parentInstance._child.slice(0, beforeChildIndex),
178
+ child,
179
+ ...parentInstance._child.slice(beforeChildIndex)
180
+ ];
181
+ child.rightOf = beforeChild.rightOf;
182
+ beforeChild.rightOf = child.entity;
183
+ child.parent = parentInstance.entity;
184
+ updateTree(child, { rightOf: child.rightOf, parent: child.parent });
185
+ updateTree(beforeChild, { rightOf: beforeChild.rightOf });
186
+ }
187
+ };
188
+ const reconciler = Reconciler(hostConfig);
189
+ const root = reconciler.createContainer({}, 0, null, false, null, '',
190
+ /* istanbul ignore next */
191
+ function () { }, null);
192
+ return {
193
+ update: function (component) {
194
+ return reconciler.updateContainer(component, root, null);
195
+ },
196
+ getEntities: () => Array.from(entities)
197
+ };
198
+ }
@@ -0,0 +1,28 @@
1
+ import type { Entity } from '@dcl/ecs';
2
+ import { CommonProps, Listeners } from '../components';
3
+ import type { EntityComponents } from '../react-ecs';
4
+ export declare type EngineComponents = Omit<EntityComponents, keyof Listeners>;
5
+ export declare type OpaqueHandle = any;
6
+ export declare type Type = 'entity';
7
+ export declare type Props = EntityComponents & CommonProps;
8
+ export declare type Container = Document | Instance | any;
9
+ export declare type Instance = {
10
+ entity: Entity;
11
+ parent?: Entity;
12
+ rightOf?: Entity;
13
+ _child: Instance[];
14
+ };
15
+ export declare type TextInstance = never;
16
+ export declare type SuspenseInstance = never;
17
+ export declare type HydratableInstance = never;
18
+ export declare type PublicInstance = Instance;
19
+ export declare type HostContext = null;
20
+ export declare type UpdatePayload = Changes[];
21
+ export declare type _ChildSet = never;
22
+ export declare type TimeoutHandle = any;
23
+ export declare type NoTimeout = number;
24
+ export declare type Changes<K extends keyof EntityComponents = keyof EntityComponents> = {
25
+ type: 'delete' | 'add' | 'put';
26
+ props?: Partial<EntityComponents[K]>;
27
+ component: K;
28
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,40 @@
1
+ import { EntityComponents } from '../react-ecs';
2
+ import { Container, HostContext, Instance, OpaqueHandle, Props, PublicInstance, SuspenseInstance, TextInstance, TimeoutHandle, Type } from './types';
3
+ export declare const componentKeys: (keyof EntityComponents)[];
4
+ export declare function isEqual<T = unknown>(val1: T, val2: T): boolean;
5
+ export declare const isNotUndefined: <T>(val: T | undefined) => val is T;
6
+ export declare const noopConfig: {
7
+ supportsMutation: boolean;
8
+ supportsPersistence: boolean;
9
+ noTimeout: number;
10
+ isPrimaryRenderer: boolean;
11
+ supportsHydration: boolean;
12
+ insertInContainerBefore(_container: Container, _child: Instance | TextInstance, _beforeChild: Instance | TextInstance | SuspenseInstance): void;
13
+ detachDeletedInstance(_node: Instance): void;
14
+ hideInstance(_instance: Instance): void;
15
+ hideTextInstance(_textInstance: TextInstance): void;
16
+ unhideInstance(_instance: Instance, _props: Props): void;
17
+ unhideTextInstance(_textInstance: TextInstance, _text: string): void;
18
+ clearContainer(_container: Container): void;
19
+ getCurrentEventPriority(): number;
20
+ getInstanceFromNode(_node: Instance): null | undefined;
21
+ beforeActiveInstanceBlur(): void;
22
+ afterActiveInstanceBlur(): void;
23
+ prepareScopeUpdate(): void;
24
+ getInstanceFromScope(): null;
25
+ removeChildFromContainer(): void;
26
+ commitMount(_instance: Instance, _type: Type, _props: Props, _internalInstanceHandle: OpaqueHandle): void;
27
+ resetTextContent(_instance: Instance): void;
28
+ commitTextUpdate(_textInstance: TextInstance, _oldText: string, _newText: string): void;
29
+ prepareForCommit(_containerInfo: Container): Record<string, any> | null;
30
+ resetAfterCommit(_containerInfo: Container): void;
31
+ preparePortalMount(_containerInfo: Container): void;
32
+ createTextInstance(_text: string, _rootContainer: Container, _hostContext: HostContext, _internalHandle: OpaqueHandle): TextInstance;
33
+ scheduleTimeout(_fn: any, _delay?: number): TimeoutHandle;
34
+ cancelTimeout(_id: TimeoutHandle): void;
35
+ shouldSetTextContent(_type: Type, _props: Props): boolean;
36
+ getRootHostContext(_rootContainer: Container): HostContext | null;
37
+ getChildHostContext(_parentHostContext: HostContext, _type: Type, _rootContainer: Container): HostContext;
38
+ getPublicInstance(instance: Instance): PublicInstance;
39
+ finalizeInitialChildren(_instance: Instance, _type: Type, _props: Props, _rootContainer: Container, _hostContext: HostContext): boolean;
40
+ };
@@ -0,0 +1,127 @@
1
+ const entityComponent = {
2
+ uiText: undefined,
3
+ uiBackground: undefined,
4
+ uiTransform: undefined,
5
+ onClick: undefined
6
+ };
7
+ export const componentKeys = Object.keys(entityComponent);
8
+ export function isEqual(val1, val2) {
9
+ if (!val1 && !val2) {
10
+ return true;
11
+ }
12
+ if (!val1 || !val2) {
13
+ return val1 === val2;
14
+ }
15
+ if (val1 === val2) {
16
+ return true;
17
+ }
18
+ if (typeof val1 !== typeof val2) {
19
+ return false;
20
+ }
21
+ if (typeof val1 !== 'object') {
22
+ return val1 === val2;
23
+ }
24
+ if (Array.isArray(val1) && Array.isArray(val2)) {
25
+ if (val1.length !== val2.length) {
26
+ return false;
27
+ }
28
+ }
29
+ if (Object.keys(val1).length !== Object.keys(val2).length) {
30
+ return false;
31
+ }
32
+ if (JSON.stringify(val1) === JSON.stringify(val2)) {
33
+ return true;
34
+ }
35
+ for (const key in val1) {
36
+ if (!isEqual(val1[key], val2[key])) {
37
+ return false;
38
+ }
39
+ }
40
+ /* istanbul ignore next */
41
+ return true;
42
+ }
43
+ export const isNotUndefined = (val) => {
44
+ return !!val;
45
+ };
46
+ export const noopConfig = {
47
+ supportsMutation: true,
48
+ supportsPersistence: false,
49
+ noTimeout: -1,
50
+ isPrimaryRenderer: true,
51
+ supportsHydration: false,
52
+ /* istanbul ignore next */
53
+ insertInContainerBefore(_container, _child, _beforeChild) { },
54
+ detachDeletedInstance(_node) { },
55
+ /* istanbul ignore next */
56
+ hideInstance(_instance) { },
57
+ /* istanbul ignore next */
58
+ hideTextInstance(_textInstance) { },
59
+ /* istanbul ignore next */
60
+ unhideInstance(_instance, _props) { },
61
+ /* istanbul ignore next */
62
+ unhideTextInstance(_textInstance, _text) { },
63
+ /* istanbul ignore next */
64
+ clearContainer(_container) { },
65
+ /* istanbul ignore next */
66
+ getCurrentEventPriority() {
67
+ /* istanbul ignore next */
68
+ return 0;
69
+ },
70
+ /* istanbul ignore next */
71
+ getInstanceFromNode(_node) {
72
+ /* istanbul ignore next */
73
+ return null;
74
+ },
75
+ /* istanbul ignore next */
76
+ beforeActiveInstanceBlur() { },
77
+ /* istanbul ignore next */
78
+ afterActiveInstanceBlur() { },
79
+ /* istanbul ignore next */
80
+ prepareScopeUpdate() { },
81
+ /* istanbul ignore next */
82
+ getInstanceFromScope() {
83
+ /* istanbul ignore next */
84
+ return null;
85
+ },
86
+ /* istanbul ignore next */
87
+ removeChildFromContainer() { },
88
+ /* istanbul ignore next */
89
+ commitMount(_instance, _type, _props, _internalInstanceHandle) { },
90
+ /* istanbul ignore next */
91
+ resetTextContent(_instance) { },
92
+ /* istanbul ignore next */
93
+ commitTextUpdate(_textInstance, _oldText, _newText) { },
94
+ prepareForCommit(_containerInfo) {
95
+ return null;
96
+ },
97
+ resetAfterCommit(_containerInfo) { },
98
+ /* istanbul ignore next */
99
+ preparePortalMount(_containerInfo) { },
100
+ /* istanbul ignore next */
101
+ createTextInstance(_text, _rootContainer, _hostContext, _internalHandle) {
102
+ /* istanbul ignore next */
103
+ return {};
104
+ },
105
+ /* istanbul ignore next */
106
+ scheduleTimeout(_fn, _delay) { },
107
+ /* istanbul ignore next */
108
+ cancelTimeout(_id) { },
109
+ shouldSetTextContent(_type, _props) {
110
+ return false;
111
+ },
112
+ getRootHostContext(_rootContainer) {
113
+ return null;
114
+ },
115
+ getChildHostContext(_parentHostContext, _type, _rootContainer) {
116
+ /* istanbul ignore next */
117
+ return null;
118
+ },
119
+ /* istanbul ignore next */
120
+ getPublicInstance(instance) {
121
+ /* istanbul ignore next */
122
+ return instance;
123
+ },
124
+ finalizeInitialChildren(_instance, _type, _props, _rootContainer, _hostContext) {
125
+ return false;
126
+ }
127
+ };
@@ -0,0 +1,8 @@
1
+ import { IEngine, PointerEventsSystem } from '@dcl/ecs';
2
+ import type { JSX } from './react-ecs';
3
+ export declare type UiComponent = () => JSX.Element;
4
+ export declare type ReactBasedUiSystem = {
5
+ destroy(): void;
6
+ setUiRenderer(ui: UiComponent): void;
7
+ };
8
+ export declare function createReactBasedUiSystem(engine: IEngine, pointerSystem: PointerEventsSystem): ReactBasedUiSystem;
package/dist/system.js ADDED
@@ -0,0 +1,21 @@
1
+ import { createReconciler } from './reconciler';
2
+ export function createReactBasedUiSystem(engine, pointerSystem) {
3
+ const renderer = createReconciler(engine, pointerSystem);
4
+ let uiComponent = undefined;
5
+ function ReactBasedUiSystem() {
6
+ if (uiComponent)
7
+ renderer.update(uiComponent());
8
+ }
9
+ engine.addSystem(ReactBasedUiSystem, 100e3, '@dcl/react-ecs');
10
+ return {
11
+ destroy() {
12
+ engine.removeSystem(ReactBasedUiSystem);
13
+ for (const entity of renderer.getEntities()) {
14
+ engine.removeEntity(entity);
15
+ }
16
+ },
17
+ setUiRenderer(ui) {
18
+ uiComponent = ui;
19
+ }
20
+ };
21
+ }
package/package.json CHANGED
@@ -1,12 +1,11 @@
1
1
  {
2
2
  "name": "@dcl/react-ecs",
3
- "version": "0.0.1-3548419522.commit-ddcf4b7",
4
- "decentralandLibrary": {},
3
+ "version": "7.0.0",
5
4
  "description": "Decentraland ECS",
6
- "main": "dist/index.js",
7
- "typings": "dist/index.d.ts",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
8
7
  "scripts": {
9
- "build": "./../dcl-rollup/node_modules/.bin/rollup -c ./../dcl-rollup/dist/libs.config.js"
8
+ "build": "tsc -p tsconfig.json"
10
9
  },
11
10
  "repository": {
12
11
  "type": "git",
@@ -26,18 +25,16 @@
26
25
  "homepage": "https://github.com/decentraland/js-sdk-toolchain#readme",
27
26
  "devDependencies": {
28
27
  "@types/react": "^18.0.18",
29
- "@types/react-reconciler": "^0.28.0",
30
- "@dcl/ecs": "file:../ecs"
28
+ "@types/react-reconciler": "^0.28.0"
31
29
  },
32
30
  "dependencies": {
31
+ "@dcl/ecs": "file:../ecs",
33
32
  "react": "^18.2.0",
34
33
  "react-reconciler": "^0.29.0"
35
34
  },
36
35
  "files": [
37
- "dist/index.js",
38
- "dist/index.d.ts",
39
- "dist/index.min.js",
40
- "dist/index.min.js.map"
36
+ "dist",
37
+ "tsconfig.json"
41
38
  ],
42
- "commit": "ddcf4b77178942be973faca9ef4e58267727c4d8"
39
+ "commit": "5420eac2bc4215f214136d8b1331864a19118824"
43
40
  }
package/tsconfig.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "es2020",
4
+ "module": "esnext",
5
+ "moduleResolution": "node",
6
+ "strict": true,
7
+ "esModuleInterop": true,
8
+ "forceConsistentCasingInFileNames": true,
9
+ "allowSyntheticDefaultImports": true,
10
+ "declaration": true,
11
+ "stripInternal": true,
12
+ "downlevelIteration": true,
13
+ "preserveConstEnums": true,
14
+ "outDir": "dist",
15
+ "jsx": "react",
16
+ "jsxFactory": "ReactEcs.createElement",
17
+ "rootDir": "src",
18
+ "types": []
19
+ },
20
+ "include": [
21
+ "src"
22
+ ],
23
+ "exclude": [
24
+ "dist"
25
+ ]
26
+ }