@dcl/react-ecs 7.0.6-3807227301.commit-1045452 → 7.0.6-3808564125.commit-7a2650b

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.
Files changed (35) hide show
  1. package/dist/components/Button/index.d.ts +7 -0
  2. package/dist/components/Button/index.js +39 -0
  3. package/dist/components/Button/types.d.ts +7 -0
  4. package/dist/components/Button/types.js +1 -0
  5. package/dist/components/Dropdown/index.d.ts +7 -0
  6. package/dist/components/Dropdown/index.js +26 -0
  7. package/dist/components/Dropdown/types.d.ts +7 -0
  8. package/dist/components/Dropdown/types.js +1 -0
  9. package/dist/components/Input/index.d.ts +7 -0
  10. package/dist/components/Input/index.js +24 -0
  11. package/dist/components/Input/types.d.ts +7 -0
  12. package/dist/components/Input/types.js +1 -0
  13. package/dist/components/Label/index.d.ts +7 -0
  14. package/dist/components/Label/index.js +16 -0
  15. package/dist/components/Label/types.d.ts +5 -0
  16. package/dist/components/Label/types.js +1 -0
  17. package/dist/components/index.d.ts +9 -2
  18. package/dist/components/index.js +13 -7
  19. package/dist/components/listeners/types.d.ts +4 -3
  20. package/dist/components/listeners/types.js +2 -1
  21. package/dist/components/types.d.ts +5 -5
  22. package/dist/components/uiBackground/index.d.ts +6 -0
  23. package/dist/components/uiBackground/index.js +40 -0
  24. package/dist/components/uiBackground/types.d.ts +21 -0
  25. package/dist/components/uiBackground/types.js +1 -0
  26. package/dist/components/uiTransform/index.js +20 -19
  27. package/dist/components/uiTransform/types.d.ts +1 -1
  28. package/dist/components/utils.d.ts +1 -0
  29. package/dist/components/utils.js +17 -0
  30. package/dist/react-ecs.d.ts +9 -8
  31. package/dist/reconciler/index.d.ts +1 -1
  32. package/dist/reconciler/index.js +68 -36
  33. package/dist/reconciler/utils.d.ts +2 -2
  34. package/dist/reconciler/utils.js +32 -3
  35. package/package.json +2 -2
@@ -0,0 +1,7 @@
1
+ import { ReactEcs } from '../../react-ecs';
2
+ import { EntityPropTypes } from '../types';
3
+ import { UiButtonProps } from './types';
4
+ /**
5
+ * @public
6
+ */
7
+ export declare function Button(props: EntityPropTypes & UiButtonProps): ReactEcs.JSX.Element;
@@ -0,0 +1,39 @@
1
+ import { ReactEcs } from '../../react-ecs';
2
+ import { parseUiBackground } from '../uiBackground';
3
+ import { parseUiTransform } from '../uiTransform';
4
+ function getButtonProps(props) {
5
+ if (props.type === 'primary') {
6
+ return {
7
+ uiBackground: { color: { r: 0.98, g: 0.17, b: 0.33, a: 1 } },
8
+ uiText: { color: { r: 1, g: 1, b: 1, a: 1 } }
9
+ };
10
+ }
11
+ if (props.type === 'secondary') {
12
+ return {
13
+ uiBackground: { color: { r: 1, g: 1, b: 1, a: 1 } },
14
+ uiText: { color: { r: 0.98, g: 0.17, b: 0.33, a: 1 } }
15
+ };
16
+ }
17
+ return {};
18
+ }
19
+ /**
20
+ * @public
21
+ */
22
+ /*#__PURE__*/
23
+ export function Button(props) {
24
+ const { uiTransform, uiBackground, onMouseDown, onMouseUp, ...uiTextProps } = props;
25
+ const buttonProps = getButtonProps(props);
26
+ const uiBackgroundProps = parseUiBackground({
27
+ ...buttonProps.uiBackground,
28
+ ...uiBackground
29
+ });
30
+ const textProps = {
31
+ ...buttonProps.uiText,
32
+ ...uiTextProps
33
+ };
34
+ const uiTransformProps = parseUiTransform({
35
+ height: 36,
36
+ ...uiTransform
37
+ });
38
+ return (ReactEcs.createElement("entity", { onMouseDown: onMouseDown, onMouseUp: onMouseUp, uiTransform: uiTransformProps, uiText: textProps, uiBackground: uiBackgroundProps }));
39
+ }
@@ -0,0 +1,7 @@
1
+ import { PBUiText } from '@dcl/ecs';
2
+ /**
3
+ * @public
4
+ */
5
+ export declare type UiButtonProps = PBUiText & {
6
+ type?: 'primary' | 'secondary';
7
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,7 @@
1
+ import { ReactEcs } from '../../react-ecs';
2
+ import { EntityPropTypes } from '../types';
3
+ import { UiDropdownProps } from './types';
4
+ /**
5
+ * @public
6
+ */
7
+ export declare function Dropdown(props: EntityPropTypes & UiDropdownProps): ReactEcs.JSX.Element;
@@ -0,0 +1,26 @@
1
+ import { parseProps } from '../utils';
2
+ import { ReactEcs } from '../../react-ecs';
3
+ function parseUiDropdown(props) {
4
+ return {
5
+ acceptEmpty: false,
6
+ options: [],
7
+ selectedIndex: props.acceptEmpty ? -1 : 0,
8
+ disabled: false,
9
+ ...props
10
+ };
11
+ }
12
+ /**
13
+ * @public
14
+ */
15
+ /*#__PURE__*/
16
+ export function Dropdown(props) {
17
+ const { uiTransform, uiBackground, onMouseDown, onMouseUp, ...otherProps } = props;
18
+ const dropdownProps = parseUiDropdown(otherProps);
19
+ const commonProps = parseProps({
20
+ uiTransform,
21
+ uiBackground,
22
+ onMouseDown,
23
+ onMouseUp
24
+ });
25
+ return ReactEcs.createElement("entity", { ...commonProps, uiDropdown: dropdownProps });
26
+ }
@@ -0,0 +1,7 @@
1
+ import { PBUiDropdown } from '@dcl/ecs';
2
+ /**
3
+ * @public
4
+ */
5
+ export declare type UiDropdownProps = Partial<PBUiDropdown> & {
6
+ onChange?(value: number): void;
7
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,7 @@
1
+ import { ReactEcs } from '../../react-ecs';
2
+ import { EntityPropTypes } from '../types';
3
+ import { UiInputProps } from './types';
4
+ /**
5
+ * @public
6
+ */
7
+ export declare function Input(props: EntityPropTypes & Partial<UiInputProps>): ReactEcs.JSX.Element;
@@ -0,0 +1,24 @@
1
+ import { parseProps } from '../utils';
2
+ import { ReactEcs } from '../../react-ecs';
3
+ function parseUiInput(props) {
4
+ return {
5
+ disabled: false,
6
+ placeholder: '',
7
+ ...props
8
+ };
9
+ }
10
+ /**
11
+ * @public
12
+ */
13
+ /*#__PURE__*/
14
+ export function Input(props) {
15
+ const { uiTransform, uiBackground, onMouseDown, onMouseUp, ...otherProps } = props;
16
+ const inputProps = parseUiInput(otherProps);
17
+ const commonProps = parseProps({
18
+ uiTransform,
19
+ uiBackground,
20
+ onMouseDown,
21
+ onMouseUp
22
+ });
23
+ return ReactEcs.createElement("entity", { ...commonProps, uiInput: inputProps });
24
+ }
@@ -0,0 +1,7 @@
1
+ import { PBUiInput } from '@dcl/ecs';
2
+ /**
3
+ * @public
4
+ */
5
+ export declare type UiInputProps = PBUiInput & {
6
+ onChange?(value: string): void;
7
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,7 @@
1
+ import { ReactEcs } from '../../react-ecs';
2
+ import { EntityPropTypes } from '../types';
3
+ import { UiTextProps } from './types';
4
+ /**
5
+ * @public
6
+ */
7
+ export declare function Label(props: EntityPropTypes & UiTextProps): ReactEcs.JSX.Element;
@@ -0,0 +1,16 @@
1
+ import { parseProps } from '../utils';
2
+ import { ReactEcs } from '../../react-ecs';
3
+ /**
4
+ * @public
5
+ */
6
+ /*#__PURE__*/
7
+ export function Label(props) {
8
+ const { uiTransform, uiBackground, onMouseDown, onMouseUp, ...uiTextProps } = props;
9
+ const commonProps = parseProps({
10
+ uiTransform,
11
+ uiBackground,
12
+ onMouseDown,
13
+ onMouseUp
14
+ });
15
+ return ReactEcs.createElement("entity", { ...commonProps, uiText: uiTextProps });
16
+ }
@@ -0,0 +1,5 @@
1
+ import { PBUiText } from '@dcl/ecs';
2
+ /**
3
+ * @public
4
+ */
5
+ export declare type UiTextProps = PBUiText;
@@ -0,0 +1 @@
1
+ export {};
@@ -5,9 +5,16 @@ export * from './types';
5
5
  export { CANVAS_ROOT_ENTITY };
6
6
  export * from './uiTransform/types';
7
7
  export * from './listeners/types';
8
+ export * from './Input/types';
9
+ export * from './uiBackground/types';
10
+ export * from './Dropdown/types';
11
+ export * from './Label/types';
12
+ export * from './Button/types';
13
+ export { Dropdown } from './Dropdown';
14
+ export { Input } from './Input';
15
+ export { Label } from './Label';
16
+ export { Button } from './Button';
8
17
  /**
9
18
  * @public
10
19
  */
11
20
  export declare function UiEntity(props: EntityPropTypes & Partial<CommonProps>): ReactEcs.JSX.Element;
12
- export declare type ContainerPropTypes = Partial<CommonProps> & EntityPropTypes['uiTransform'];
13
- export declare function Container({ width, height, children }: ContainerPropTypes): ReactEcs.JSX.Element;
@@ -1,17 +1,23 @@
1
1
  import { ReactEcs } from '../react-ecs';
2
- import { parseUiTransform, CANVAS_ROOT_ENTITY } from './uiTransform';
2
+ import { CANVAS_ROOT_ENTITY } from './uiTransform';
3
+ import { parseProps } from './utils';
3
4
  export * from './types';
4
5
  export { CANVAS_ROOT_ENTITY };
5
6
  export * from './uiTransform/types';
6
7
  export * from './listeners/types';
8
+ export * from './Input/types';
9
+ export * from './uiBackground/types';
10
+ export * from './Dropdown/types';
11
+ export * from './Label/types';
12
+ export * from './Button/types';
13
+ export { Dropdown } from './Dropdown';
14
+ export { Input } from './Input';
15
+ export { Label } from './Label';
16
+ export { Button } from './Button';
7
17
  /**
8
18
  * @public
9
19
  */
20
+ /*#__PURE__*/
10
21
  export function UiEntity(props) {
11
- const { uiTransform, ...otherProps } = props;
12
- const uiTransformProps = parseUiTransform(uiTransform);
13
- return ReactEcs.createElement("entity", { uiTransform: uiTransformProps, ...otherProps });
14
- }
15
- export function Container({ width, height, children }) {
16
- return (ReactEcs.createElement(UiEntity, { uiTransform: { width, height, display: 0 /* YGDisplay.YGD_FLEX */ } }, children));
22
+ return ReactEcs.createElement("entity", { ...parseProps(props) });
17
23
  }
@@ -1,5 +1,6 @@
1
- import type { EventSystemCallback } from '@dcl/ecs';
1
+ export declare type Callback = () => void;
2
2
  export declare type Listeners = {
3
- onClick?: EventSystemCallback;
3
+ onMouseDown?: Callback;
4
+ onMouseUp?: Callback;
4
5
  };
5
- export declare const isListener: (key: string) => key is "onClick";
6
+ export declare const isListener: (key: string) => key is keyof Listeners;
@@ -1,5 +1,6 @@
1
1
  const listeners = {
2
- onClick: undefined
2
+ onMouseDown: undefined,
3
+ onMouseUp: undefined
3
4
  };
4
5
  const listenersKey = Object.keys(listeners);
5
6
  export const isListener = (key) => listenersKey.includes(key);
@@ -1,15 +1,15 @@
1
- import { PBUiBackground, PBUiText } from '@dcl/ecs/dist/components';
1
+ import { Listeners } from './listeners/types';
2
+ import { UiBackgroundProps } from './uiBackground/types';
2
3
  import { UiTransformProps } from './uiTransform/types';
3
4
  /**
4
5
  * @public
5
6
  */
6
7
  export declare type EntityPropTypes = {
7
8
  uiTransform?: UiTransformProps;
8
- uiText?: PBUiText;
9
- uiBackground?: PBUiBackground;
10
- };
9
+ uiBackground?: UiBackgroundProps;
10
+ } & Listeners;
11
11
  export declare type Key = number | string;
12
- export declare type Children = any;
12
+ export declare type Children = unknown;
13
13
  export declare type CommonProps = {
14
14
  key: Key;
15
15
  children: Children;
@@ -0,0 +1,6 @@
1
+ import { PBUiBackground } from '@dcl/ecs';
2
+ import { UiBackgroundProps } from './types';
3
+ /**
4
+ * @public
5
+ */
6
+ export declare function parseUiBackground(props: UiBackgroundProps | undefined): PBUiBackground | undefined;
@@ -0,0 +1,40 @@
1
+ function isAvatarTexture(props) {
2
+ return !!props.avatarTexture;
3
+ }
4
+ function isTexture(props) {
5
+ return !!props.texture;
6
+ }
7
+ function getTexture(props) {
8
+ if (isTexture(props) && props.texture) {
9
+ return {
10
+ tex: {
11
+ $case: 'texture',
12
+ texture: props.texture
13
+ }
14
+ };
15
+ }
16
+ if (isAvatarTexture(props) && props.avatarTexture) {
17
+ return {
18
+ tex: {
19
+ $case: 'avatarTexture',
20
+ avatarTexture: props.avatarTexture
21
+ }
22
+ };
23
+ }
24
+ return undefined;
25
+ }
26
+ /**
27
+ * @public
28
+ */
29
+ /*#__PURE__*/
30
+ export function parseUiBackground(props) {
31
+ if (!props || !Object.keys(props).length)
32
+ return undefined;
33
+ const texture = getTexture(props);
34
+ return {
35
+ ...props,
36
+ uvs: props.uvs ?? [],
37
+ texture,
38
+ textureMode: props.textureMode ?? 1 /* BackgroundTextureMode.CENTER */
39
+ };
40
+ }
@@ -0,0 +1,21 @@
1
+ import { PBUiBackground, Texture, AvatarTexture } from '@dcl/ecs';
2
+ /**
3
+ * @public
4
+ */
5
+ export declare type UiBackgroundProps = Partial<Omit<PBUiBackground, 'texture'>> & UiTextureUnion;
6
+ /**
7
+ * @public
8
+ */
9
+ export declare type UiTextureUnion = UiAvatarTexture | UiTexture;
10
+ /**
11
+ * @public
12
+ */
13
+ export declare type UiAvatarTexture = {
14
+ avatarTexture?: AvatarTexture;
15
+ };
16
+ /**
17
+ * @public
18
+ */
19
+ export declare type UiTexture = {
20
+ texture?: Texture;
21
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -1,24 +1,5 @@
1
1
  import { parsePosition, parseSize } from './utils';
2
2
  export const CANVAS_ROOT_ENTITY = 0;
3
- /**
4
- * @public
5
- */
6
- export function parseUiTransform(props = {}) {
7
- const { position, padding, margin, height, minHeight, maxHeight, width, maxWidth, minWidth, ...otherProps } = props;
8
- return {
9
- ...defaultUiTransform,
10
- ...otherProps,
11
- ...parsePosition(position, 'position'),
12
- ...parsePosition(margin, 'margin'),
13
- ...parsePosition(padding, 'padding'),
14
- ...parseSize(height, 'height'),
15
- ...parseSize(minHeight, 'minHeight'),
16
- ...parseSize(maxHeight, 'maxHeight'),
17
- ...parseSize(width, 'width'),
18
- ...parseSize(minWidth, 'minWidth'),
19
- ...parseSize(maxWidth, 'maxWidth')
20
- };
21
- }
22
3
  const defaultUiTransform = {
23
4
  parent: CANVAS_ROOT_ENTITY,
24
5
  rightOf: 0,
@@ -68,3 +49,23 @@ const defaultUiTransform = {
68
49
  widthUnit: 0 /* YGUnit.YGU_UNDEFINED */,
69
50
  heightUnit: 0 /* YGUnit.YGU_UNDEFINED */
70
51
  };
52
+ /**
53
+ * @public
54
+ */
55
+ /*#__PURE__*/
56
+ export function parseUiTransform(props = {}) {
57
+ const { position, padding, margin, height, minHeight, maxHeight, width, maxWidth, minWidth, ...otherProps } = props;
58
+ return {
59
+ ...defaultUiTransform,
60
+ ...otherProps,
61
+ ...parsePosition(position, 'position'),
62
+ ...parsePosition(margin, 'margin'),
63
+ ...parsePosition(padding, 'padding'),
64
+ ...parseSize(height, 'height'),
65
+ ...parseSize(minHeight, 'minHeight'),
66
+ ...parseSize(maxHeight, 'maxHeight'),
67
+ ...parseSize(width, 'width'),
68
+ ...parseSize(minWidth, 'minWidth'),
69
+ ...parseSize(maxWidth, 'maxWidth')
70
+ };
71
+ }
@@ -1,4 +1,4 @@
1
- import { YGAlign, YGDisplay, YGFlexDirection, YGJustify, YGOverflow, YGPositionType, YGWrap } from '@dcl/ecs/dist/runtime/types';
1
+ import { YGAlign, YGDisplay, YGFlexDirection, YGJustify, YGOverflow, YGPositionType, YGWrap } from '@dcl/ecs';
2
2
  export declare type PositionUnit = `${number}px` | `${number}%` | number;
3
3
  /**
4
4
  * @public
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,17 @@
1
+ import { parseUiBackground } from './uiBackground';
2
+ import { parseUiTransform } from './uiTransform';
3
+ /**
4
+ * @internal
5
+ */
6
+ export function parseProps(props) {
7
+ const { uiTransform, uiBackground, ...otherProps } = props;
8
+ const uiTransformProps = parseUiTransform(uiTransform);
9
+ const uiBackgroundProps = uiBackground
10
+ ? { uiBackground: parseUiBackground(uiBackground) }
11
+ : undefined;
12
+ return {
13
+ ...otherProps,
14
+ uiTransform: uiTransformProps,
15
+ ...uiBackgroundProps
16
+ };
17
+ }
@@ -1,26 +1,27 @@
1
- import { EventSystemCallback } from '@dcl/ecs';
2
- import { PBUiBackground, PBUiText, PBUiTransform } from '@dcl/ecs/dist/components';
1
+ import { PBUiBackground, PBUiText, PBUiTransform, PBUiInput, PBUiDropdown } from '@dcl/ecs';
2
+ import { Callback } from './components';
3
3
  import { CommonProps } from './components/types';
4
4
  export declare type EcsElements = {
5
- entity: Partial<Omit<EntityComponents, 'onClick'> & CommonProps>;
5
+ entity: Partial<EntityComponents & CommonProps>;
6
6
  };
7
7
  export declare type EntityComponents = {
8
8
  uiTransform: PBUiTransform;
9
9
  uiText: PBUiText;
10
10
  uiBackground: PBUiBackground;
11
- onClick: EventSystemCallback;
11
+ uiInput: PBUiInput;
12
+ uiDropdown: PBUiDropdown;
13
+ onMouseDown: Callback;
14
+ onMouseUp: Callback;
12
15
  };
13
16
  export declare namespace JSX {
14
- interface Element {
15
- }
17
+ type Element = {} | null;
16
18
  type IntrinsicElements = EcsElements;
17
19
  interface Component {
18
20
  }
19
21
  }
20
22
  export declare namespace ReactEcs {
21
23
  namespace JSX {
22
- interface Element {
23
- }
24
+ type Element = {} | null;
24
25
  type IntrinsicElements = EcsElements;
25
26
  interface Component {
26
27
  }
@@ -1,6 +1,6 @@
1
1
  import { IEngine, PointerEventsSystem } from '@dcl/ecs';
2
2
  import { JSX } from '../react-ecs';
3
- export declare function createReconciler(engine: Pick<IEngine, 'getComponent' | 'addEntity' | 'removeEntity' | 'defineComponentFromSchema'>, pointerEvents: PointerEventsSystem): {
3
+ export declare function createReconciler(engine: Pick<IEngine, 'getComponent' | 'addEntity' | 'removeEntity' | 'defineComponentFromSchema' | 'getEntitiesWith'>, pointerEvents: PointerEventsSystem): {
4
4
  update: (component: JSX.Element) => number;
5
5
  getEntities: () => unknown[];
6
6
  };
@@ -2,62 +2,56 @@ import * as components from '@dcl/ecs/dist/components';
2
2
  import Reconciler from 'react-reconciler';
3
3
  import { isListener } from '../components';
4
4
  import { CANVAS_ROOT_ENTITY } from '../components/uiTransform';
5
- import { componentKeys, isEqual, isNotUndefined, noopConfig } from './utils';
6
- function propsChanged(component, prevProps, nextProps) {
7
- if (prevProps && !nextProps) {
8
- return { type: 'delete', component };
9
- }
10
- if (!nextProps) {
11
- return;
12
- }
13
- if (!prevProps && nextProps) {
14
- return { type: 'add', props: nextProps, component };
15
- }
16
- if (isListener(component)) {
17
- if (!isEqual(prevProps, nextProps)) {
18
- return { type: 'put', component, props: nextProps };
19
- }
20
- }
21
- const changes = {};
22
- for (const k in prevProps) {
23
- const propKey = k;
24
- if (!isEqual(prevProps[propKey], nextProps[propKey])) {
25
- changes[propKey] = nextProps[propKey];
26
- }
27
- }
28
- if (!Object.keys(changes).length) {
29
- return;
30
- }
31
- return { type: 'put', props: changes, component };
32
- }
5
+ import { componentKeys, isNotUndefined, noopConfig, propsChanged } from './utils';
33
6
  export function createReconciler(engine, pointerEvents) {
7
+ // Store all the entities so when we destroy the UI we can also destroy them
34
8
  const entities = new Set();
9
+ // Store the onChange callbacks to be runned every time a Result has changed
10
+ const changeEvents = new Map();
11
+ // Initialize components
35
12
  const UiTransform = components.UiTransform(engine);
36
13
  const UiText = components.UiText(engine);
37
14
  const UiBackground = components.UiBackground(engine);
15
+ const UiInput = components.UiInput(engine);
16
+ const UiInputResult = components.UiInputResult(engine);
17
+ const UiDropdown = components.UiDropdown(engine);
18
+ const UiDropdownResult = components.UiDropdownResult(engine);
19
+ // Component ID Helper
38
20
  const getComponentId = {
39
21
  uiTransform: UiTransform._id,
40
22
  uiText: UiText._id,
41
- uiBackground: UiBackground._id
23
+ uiBackground: UiBackground._id,
24
+ uiInput: UiInput._id,
25
+ uiDropdown: UiDropdown._id
42
26
  };
43
27
  function updateTree(instance, props) {
44
28
  upsertComponent(instance, props, 'uiTransform');
45
29
  }
46
30
  function upsertListener(instance, update) {
47
- // TODO: This handles only onClick listener for the moment
48
31
  if (update.type === 'delete' || !update.props) {
49
- pointerEvents.removeOnPointerDown(instance.entity);
32
+ if (update.component === 'onMouseDown') {
33
+ pointerEvents.removeOnPointerDown(instance.entity);
34
+ }
35
+ else if (update.component === 'onMouseUp') {
36
+ pointerEvents.removeOnPointerUp(instance.entity);
37
+ }
50
38
  return;
51
39
  }
52
40
  if (update.props) {
53
- pointerEvents.onPointerDown(instance.entity, update.props, {
41
+ const pointerEvent = update.component === 'onMouseDown'
42
+ ? pointerEvents.onPointerDown
43
+ : pointerEvents.onPointerUp;
44
+ pointerEvent(instance.entity, update.props, {
54
45
  button: 0 /* InputAction.IA_POINTER */,
55
- hoverText: ''
46
+ // We add this showFeedBack so the pointerEventSystem creates a PointerEvent component with our entity
47
+ // This is needed for the renderer to know which entities are clickeables
48
+ showFeedback: true
56
49
  });
57
50
  }
58
51
  }
59
52
  function removeComponent(instance, component) {
60
- const Component = engine.getComponent(getComponentId[component]);
53
+ const componentId = getComponentId[component];
54
+ const Component = engine.getComponent(componentId);
61
55
  Component.deleteFrom(instance.entity);
62
56
  }
63
57
  function upsertComponent(instance, props, componentName) {
@@ -67,10 +61,18 @@ export function createReconciler(engine, pointerEvents) {
67
61
  Component.create(instance.entity);
68
62
  for (const key in props) {
69
63
  const keyProp = key;
70
- component[keyProp] = props[keyProp];
64
+ if (key === 'onChange') {
65
+ const onChange = props[keyProp];
66
+ updateOnChange(instance.entity, componentId, { fn: onChange });
67
+ }
68
+ else {
69
+ ;
70
+ component[keyProp] = props[keyProp];
71
+ }
71
72
  }
72
73
  }
73
74
  function removeChildEntity(instance) {
75
+ changeEvents.delete(instance.entity);
74
76
  engine.removeEntity(instance.entity);
75
77
  for (const child of instance._child) {
76
78
  removeChildEntity(child);
@@ -116,6 +118,14 @@ export function createReconciler(engine, pointerEvents) {
116
118
  parentInstance._child.splice(childIndex, 1);
117
119
  removeChildEntity(child);
118
120
  }
121
+ function updateOnChange(entity, componentId, state) {
122
+ const event = changeEvents.get(entity) ||
123
+ changeEvents.set(entity, new Map()).get(entity);
124
+ const oldState = event.get(componentId);
125
+ const fn = state?.fn;
126
+ const value = state?.value ?? oldState?.value;
127
+ event.set(componentId, { fn, value });
128
+ }
119
129
  const hostConfig = {
120
130
  ...noopConfig,
121
131
  createInstance(type, props) {
@@ -154,7 +164,7 @@ export function createReconciler(engine, pointerEvents) {
154
164
  .map((component) => propsChanged(component, oldProps[component], newProps[component]))
155
165
  .filter(isNotUndefined);
156
166
  },
157
- commitUpdate(instance, updatePayload, _type, _prevPropsProps, _nextProps, _internalHandle) {
167
+ commitUpdate(instance, updatePayload, _type, _prevProps, _nextProps, _internalHandle) {
158
168
  for (const update of updatePayload) {
159
169
  if (isListener(update.component)) {
160
170
  upsertListener(instance, update);
@@ -180,14 +190,36 @@ export function createReconciler(engine, pointerEvents) {
180
190
  child.parent = parentInstance.entity;
181
191
  updateTree(child, { rightOf: child.rightOf, parent: child.parent });
182
192
  updateTree(beforeChild, { rightOf: beforeChild.rightOf });
193
+ },
194
+ removeChildFromContainer(parenInstance, child) {
195
+ removeChildEntity(child);
183
196
  }
184
197
  };
185
198
  const reconciler = Reconciler(hostConfig);
186
199
  const root = reconciler.createContainer({}, 0, null, false, null, '',
187
200
  /* istanbul ignore next */
188
201
  function () { }, null);
202
+ // Maybe this could be something similar to Input system, but since we
203
+ // are going to use this only here, i prefer to scope it here.
204
+ function handleOnChange(componentId, resultComponent) {
205
+ for (const [entity, Result] of engine.getEntitiesWith(resultComponent)) {
206
+ const entityState = changeEvents.get(entity)?.get(componentId);
207
+ if (entityState?.fn && Result.value !== entityState.value) {
208
+ // Call onChange callback and update internal timestamp
209
+ entityState.fn(Result.value);
210
+ updateOnChange(entity, componentId, {
211
+ fn: entityState.fn,
212
+ value: Result.value
213
+ });
214
+ }
215
+ }
216
+ }
189
217
  return {
190
218
  update: function (component) {
219
+ if (changeEvents.size) {
220
+ handleOnChange(UiInput._id, UiInputResult);
221
+ handleOnChange(UiDropdown._id, UiDropdownResult);
222
+ }
191
223
  return reconciler.updateContainer(component, root, null);
192
224
  },
193
225
  getEntities: () => Array.from(entities)
@@ -1,5 +1,6 @@
1
1
  import { EntityComponents } from '../react-ecs';
2
- import { Container, HostContext, Instance, OpaqueHandle, Props, PublicInstance, SuspenseInstance, TextInstance, TimeoutHandle, Type } from './types';
2
+ import { Changes, Container, HostContext, Instance, OpaqueHandle, Props, PublicInstance, SuspenseInstance, TextInstance, TimeoutHandle, Type } from './types';
3
+ export declare function propsChanged<K extends keyof EntityComponents>(component: K, prevProps: Partial<EntityComponents[K]>, nextProps: Partial<EntityComponents[K]>): Changes<K> | undefined;
3
4
  export declare const componentKeys: (keyof EntityComponents)[];
4
5
  export declare function isEqual<T = unknown>(val1: T, val2: T): boolean;
5
6
  export declare const isNotUndefined: <T>(val: T | undefined) => val is T;
@@ -22,7 +23,6 @@ export declare const noopConfig: {
22
23
  afterActiveInstanceBlur(): void;
23
24
  prepareScopeUpdate(): void;
24
25
  getInstanceFromScope(): null;
25
- removeChildFromContainer(): void;
26
26
  commitMount(_instance: Instance, _type: Type, _props: Props, _internalInstanceHandle: OpaqueHandle): void;
27
27
  resetTextContent(_instance: Instance): void;
28
28
  commitTextUpdate(_textInstance: TextInstance, _oldText: string, _newText: string): void;
@@ -1,9 +1,40 @@
1
+ import { isListener } from '../components';
2
+ export function propsChanged(component, prevProps, nextProps) {
3
+ if (prevProps && !nextProps) {
4
+ return { type: 'delete', component };
5
+ }
6
+ if (!nextProps) {
7
+ return;
8
+ }
9
+ if (!prevProps && nextProps) {
10
+ return { type: 'add', props: nextProps, component };
11
+ }
12
+ if (isListener(component)) {
13
+ if (!isEqual(prevProps, nextProps)) {
14
+ return { type: 'put', component, props: nextProps };
15
+ }
16
+ }
17
+ const changes = {};
18
+ for (const k in prevProps) {
19
+ const propKey = k;
20
+ if (!isEqual(prevProps[propKey], nextProps[propKey])) {
21
+ changes[propKey] = nextProps[propKey];
22
+ }
23
+ }
24
+ if (!Object.keys(changes).length) {
25
+ return;
26
+ }
27
+ return { type: 'put', props: changes, component };
28
+ }
1
29
  // as any HACK so every time we add a new component, we must add also the component here.
2
30
  const entityComponent = {
3
31
  uiText: undefined,
4
32
  uiBackground: undefined,
5
33
  uiTransform: undefined,
6
- onClick: undefined
34
+ onMouseDown: undefined,
35
+ onMouseUp: undefined,
36
+ uiInput: undefined,
37
+ uiDropdown: undefined
7
38
  };
8
39
  export const componentKeys = Object.keys(entityComponent);
9
40
  export function isEqual(val1, val2) {
@@ -85,8 +116,6 @@ export const noopConfig = {
85
116
  return null;
86
117
  },
87
118
  /* istanbul ignore next */
88
- removeChildFromContainer() { },
89
- /* istanbul ignore next */
90
119
  commitMount(_instance, _type, _props, _internalInstanceHandle) { },
91
120
  /* istanbul ignore next */
92
121
  resetTextContent(_instance) { },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dcl/react-ecs",
3
- "version": "7.0.6-3807227301.commit-1045452",
3
+ "version": "7.0.6-3808564125.commit-7a2650b",
4
4
  "description": "Decentraland ECS",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -36,5 +36,5 @@
36
36
  "dist",
37
37
  "tsconfig.json"
38
38
  ],
39
- "commit": "104545291581dd38595dbfc46135d0f573d306ff"
39
+ "commit": "7a2650b741ac5f5a5d3f00ac1c955e5f773d679a"
40
40
  }