diff --git a/scripts/build-node.js b/scripts/build-node.js index d4a21b4e..83cc0668 100755 --- a/scripts/build-node.js +++ b/scripts/build-node.js @@ -29,7 +29,7 @@ config.entry = "./src/index-node"; // By default, webpack is going to replace the require of the canvas.node file // to just a string with the path of the canvas.node file. We need to tell // webpack to avoid rewriting that dependency. -config.externals = function (context, request, callback) { +config.externals = (context, request, callback) => { if (/\.node$/.test(request)) { return callback( null, diff --git a/src/actions/actionAlign.tsx b/src/actions/actionAlign.tsx index 2b130df4..d5140edc 100644 --- a/src/actions/actionAlign.tsx +++ b/src/actions/actionAlign.tsx @@ -23,11 +23,11 @@ const enableActionGroup = ( appState: AppState, ) => getSelectedElements(getNonDeletedElements(elements), appState).length > 1; -function alignSelectedElements( +const alignSelectedElements = ( elements: readonly ExcalidrawElement[], appState: Readonly, alignment: Alignment, -) { +) => { const selectedElements = getSelectedElements( getNonDeletedElements(elements), appState, @@ -38,7 +38,7 @@ function alignSelectedElements( const updatedElementsMap = getElementMap(updatedElements); return elements.map((element) => updatedElementsMap[element.id] || element); -} +}; export const actionAlignTop = register({ name: "alignTop", diff --git a/src/actions/actionDeleteSelected.tsx b/src/actions/actionDeleteSelected.tsx index a94b8aa5..a5193c28 100644 --- a/src/actions/actionDeleteSelected.tsx +++ b/src/actions/actionDeleteSelected.tsx @@ -31,10 +31,10 @@ const deleteSelectedElements = ( }; }; -function handleGroupEditingState( +const handleGroupEditingState = ( appState: AppState, elements: readonly ExcalidrawElement[], -): AppState { +): AppState => { if (appState.editingGroupId) { const siblingElements = getElementsInGroup( getNonDeletedElements(elements), @@ -48,7 +48,7 @@ function handleGroupEditingState( } } return appState; -} +}; export const actionDeleteSelected = register({ name: "deleteSelectedElements", diff --git a/src/align.ts b/src/align.ts index d6c745a3..745cd13b 100644 --- a/src/align.ts +++ b/src/align.ts @@ -89,7 +89,7 @@ const calculateTranslation = ( }; }; -function getCommonBoundingBox(elements: ExcalidrawElement[]): Box { +const getCommonBoundingBox = (elements: ExcalidrawElement[]): Box => { const [minX, minY, maxX, maxY] = getCommonBounds(elements); return { minX, minY, maxX, maxY }; -} +}; diff --git a/src/charts.ts b/src/charts.ts index a00f064c..daf9de6a 100644 --- a/src/charts.ts +++ b/src/charts.ts @@ -24,21 +24,21 @@ type ParseSpreadsheetResult = error: string; }; -function tryParseNumber(s: string): number | null { +const tryParseNumber = (s: string): number | null => { const match = /^[$€£¥₩]?([0-9]+(\.[0-9]+)?)$/.exec(s); if (!match) { return null; } return parseFloat(match[1]); -} +}; -function isNumericColumn(lines: string[][], columnIndex: number) { +const isNumericColumn = (lines: string[][], columnIndex: number) => { return lines .slice(1) .every((line) => tryParseNumber(line[columnIndex]) !== null); -} +}; -function tryParseCells(cells: string[][]): ParseSpreadsheetResult { +const tryParseCells = (cells: string[][]): ParseSpreadsheetResult => { const numCols = cells[0].length; if (numCols > 2) { @@ -94,9 +94,9 @@ function tryParseCells(cells: string[][]): ParseSpreadsheetResult { values: rows.map((row) => tryParseNumber(row[valueColumnIndex])!), }, }; -} +}; -function transposeCells(cells: string[][]) { +const transposeCells = (cells: string[][]) => { const nextCells: string[][] = []; for (let col = 0; col < cells[0].length; col++) { const nextCellRow: string[] = []; @@ -107,9 +107,9 @@ function transposeCells(cells: string[][]) { } return nextCells; -} +}; -export function tryParseSpreadsheet(text: string): ParseSpreadsheetResult { +export const tryParseSpreadsheet = (text: string): ParseSpreadsheetResult => { // copy/paste from excel, in-browser excel, and google sheets is tsv // for now we only accept 2 columns with an optional header const lines = text @@ -139,7 +139,7 @@ export function tryParseSpreadsheet(text: string): ParseSpreadsheetResult { } return result; -} +}; const BAR_WIDTH = 32; const BAR_SPACING = 12; @@ -148,12 +148,12 @@ const LABEL_SPACING = 3 * BAR_SPACING; const Y_AXIS_LABEL_SPACING = LABEL_SPACING; const ANGLE = 5.87; -export function renderSpreadsheet( +export const renderSpreadsheet = ( appState: AppState, spreadsheet: Spreadsheet, x: number, y: number, -): ExcalidrawElement[] { +): ExcalidrawElement[] => { const max = Math.max(...spreadsheet.values); const min = Math.min(0, ...spreadsheet.values); const range = max - min; @@ -268,4 +268,4 @@ export function renderSpreadsheet( return [...bars, yAxisLabel, minYLabel, maxYLabel, ...xLabels].filter( (element) => element !== null, ) as ExcalidrawElement[]; -} +}; diff --git a/src/components/LayerUI.tsx b/src/components/LayerUI.tsx index f8f8b41b..cf8a0a9f 100644 --- a/src/components/LayerUI.tsx +++ b/src/components/LayerUI.tsx @@ -62,10 +62,10 @@ interface LayerUIProps { lng: string; } -function useOnClickOutside( +const useOnClickOutside = ( ref: RefObject, cb: (event: MouseEvent) => void, -) { +) => { useEffect(() => { const listener = (event: MouseEvent) => { if (!ref.current) { @@ -88,7 +88,7 @@ function useOnClickOutside( document.removeEventListener("pointerdown", listener); }; }, [ref, cb]); -} +}; const LibraryMenuItems = ({ library, diff --git a/src/data/firebase.ts b/src/data/firebase.ts index db816558..7240e318 100644 --- a/src/data/firebase.ts +++ b/src/data/firebase.ts @@ -8,7 +8,7 @@ let firebasePromise: Promise< typeof import("firebase/app").default > | null = null; -async function loadFirebase() { +const loadFirebase = async () => { const firebase = ( await import(/* webpackChunkName: "firebase" */ "firebase/app") ).default; @@ -18,15 +18,17 @@ async function loadFirebase() { firebase.initializeApp(firebaseConfig); return firebase; -} +}; -async function getFirebase(): Promise { +const getFirebase = async (): Promise< + typeof import("firebase/app").default +> => { if (!firebasePromise) { firebasePromise = loadFirebase(); } const firebase = await firebasePromise!; return firebase; -} +}; interface FirebaseStoredScene { sceneVersion: number; @@ -34,10 +36,10 @@ interface FirebaseStoredScene { ciphertext: firebase.default.firestore.Blob; } -async function encryptElements( +const encryptElements = async ( key: string, elements: readonly ExcalidrawElement[], -): Promise<{ ciphertext: ArrayBuffer; iv: Uint8Array }> { +): Promise<{ ciphertext: ArrayBuffer; iv: Uint8Array }> => { const importedKey = await getImportedKey(key, "encrypt"); const iv = createIV(); const json = JSON.stringify(elements); @@ -52,13 +54,13 @@ async function encryptElements( ); return { ciphertext, iv }; -} +}; -async function decryptElements( +const decryptElements = async ( key: string, iv: Uint8Array, ciphertext: ArrayBuffer, -): Promise { +): Promise => { const importedKey = await getImportedKey(key, "decrypt"); const decrypted = await window.crypto.subtle.decrypt( { @@ -73,7 +75,7 @@ async function decryptElements( new Uint8Array(decrypted) as any, ); return JSON.parse(decodedData); -} +}; const firebaseSceneVersionCache = new WeakMap(); @@ -90,10 +92,10 @@ export const isSavedToFirebase = ( return true; }; -export async function saveToFirebase( +export const saveToFirebase = async ( portal: Portal, elements: readonly ExcalidrawElement[], -) { +) => { const { roomID, roomKey, socket } = portal; if ( // if no room exists, consider the room saved because there's nothing we can @@ -141,12 +143,12 @@ export async function saveToFirebase( } return didUpdate; -} +}; -export async function loadFromFirebase( +export const loadFromFirebase = async ( roomID: string, roomKey: string, -): Promise { +): Promise => { const firebase = await getFirebase(); const db = firebase.firestore(); @@ -159,4 +161,4 @@ export async function loadFromFirebase( const ciphertext = storedScene.ciphertext.toUint8Array(); const iv = storedScene.iv.toUint8Array(); return restoreElements(await decryptElements(roomKey, iv, ciphertext)); -} +}; diff --git a/src/element/newElement.ts b/src/element/newElement.ts index 42254836..ab2742b8 100644 --- a/src/element/newElement.ts +++ b/src/element/newElement.ts @@ -82,7 +82,7 @@ export const newElement = ( _newElementBase(opts.type, opts); /** computes element x/y offset based on textAlign/verticalAlign */ -function getTextElementPositionOffsets( +const getTextElementPositionOffsets = ( opts: { textAlign: ExcalidrawTextElement["textAlign"]; verticalAlign: ExcalidrawTextElement["verticalAlign"]; @@ -91,7 +91,7 @@ function getTextElementPositionOffsets( width: number; height: number; }, -) { +) => { return { x: opts.textAlign === "center" @@ -101,7 +101,7 @@ function getTextElementPositionOffsets( : 0, y: opts.verticalAlign === "middle" ? metrics.height / 2 : 0, }; -} +}; export const newTextElement = ( opts: { diff --git a/src/element/textWysiwyg.tsx b/src/element/textWysiwyg.tsx index 957bafce..7264ff2f 100644 --- a/src/element/textWysiwyg.tsx +++ b/src/element/textWysiwyg.tsx @@ -46,7 +46,7 @@ export const textWysiwyg = ({ getViewportCoords: (x: number, y: number) => [number, number]; element: ExcalidrawElement; }) => { - function updateWysiwygStyle() { + const updateWysiwygStyle = () => { const updatedElement = Scene.getScene(element)?.getElement(id); if (updatedElement && isTextElement(updatedElement)) { const [viewportX, viewportY] = getViewportCoords( @@ -80,7 +80,7 @@ export const textWysiwyg = ({ filter: "var(--appearance-filter)", }); } - } + }; const editable = document.createElement("textarea"); diff --git a/src/ga.ts b/src/ga.ts index 6a6f5be3..23bee4e8 100644 --- a/src/ga.ts +++ b/src/ga.ts @@ -22,22 +22,25 @@ export type Direction = NVector; export type Line = NVector; export type Transform = NVector; -export function point(x: number, y: number): Point { - return [0, 0, 0, 0, y, x, 1, 0]; -} +export const point = (x: number, y: number): Point => [0, 0, 0, 0, y, x, 1, 0]; -export function origin(): Point { - return [0, 0, 0, 0, 0, 0, 1, 0]; -} +export const origin = (): Point => [0, 0, 0, 0, 0, 0, 1, 0]; -export function direction(x: number, y: number): Direction { +export const direction = (x: number, y: number): Direction => { const norm = Math.hypot(x, y); // same as `inorm(direction(x, y))` return [0, 0, 0, 0, y / norm, x / norm, 0, 0]; -} +}; -export function offset(x: number, y: number): Direction { - return [0, 0, 0, 0, y, x, 0, 0]; -} +export const offset = (x: number, y: number): Direction => [ + 0, + 0, + 0, + 0, + y, + x, + 0, + 0, +]; /// This is the "implementation" part of the library @@ -56,7 +59,7 @@ type NVector = readonly [ const NVECTOR_BASE = ["1", "e0", "e1", "e2", "e01", "e20", "e12", "e012"]; // Used to represent points, lines and transformations -export function nvector(value: number = 0, index: number = 0): NVector { +export const nvector = (value: number = 0, index: number = 0): NVector => { const result = [0, 0, 0, 0, 0, 0, 0, 0]; if (index < 0 || index > 7) { throw new Error(`Expected \`index\` betwen 0 and 7, got \`${index}\``); @@ -65,10 +68,10 @@ export function nvector(value: number = 0, index: number = 0): NVector { result[index] = value; } return (result as unknown) as NVector; -} +}; const STRING_EPSILON = 0.000001; -export function toString(nvector: NVector): string { +export const toString = (nvector: NVector): string => { const result = nvector .map((value, index) => Math.abs(value) > STRING_EPSILON @@ -79,66 +82,58 @@ export function toString(nvector: NVector): string { .filter((representation) => representation != null) .join(" + "); return result === "" ? "0" : result; -} +}; // Reverse the order of the basis blades. -export function reverse(nvector: NVector): NVector { - return [ - nvector[0], - nvector[1], - nvector[2], - nvector[3], - -nvector[4], - -nvector[5], - -nvector[6], - -nvector[7], - ]; -} +export const reverse = (nvector: NVector): NVector => [ + nvector[0], + nvector[1], + nvector[2], + nvector[3], + -nvector[4], + -nvector[5], + -nvector[6], + -nvector[7], +]; // Poincare duality operator. -export function dual(nvector: NVector): NVector { - return [ - nvector[7], - nvector[6], - nvector[5], - nvector[4], - nvector[3], - nvector[2], - nvector[1], - nvector[0], - ]; -} +export const dual = (nvector: NVector): NVector => [ + nvector[7], + nvector[6], + nvector[5], + nvector[4], + nvector[3], + nvector[2], + nvector[1], + nvector[0], +]; // Clifford Conjugation -export function conjugate(nvector: NVector): NVector { - return [ - nvector[0], - -nvector[1], - -nvector[2], - -nvector[3], - -nvector[4], - -nvector[5], - -nvector[6], - nvector[7], - ]; -} +export const conjugate = (nvector: NVector): NVector => [ + nvector[0], + -nvector[1], + -nvector[2], + -nvector[3], + -nvector[4], + -nvector[5], + -nvector[6], + nvector[7], +]; // Main involution -export function involute(nvector: NVector): NVector { - return [ - nvector[0], - -nvector[1], - -nvector[2], - -nvector[3], - nvector[4], - nvector[5], - nvector[6], - -nvector[7], - ]; -} +export const involute = (nvector: NVector): NVector => [ + nvector[0], + -nvector[1], + -nvector[2], + -nvector[3], + nvector[4], + nvector[5], + nvector[6], + -nvector[7], +]; // Multivector addition -export function add(a: NVector, b: NVector | number): NVector { +export const add = (a: NVector, b: NVector | number): NVector => { if (isNumber(b)) { return [a[0] + b, a[1], a[2], a[3], a[4], a[5], a[6], a[7]]; } @@ -152,10 +147,10 @@ export function add(a: NVector, b: NVector | number): NVector { a[6] + b[6], a[7] + b[7], ]; -} +}; // Multivector subtraction -export function sub(a: NVector, b: NVector | number): NVector { +export const sub = (a: NVector, b: NVector | number): NVector => { if (isNumber(b)) { return [a[0] - b, a[1], a[2], a[3], a[4], a[5], a[6], a[7]]; } @@ -169,10 +164,10 @@ export function sub(a: NVector, b: NVector | number): NVector { a[6] - b[6], a[7] - b[7], ]; -} +}; // The geometric product. -export function mul(a: NVector, b: NVector | number): NVector { +export const mul = (a: NVector, b: NVector | number): NVector => { if (isNumber(b)) { return [ a[0] * b, @@ -223,112 +218,94 @@ export function mul(a: NVector, b: NVector | number): NVector { b[1] * a[6] + b[0] * a[7], ]; -} +}; -export function mulScalar(a: NVector, b: NVector): number { - return b[0] * a[0] + b[2] * a[2] + b[3] * a[3] - b[6] * a[6]; -} +export const mulScalar = (a: NVector, b: NVector): number => + b[0] * a[0] + b[2] * a[2] + b[3] * a[3] - b[6] * a[6]; // The outer/exterior/wedge product. -export function meet(a: NVector, b: NVector): NVector { - return [ - b[0] * a[0], - b[1] * a[0] + b[0] * a[1], - b[2] * a[0] + b[0] * a[2], - b[3] * a[0] + b[0] * a[3], - b[4] * a[0] + b[2] * a[1] - b[1] * a[2] + b[0] * a[4], - b[5] * a[0] - b[3] * a[1] + b[1] * a[3] + b[0] * a[5], - b[6] * a[0] + b[3] * a[2] - b[2] * a[3] + b[0] * a[6], - b[7] * a[0] + - b[6] * a[1] + - b[5] * a[2] + - b[4] * a[3] + - b[3] * a[4] + - b[2] * a[5] + - b[1] * a[6], - ]; -} +export const meet = (a: NVector, b: NVector): NVector => [ + b[0] * a[0], + b[1] * a[0] + b[0] * a[1], + b[2] * a[0] + b[0] * a[2], + b[3] * a[0] + b[0] * a[3], + b[4] * a[0] + b[2] * a[1] - b[1] * a[2] + b[0] * a[4], + b[5] * a[0] - b[3] * a[1] + b[1] * a[3] + b[0] * a[5], + b[6] * a[0] + b[3] * a[2] - b[2] * a[3] + b[0] * a[6], + b[7] * a[0] + + b[6] * a[1] + + b[5] * a[2] + + b[4] * a[3] + + b[3] * a[4] + + b[2] * a[5] + + b[1] * a[6], +]; // The regressive product. -export function join(a: NVector, b: NVector): NVector { - return [ - joinScalar(a, b), - a[1] * b[7] + a[4] * b[5] - a[5] * b[4] + a[7] * b[1], - a[2] * b[7] - a[4] * b[6] + a[6] * b[4] + a[7] * b[2], - a[3] * b[7] + a[5] * b[6] - a[6] * b[5] + a[7] * b[3], - a[4] * b[7] + a[7] * b[4], - a[5] * b[7] + a[7] * b[5], - a[6] * b[7] + a[7] * b[6], - a[7] * b[7], - ]; -} +export const join = (a: NVector, b: NVector): NVector => [ + joinScalar(a, b), + a[1] * b[7] + a[4] * b[5] - a[5] * b[4] + a[7] * b[1], + a[2] * b[7] - a[4] * b[6] + a[6] * b[4] + a[7] * b[2], + a[3] * b[7] + a[5] * b[6] - a[6] * b[5] + a[7] * b[3], + a[4] * b[7] + a[7] * b[4], + a[5] * b[7] + a[7] * b[5], + a[6] * b[7] + a[7] * b[6], + a[7] * b[7], +]; -export function joinScalar(a: NVector, b: NVector): number { - return ( - a[0] * b[7] + - a[1] * b[6] + - a[2] * b[5] + - a[3] * b[4] + - a[4] * b[3] + - a[5] * b[2] + - a[6] * b[1] + - a[7] * b[0] - ); -} +export const joinScalar = (a: NVector, b: NVector): number => + a[0] * b[7] + + a[1] * b[6] + + a[2] * b[5] + + a[3] * b[4] + + a[4] * b[3] + + a[5] * b[2] + + a[6] * b[1] + + a[7] * b[0]; // The inner product. -export function dot(a: NVector, b: NVector): NVector { - return [ - b[0] * a[0] + b[2] * a[2] + b[3] * a[3] - b[6] * a[6], - b[1] * a[0] + - b[0] * a[1] - - b[4] * a[2] + - b[5] * a[3] + - b[2] * a[4] - - b[3] * a[5] - - b[7] * a[6] - - b[6] * a[7], - b[2] * a[0] + b[0] * a[2] - b[6] * a[3] + b[3] * a[6], - b[3] * a[0] + b[6] * a[2] + b[0] * a[3] - b[2] * a[6], - b[4] * a[0] + b[7] * a[3] + b[0] * a[4] + b[3] * a[7], - b[5] * a[0] + b[7] * a[2] + b[0] * a[5] + b[2] * a[7], - b[6] * a[0] + b[0] * a[6], - b[7] * a[0] + b[0] * a[7], - ]; -} +export const dot = (a: NVector, b: NVector): NVector => [ + b[0] * a[0] + b[2] * a[2] + b[3] * a[3] - b[6] * a[6], + b[1] * a[0] + + b[0] * a[1] - + b[4] * a[2] + + b[5] * a[3] + + b[2] * a[4] - + b[3] * a[5] - + b[7] * a[6] - + b[6] * a[7], + b[2] * a[0] + b[0] * a[2] - b[6] * a[3] + b[3] * a[6], + b[3] * a[0] + b[6] * a[2] + b[0] * a[3] - b[2] * a[6], + b[4] * a[0] + b[7] * a[3] + b[0] * a[4] + b[3] * a[7], + b[5] * a[0] + b[7] * a[2] + b[0] * a[5] + b[2] * a[7], + b[6] * a[0] + b[0] * a[6], + b[7] * a[0] + b[0] * a[7], +]; -export function norm(a: NVector): number { - return Math.sqrt( - Math.abs(a[0] * a[0] - a[2] * a[2] - a[3] * a[3] + a[6] * a[6]), - ); -} +export const norm = (a: NVector): number => + Math.sqrt(Math.abs(a[0] * a[0] - a[2] * a[2] - a[3] * a[3] + a[6] * a[6])); -export function inorm(a: NVector): number { - return Math.sqrt( - Math.abs(a[7] * a[7] - a[5] * a[5] - a[4] * a[4] + a[1] * a[1]), - ); -} +export const inorm = (a: NVector): number => + Math.sqrt(Math.abs(a[7] * a[7] - a[5] * a[5] - a[4] * a[4] + a[1] * a[1])); -export function normalized(a: NVector): NVector { +export const normalized = (a: NVector): NVector => { const n = norm(a); if (n === 0 || n === 1) { return a; } const sign = a[6] < 0 ? -1 : 1; return mul(a, sign / n); -} +}; -export function inormalized(a: NVector): NVector { +export const inormalized = (a: NVector): NVector => { const n = inorm(a); if (n === 0 || n === 1) { return a; } return mul(a, 1 / n); -} +}; -function isNumber(a: any): a is number { - return typeof a === "number"; -} +const isNumber = (a: any): a is number => typeof a === "number"; export const E0: NVector = nvector(1, 1); export const E1: NVector = nvector(1, 2); diff --git a/src/gadirections.ts b/src/gadirections.ts index 0307c9bf..ad026c17 100644 --- a/src/gadirections.ts +++ b/src/gadirections.ts @@ -6,18 +6,21 @@ import { Line, Direction, Point } from "./ga"; * vector `(x, y)`. */ -export function from(point: Point): Point { - return [0, 0, 0, 0, point[4], point[5], 0, 0]; -} +export const from = (point: Point): Point => [ + 0, + 0, + 0, + 0, + point[4], + point[5], + 0, + 0, +]; -export function fromTo(from: Point, to: Point): Direction { - return GA.inormalized([0, 0, 0, 0, to[4] - from[4], to[5] - from[5], 0, 0]); -} +export const fromTo = (from: Point, to: Point): Direction => + GA.inormalized([0, 0, 0, 0, to[4] - from[4], to[5] - from[5], 0, 0]); -export function orthogonal(direction: Direction): Direction { - return GA.inormalized([0, 0, 0, 0, -direction[5], direction[4], 0, 0]); -} +export const orthogonal = (direction: Direction): Direction => + GA.inormalized([0, 0, 0, 0, -direction[5], direction[4], 0, 0]); -export function orthogonalToLine(line: Line): Direction { - return GA.mul(line, GA.I); -} +export const orthogonalToLine = (line: Line): Direction => GA.mul(line, GA.I); diff --git a/src/galines.ts b/src/galines.ts index 9d83b9e5..e57527b8 100644 --- a/src/galines.ts +++ b/src/galines.ts @@ -15,48 +15,38 @@ import { Line, Point } from "./ga"; */ // Returns line with direction (x, y) through origin -export function vector(x: number, y: number): Line { - return GA.normalized([0, 0, -y, x, 0, 0, 0, 0]); -} +export const vector = (x: number, y: number): Line => + GA.normalized([0, 0, -y, x, 0, 0, 0, 0]); // For equation ax + by + c = 0. -export function equation(a: number, b: number, c: number): Line { - return GA.normalized([0, c, a, b, 0, 0, 0, 0]); -} +export const equation = (a: number, b: number, c: number): Line => + GA.normalized([0, c, a, b, 0, 0, 0, 0]); -export function through(from: Point, to: Point): Line { - return GA.normalized(GA.join(to, from)); -} +export const through = (from: Point, to: Point): Line => + GA.normalized(GA.join(to, from)); -export function orthogonal(line: Line, point: Point): Line { - return GA.dot(line, point); -} +export const orthogonal = (line: Line, point: Point): Line => + GA.dot(line, point); // Returns a line perpendicular to the line through `against` and `intersection` // going through `intersection`. -export function orthogonalThrough(against: Point, intersection: Point): Line { - return orthogonal(through(against, intersection), intersection); -} +export const orthogonalThrough = (against: Point, intersection: Point): Line => + orthogonal(through(against, intersection), intersection); -export function parallel(line: Line, distance: number): Line { +export const parallel = (line: Line, distance: number): Line => { const result = line.slice(); result[1] -= distance; return (result as unknown) as Line; -} +}; -export function parallelThrough(line: Line, point: Point): Line { - return orthogonal(orthogonal(point, line), point); -} +export const parallelThrough = (line: Line, point: Point): Line => + orthogonal(orthogonal(point, line), point); -export function distance(line1: Line, line2: Line): number { - return GA.inorm(GA.meet(line1, line2)); -} +export const distance = (line1: Line, line2: Line): number => + GA.inorm(GA.meet(line1, line2)); -export function angle(line1: Line, line2: Line): number { - return Math.acos(GA.dot(line1, line2)[0]); -} +export const angle = (line1: Line, line2: Line): number => + Math.acos(GA.dot(line1, line2)[0]); // The orientation of the line -export function sign(line: Line): number { - return Math.sign(line[1]); -} +export const sign = (line: Line): number => Math.sign(line[1]); diff --git a/src/gapoints.ts b/src/gapoints.ts index 8d749468..25ad6079 100644 --- a/src/gapoints.ts +++ b/src/gapoints.ts @@ -2,36 +2,40 @@ import * as GA from "./ga"; import * as GALine from "./galines"; import { Point, Line, join } from "./ga"; -/** - * TODO: docs - */ +export const from = ([x, y]: readonly [number, number]): Point => [ + 0, + 0, + 0, + 0, + y, + x, + 1, + 0, +]; -export function from([x, y]: readonly [number, number]): Point { - return [0, 0, 0, 0, y, x, 1, 0]; -} +export const toTuple = (point: Point): [number, number] => [point[5], point[4]]; -export function toTuple(point: Point): [number, number] { - return [point[5], point[4]]; -} +export const abs = (point: Point): Point => [ + 0, + 0, + 0, + 0, + Math.abs(point[4]), + Math.abs(point[5]), + 1, + 0, +]; -export function abs(point: Point): Point { - return [0, 0, 0, 0, Math.abs(point[4]), Math.abs(point[5]), 1, 0]; -} - -export function intersect(line1: Line, line2: Line): Point { - return GA.normalized(GA.meet(line1, line2)); -} +export const intersect = (line1: Line, line2: Line): Point => + GA.normalized(GA.meet(line1, line2)); // Projects `point` onto the `line`. // The returned point is the closest point on the `line` to the `point`. -export function project(point: Point, line: Line): Point { - return intersect(GALine.orthogonal(line, point), line); -} +export const project = (point: Point, line: Line): Point => + intersect(GALine.orthogonal(line, point), line); -export function distance(point1: Point, point2: Point): number { - return GA.norm(join(point1, point2)); -} +export const distance = (point1: Point, point2: Point): number => + GA.norm(join(point1, point2)); -export function distanceToLine(point: Point, line: Line): number { - return GA.joinScalar(point, line); -} +export const distanceToLine = (point: Point, line: Line): number => + GA.joinScalar(point, line); diff --git a/src/gatransforms.ts b/src/gatransforms.ts index 2a1d5f09..ca57434e 100644 --- a/src/gatransforms.ts +++ b/src/gatransforms.ts @@ -6,33 +6,36 @@ import * as GADirection from "./gadirections"; * TODO: docs */ -export function rotation(pivot: Point, angle: number): Transform { - return GA.add(GA.mul(pivot, Math.sin(angle / 2)), Math.cos(angle / 2)); -} +export const rotation = (pivot: Point, angle: number): Transform => + GA.add(GA.mul(pivot, Math.sin(angle / 2)), Math.cos(angle / 2)); -export function translation(direction: Direction): Transform { - return [1, 0, 0, 0, -(0.5 * direction[5]), 0.5 * direction[4], 0, 0]; -} +export const translation = (direction: Direction): Transform => [ + 1, + 0, + 0, + 0, + -(0.5 * direction[5]), + 0.5 * direction[4], + 0, + 0, +]; -export function translationOrthogonal( +export const translationOrthogonal = ( direction: Direction, distance: number, -): Transform { +): Transform => { const scale = 0.5 * distance; return [1, 0, 0, 0, scale * direction[4], scale * direction[5], 0, 0]; -} +}; -export function translationAlong(line: Line, distance: number): Transform { - return GA.add(GA.mul(GADirection.orthogonalToLine(line), 0.5 * distance), 1); -} +export const translationAlong = (line: Line, distance: number): Transform => + GA.add(GA.mul(GADirection.orthogonalToLine(line), 0.5 * distance), 1); -export function compose(motor1: Transform, motor2: Transform): Transform { - return GA.mul(motor2, motor1); -} +export const compose = (motor1: Transform, motor2: Transform): Transform => + GA.mul(motor2, motor1); -export function apply( +export const apply = ( motor: Transform, nvector: Point | Direction | Line, -): Point | Direction | Line { - return GA.normalized(GA.mul(GA.mul(motor, nvector), GA.reverse(motor))); -} +): Point | Direction | Line => + GA.normalized(GA.mul(GA.mul(motor, nvector), GA.reverse(motor))); diff --git a/src/groups.ts b/src/groups.ts index 589e3241..1c27d452 100644 --- a/src/groups.ts +++ b/src/groups.ts @@ -2,11 +2,11 @@ import { GroupId, ExcalidrawElement, NonDeleted } from "./element/types"; import { AppState } from "./types"; import { getSelectedElements } from "./scene"; -export function selectGroup( +export const selectGroup = ( groupId: GroupId, appState: AppState, elements: readonly NonDeleted[], -): AppState { +): AppState => { const elementsInGroup = elements.filter((element) => element.groupIds.includes(groupId), ); @@ -35,42 +35,38 @@ export function selectGroup( ), }, }; -} +}; /** * If the element's group is selected, don't render an individual * selection border around it. */ -export function isSelectedViaGroup( +export const isSelectedViaGroup = ( appState: AppState, element: ExcalidrawElement, -) { - return getSelectedGroupForElement(appState, element) != null; -} +) => getSelectedGroupForElement(appState, element) != null; export const getSelectedGroupForElement = ( appState: AppState, element: ExcalidrawElement, -) => { - return element.groupIds +) => + element.groupIds .filter((groupId) => groupId !== appState.editingGroupId) .find((groupId) => appState.selectedGroupIds[groupId]); -}; -export function getSelectedGroupIds(appState: AppState): GroupId[] { - return Object.entries(appState.selectedGroupIds) +export const getSelectedGroupIds = (appState: AppState): GroupId[] => + Object.entries(appState.selectedGroupIds) .filter(([groupId, isSelected]) => isSelected) .map(([groupId, isSelected]) => groupId); -} /** * When you select an element, you often want to actually select the whole group it's in, unless * you're currently editing that group. */ -export function selectGroupsForSelectedElements( +export const selectGroupsForSelectedElements = ( appState: AppState, elements: readonly NonDeleted[], -): AppState { +): AppState => { let nextAppState = { ...appState }; const selectedElements = getSelectedElements(elements, appState); @@ -91,7 +87,7 @@ export function selectGroupsForSelectedElements( } return nextAppState; -} +}; export const editGroupForSelectedElement = ( appState: AppState, @@ -107,29 +103,24 @@ export const editGroupForSelectedElement = ( }; }; -export function isElementInGroup(element: ExcalidrawElement, groupId: string) { - return element.groupIds.includes(groupId); -} +export const isElementInGroup = (element: ExcalidrawElement, groupId: string) => + element.groupIds.includes(groupId); -export function getElementsInGroup( +export const getElementsInGroup = ( elements: readonly ExcalidrawElement[], groupId: string, -) { - return elements.filter((element) => isElementInGroup(element, groupId)); -} +) => elements.filter((element) => isElementInGroup(element, groupId)); -export function getSelectedGroupIdForElement( +export const getSelectedGroupIdForElement = ( element: ExcalidrawElement, selectedGroupIds: { [groupId: string]: boolean }, -) { - return element.groupIds.find((groupId) => selectedGroupIds[groupId]); -} +) => element.groupIds.find((groupId) => selectedGroupIds[groupId]); -export function getNewGroupIdsForDuplication( +export const getNewGroupIdsForDuplication = ( groupIds: ExcalidrawElement["groupIds"], editingGroupId: AppState["editingGroupId"], mapper: (groupId: GroupId) => GroupId, -) { +) => { const copy = [...groupIds]; const positionOfEditingGroupId = editingGroupId ? groupIds.indexOf(editingGroupId) @@ -141,13 +132,13 @@ export function getNewGroupIdsForDuplication( } return copy; -} +}; -export function addToGroup( +export const addToGroup = ( prevGroupIds: ExcalidrawElement["groupIds"], newGroupId: GroupId, editingGroupId: AppState["editingGroupId"], -) { +) => { // insert before the editingGroupId, or push to the end. const groupIds = [...prevGroupIds]; const positionOfEditingGroupId = editingGroupId @@ -157,11 +148,9 @@ export function addToGroup( positionOfEditingGroupId > -1 ? positionOfEditingGroupId : groupIds.length; groupIds.splice(positionToInsert, 0, newGroupId); return groupIds; -} +}; -export function removeFromSelectedGroups( +export const removeFromSelectedGroups = ( groupIds: ExcalidrawElement["groupIds"], selectedGroupIds: { [groupId: string]: boolean }, -) { - return groupIds.filter((groupId) => !selectedGroupIds[groupId]); -} +) => groupIds.filter((groupId) => !selectedGroupIds[groupId]); diff --git a/src/renderer/renderScene.ts b/src/renderer/renderScene.ts index ef61f693..a2d694d4 100644 --- a/src/renderer/renderScene.ts +++ b/src/renderer/renderScene.ts @@ -334,7 +334,7 @@ export const renderScene = ( return acc; }, [] as { angle: number; elementX1: number; elementY1: number; elementX2: number; elementY2: number; selectionColors: string[] }[]); - function addSelectionForGroupId(groupId: GroupId) { + const addSelectionForGroupId = (groupId: GroupId) => { const groupElements = getElementsInGroup(elements, groupId); const [elementX1, elementY1, elementX2, elementY2] = getCommonBounds( groupElements, @@ -347,7 +347,7 @@ export const renderScene = ( elementY2, selectionColors: [oc.black], }); - } + }; for (const groupId of getSelectedGroupIds(appState)) { // TODO: support multiplayer selected group IDs diff --git a/src/scene/scroll.ts b/src/scene/scroll.ts index f976faa1..51cc7da4 100644 --- a/src/scene/scroll.ts +++ b/src/scene/scroll.ts @@ -10,11 +10,11 @@ import { export const normalizeScroll = (pos: number) => Math.floor(pos) as FlooredNumber; -function isOutsideViewPort( +const isOutsideViewPort = ( appState: AppState, canvas: HTMLCanvasElement | null, cords: Array, -) { +) => { const [x1, y1, x2, y2] = cords; const { x: viewportX1, y: viewportY1 } = sceneCoordsToViewportCoords( { sceneX: x1, sceneY: y1 }, @@ -28,7 +28,7 @@ function isOutsideViewPort( viewportX2 - viewportX1 > appState.width || viewportY2 - viewportY1 > appState.height ); -} +}; export const centerScrollOn = ({ scenePoint, diff --git a/src/tests/align.test.tsx b/src/tests/align.test.tsx index f2ef20a3..2d17a249 100644 --- a/src/tests/align.test.tsx +++ b/src/tests/align.test.tsx @@ -29,7 +29,7 @@ beforeEach(async () => { render(); }); -function createAndSelectTwoRectangles() { +const createAndSelectTwoRectangles = () => { UI.clickTool("rectangle"); mouse.down(); mouse.up(100, 100); @@ -44,9 +44,9 @@ function createAndSelectTwoRectangles() { Keyboard.withModifierKeys({ shift: true }, () => { mouse.click(); }); -} +}; -function createAndSelectTwoRectanglesWithDifferentSizes() { +const createAndSelectTwoRectanglesWithDifferentSizes = () => { UI.clickTool("rectangle"); mouse.down(); mouse.up(100, 100); @@ -61,7 +61,7 @@ function createAndSelectTwoRectanglesWithDifferentSizes() { Keyboard.withModifierKeys({ shift: true }, () => { mouse.click(); }); -} +}; it("aligns two objects correctly to the top", () => { createAndSelectTwoRectangles(); @@ -185,7 +185,7 @@ it("centers two objects with different sizes correctly horizontally", () => { expect(API.getSelectedElements()[1].y).toEqual(110); }); -function createAndSelectGroupAndRectangle() { +const createAndSelectGroupAndRectangle = () => { UI.clickTool("rectangle"); mouse.down(); mouse.up(100, 100); @@ -213,7 +213,7 @@ function createAndSelectGroupAndRectangle() { Keyboard.withModifierKeys({ shift: true }, () => { mouse.click(); }); -} +}; it("aligns a group with another element correctly to the top", () => { createAndSelectGroupAndRectangle(); @@ -299,7 +299,7 @@ it("centers a group with another element correctly horizontally", () => { expect(API.getSelectedElements()[2].x).toEqual(100); }); -function createAndSelectTwoGroups() { +const createAndSelectTwoGroups = () => { UI.clickTool("rectangle"); mouse.down(); mouse.up(100, 100); @@ -339,7 +339,7 @@ function createAndSelectTwoGroups() { Keyboard.withModifierKeys({ shift: true }, () => { mouse.click(); }); -} +}; it("aligns two groups correctly to the top", () => { createAndSelectTwoGroups(); @@ -437,7 +437,7 @@ it("centers two groups correctly horizontally", () => { expect(API.getSelectedElements()[3].x).toEqual(200); }); -function createAndSelectNestedGroupAndRectangle() { +const createAndSelectNestedGroupAndRectangle = () => { UI.clickTool("rectangle"); mouse.down(); mouse.up(100, 100); @@ -480,7 +480,7 @@ function createAndSelectNestedGroupAndRectangle() { Keyboard.withModifierKeys({ shift: true }, () => { mouse.click(); }); -} +}; it("aligns nested group and other element correctly to the top", () => { createAndSelectNestedGroupAndRectangle(); diff --git a/src/utils.ts b/src/utils.ts index a494b1d3..a73a4d9a 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -242,12 +242,12 @@ const RE_RTL_CHECK = new RegExp(`^[^${RS_LTR_CHARS}]*[${RS_RTL_CHARS}]`); */ export const isRTL = (text: string) => RE_RTL_CHECK.test(text); -export function tupleToCoors( +export const tupleToCoors = ( xyTuple: readonly [number, number], -): { x: number; y: number } { +): { x: number; y: number } => { const [x, y] = xyTuple; return { x, y }; -} +}; /** use as a rejectionHandler to mute filesystem Abort errors */ export const muteFSAbortError = (error?: Error) => {