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

Commit

Permalink
feat(preview): highlight element on select
Browse files Browse the repository at this point in the history
  • Loading branch information
Lasse Kuechler authored and lkuechler committed Feb 19, 2018
1 parent d2ee04a commit 2423a5d
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 9 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
"@types/node": "^9.4.0",
"@types/react": "^16.0.0",
"@types/react-dom": "^16.0.3",
"@types/smoothscroll-polyfill": "^0.3.0",
"concurrently": "^3.5.1",
"electron": "^1.7.10",
"electron-builder": "20.0.5",
Expand All @@ -113,6 +114,7 @@
"react-dom": "16.2.0",
"react-router": "4.2.0",
"readts": "0.1.0",
"smoothscroll-polyfill": "0.4.0",
"styled-components": "3.1.6",
"tslib": "1.9.0",
"typescript": "2.6.2"
Expand Down
27 changes: 20 additions & 7 deletions src/component/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -193,26 +193,39 @@ function getDevTools(): React.StatelessComponent | null {

const store = new Store();

function sendWebViewMessage(message: JsonObject, channel: string): void {
const webviewTag: WebviewTag = document.getElementById('preview') as WebviewTag;
if (webviewTag && webviewTag.send) {
webviewTag.send(channel, message);
}
}

MobX.autorun(() => {
const page: Page | undefined = store.getCurrentPage();
const message: JsonObject = {
page: page ? page.toJsonObject() : undefined,
pageId: page ? page.getId() : undefined
};

const webviewTag: WebviewTag = document.getElementById('preview') as WebviewTag;
if (webviewTag && webviewTag.send) {
webviewTag.send('page-change', message);
}
sendWebViewMessage(message, 'page-change');
});

MobX.autorun(() => {
const message: JsonObject = { styleGuidePath: store.getStyleGuidePath() };

const webviewTag: WebviewTag = document.getElementById('preview') as WebviewTag;
if (webviewTag && webviewTag.send) {
webviewTag.send('open-styleguide', message);
sendWebViewMessage(message, 'open-styleguide');
});

MobX.autorun(() => {
const selectedElement = store.getSelectedElement();

if (!selectedElement) {
return;
}

const message: JsonObject = { selectedElementId: selectedElement.getId() };

sendWebViewMessage(message, 'selectedElement-change');
});

ReactDom.render(<App store={store} />, document.getElementById('app'));
Expand Down
103 changes: 102 additions & 1 deletion src/component/presentation/preview.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
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/pattern/pattern';
import { PropertyValue } from '../../store/page/property-value';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { TextPattern } from '../../store/pattern/text-pattern';

class PatternWrapper extends React.Component<{}, PatternWrapperState> {
Expand All @@ -25,22 +27,60 @@ class PatternWrapper extends React.Component<{}, PatternWrapperState> {
}
}

export interface HighlightAreaProps extends ClientRect {
opacity?: number;
}

export interface PreviewProps {
page?: Page;
selectedElementId?: number[];
}

@observer
export class Preview extends React.Component<PreviewProps> {
private patternFactories: { [folder: string]: React.StatelessComponent };
@observable private highlightArea: HighlightAreaProps;

public constructor(props: PreviewProps) {
super(props);
this.patternFactories = {};

this.highlightArea = {
bottom: 0,
height: 0,
left: 0,
opacity: 0,
right: 0,
top: 0,
width: 0
};
}

public render(): JSX.Element | null {
if (this.props.page) {
return this.createComponent(this.props.page.getRoot()) as JSX.Element;
const highlightArea: HighlightAreaProps = this.highlightArea;
return (
<>
{this.createComponent(this.props.page.getRoot()) as JSX.Element}
<div
style={{
position: 'absolute',
boxSizing: 'border-box',
border: '1px dashed rgba(55, 55, 55, .5)',
background:
'repeating-linear-gradient(135deg,transparent,transparent 2.5px,rgba(51,141,222, .5) 2.5px,rgba(51,141,222, .5) 5px), rgba(102,169,230, .5)',
transition: 'all .25s ease-in-out',
bottom: highlightArea.bottom,
height: highlightArea.height,
left: highlightArea.left,
opacity: highlightArea.opacity,
right: highlightArea.right,
top: highlightArea.top,
width: highlightArea.width
}}
/>
</>
);
}
return null;
}
Expand Down Expand Up @@ -98,6 +138,26 @@ export class Preview extends React.Component<PreviewProps> {
const reactComponent = patternFactory(componentProps);

// Finally, build the component
if (
pageElement.getId().toString() ===
(this.props.selectedElementId && this.props.selectedElementId.toString())
) {
return (
<PatternWrapper
key={key}
ref={(el: PatternWrapper) => {
const domNode = ReactDOM.findDOMNode(el);
if (!domNode) {
return;
}

this.highlightElement(domNode);
}}
>
{reactComponent}
</PatternWrapper>
);
}
return <PatternWrapper key={key}>{reactComponent}</PatternWrapper>;
} else {
// The model is an object, but not a pattern declaration.
Expand All @@ -112,6 +172,47 @@ export class Preview extends React.Component<PreviewProps> {
return result;
}
}

@action
private highlightElement(element: Element): void {
const highlightArea: HighlightAreaProps = this.highlightArea;
const clientRect: ClientRect = element.getBoundingClientRect();
const newHighlightArea: HighlightAreaProps = {
bottom: clientRect.bottom,
height: clientRect.height,
left: clientRect.left + window.scrollX,
opacity: 1,
right: clientRect.right,
top: clientRect.top + window.scrollY,
width: clientRect.width
};

if (
newHighlightArea.top === highlightArea.top &&
newHighlightArea.right === highlightArea.right &&
newHighlightArea.bottom === highlightArea.bottom &&
newHighlightArea.left === highlightArea.left &&
newHighlightArea.height === highlightArea.height &&
newHighlightArea.width === highlightArea.width
) {
return;
}

element.scrollIntoView({
behavior: 'smooth',
block: 'center',
inline: 'nearest'
});

this.highlightArea = newHighlightArea;

setTimeout(() => this.hideHighlightArea(), 500);
}

@action
private hideHighlightArea(): void {
this.highlightArea.opacity = 0;
}
}

interface PatternWrapperState {
Expand Down
16 changes: 15 additions & 1 deletion src/component/preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import { ipcRenderer } from 'electron';
import { JsonObject } from '../store/json';
import { observer } from 'mobx-react';
import { Page } from '../store/page/page';
import { PageElement } from '../store/page/page-element';
import { Preview } from './presentation/preview';
import * as React from 'react';
import * as ReactDom from 'react-dom';
import * as SmoothscrollPolyfill from 'smoothscroll-polyfill';
import { Store } from '../store/store';

interface PreviewAppProps {
Expand All @@ -21,6 +23,10 @@ class PreviewApp extends React.Component<PreviewAppProps, PreviewAppState> {
super(props);
}

public componentDidMount(): void {
SmoothscrollPolyfill.polyfill();
}

public render(): JSX.Element {
let DevTools;
try {
Expand All @@ -30,9 +36,13 @@ class PreviewApp extends React.Component<PreviewAppProps, PreviewAppState> {
// Ignored
}

const selectedElement: PageElement | undefined = this.props.store.getSelectedElement();
return (
<div>
<Preview page={this.props.store.getCurrentPage()} />
<Preview
page={this.props.store.getCurrentPage()}
selectedElementId={selectedElement && selectedElement.getId()}
/>
{DevTools ? <DevTools /> : ''}
</div>
);
Expand All @@ -49,6 +59,10 @@ ipcRenderer.on('open-styleguide', (event: {}, message: JsonObject) => {
store.openStyleguide(message.styleGuidePath as string);
});

ipcRenderer.on('selectedElement-change', (event: {}, message: JsonObject) => {
store.setSelectedElementById(message.selectedElementId as number[]);
});

window.onload = () => {
ReactDom.render(<PreviewApp store={store} />, document.getElementById('app'));
};
Expand Down
6 changes: 6 additions & 0 deletions src/store/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,12 @@ export class Store {
return;
}
startElement = currentPage.getRoot();

// if selected element is root element return immediately
if (id.length === 1) {
return startElement;
}

id.splice(0, 1);
}

Expand Down

0 comments on commit 2423a5d

Please sign in to comment.