Fix flow type errors of all viewers #2039

Merged
btzr-io merged 4 commits from fix-flow into master 2018-10-15 19:19:41 +02:00
9 changed files with 154 additions and 88 deletions

View file

@ -32,6 +32,7 @@
"postinstall": "electron-builder install-app-deps && node build/downloadDaemon.js" "postinstall": "electron-builder install-app-deps && node build/downloadDaemon.js"
}, },
"dependencies": { "dependencies": {
"@types/three": "^0.93.1",
"bluebird": "^3.5.1", "bluebird": "^3.5.1",
"breakdance": "^3.0.1", "breakdance": "^3.0.1",
"classnames": "^2.2.5", "classnames": "^2.2.5",

View file

@ -6,25 +6,34 @@ import remarkEmoji from 'remark-emoji';
import ExternalLink from 'component/externalLink'; import ExternalLink from 'component/externalLink';
import defaultSchema from 'hast-util-sanitize/lib/github.json'; import defaultSchema from 'hast-util-sanitize/lib/github.json';
type MarkdownProps = {
content: ?string,
promptLinks?: boolean,
};
type SimpleLinkProps = {
href?: string,
title?: string,
children?: React.Node,
};
const SimpleLink = (props: SimpleLinkProps) => {
const { href, title, children } = props;
return (
<a href={href} title={title}>
{children}
</a>
);
};
// Use github sanitation schema // Use github sanitation schema
const schema = { ...defaultSchema }; const schema = { ...defaultSchema };
// Extend sanitation schema to support lbry protocol // Extend sanitation schema to support lbry protocol
schema.protocols.href[3] = 'lbry'; schema.protocols.href[3] = 'lbry';
type MarkdownProps = {
content: string,
promptLinks?: boolean,
};
const SimpleLink = ({ href, title, children }) => (
<a href={href} title={title}>
{children}
</a>
);
const MarkdownPreview = (props: MarkdownProps) => { const MarkdownPreview = (props: MarkdownProps) => {
const { content, externalLinks, promptLinks } = props; const { content, promptLinks } = props;
const remarkOptions = { const remarkOptions = {
sanitize: schema, sanitize: schema,
remarkReactComponents: { remarkReactComponents: {

View file

@ -10,11 +10,11 @@ import HtmlViewer from 'component/viewers/htmlViewer';
type Props = { type Props = {
mediaType: string, mediaType: string,
source: { source: {
stream: string => void,
fileName: string, fileName: string,
fileType: string, fileType: string,
contentType: string,
downloadPath: string, downloadPath: string,
stream: opts => void,
blob: callback => void,
}, },
currentTheme: string, currentTheme: string,
}; };

View file

@ -1,6 +1,6 @@
// @flow // @flow
import React from 'react'; import * as React from 'react';
import CodeMirror from 'codemirror/lib/codemirror'; import CodeMirror from 'codemirror/lib/codemirror';
import { openSnippetMenu, stopContextMenu } from 'util/contextMenu'; import { openSnippetMenu, stopContextMenu } from 'util/contextMenu';
@ -22,21 +22,20 @@ import 'codemirror/mode/javascript/javascript';
type Props = { type Props = {
theme: string, theme: string,
value: string, value: ?string,
contentType: string, contentType: string,
}; };
class CodeViewer extends React.PureComponent<Props> { class CodeViewer extends React.PureComponent<Props> {
constructor(props) { constructor(props: Props) {
super(props); super(props);
this.codeMirror = null; this.codeMirror = null;
this.textarea = React.createRef();
} }
componentDidMount() { componentDidMount() {
const { theme, contentType } = this.props; const { theme, contentType } = this.props;
// Init CodeMirror // Init CodeMirror
this.codeMirror = CodeMirror.fromTextArea(this.textarea.current, { this.codeMirror = CodeMirror.fromTextArea(this.textarea, {
// Auto detect syntax with file contentType // Auto detect syntax with file contentType
mode: contentType, mode: contentType,
// Adaptive theme // Adaptive theme
@ -54,11 +53,14 @@ class CodeViewer extends React.PureComponent<Props> {
this.codeMirror.on('contextmenu', openSnippetMenu); this.codeMirror.on('contextmenu', openSnippetMenu);
} }
textarea: ?HTMLTextAreaElement;
codeMirror: any;
render() { render() {
const { value } = this.props; const { value } = this.props;
return ( return (
<div className="code-viewer" onContextMenu={stopContextMenu}> <div className="code-viewer" onContextMenu={stopContextMenu}>
<textarea ref={this.textarea} disabled value={value} /> <textarea ref={textarea => (this.textarea = textarea)} disabled value={value} />
</div> </div>
); );
} }

View file

@ -8,19 +8,25 @@ import MarkdownPreview from 'component/common/markdown-preview';
type Props = { type Props = {
theme: string, theme: string,
source: { source: {
stream: opts => void, stream: string => any,
fileType: string, fileType: string,
contentType: string, contentType: string,
}, },
}; };
class DocumentViewer extends React.PureComponent<Props> { type State = {
constructor(props) { error: boolean,
loading: boolean,
content: ?string,
};
class DocumentViewer extends React.PureComponent<Props, State> {
constructor(props: Props) {
super(props); super(props);
this.state = { this.state = {
error: null, error: false,
content: null,
loading: true, loading: true,
content: null,
}; };
} }
@ -38,13 +44,14 @@ class DocumentViewer extends React.PureComponent<Props> {
this.setState({ content: data, loading: false }); this.setState({ content: data, loading: false });
}); });
stream.on('error', error => { stream.on('error', () => {
this.setState({ error: true, loading: false }); this.setState({ error: true, loading: false });
}); });
} }
renderDocument(content = null) { renderDocument() {
let viewer = null; let viewer = null;
const { content } = this.state;
const { source, theme } = this.props; const { source, theme } = this.props;
const { fileType, contentType } = source; const { fileType, contentType } = source;
const markdownType = ['md', 'markdown']; const markdownType = ['md', 'markdown'];
@ -70,7 +77,7 @@ class DocumentViewer extends React.PureComponent<Props> {
<div className="file-render__viewer document-viewer"> <div className="file-render__viewer document-viewer">
{loading && !error && <LoadingScreen status={loadingMessage} spinner />} {loading && !error && <LoadingScreen status={loadingMessage} spinner />}
{error && <LoadingScreen status={errorMessage} spinner={!error} />} {error && <LoadingScreen status={errorMessage} spinner={!error} />}
{isReady && this.renderDocument(content)} {isReady && this.renderDocument()}
</div> </div>
); );
} }

View file

@ -10,11 +10,17 @@ type Props = {
source: string, source: string,
}; };
class DocxViewer extends React.PureComponent<Props> { type State = {
constructor(props) { error: boolean,
loading: boolean,
content: ?string,
};
class DocxViewer extends React.PureComponent<Props, State> {
constructor(props: Props) {
super(props); super(props);
this.state = { this.state = {
error: null, error: false,
content: null, content: null,
loading: true, loading: true,
}; };
@ -46,7 +52,7 @@ class DocxViewer extends React.PureComponent<Props> {
const markdown = breakdance.render(result.value); const markdown = breakdance.render(result.value);
this.setState({ content: markdown, loading: false }); this.setState({ content: markdown, loading: false });
}) })
.catch(error => { .catch(() => {
this.setState({ error: true, loading: false }); this.setState({ error: true, loading: false });
}) })
.done(); .done();

View file

@ -1,5 +1,5 @@
// @flow // @flow
import React from 'react'; import * as React from 'react';
import { stopContextMenu } from 'util/contextMenu'; import { stopContextMenu } from 'util/contextMenu';
type Props = { type Props = {
@ -7,16 +7,11 @@ type Props = {
}; };
class PdfViewer extends React.PureComponent<Props> { class PdfViewer extends React.PureComponent<Props> {
constructor(props) {
super(props);
this.viewer = React.createRef();
}
render() { render() {
const { source } = this.props; const { source } = this.props;
return ( return (
<div className="file-render__viewer" onContextMenu={stopContextMenu}> <div className="file-render__viewer" onContextMenu={stopContextMenu}>
<webview ref={this.viewer} src={`chrome://pdf-viewer/index.html?src=file://${source}`} /> <webview src={`chrome://pdf-viewer/index.html?src=file://${source}`} />
</div> </div>
); );
} }

View file

@ -12,6 +12,13 @@ import ThreeScene from './internal/scene';
import ThreeLoader from './internal/loader'; import ThreeLoader from './internal/loader';
import ThreeRenderer from './internal/renderer'; import ThreeRenderer from './internal/renderer';
type viewerTheme = {
gridColor: string,
groundColor: string,
backgroundColor: string,
centerLineColor: string,
};
type Props = { type Props = {
theme: string, theme: string,
source: { source: {
@ -27,12 +34,13 @@ type State = {
}; };
class ThreeViewer extends React.PureComponent<Props, State> { class ThreeViewer extends React.PureComponent<Props, State> {
static testWebgl = new Promise((resolve, reject) => { static testWebgl = (): Promise<void> =>
if (detectWebGL()) resolve(); new Promise((resolve, reject) => {
else reject(); if (detectWebGL()) resolve();
}); else reject();
});
static createOrbitControls(camera, canvas) { static createOrbitControls(camera: any, canvas: any) {
const controls = new THREE.OrbitControls(camera, canvas); const controls = new THREE.OrbitControls(camera, canvas);
// Controls configuration // Controls configuration
controls.enableDamping = true; controls.enableDamping = true;
@ -46,7 +54,7 @@ class ThreeViewer extends React.PureComponent<Props, State> {
return controls; return controls;
} }
static fitMeshToCamera(group) { static fitMeshToCamera(group: any) {
const max = { x: 0, y: 0, z: 0 }; const max = { x: 0, y: 0, z: 0 };
const min = { x: 0, y: 0, z: 0 }; const min = { x: 0, y: 0, z: 0 };
@ -82,23 +90,9 @@ class ThreeViewer extends React.PureComponent<Props, State> {
See: https://github.com/mrdoob/three.js/blob/dev/docs/scenes/js/material.js#L195 See: https://github.com/mrdoob/three.js/blob/dev/docs/scenes/js/material.js#L195
*/ */
static updateMaterial(material, geometry) {
material.vertexColors = +material.vertexColors; // Ensure number
material.side = +material.side; // Ensure number
material.needsUpdate = true;
// If Geometry needs update
if (geometry) {
geometry.verticesNeedUpdate = true;
geometry.normalsNeedUpdate = true;
geometry.colorsNeedUpdate = true;
}
}
constructor(props: Props) { constructor(props: Props) {
super(props); super(props);
const { theme } = this.props; const { theme } = this.props;
this.viewer = React.createRef();
this.guiContainer = React.createRef();
// Object defualt color // Object defualt color
this.materialColor = '#44b098'; this.materialColor = '#44b098';
// Viewer themes // Viewer themes
@ -124,10 +118,21 @@ class ThreeViewer extends React.PureComponent<Props, State> {
isReady: false, isReady: false,
isLoading: false, isLoading: false,
}; };
// Internal objects
this.gui = null;
this.grid = null;
this.mesh = null;
this.camera = null;
this.frameID = null;
this.renderer = null;
this.material = null;
this.geometry = null;
this.targetCenter = null;
this.bufferGeometry = null;
} }
componentDidMount() { componentDidMount() {
ThreeViewer.testWebgl ThreeViewer.testWebgl()
.then(() => { .then(() => {
this.renderScene(); this.renderScene();
// Update render on resize window // Update render on resize window
@ -187,7 +192,39 @@ class ThreeViewer extends React.PureComponent<Props, State> {
} }
btzr-io commented 2018-10-15 03:52:50 +02:00 (Migrated from github.com)
Review

Should we use this instead of any?
https://www.npmjs.com/package/@types/three

Should we use this instead of `any`? https://www.npmjs.com/package/@types/three
neb-b commented 2018-10-15 04:09:42 +02:00 (Migrated from github.com)
Review

Nice. Definitely

Nice. Definitely
btzr-io commented 2018-10-15 04:47:10 +02:00 (Migrated from github.com)
Review

Looks like they are TypeScript type definitions 😞

Looks like they are `TypeScript` type definitions :disappointed:
btzr-io commented 2018-10-15 04:50:58 +02:00 (Migrated from github.com)
Review

I can't find anything for flow 😛

I can't find anything for flow :stuck_out_tongue:
btzr-io commented 2018-10-15 07:06:05 +02:00 (Migrated from github.com)
Review
I can't use / import it: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/three/index.d.ts
neb-b commented 2018-10-15 07:39:19 +02:00 (Migrated from github.com)
Review

I gotcha. Oh well.

I gotcha. Oh well.
} }
transformGroup(group) { // Define component types
theme: viewerTheme;
themes: { dark: viewerTheme, light: viewerTheme };
materialColor: string;
// Refs
viewer: ?HTMLElement;
guiContainer: ?HTMLElement;
// Too complex to add a custom type
gui: any;
grid: any;
mesh: any;
scene: any;
camera: any;
frameID: any;
controls: any;
material: any;
geometry: any;
targetCenter: any;
bufferGeometry: any;
updateMaterial(material: any, geometry: any) {
this.material.vertexColors = +material.vertexColors; // Ensure number
this.material.side = +material.side; // Ensure number
this.material.needsUpdate = true;
// If Geometry needs update
if (geometry) {
this.geometry.verticesNeedUpdate = true;
this.geometry.normalsNeedUpdate = true;
this.geometry.colorsNeedUpdate = true;
}
}
transformGroup(group: any) {
ThreeViewer.fitMeshToCamera(group); ThreeViewer.fitMeshToCamera(group);
if (!this.targetCenter) { if (!this.targetCenter) {
@ -203,20 +240,19 @@ class ThreeViewer extends React.PureComponent<Props, State> {
const config = { const config = {
color: this.materialColor, color: this.materialColor,
}; reset: () => {
// Reset material color
config.reset = () => { config.color = this.materialColor;
// Reset material color // Reset material
config.color = this.materialColor; this.material.color.set(config.color);
// Reset material this.material.flatShading = true;
this.material.color.set(config.color); this.material.shininess = 30;
this.material.flatShading = true; this.material.wireframe = false;
this.material.shininess = 30; // Reset autoRotate
this.material.wireframe = false; this.controls.autoRotate = false;
// Reset autoRotate // Reset camera
this.controls.autoRotate = false; this.restoreCamera();
// Reset camera },
this.restoreCamera();
}; };
const materialFolder = this.gui.addFolder('Material'); const materialFolder = this.gui.addFolder('Material');
@ -240,7 +276,7 @@ class ThreeViewer extends React.PureComponent<Props, State> {
.add(this.material, 'flatShading') .add(this.material, 'flatShading')
.name('FlatShading') .name('FlatShading')
.onChange(() => { .onChange(() => {
ThreeViewer.updateMaterial(this.material); this.updateMaterial(this.material);
}) })
.listen(); .listen();
@ -258,11 +294,13 @@ class ThreeViewer extends React.PureComponent<Props, State> {
sceneFolder.add(config, 'reset').name('Reset'); sceneFolder.add(config, 'reset').name('Reset');
this.guiContainer.current.appendChild(this.gui.domElement); if (this.guiContainer) {
this.guiContainer.appendChild(this.gui.domElement);
}
} }
} }
createGeometry(data) { createGeometry(data: any) {
this.bufferGeometry = data; this.bufferGeometry = data;
this.bufferGeometry.computeBoundingBox(); this.bufferGeometry.computeBoundingBox();
this.bufferGeometry.center(); this.bufferGeometry.center();
@ -301,14 +339,14 @@ class ThreeViewer extends React.PureComponent<Props, State> {
}; };
handleResize = () => { handleResize = () => {
const { offsetWidth: width, offsetHeight: height } = this.viewer.current; const { offsetWidth: width, offsetHeight: height } = this.viewer || {};
this.camera.aspect = width / height; this.camera.aspect = width / height;
this.camera.updateProjectionMatrix(); this.camera.updateProjectionMatrix();
this.controls.update(); this.controls.update();
this.renderer.setSize(width, height); this.renderer.setSize(width, height);
}; };
updateControlsTarget(point) { updateControlsTarget(point: { x: number, y: number, z: number }) {
this.controls.target.fromArray([point.x, point.y, point.z]); this.controls.target.fromArray([point.x, point.y, point.z]);
this.controls.update(); this.controls.update();
} }
@ -319,7 +357,10 @@ class ThreeViewer extends React.PureComponent<Props, State> {
this.updateControlsTarget(this.targetCenter); this.updateControlsTarget(this.targetCenter);
} }
renderStl(data) { // Flow requested to add it here
renderer: any;
renderStl(data: any) {
this.createGeometry(data); this.createGeometry(data);
this.mesh = new THREE.Mesh(this.geometry, this.material); this.mesh = new THREE.Mesh(this.geometry, this.material);
this.mesh.name = 'model'; this.mesh.name = 'model';
@ -327,7 +368,7 @@ class ThreeViewer extends React.PureComponent<Props, State> {
this.transformGroup(this.mesh); this.transformGroup(this.mesh);
} }
renderObj(event) { renderObj(event: any) {
const mesh = event.detail.loaderRootNode; const mesh = event.detail.loaderRootNode;
this.mesh = new THREE.Group(); this.mesh = new THREE.Group();
this.mesh.name = 'model'; this.mesh.name = 'model';
@ -352,7 +393,7 @@ class ThreeViewer extends React.PureComponent<Props, State> {
this.transformGroup(this.mesh); this.transformGroup(this.mesh);
} }
renderModel(fileType, parsedData) { renderModel(fileType: string, parsedData: any) {
const renderTypes = { const renderTypes = {
stl: data => this.renderStl(data), stl: data => this.renderStl(data),
obj: data => this.renderObj(data), obj: data => this.renderObj(data),
@ -377,9 +418,8 @@ class ThreeViewer extends React.PureComponent<Props, State> {
...this.theme, ...this.theme,
}); });
const viewer = this.viewer.current;
const canvas = this.renderer.domElement; const canvas = this.renderer.domElement;
const { offsetWidth: width, offsetHeight: height } = viewer; const { offsetWidth: width, offsetHeight: height } = this.viewer || {};
// Grid // Grid
this.grid = ThreeGrid({ size: 100, gridColor, centerLineColor }); this.grid = ThreeGrid({ size: 100, gridColor, centerLineColor });
@ -408,7 +448,9 @@ class ThreeViewer extends React.PureComponent<Props, State> {
this.startLoader(); this.startLoader();
// Append canvas // Append canvas
viewer.appendChild(canvas); if (this.viewer) {
this.viewer.appendChild(canvas);
}
const updateScene = () => { const updateScene = () => {
this.frameID = requestAnimationFrame(updateScene); this.frameID = requestAnimationFrame(updateScene);
@ -433,11 +475,11 @@ class ThreeViewer extends React.PureComponent<Props, State> {
<React.Fragment> <React.Fragment>
{error && <LoadingScreen status={error} spinner={false} />} {error && <LoadingScreen status={error} spinner={false} />}
{showLoading && <LoadingScreen status={loadingMessage} spinner />} {showLoading && <LoadingScreen status={loadingMessage} spinner />}
<div ref={this.guiContainer} className={containerClass} /> <div ref={element => (this.guiContainer = element)} className={containerClass} />
<div <div
style={{ opacity: showViewer ? 1 : 0 }} style={{ opacity: showViewer ? 1 : 0 }}
className="three-viewer file-render__viewer" className="three-viewer file-render__viewer"
ref={this.viewer} ref={viewer => (this.viewer = viewer)}
/> />
</React.Fragment> </React.Fragment>
); );

View file

@ -130,6 +130,10 @@
version "8.10.21" version "8.10.21"
resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.21.tgz#12b3f2359b27aa05a45d886c8ba1eb8d1a77e285" resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.21.tgz#12b3f2359b27aa05a45d886c8ba1eb8d1a77e285"
"@types/three@^0.93.1":
version "0.93.1"
resolved "https://registry.yarnpkg.com/@types/three/-/three-0.93.1.tgz#0b9ba53182afe16659e220d670471b4475687d64"
"@types/webpack-env@^1.13.5": "@types/webpack-env@^1.13.5":
version "1.13.6" version "1.13.6"
resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.13.6.tgz#128d1685a7c34d31ed17010fc87d6a12c1de6976" resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.13.6.tgz#128d1685a7c34d31ed17010fc87d6a12c1de6976"