Skip to content

Commit

Permalink
feat(modal): add topInsetEnabled prop when StatusBar is translucent (#…
Browse files Browse the repository at this point in the history
…1372)

closes #743
  • Loading branch information
whitestranger7 committed Mar 18, 2021
1 parent 4a117e7 commit 407356e
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 20 deletions.
19 changes: 14 additions & 5 deletions src/components/devsupport/components/measure/measure.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,19 @@ import React from 'react';
import {
findNodeHandle,
UIManager,
StatusBar,
} from 'react-native';
import { Frame } from './type';

export interface MeasureElementProps<P = any> {
force?: boolean;
shouldUseTopInsets?: boolean;
onMeasure: (frame: Frame) => void;
children: React.ReactElement<P>;
}

export type MeasuringElement<P = any> = React.ReactElement;

/**
* Measures child element size and it's screen position asynchronously.
* Returns measure result in `onMeasure` callback.
Expand All @@ -32,7 +34,9 @@ export type MeasuringElement<P = any> = React.ReactElement;
* ...
* };
*
* <MeasureElement onMeasure={onMeasure}>
* <MeasureElement
* shouldUseTopInsets={ModalService.getShouldUseTopInsets}
* onMeasure={onMeasure}>
* <ElementToMeasure />
* </MeasureElement>
* ```
Expand All @@ -41,7 +45,7 @@ export type MeasuringElement<P = any> = React.ReactElement;
* but `force` property may be used to measure any time it's needed.
* DON'T USE THIS FLAG IF THE COMPONENT RENDERS FIRST TIME OR YOU KNOW `onLayout` WILL BE CALLED.
*/
export const MeasureElement = (props: MeasureElementProps): MeasuringElement => {
export const MeasureElement: React.FC<MeasureElementProps> = (props): MeasuringElement => {

const ref = React.useRef<any>();

Expand All @@ -61,7 +65,8 @@ export const MeasureElement = (props: MeasureElementProps): MeasuringElement =>
};

const onUIManagerMeasure = (x: number, y: number, w: number, h: number): void => {
const frame: Frame = bindToWindow(new Frame(x, y, w, h), Frame.window());
const originY = props.shouldUseTopInsets ? y + StatusBar.currentHeight || 0 : y;
const frame: Frame = bindToWindow(new Frame(x, originY, w, h), Frame.window());
props.onMeasure(frame);
};

Expand All @@ -76,3 +81,7 @@ export const MeasureElement = (props: MeasureElementProps): MeasuringElement =>

return React.cloneElement(props.children, { ref, onLayout: measureSelf });
};

MeasureElement.defaultProps = {
shouldUseTopInsets: false,
}
24 changes: 12 additions & 12 deletions src/components/theme/application/applicationProvider.component.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/**
* @license
* Copyright Akveo. All Rights Reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/
* @license
* Copyright Akveo. All Rights Reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/

import React from 'react';
import merge from 'lodash.merge';
Expand All @@ -15,25 +15,25 @@ import {
import { StyleProvider } from '../style/styleProvider.component';
import { ThemeProviderProps } from '../theme/themeProvider.component';
import { ModalPanel } from '../modal/modalPanel.component';

interface EvaRuntimeProcessingProps {
mapping: SchemaType;
customMapping?: CustomSchemaType;
}

interface EvaBuildtimeProcessingProps {
styles: ThemeStyleType;
}

type EvaProcessingProps = EvaRuntimeProcessingProps | EvaBuildtimeProcessingProps;

export type ApplicationProviderProps = EvaProcessingProps & ThemeProviderProps;
export type ApplicationProviderElement = React.ReactElement<ApplicationProviderProps>;

interface State {
styles: ThemeStyleType;
}

/**
* Overall application container.
*
Expand Down Expand Up @@ -110,7 +110,7 @@ export class ApplicationProvider extends React.Component<ApplicationProviderProp
this.state.styles = this.createStyles(mapping, customMapping);
}
}

private createStyles = (mapping: SchemaType, custom: CustomSchemaType): ThemeStyleType => {
const customizedMapping: SchemaType = merge({}, mapping, custom);
return this.schemaProcessor.process(customizedMapping);
Expand All @@ -127,4 +127,4 @@ export class ApplicationProvider extends React.Component<ApplicationProviderProp
</StyleProvider>
);
}
}
}
9 changes: 9 additions & 0 deletions src/components/theme/modal/modal.service.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ import {
class ModalServiceType {

panel: ModalPresenting | null = null;
private shouldUseTopInsets: boolean = false;

public mount(panel: ModalPresenting | null): void {
this.panel = panel;
Expand All @@ -87,6 +88,14 @@ class ModalServiceType {
return this.panel.hide(identifier);
}
}

public set setShouldUseTopInsets(state: boolean) {
this.shouldUseTopInsets = state;
};

public get getShouldUseTopInsets(): boolean {
return this.shouldUseTopInsets;
}
}

export interface ModalPresentingConfig {
Expand Down
5 changes: 4 additions & 1 deletion src/components/ui/menu/menuGroup.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
MenuItemElement,
MenuItemProps,
} from './menuItem.component';
import { ModalService } from '../../theme';
import { MenuItemDescriptor } from './menu.service';

export interface MenuGroupProps extends MenuItemProps {
Expand Down Expand Up @@ -149,7 +150,9 @@ export class MenuGroup extends React.Component<MenuGroupProps, State> {

private renderMeasuringGroupedItems = (evaStyle): MeasuringElement => {
return (
<MeasureElement onMeasure={this.onSubmenuMeasure}>
<MeasureElement
shouldUseTopInsets={ModalService.getShouldUseTopInsets}
onMeasure={this.onSubmenuMeasure}>
{this.renderGroupedItems(evaStyle)}
</MeasureElement>
);
Expand Down
4 changes: 3 additions & 1 deletion src/components/ui/modal/modal.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,9 @@ export class Modal extends React.PureComponent<ModalProps, State> {

private renderMeasuringContentElement = (): MeasuringElement => {
return (
<MeasureElement onMeasure={this.onContentMeasure}>
<MeasureElement
shouldUseTopInsets={ModalService.getShouldUseTopInsets}
onMeasure={this.onContentMeasure}>
{this.renderContentElement()}
</MeasureElement>
);
Expand Down
5 changes: 4 additions & 1 deletion src/components/ui/popover/popover.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,9 @@ export class Popover extends React.Component<PopoverProps, State> {

private renderMeasuringPopoverElement = (): MeasuringElement => {
return (
<MeasureElement onMeasure={this.onContentMeasure}>
<MeasureElement
shouldUseTopInsets={ModalService.getShouldUseTopInsets}
onMeasure={this.onContentMeasure}>
{this.renderPopoverElement()}
</MeasureElement>
);
Expand All @@ -227,6 +229,7 @@ export class Popover extends React.Component<PopoverProps, State> {
public render(): React.ReactElement {
return (
<MeasureElement
shouldUseTopInsets={ModalService.getShouldUseTopInsets}
force={this.state.forceMeasure}
onMeasure={this.onChildMeasure}>
{this.props.anchor()}
Expand Down

0 comments on commit 407356e

Please sign in to comment.