Skip to content

Commit

Permalink
feat(ui/theme): "modal-team" missing update functionality add
Browse files Browse the repository at this point in the history
  • Loading branch information
32penkin committed Jul 26, 2019
1 parent 144abb4 commit 71dd6f7
Show file tree
Hide file tree
Showing 7 changed files with 228 additions and 118 deletions.
10 changes: 10 additions & 0 deletions src/framework/theme/modal/modal.service.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import { ModalPresentingBased } from '../../ui/support/typings';
*
* @method {(identifier: string) => string} hide - Hides component from a modal window and returns empty string.
*
* @method {(identifier: string, children: React.ReactNode) => void} update - Updates component from a modal window.
*
* @example Simple Usage example
*
* ```
Expand Down Expand Up @@ -87,6 +89,12 @@ class ModalServiceType {
}
}

public update(identifier: string, children: React.ReactNode): void {
if (this.panel) {
this.panel.update(identifier, children);
}
}

public hide(identifier: string): string {
if (this.panel) {
return this.panel.hide(identifier);
Expand All @@ -104,6 +112,8 @@ export interface ModalPresenting {
config: ModalPresentingConfig): string;

hide(identifier: string): string;

update(identifier: string, children: React.ReactNode): void;
}

export const ModalService = new ModalServiceType();
14 changes: 14 additions & 0 deletions src/framework/theme/modal/modalPanel.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,20 @@ export class ModalPanel extends React.Component<ModalPanelProps, ModalPanelState
return key;
}

public update(identifier: string, children: React.ReactNode): void {
const panelChild: ModalPanelChild = this.state.components.get(identifier);
const childElement: React.ReactElement<ModalPresentingBased> = panelChild.element;

panelChild.element = React.cloneElement(childElement, {
children: children,
});

const components: Map<string, ModalPanelChild> = this.state.components;
components.delete(identifier);
components.set(identifier, panelChild);
this.setState({ components });
}

private generateUniqueComponentKey = (): string => {
return Math.random().toString(36).substring(2);
};
Expand Down
12 changes: 8 additions & 4 deletions src/framework/ui/modal/modal.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,14 +106,18 @@ export class Modal extends React.Component<ModalProps> {
private contentSize: Size = initialContentSize;
private id: string = '';

public componentWillReceiveProps(nextProps: ModalProps): void {
this.handleVisibility(nextProps);
public componentDidUpdate(prevProps: ModalProps): void {
if (prevProps.visible !== this.props.visible) {
this.handleVisibility(this.props);
} else if (prevProps.visible && this.props.visible) {
ModalService.update(this.id, this.props.children);
}
}

private handleVisibility = (nextProps: ModalProps): void => {
private handleVisibility = (props: ModalProps): void => {
const { allowBackdrop, onBackdropPress } = this.props;

if (nextProps.visible) {
if (props.visible) {
const element: React.ReactElement = this.renderModal();
this.id = ModalService.show(element, { allowBackdrop, onBackdropPress });
} else {
Expand Down
96 changes: 95 additions & 1 deletion src/framework/ui/modal/modal.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ import {
Modal,
baseModalTestId,
} from './modal.component';
import { StyleType } from '@kitten/theme';
import {
ModalPanel,
StyleType,
} from '@kitten/theme';

const buttonShowModalTestId: string = '@button-show-modal';
const buttonHideModalTestId: string = '@button-hide-modal';
Expand Down Expand Up @@ -99,3 +102,94 @@ describe('@modal component checks', () => {
});

});

describe('@modal panel checks', () => {

const showModalButtonTestId: string = '@modal/button-show';
const changeModalTextButtonTestId: string = '@modal/button-change-text';
const modalTextTestId: string = '@modal/text';

interface Props {
textValue: string;
redTextValue: string;
}

interface State {
modalVisible: boolean;
isModalTextRed: boolean;
}

class TestApplication extends React.Component<Props, State> {

public state: State = {
modalVisible: false,
isModalTextRed: false,
};

private setModalVisible = (): void => {
const modalVisible: boolean = !this.state.modalVisible;

this.setState({ modalVisible });
};

private setModalTextRed = (): void => {
const isModalTextRed: boolean = !this.state.isModalTextRed;

this.setState({ isModalTextRed });
};


public render(): React.ReactNode {
const { textValue, redTextValue } = this.props;
const { modalVisible, isModalTextRed } = this.state;
const modalTextStyle: StyleType = isModalTextRed ? { color: 'red' } : null;
const modalTextValue: string = isModalTextRed ? redTextValue : textValue;

return (
<ModalPanel>
<Button
testID={showModalButtonTestId}
title='Show Modal'
onPress={this.setModalVisible}
/>
<Modal
visible={modalVisible}
onBackdropPress={this.setModalVisible}>
<Text
style={modalTextStyle}
testID={modalTextTestId}>
{modalTextValue}
</Text>
<Button
testID={changeModalTextButtonTestId}
title='Set Text Red'
onPress={this.setModalTextRed}
/>
</Modal>
</ModalPanel>
);
}
}

it('* modal "team" updates content properly', () => {
const textValue: string = 'Text Value';
const redTextValue: string = 'Red Text Value';
const expectedTextStyle: StyleType = { color: 'red' };
const application: any = render(
<TestApplication
textValue={textValue}
redTextValue={redTextValue}
/>,
);

fireEvent.press(application.getByTestId(showModalButtonTestId));
fireEvent.press(application.getAllByTestId(changeModalTextButtonTestId)[0]);

const { children, style } = application.getAllByTestId(modalTextTestId)[0].props;

expect(stringify(style)).toBe(stringify(expectedTextStyle));
expect(children).toBe(redTextValue);
});

});

17 changes: 16 additions & 1 deletion src/framework/ui/popover/popover.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -148,15 +148,30 @@ export class PopoverComponent extends React.Component<PopoverProps> {
private popoverPlacement: PopoverPlacement;

public componentDidUpdate(prevProps: PopoverProps) {
this.handleVisibility(prevProps);
}

private handleVisibility = (prevProps: PopoverProps): void => {
if (prevProps.visible !== this.props.visible) {
if (this.props.visible) {
// Toggles re-measuring. This is needed for dynamic containers like ScrollView
this.setState({ layout: undefined });
} else {
this.popoverId = ModalService.hide(this.popoverId);
}
} else if (prevProps.visible && this.props.visible) {
this.updatePopoverElement();
}
}
};

private updatePopoverElement = (): void => {
const element: ContentElement = this.renderPopoverElement(this.props.content, this.popoverPlacement);

const popoverElement: ContentElement = React.cloneElement(element, {
style: [element.props.style, styles.popoverVisible],
});
this.popoverId && ModalService.update(this.popoverId, popoverElement);
};

private getComponentStyle = (source: StyleType): StyleType => {
const {
Expand Down
2 changes: 2 additions & 0 deletions src/framework/ui/support/typings/type.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import React from 'react';
import {
GestureResponderEvent,
NativeScrollEvent,
Expand All @@ -20,6 +21,7 @@ export type ScrollEvent = NativeSyntheticEvent<NativeScrollEvent>;
export type InputFocusEvent = NativeSyntheticEvent<TextInputFocusEventData>;

export interface ModalPresentingBased {
children?: React.ReactNode;
allowBackdrop?: boolean;
onBackdropPress: () => void;
}

0 comments on commit 71dd6f7

Please sign in to comment.