Remove decorators and bundler workarounds

This commit is contained in:
Jason Miller
2020-08-19 23:41:35 -04:00
parent d383fa6b12
commit e6111be998
20 changed files with 118 additions and 188 deletions

View File

@@ -1,6 +1,6 @@
import { h, Component } from 'preact';
import { bind, linkRef, Fileish } from '../../lib/initial-util';
import { linkRef, Fileish } from '../../lib/initial-util';
import * as style from './style.module.scss';
import { FileDropEvent } from 'file-drop-element';
import 'file-drop-element';
@@ -43,6 +43,12 @@ export default class App extends Component<Props, State> {
constructor() {
super();
this.onFileDrop = this.onFileDrop.bind(this);
this.onIntroPickFile = this.onIntroPickFile.bind(this);
this.showSnack = this.showSnack.bind(this);
this.onPopState = this.onPopState.bind(this);
this.openEditor = this.openEditor.bind(this);
compressPromise.then((module) => {
this.setState({ Compress: module.default });
}).catch((e) => {
@@ -61,7 +67,8 @@ export default class App extends Component<Props, State> {
});
// In development, persist application state across hot reloads:
if (process.env.NODE_ENV === 'development') {
// if (process.env.NODE_ENV === 'development') {
if (module.hot) {
this.setState(window.STATE);
const oldCDU = this.componentDidUpdate;
this.componentDidUpdate = (props, state, prev) => {
@@ -81,7 +88,6 @@ export default class App extends Component<Props, State> {
window.addEventListener('popstate', this.onPopState);
}
@bind
private onFileDrop({ files }: FileDropEvent) {
if (!files || files.length === 0) return;
const file = files[0];
@@ -89,24 +95,20 @@ export default class App extends Component<Props, State> {
this.setState({ file });
}
@bind
private onIntroPickFile(file: File | Fileish) {
this.openEditor();
this.setState({ file });
}
@bind
private showSnack(message: string, options: SnackOptions = {}): Promise<string> {
if (!this.snackbar) throw Error('Snackbar missing');
return this.snackbar.showSnackbar(message, options);
}
@bind
private onPopState() {
this.setState({ isEditorOpen: location.pathname === ROUTE_EDITOR });
}
@bind
private openEditor() {
if (this.state.isEditorOpen) return;
// Change path, but preserve query string.

View File

@@ -1,7 +1,6 @@
import { h, Component } from 'preact';
import * as style from './style.module.scss';
import { bind } from '../../lib/initial-util';
import { cleanSet, cleanMerge } from '../../lib/clean-modify';
import OxiPNGEncoderOptions from '../../codecs/oxipng/options';
import MozJpegEncoderOptions from '../../codecs/mozjpeg/options';
@@ -82,8 +81,7 @@ export default class Options extends Component<Props, State> {
encodersSupported.then(encoderSupportMap => this.setState({ encoderSupportMap }));
}
@bind
private onEncoderTypeChange(event: Event) {
private onEncoderTypeChange = (event: Event) => {
const el = event.currentTarget as HTMLSelectElement;
// The select element only has values matching encoder types,
@@ -92,8 +90,7 @@ export default class Options extends Component<Props, State> {
this.props.onEncoderTypeChange(type);
}
@bind
private onPreprocessorEnabledChange(event: Event) {
private onPreprocessorEnabledChange = (event: Event) => {
const el = event.currentTarget as HTMLInputElement;
const preprocessor = el.name.split('.')[0] as keyof PreprocessorState;
@@ -102,15 +99,13 @@ export default class Options extends Component<Props, State> {
);
}
@bind
private onQuantizerOptionsChange(opts: QuantizeOptions) {
private onQuantizerOptionsChange = (opts: QuantizeOptions) => {
this.props.onPreprocessorOptionsChange(
cleanMerge(this.props.preprocessorState, 'quantizer', opts),
);
}
@bind
private onResizeOptionsChange(opts: ResizeOptions) {
private onResizeOptionsChange = (opts: ResizeOptions) => {
this.props.onPreprocessorOptionsChange(
cleanMerge(this.props.preprocessorState, 'resize', opts),
);

View File

@@ -3,7 +3,7 @@ import PinchZoom, { ScaleToOpts } from './custom-els/PinchZoom';
import './custom-els/PinchZoom';
import './custom-els/TwoUp';
import * as style from './style.module.scss';
import { bind, linkRef } from '../../lib/initial-util';
import { linkRef } from '../../lib/initial-util';
import { shallowEqual, drawDataToCanvas } from '../../lib/util';
import {
ToggleBackgroundIcon,
@@ -135,29 +135,25 @@ export default class Output extends Component<Props, State> {
return props.rightCompressed || (props.source && props.source.processed);
}
@bind
private toggleBackground() {
private toggleBackground = () => {
this.setState({
altBackground: !this.state.altBackground,
});
}
@bind
private zoomIn() {
private zoomIn = () => {
if (!this.pinchZoomLeft) throw Error('Missing pinch-zoom element');
this.pinchZoomLeft.scaleTo(this.state.scale * 1.25, scaleToOpts);
}
@bind
private zoomOut() {
private zoomOut = () => {
if (!this.pinchZoomLeft) throw Error('Missing pinch-zoom element');
this.pinchZoomLeft.scaleTo(this.state.scale / 1.25, scaleToOpts);
}
@bind
private onRotateClick() {
private onRotateClick = () => {
const { inputProcessorState } = this.props;
if (!inputProcessorState) return;
@@ -170,8 +166,7 @@ export default class Output extends Component<Props, State> {
this.props.onInputProcessorChange(newState);
}
@bind
private onScaleValueFocus() {
private onScaleValueFocus = () => {
this.setState({ editingScale: true }, () => {
if (this.scaleInput) {
// Firefox unfocuses the input straight away unless I force a style calculation here. I have
@@ -182,13 +177,11 @@ export default class Output extends Component<Props, State> {
});
}
@bind
private onScaleInputBlur() {
private onScaleInputBlur = () => {
this.setState({ editingScale: false });
}
@bind
private onScaleInputChanged(event: Event) {
private onScaleInputChanged = (event: Event) => {
const target = event.target as HTMLInputElement;
const percent = parseFloat(target.value);
if (isNaN(percent)) return;
@@ -197,8 +190,7 @@ export default class Output extends Component<Props, State> {
this.pinchZoomLeft.scaleTo(percent / 100, scaleToOpts);
}
@bind
private onPinchZoomLeftChange(event: Event) {
private onPinchZoomLeftChange = (event: Event) => {
if (!this.pinchZoomRight || !this.pinchZoomLeft) throw Error('Missing pinch-zoom element');
this.setState({
scale: this.pinchZoomLeft.scale,
@@ -218,8 +210,7 @@ export default class Output extends Component<Props, State> {
*
* @param event Event to redirect
*/
@bind
private onRetargetableEvent(event: Event) {
private onRetargetableEvent = (event: Event) => {
const targetEl = event.target as HTMLElement;
if (!this.pinchZoomLeft) throw Error('Missing pinch-zoom element');
// If the event is on the handle of the two-up, let it through,

View File

@@ -1,6 +1,6 @@
import { h, Component } from 'preact';
import { bind, Fileish } from '../../lib/initial-util';
import { Fileish } from '../../lib/initial-util';
import { blobToImg, drawableToImageData, blobToText } from '../../lib/util';
import * as style from './style.module.scss';
import Output from '../Output';
@@ -254,8 +254,7 @@ export default class Compress extends Component<Props, State> {
import('../../lib/sw-bridge').then(({ mainAppLoaded }) => mainAppLoaded());
}
@bind
private onMobileWidthChange() {
private onMobileWidthChange = () => {
this.setState({ mobileView: this.widthQuery.matches });
}
@@ -344,8 +343,7 @@ export default class Compress extends Component<Props, State> {
});
}
@bind
private async onInputProcessorChange(options: InputProcessorState): Promise<void> {
private onInputProcessorChange = async (options: InputProcessorState): Promise<void> => {
const source = this.state.source;
if (!source) return;
@@ -396,8 +394,7 @@ export default class Compress extends Component<Props, State> {
}
}
@bind
private async updateFile(file: File | Fileish) {
private updateFile = async (file: File | Fileish) => {
const loadingCounter = this.state.loadingCounter + 1;
// Either processor is good enough here.
const processor = this.leftProcessor;

View File

@@ -1,6 +1,6 @@
import { h, Component } from 'preact';
import { bind, linkRef, Fileish } from '../../lib/initial-util';
import { linkRef, Fileish } from '../../lib/initial-util';
import '../custom-els/LoadingSpinner';
import logo from 'url:./imgs/logo.svg';
@@ -67,13 +67,11 @@ export default class Intro extends Component<Props, State> {
window.addEventListener('appinstalled', this.onAppInstalled);
}
@bind
private resetFileInput() {
private resetFileInput = () => {
this.fileInput!.value = '';
}
@bind
private onFileChange(event: Event): void {
private onFileChange = (event: Event) => {
const fileInput = event.target as HTMLInputElement;
const file = fileInput.files && fileInput.files[0];
if (!file) return;
@@ -81,13 +79,11 @@ export default class Intro extends Component<Props, State> {
this.props.onFile(file);
}
@bind
private onButtonClick() {
private onButtonClick = () => {
this.fileInput!.click();
}
@bind
private async onDemoClick(index: number, event: Event) {
private onDemoClick = async (index: number, event: Event) => {
try {
this.setState({ fetchingDemoIndex: index });
const demo = demos[index];
@@ -104,8 +100,7 @@ export default class Intro extends Component<Props, State> {
}
}
@bind
private onBeforeInstallPromptEvent(event: BeforeInstallPromptEvent) {
private onBeforeInstallPromptEvent = (event: BeforeInstallPromptEvent) => {
// Don't show the mini-infobar on mobile
event.preventDefault();
@@ -121,8 +116,7 @@ export default class Intro extends Component<Props, State> {
ga('send', 'event', gaEventInfo);
}
@bind
private async onInstallClick(event: Event) {
private onInstallClick = async (event: Event) => {
// Get the deferred beforeinstallprompt event
const beforeInstallEvent = this.state.beforeInstallEvent;
// If there's no deferred prompt, bail.
@@ -150,8 +144,7 @@ export default class Intro extends Component<Props, State> {
}
}
@bind
private onAppInstalled() {
private onAppInstalled = () => {
// We don't need the install button, if it's shown
this.setState({ beforeInstallEvent: undefined });

View File

@@ -2,7 +2,7 @@ import { h, Component } from 'preact';
import * as style from './style.module.scss';
import RangeInputElement from '../../custom-els/RangeInput';
import '../../custom-els/RangeInput';
import { linkRef, bind } from '../../lib/initial-util';
import { linkRef } from '../../lib/initial-util';
interface Props extends JSX.HTMLAttributes {}
interface State {}
@@ -10,8 +10,7 @@ interface State {}
export default class Range extends Component<Props, State> {
rangeWc?: RangeInputElement;
@bind
private onTextInput(event: Event) {
private onTextInput = (event: Event) => {
const input = event.target as HTMLInputElement;
const value = input.value.trim();
if (!value) return;

View File

@@ -5,7 +5,7 @@ import FileSize from './FileSize';
import { DownloadIcon, CopyAcrossIcon, CopyAcrossIconProps } from '../../lib/icons';
import '../custom-els/LoadingSpinner';
import { SourceImage } from '../compress';
import { Fileish, bind } from '../../lib/initial-util';
import { Fileish } from '../../lib/initial-util';
interface Props {
loading: boolean;
@@ -52,14 +52,12 @@ export default class Results extends Component<Props, State> {
}
}
@bind
private onCopyToOtherClick(event: Event) {
private onCopyToOtherClick = (event: Event) => {
event.preventDefault();
this.props.onCopyToOtherClick();
}
@bind
onDownload() {
onDownload = () => {
// GA cant do floats. So we round to ints. We're deliberately rounding to nearest kilobyte to
// avoid cases where exact image sizes leak something interesting about the user.
const before = Math.round(this.props.source!.file.size / 1024);