Skip to content
This repository has been archived by the owner on Oct 23, 2023. It is now read-only.

Commit

Permalink
feat(preview): pattern error handling (fixes #271)
Browse files Browse the repository at this point in the history
  • Loading branch information
TheReincarnator committed Mar 23, 2018
1 parent bcfe1b9 commit 9fdad0b
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 46 deletions.
29 changes: 29 additions & 0 deletions src/component/presentation/react/error-message.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import * as React from 'react';

export interface ErrorMessageProps {
error: string;
patternName: string;
}

export const ErrorMessage: React.StatelessComponent<ErrorMessageProps> = props => (
<div
style={{
'background-color': 'rgb(240, 40, 110)',
color: 'white',
padding: '12px 15px',
'text-align': 'center'
}}
>
<p
style={{
margin: '0',
'font-family':
'-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"',
'font-size': '15px',
'line-height': '22px'
}}
>
{props.patternName} failed to render: {props.error}
</p>
</div>
);
99 changes: 56 additions & 43 deletions src/component/presentation/react/preview.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { ErrorMessage } from './error-message';
import { action, observable } from 'mobx';
import { observer } from 'mobx-react';
import { Page } from '../../../store/page/page';
import { PageElement } from '../../../store/page/page-element';
import { Pattern } from '../../../store/styleguide/pattern';
import { HighlightAreaProps, HighlightElementFunction } from '../../preview';
import { PropertyValue } from '../../../store/page/property-value';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { Store } from '../../../store/store';
import { StringProperty } from '../../../store/styleguide/property/string-property';

import { HighlightAreaProps, HighlightElementFunction } from '../../preview';

export interface PreviewAppProps {
highlightElement: HighlightElementFunction;
store: Store;
Expand All @@ -30,8 +30,12 @@ interface PatternWrapperState {
errorMessage?: string;
}

class PatternWrapper extends React.Component<{}, PatternWrapperState> {
public constructor(props: {}) {
interface PatternWrapperProps {
pattern: Pattern;
}

class PatternWrapper extends React.Component<PatternWrapperProps, PatternWrapperState> {
public constructor(props: PatternWrapperProps) {
super(props);
this.state = {};
}
Expand All @@ -42,7 +46,12 @@ class PatternWrapper extends React.Component<{}, PatternWrapperState> {

public render(): React.ReactNode {
if (this.state.errorMessage) {
return <span>{this.state.errorMessage}</span>;
return (
<ErrorMessage
patternName={this.props.pattern.getName()}
error={this.state.errorMessage}
/>
);
} else {
return this.props.children;
}
Expand Down Expand Up @@ -103,57 +112,61 @@ class Preview extends React.Component<PreviewProps> {
// First, process the properties and children of the declaration recursively
const pageElement: PageElement = value;
const pattern = pageElement.getPattern();

if (!pattern) {
return null;
}

const patternId: string = pattern.getId();
if (patternId === Pattern.SYNTHETIC_TEXT_ID) {
return pageElement.getPropertyValue(StringProperty.SYNTHETIC_TEXT_ID);
}
try {
const patternId: string = pattern.getId();
if (patternId === Pattern.SYNTHETIC_TEXT_ID) {
return pageElement.getPropertyValue(StringProperty.SYNTHETIC_TEXT_ID);
}

// tslint:disable-next-line:no-any
const componentProps: any = {};
pattern.getProperties().forEach(property => {
const propertyId = property.getId();

componentProps[propertyId] = this.createComponent(
property.convertToRender(pageElement.getPropertyValue(propertyId)),
propertyId
);
});

componentProps.children = pageElement
.getChildren()
.map((child, index) => this.createComponent(child, String(index)));

// Then, load the pattern factory
const patternPath: string = pattern.getImplementationPath();
let patternFactory: React.StatelessComponent | ObjectConstructor = this.patternFactories[
patternId
];
if (patternFactory == null) {
const exportName = pattern.getExportName();
const module = require(patternPath);
patternFactory = module[exportName];
this.patternFactories[patternId] = patternFactory;
}

const reactComponent = React.createElement(patternFactory, componentProps);

// Finally, build the component
if (pageElement.getId() === this.props.selectedElementId) {
// tslint:disable-next-line:no-any
const componentProps: any = {};
pattern.getProperties().forEach(property => {
const propertyId = property.getId();

componentProps[propertyId] = this.createComponent(
property.convertToRender(pageElement.getPropertyValue(propertyId)),
propertyId
);
});

componentProps.children = pageElement
.getChildren()
.map((child, index) => this.createComponent(child, String(index)));

// Then, load the pattern factory
const patternPath: string = pattern.getImplementationPath();
let patternFactory: React.StatelessComponent | ObjectConstructor = this
.patternFactories[patternId];
if (patternFactory == null) {
const exportName = pattern.getExportName();
const module = require(patternPath);
patternFactory = module[exportName];
this.patternFactories[patternId] = patternFactory;
}

const reactComponent = React.createElement(patternFactory, componentProps);

// Finally, build the component
return (
<PatternWrapper
key={key}
ref={(ref: PatternWrapper) => (this.patternWrapperRef = ref)}
pattern={pattern}
ref={
pageElement.getId() === this.props.selectedElementId
? (ref: PatternWrapper) => (this.patternWrapperRef = ref)
: undefined
}
>
{reactComponent}
</PatternWrapper>
);
} catch (error) {
return <ErrorMessage patternName={pattern.getName()} error={error.toString()} />;
}
return <PatternWrapper key={key}>{reactComponent}</PatternWrapper>;
} else {
// The model is an object, but not a pattern declaration.
// Create a new object with recursively processed values.
Expand Down
5 changes: 2 additions & 3 deletions src/component/presentation/react/render.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import * as React from 'react';
import * as ReactDom from 'react-dom';

import { PreviewApp } from './preview';
import { HighlightElementFunction } from '../../preview';
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { Store } from '../../../store/store';

export const renderReact = (store: Store, highlightElement: HighlightElementFunction) => {
Expand Down

0 comments on commit 9fdad0b

Please sign in to comment.