Major frontend code cleanup (#452)

Many large changes, including:
- TypeScript enums are now string unions throughout
- Strong type-checking throughout the TS and Vue codebase
- Vue component props now all specify `as PropType<...>`
- Usage of annotated return types on all functions
- Sorting of JS import statements
- Explicit usage of Vue bind attribute function call arguments (`@click="foo"` is now `@click=(e) => foo(e)`)
- Much improved code quality related to the color picker
- Consistent camelCase Vue bind and v-model attributes
- Consistent Vue HTML attribute strings with single quotes
- Bug fix and clarity improvement with incorrect hint class parameters
- Empty Vue component objects like `props: {}` and `components: {}` removed
This commit is contained in:
Keavon Chambers
2022-01-02 06:00:02 -08:00
parent 6662a9a04f
commit 2c8d70acb4
53 changed files with 842 additions and 946 deletions
+4 -2
View File
@@ -1,4 +1,5 @@
import { plainToInstance } from "class-transformer";
import { JsMessageType, messageConstructors, JsMessage } from "@/dispatcher/js-messages";
import type { RustEditorInstance, WasmInstance } from "@/state/wasm-loader";
@@ -10,14 +11,15 @@ type JsMessageCallbackMap = {
[message: string]: JsMessageCallback<any> | undefined;
};
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
export function createJsDispatcher() {
const subscriptions: JsMessageCallbackMap = {};
const subscribeJsMessage = <T extends JsMessage, Args extends unknown[]>(messageType: new (...args: Args) => T, callback: JsMessageCallback<T>) => {
const subscribeJsMessage = <T extends JsMessage, Args extends unknown[]>(messageType: new (...args: Args) => T, callback: JsMessageCallback<T>): void => {
subscriptions[messageType.name] = callback;
};
const handleJsMessage = (messageType: JsMessageType, messageData: Record<string, unknown>, wasm: WasmInstance, instance: RustEditorInstance) => {
const handleJsMessage = (messageType: JsMessageType, messageData: Record<string, unknown>, wasm: WasmInstance, instance: RustEditorInstance): void => {
const messageConstructor = messageConstructors[messageType];
if (!messageConstructor) {
// eslint-disable-next-line no-console
+27 -19
View File
@@ -30,7 +30,7 @@ export abstract class DocumentDetails {
readonly id!: BigInt | string;
get displayName() {
get displayName(): string {
return `${this.name}${this.is_saved ? "" : "*"}`;
}
}
@@ -44,25 +44,43 @@ export class UpdateOpenDocumentsList extends JsMessage {
readonly open_documents!: FrontendDocumentDetails[];
}
export type HintData = HintInfo[][];
export class UpdateInputHints extends JsMessage {
@Type(() => HintInfo)
readonly hint_data!: HintData;
}
export type KeysGroup = string[];
export type HintData = HintGroup[];
export type HintGroup = HintInfo[];
export class HintInfo {
readonly keys!: string[];
readonly key_groups!: KeysGroup[];
readonly mouse!: KeysGroup | null;
readonly mouse!: MouseMotion | null;
readonly label!: string;
readonly plus!: boolean;
}
export type KeysGroup = string[]; // Array of Rust enum `Key`
export type MouseMotion = string;
export type RGBA = {
r: number;
g: number;
b: number;
a: number;
};
export type HSVA = {
h: number;
s: number;
v: number;
a: number;
};
const To255Scale = Transform(({ value }) => value * 255);
export class Color {
@To255Scale
@@ -76,11 +94,11 @@ export class Color {
readonly alpha!: number;
toRgba() {
toRgba(): RGBA {
return { r: this.red, g: this.green, b: this.blue, a: this.alpha };
}
toRgbaCSS() {
toRgbaCSS(): string {
const { r, g, b, a } = this.toRgba();
return `rgba(${r}, ${g}, ${b}, ${a})`;
}
@@ -296,17 +314,7 @@ export class LayerMetadata {
selected!: boolean;
}
export const LayerTypeOptions = {
Folder: "Folder",
Shape: "Shape",
Circle: "Circle",
Rect: "Rect",
Line: "Line",
PolyLine: "PolyLine",
Ellipse: "Ellipse",
} as const;
export type LayerType = typeof LayerTypeOptions[keyof typeof LayerTypeOptions];
export type LayerType = "Folder" | "Shape" | "Circle" | "Rect" | "Line" | "PolyLine" | "Ellipse";
export class IndexedDbDocumentDetails extends DocumentDetails {
@Transform(({ value }: { value: BigInt }) => value.toString())