Skip to content

Commit de10ae3

Browse files
committed
Code styling fixes and docs for the importantForLayout property.
1 parent 70ae226 commit de10ae3

3 files changed

Lines changed: 70 additions & 45 deletions

File tree

docs/docs/components/view.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ ignorePointerEvents: boolean = false; // web only
4343
// Can the component accept keyboard focus?
4444
focusable: boolean = false; // web only
4545

46+
// Additional invisible DOM elements will be added inside the view
47+
// to track the size changes that are performed behind our back by
48+
// the browser's layout engine faster (ViewBase checks for the layout
49+
// updates once a second and sometimes it's not fast enough)
50+
importantForLayout?: boolean = false; // web only
51+
4652
// Mouse-specific Events
4753
onDragEnter?: (e: DragEvent) => void = undefined;
4854
onDragOver?: (e: DragEvent) => void = undefined;
@@ -97,7 +103,7 @@ disableTouchOpacityAnimation?: boolean; // iOS and Android only
97103
// Opacity value the button should animate to, on touch on views that have onPress handlers.
98104
activeOpacity?: number; // iOS and Android only
99105

100-
// Background color that will be visible on touch on views that have onPress handlers.
106+
// Background color that will be visible on touch on views that have onPress handlers.
101107
underlayColor?: string; // ßiOS and Android only
102108
```
103109

src/common/Types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,7 @@ export interface ViewPropsShared extends CommonProps, CommonAccessibilityProps {
522522
viewLayerTypeAndroid?: ViewLayerType; // Android only property
523523
children?: ReactNode;
524524
focusable?: boolean;
525+
525526
importantForLayout?: boolean; // Web-only, additional invisible DOM elements will be added to track the size changes faster
526527

527528
// There are a couple of constraints when child animations are enabled:

src/web/View.tsx

Lines changed: 62 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ const _styles = {
2727
alignItems: 'stretch'
2828
},
2929

30+
// See resize detector comments in renderResizeDetectorIfNeeded() method below.
3031
resizeDetectorContainerStyles: {
3132
position: 'absolute',
3233
left: '0',
@@ -77,40 +78,22 @@ export class View extends ViewBase<Types.ViewProps, {}> {
7778
};
7879

7980
private resizeDetectorAnimationFrame: number;
80-
private resizeDetectorNodes: {grow?: HTMLElement, shrink?: HTMLElement} = {};
81-
82-
private resizeDetectorReset() {
83-
const scrollMax = 100500;
84-
85-
let node = this.resizeDetectorNodes.grow;
86-
87-
if (node) {
88-
node.scrollLeft = scrollMax;
89-
node.scrollTop = scrollMax;
90-
}
91-
92-
node = this.resizeDetectorNodes.shrink;
93-
94-
if (node) {
95-
node.scrollLeft = scrollMax;
96-
node.scrollTop = scrollMax;
97-
}
98-
}
99-
100-
private resizeDetectorOnScroll() {
101-
if (this.resizeDetectorAnimationFrame) {
102-
return;
103-
}
104-
105-
this.resizeDetectorAnimationFrame = window.requestAnimationFrame(() => {
106-
this.resizeDetectorReset();
107-
this.resizeDetectorAnimationFrame = undefined;
108-
ViewBase._checkViews();
109-
});
110-
111-
}
81+
private resizeDetectorNodes: { grow?: HTMLElement, shrink?: HTMLElement } = {};
11282

11383
private renderResizeDetectorIfNeeded(containerStyles: any): React.ReactNode {
84+
// If needed, additional invisible DOM elements will be added inside the
85+
// view to track the size changes that are performed behind our back by
86+
// the browser's layout engine faster (ViewBase checks for the layout
87+
// updates once a second and sometimes it's not fast enough).
88+
89+
// Unfortunately <div> doesn't have `resize` event, so we're trying to
90+
// detect the fact that the view has been resized with `scroll` events.
91+
// To do that, we create two scrollable <div>s and we put them into a
92+
// state in which `scroll` event is triggered by the browser when the
93+
// container gets resized (one element triggers `scroll` when the
94+
// container gets bigger, another triggers `scroll` when the container
95+
// gets smaller).
96+
11497
if (!this.props.importantForLayout) {
11598
return null;
11699
}
@@ -138,27 +121,62 @@ export class View extends ViewBase<Types.ViewProps, {}> {
138121
return [
139122
(
140123
<div
141-
key='grow'
124+
key={ 'grow' }
142125
style={ _styles.resizeDetectorContainerStyles }
143126
ref={ (ref) => initResizer('grow', ref) }
144127
onScroll={ () => this.resizeDetectorOnScroll() }>
145128

146-
<div style={_styles.resizeGrowDetectorStyles}></div>
129+
<div style={ _styles.resizeGrowDetectorStyles }></div>
147130
</div>
148131
),
149132
(
150133
<div
151-
key='shrink'
134+
key={ 'shrink' }
152135
style={ _styles.resizeDetectorContainerStyles }
153136
ref={ (ref) => initResizer('shrink', ref) }
154137
onScroll={ () => this.resizeDetectorOnScroll() }>
155138

156-
<div style={_styles.resizeShrinkDetectorStyles}></div>
139+
<div style={ _styles.resizeShrinkDetectorStyles }></div>
157140
</div>
158141
)
159142
];
160143
}
161144

145+
private resizeDetectorReset() {
146+
// Scroll the detectors to the bottom-right corner so
147+
// that `scroll` events will be triggered when the container
148+
// is resized.
149+
const scrollMax = 100500;
150+
151+
let node = this.resizeDetectorNodes.grow;
152+
153+
if (node) {
154+
node.scrollLeft = scrollMax;
155+
node.scrollTop = scrollMax;
156+
}
157+
158+
node = this.resizeDetectorNodes.shrink;
159+
160+
if (node) {
161+
node.scrollLeft = scrollMax;
162+
node.scrollTop = scrollMax;
163+
}
164+
}
165+
166+
private resizeDetectorOnScroll() {
167+
if (this.resizeDetectorAnimationFrame) {
168+
// Do not execute action more often than once per animation frame.
169+
return;
170+
}
171+
172+
this.resizeDetectorAnimationFrame = window.requestAnimationFrame(() => {
173+
this.resizeDetectorReset();
174+
this.resizeDetectorAnimationFrame = undefined;
175+
ViewBase._checkViews();
176+
});
177+
178+
}
179+
162180
getChildContext() {
163181
// Let descendant Types components know that their nearest Types ancestor is not an Types.Text.
164182
// Because they're in an Types.View, they should use their normal styling rather than their
@@ -209,19 +227,19 @@ export class View extends ViewBase<Types.ViewProps, {}> {
209227
if (childAnimationsEnabled) {
210228
reactElement = (
211229
<AnimateListEdits
212-
{...props}
213-
animateChildEnter={this.props.animateChildEnter}
214-
animateChildMove={this.props.animateChildMove}
215-
animateChildLeave={this.props.animateChildLeave}
230+
{ ...props }
231+
animateChildEnter={ this.props.animateChildEnter }
232+
animateChildMove={ this.props.animateChildMove }
233+
animateChildLeave={ this.props.animateChildLeave }
216234
>
217-
{this.props.children}
235+
{ this.props.children }
218236
</AnimateListEdits>
219237
);
220238
} else {
221239
reactElement = (
222-
<div {...props} >
223-
{this.renderResizeDetectorIfNeeded(combinedStyles)}
224-
{this.props.children}
240+
<div { ...props } >
241+
{ this.renderResizeDetectorIfNeeded(combinedStyles) }
242+
{ this.props.children }
225243
</div>
226244
);
227245
}

0 commit comments

Comments
 (0)