@dcl/react-ecs 7.23.4-26723618219.commit-ea97433 → 7.23.4-26770223094.commit-52b9415

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,22 @@
1
+ import { ReactEcs } from '../../react-ecs';
2
+ import { UiScreenInsetAreaProps } from './types';
3
+ /**
4
+ *
5
+ * @public
6
+ * ScreenInsetArea component
7
+ *
8
+ * Constrains its children to the area inside the renderer-reported screen
9
+ * inset (safe margins). On mobile this is the area excluding the notch,
10
+ * status bar, home indicator and rounded corners. On desktop the insets are
11
+ * typically zero, so the container fills the canvas.
12
+ *
13
+ * The container is absolutely positioned with top/left/right/bottom matching
14
+ * the current `UiCanvasInformation.screenInsetArea`, so a child sized
15
+ * 100%x100% fills the safe area exactly.
16
+ *
17
+ * @example
18
+ * <ScreenInsetArea><MyHud /></ScreenInsetArea>
19
+ *
20
+ * @category Component
21
+ */
22
+ export declare function ScreenInsetArea(props: UiScreenInsetAreaProps): ReactEcs.JSX.Element;
@@ -0,0 +1,32 @@
1
+ import { ReactEcs } from '../../react-ecs';
2
+ import { UiEntity } from '../index';
3
+ import { getScreenInsetArea } from '../utils';
4
+ /**
5
+ *
6
+ * @public
7
+ * ScreenInsetArea component
8
+ *
9
+ * Constrains its children to the area inside the renderer-reported screen
10
+ * inset (safe margins). On mobile this is the area excluding the notch,
11
+ * status bar, home indicator and rounded corners. On desktop the insets are
12
+ * typically zero, so the container fills the canvas.
13
+ *
14
+ * The container is absolutely positioned with top/left/right/bottom matching
15
+ * the current `UiCanvasInformation.screenInsetArea`, so a child sized
16
+ * 100%x100% fills the safe area exactly.
17
+ *
18
+ * @example
19
+ * <ScreenInsetArea><MyHud /></ScreenInsetArea>
20
+ *
21
+ * @category Component
22
+ */
23
+ /* @__PURE__ */
24
+ export function ScreenInsetArea(props) {
25
+ const { top, left, right, bottom } = getScreenInsetArea();
26
+ const { uiTransform, ...otherProps } = props;
27
+ return (ReactEcs.createElement(UiEntity, { ...otherProps, uiTransform: {
28
+ ...uiTransform,
29
+ positionType: 'absolute',
30
+ position: { top, left, right, bottom }
31
+ } }));
32
+ }
@@ -0,0 +1,22 @@
1
+ import { EntityPropTypes } from '../types';
2
+ /**
3
+ * ScreenInsetArea component props
4
+ *
5
+ * The container reads the current `screenInsetArea` reported by the renderer
6
+ * via `UiCanvasInformation` (the device safe margins — notch, status bar,
7
+ * home indicator, rounded corners) and constrains its children to the area
8
+ * inside those insets using absolute positioning. Layout props that control
9
+ * the container's own position (`positionType`, `position`) are owned by the
10
+ * component and are not configurable from props — every other layout,
11
+ * background and event prop is forwarded as usual.
12
+ *
13
+ * @public
14
+ */
15
+ export type UiScreenInsetAreaProps = Omit<EntityPropTypes, 'uiTransform'> & {
16
+ /**
17
+ * Layout overrides forwarded to the underlying entity. The
18
+ * `positionType` and `position` fields are reserved by the container and
19
+ * any value provided here is ignored.
20
+ */
21
+ uiTransform?: Omit<NonNullable<EntityPropTypes['uiTransform']>, 'positionType' | 'position'>;
22
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -9,10 +9,12 @@ export * from './uiBackground/types';
9
9
  export * from './Dropdown/types';
10
10
  export * from './Label/types';
11
11
  export * from './Button/types';
12
+ export * from './ScreenInsetArea/types';
12
13
  export { Dropdown } from './Dropdown';
13
14
  export { Input } from './Input';
14
15
  export { Label, scaleFontSize } from './Label';
15
16
  export { Button } from './Button';
17
+ export { ScreenInsetArea } from './ScreenInsetArea';
16
18
  /**
17
19
  * @public
18
20
  * @category Component
@@ -9,10 +9,12 @@ export * from './uiBackground/types';
9
9
  export * from './Dropdown/types';
10
10
  export * from './Label/types';
11
11
  export * from './Button/types';
12
+ export * from './ScreenInsetArea/types';
12
13
  export { Dropdown } from './Dropdown';
13
14
  export { Input } from './Input';
14
15
  export { Label, scaleFontSize } from './Label';
15
16
  export { Button } from './Button';
17
+ export { ScreenInsetArea } from './ScreenInsetArea';
16
18
  /**
17
19
  * @public
18
20
  * @category Component
@@ -3,6 +3,9 @@ import { parseUiBackground } from './uiBackground';
3
3
  import { parseUiTransform } from './uiTransform';
4
4
  let uiScaleFactor = 1;
5
5
  let uiScaleOwner = undefined;
6
+ const ZERO_INSETS = { top: 0, left: 0, right: 0, bottom: 0 };
7
+ let screenInsetArea = { ...ZERO_INSETS };
8
+ let screenInsetAreaOwner = undefined;
6
9
  /**
7
10
  * @internal
8
11
  */
@@ -54,13 +57,22 @@ export function getUiScaleFactor() {
54
57
  return uiScaleFactor;
55
58
  }
56
59
  /**
60
+ * Sets the global UI scale factor.
61
+ *
62
+ * The `owner` symbol implements a cooperative reset-protection scheme shared
63
+ * with {@link resetUiScaleFactor}:
64
+ * - Writes always succeed — last writer claims ownership (the most recent
65
+ * `owner` passed to `set` is the one allowed to `reset`).
66
+ * - Resets from a non-matching owner are ignored, so a stale system can't
67
+ * stomp the active scale while another system is driving it.
68
+ * - A reset called without an owner always wins (used by tests / teardown).
69
+ *
57
70
  * @internal
58
71
  */
59
72
  export function setUiScaleFactor(nextScale, owner) {
60
73
  if (!Number.isFinite(nextScale) || nextScale < 0)
61
74
  return;
62
75
  if (owner) {
63
- // Mark ownership so only that system can reset the scale.
64
76
  uiScaleOwner = owner;
65
77
  }
66
78
  uiScaleFactor = nextScale;
@@ -69,12 +81,49 @@ export function setUiScaleFactor(nextScale, owner) {
69
81
  * @internal
70
82
  */
71
83
  export function resetUiScaleFactor(owner) {
72
- // Ignore resets from non-owners to avoid stomping active scale.
84
+ // No-op for non-owners (see ownership rules on `setUiScaleFactor`).
85
+ // A reset with no owner always wins — used by tests and teardown.
73
86
  if (owner && uiScaleOwner !== owner)
74
87
  return;
75
88
  uiScaleOwner = undefined;
76
89
  uiScaleFactor = 1;
77
90
  }
91
+ /**
92
+ * @internal
93
+ */
94
+ export function getScreenInsetArea() {
95
+ return { ...screenInsetArea };
96
+ }
97
+ /**
98
+ * Sets the global screen inset area.
99
+ *
100
+ * The `owner` symbol implements a cooperative reset-protection scheme shared
101
+ * with {@link resetScreenInsetArea}:
102
+ * - Writes always succeed — last writer claims ownership (the most recent
103
+ * `owner` passed to `set` is the one allowed to `reset`).
104
+ * - Resets from a non-matching owner are ignored, so a stale system can't
105
+ * stomp the active insets while another system is driving them.
106
+ * - A reset called without an owner always wins (used by tests / teardown).
107
+ *
108
+ * @internal
109
+ */
110
+ export function setScreenInsetArea(next, owner) {
111
+ if (owner) {
112
+ screenInsetAreaOwner = owner;
113
+ }
114
+ screenInsetArea = { top: next.top, left: next.left, right: next.right, bottom: next.bottom };
115
+ }
116
+ /**
117
+ * @internal
118
+ */
119
+ export function resetScreenInsetArea(owner) {
120
+ // No-op for non-owners (see ownership rules on `setScreenInsetArea`).
121
+ // A reset with no owner always wins — used by tests and teardown.
122
+ if (owner && screenInsetAreaOwner !== owner)
123
+ return;
124
+ screenInsetAreaOwner = undefined;
125
+ screenInsetArea = { ...ZERO_INSETS };
126
+ }
78
127
  /**
79
128
  * @internal
80
129
  */
package/dist/system.js CHANGED
@@ -2,7 +2,7 @@ import { EntityState } from '@dcl/ecs';
2
2
  import * as ecsComponents from '@dcl/ecs/dist/components';
3
3
  import React from 'react';
4
4
  import { createReconciler } from './reconciler';
5
- import { getUiScaleFactor, resetUiScaleFactor, setUiScaleFactor } from './components/utils';
5
+ import { getUiScaleFactor, resetScreenInsetArea, resetUiScaleFactor, setScreenInsetArea, setUiScaleFactor } from './components/utils';
6
6
  /**
7
7
  * @public
8
8
  */
@@ -14,6 +14,8 @@ export function createReactBasedUiSystem(engine, pointerSystem) {
14
14
  const UiCanvasInformation = ecsComponents.UiCanvasInformation(engine);
15
15
  // Unique owner to prevent other UI systems resetting this scale factor.
16
16
  const uiScaleFactorOwner = Symbol('react-ecs-ui-scale');
17
+ // Unique owner for the screen inset module variable.
18
+ const screenInsetAreaOwner = Symbol('react-ecs-screen-inset-area');
17
19
  function getActiveVirtualSize() {
18
20
  // Main renderer options win; otherwise use the first additional renderer option.
19
21
  if (virtualSize)
@@ -53,13 +55,19 @@ export function createReactBasedUiSystem(engine, pointerSystem) {
53
55
  }
54
56
  }
55
57
  function UiScaleSystem() {
58
+ const canvasInfo = UiCanvasInformation.getOrNull(engine.RootEntity);
59
+ // Update the screen inset module variable unconditionally — it is
60
+ // independent of the virtual size and useful even when the renderer has no
61
+ // virtual canvas.
62
+ if (canvasInfo?.screenInsetArea) {
63
+ setScreenInsetArea(canvasInfo.screenInsetArea, screenInsetAreaOwner);
64
+ }
56
65
  const activeVirtualSize = getActiveVirtualSize();
57
66
  if (!activeVirtualSize) {
58
67
  // Reset only if this system owns the scale factor.
59
68
  resetUiScaleFactor(uiScaleFactorOwner);
60
69
  return;
61
70
  }
62
- const canvasInfo = UiCanvasInformation.getOrNull(engine.RootEntity);
63
71
  if (!canvasInfo)
64
72
  return;
65
73
  const { width, height } = canvasInfo;
@@ -79,6 +87,7 @@ export function createReactBasedUiSystem(engine, pointerSystem) {
79
87
  engine.removeSystem(UiScaleSystem);
80
88
  engine.removeSystem(ReactBasedUiSystem);
81
89
  resetUiScaleFactor(uiScaleFactorOwner);
90
+ resetScreenInsetArea(screenInsetAreaOwner);
82
91
  for (const entity of renderer.getEntities()) {
83
92
  engine.removeEntity(entity);
84
93
  }
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@dcl/react-ecs",
3
3
  "description": "Decentraland ECS",
4
- "version": "7.23.4-26723618219.commit-ea97433",
4
+ "version": "7.23.4-26770223094.commit-52b9415",
5
5
  "author": "DCL",
6
6
  "bugs": "https://github.com/decentraland/js-sdk-toolchain/issues",
7
7
  "dependencies": {
8
- "@dcl/ecs": "7.23.4-26723618219.commit-ea97433",
8
+ "@dcl/ecs": "7.23.4-26770223094.commit-52b9415",
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": "ea974331caffe948877a5bfadb0dc458ae60e15a"
43
+ "commit": "52b9415ebab8c77313e9fbc0725fd2e5f916d3c3"
44
44
  }