diff --git a/eslint.config.js b/eslint.config.js index 6e7779c..94b1802 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -6,7 +6,7 @@ import react from "eslint-plugin-react"; export default tseslint.config( eslint.configs.recommended, - // ...tseslint.configs.recommendedTypeChecked, + ...tseslint.configs.recommendedTypeChecked, { languageOptions: { parserOptions: { @@ -53,7 +53,13 @@ export default tseslint.config( } ], "comma-spacing": "off", - "@typescript-eslint/comma-spacing": "error" + "@typescript-eslint/comma-spacing": "error", + "@typescript-eslint/no-unused-vars": [ + "error", + { + "argsIgnorePattern": "^_" + } + ] }, } ); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 657d519..d4015c7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,6 +36,7 @@ "devDependencies": { "@babel/plugin-proposal-private-property-in-object": "^7.21.11", "@eslint/js": "^9.2.0", + "@types/react-syntax-highlighter": "^15.5.13", "@types/webpack-env": "^1.18.4", "@typescript-eslint/eslint-plugin": "^7.8.0", "@typescript-eslint/parser": "^7.8.0", @@ -4623,6 +4624,15 @@ "@types/react": "*" } }, + "node_modules/@types/react-syntax-highlighter": { + "version": "15.5.13", + "resolved": "https://registry.npmjs.org/@types/react-syntax-highlighter/-/react-syntax-highlighter-15.5.13.tgz", + "integrity": "sha512-uLGJ87j6Sz8UaBAooU0T6lWJ0dBmjZgN1PZTrj05TNql2/XpC6+4HhMT5syIdFUUt+FASfCeLLv4kBygNU+8qA==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/resolve": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", diff --git a/package.json b/package.json index 69cab35..1f8c1e6 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "devDependencies": { "@babel/plugin-proposal-private-property-in-object": "^7.21.11", "@eslint/js": "^9.2.0", + "@types/react-syntax-highlighter": "^15.5.13", "@types/webpack-env": "^1.18.4", "@typescript-eslint/eslint-plugin": "^7.8.0", "@typescript-eslint/parser": "^7.8.0", diff --git a/src/App.tsx b/src/App.tsx index c1c98ad..3a1c720 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -8,11 +8,8 @@ import { SettingsManagerProvider } from "./hooks/settings/settingsManagerContext import { ModalsView } from "./components/modals/ModalsView"; import { FC, useEffect } from "react"; import { ZIndexManagerProvider } from "./hooks/z-index/zIndexManagerContext"; -import { TrackingManager } from "./features/tracking/trackingManager"; import { ModalsManagerProvider } from "./hooks/modals/modalsManagerContext"; -TrackingManager.initialize(); - const App: FC = () => { useEffect(() => { const onContextMenu = (event: Event) => { diff --git a/src/components/actions/Actions.tsx b/src/components/actions/Actions.tsx index c6d7f91..59e8f62 100644 --- a/src/components/actions/Actions.tsx +++ b/src/components/actions/Actions.tsx @@ -1,4 +1,4 @@ -import { Children, cloneElement, isValidElement, ReactElement, ReactNode } from "react"; +import { Children, cloneElement, isValidElement, ReactElement, ReactNode, Ref } from "react"; import { useShortcuts } from "../../hooks/_utils/keyboard"; import styles from "./Actions.module.css"; import { useScreenBounds } from "../../hooks/_utils/screen"; @@ -11,17 +11,17 @@ export const STYLES = { export interface ActionProps { actionId?: string; label?: string; - icon?: string|object; + icon?: string | object; shortcut?: string[]; - onTrigger?: (event: Event, triggerParams: any, ...args: any[]) => void; + onTrigger?: (event: Event, triggerParams: unknown, ...args: unknown[]) => void; children?: ReactNode; } export interface ActionsProps { className?: string; - onAnyTrigger?: (event: Event, triggerParams: any, ...args: any[]) => void; + onAnyTrigger?: (event: Event, triggerParams: unknown, ...args: unknown[]) => void; children?: ReactNode; - triggerParams?: any; + triggerParams?: unknown; avoidTaskbar?: boolean; } @@ -44,7 +44,7 @@ export function Actions({ children, className, onAnyTrigger, triggerParams, avoi const options = {}; const shortcuts = {}; - const iterateOverChildren = (children: ReactNode) => { + const iterateOverChildren = (children: ReactNode): ReactNode => { let actionId = 0; const newChildren = Children.map(children, (child) => { if (!isValidElement(child)) @@ -52,7 +52,7 @@ export function Actions({ children, className, onAnyTrigger, triggerParams, avoi actionId++; - const { label, shortcut, onTrigger } = child.props; + const { label, shortcut, onTrigger } = child.props as ActionProps; if (label != null && onTrigger != null) { options[actionId] = onTrigger; @@ -61,19 +61,18 @@ export function Actions({ children, className, onAnyTrigger, triggerParams, avoi } if (isListener) { - iterateOverChildren(child.props.children); - return; + return iterateOverChildren((child.props as ActionProps).children); } return cloneElement(child, { ...child.props, actionId, - children: iterateOverChildren(child.props.children), + children: iterateOverChildren((child.props as ActionProps).children), onTrigger: (event, ...args) => { onAnyTrigger?.(event, triggerParams, ...args); onTrigger?.(event, triggerParams, ...args); } - }); + } as ActionProps); }); return newChildren; @@ -82,7 +81,7 @@ export function Actions({ children, className, onAnyTrigger, triggerParams, avoi useShortcuts({ options, shortcuts, useCategories: false }); if (isListener) - return iterateOverChildren(children); + return iterateOverChildren(children) as ReactElement; const classNames = [styles.Container]; if (className != null) @@ -94,7 +93,7 @@ export function Actions({ children, className, onAnyTrigger, triggerParams, avoi if (!initiated) classNames.push(styles.Uninitiated); - return
+ return
} className={classNames.join(" ")}> {iterateOverChildren(children)}
; } \ No newline at end of file diff --git a/src/components/apps/_utils/web-view/WebView.tsx b/src/components/apps/_utils/web-view/WebView.tsx index cea90a3..899c356 100644 --- a/src/components/apps/_utils/web-view/WebView.tsx +++ b/src/components/apps/_utils/web-view/WebView.tsx @@ -4,6 +4,7 @@ import { WindowProps } from "../../../windows/WindowView"; interface WebViewProps extends WindowProps { source: string; + title: string; } export const WebView: FC = forwardRef(({ source, focus, ...props }: WebViewProps, ref) => { diff --git a/src/components/apps/browser/Browser.tsx b/src/components/apps/browser/Browser.tsx index afd6dfc..0e0bd2c 100644 --- a/src/components/apps/browser/Browser.tsx +++ b/src/components/apps/browser/Browser.tsx @@ -1,4 +1,4 @@ -import { useEffect, useRef, useState } from "react"; +import { ChangeEventHandler, KeyboardEventHandler, useEffect, useRef, useState } from "react"; import styles from "./Browser.module.css"; import { WebView } from "../_utils/web-view/WebView"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; @@ -15,10 +15,10 @@ interface BrowserProps extends WindowProps { export function Browser({ startUrl, focus }: BrowserProps) { const initialUrl = startUrl ?? HOME_URL; - const [url, setUrl] = useState(initialUrl); + const [url, setUrl] = useState(initialUrl); const [input, setInput] = useState(initialUrl); const { history, pushState, stateIndex, undo, redo, undoAvailable, redoAvailable } = useHistory(initialUrl); - const ref = useRef(null); + const ref = useRef(null); useEffect(() => { if (history.length === 0) @@ -34,7 +34,7 @@ export function Browser({ startUrl, focus }: BrowserProps) { ref.current.contentWindow.location.href = url; }; - const updateUrl = (newUrl) => { + const updateUrl = (newUrl: string) => { if (url === newUrl) { return reload(); } @@ -44,12 +44,12 @@ export function Browser({ startUrl, focus }: BrowserProps) { pushState(newUrl); }; - const onInputChange = (event) => { - setInput(event.target.value); + const onInputChange = (event: Event) => { + setInput((event.target as HTMLInputElement).value); }; - const onKeyDown = (event) => { - const value = event.target.value; + const onKeyDown = (event: KeyboardEvent) => { + const value = (event.target as HTMLInputElement).value; if (event.key === "Enter" && value !== "") { if (isValidUrl(value)) { @@ -67,7 +67,7 @@ export function Browser({ startUrl, focus }: BrowserProps) { title="Back" tabIndex={0} className={styles["Icon-button"]} - onClick={undo} + onClick={() => { undo(); }} disabled={!undoAvailable} > @@ -76,7 +76,7 @@ export function Browser({ startUrl, focus }: BrowserProps) { title="Forward" tabIndex={0} className={styles["Icon-button"]} - onClick={redo} + onClick={() => { redo(); }} disabled={!redoAvailable} > @@ -103,8 +103,8 @@ export function Browser({ startUrl, focus }: BrowserProps) { aria-label="Search bar" className={styles["Search-bar"]} tabIndex={0} - onChange={onInputChange} - onKeyDown={onKeyDown} + onChange={onInputChange as unknown as ChangeEventHandler} + onKeyDown={onKeyDown as unknown as KeyboardEventHandler} />
diff --git a/src/components/apps/calculator/Calculator.tsx b/src/components/apps/calculator/Calculator.tsx index 11a2c62..b056bcc 100644 --- a/src/components/apps/calculator/Calculator.tsx +++ b/src/components/apps/calculator/Calculator.tsx @@ -5,9 +5,9 @@ import { WindowProps } from "../../windows/WindowView"; export function Calculator({ active }: WindowProps) { const [input, setInput] = useState("0"); - const [firstNumber, setFirstNumber] = useState(null); - const [secondNumber, setSecondNumber] = useState(null); - const [operation, setOperation] = useState(null); + const [firstNumber, setFirstNumber] = useState(null); + const [secondNumber, setSecondNumber] = useState(null); + const [operation, setOperation] = useState(null); const [isIntermediate, setIsIntermediate] = useState(false); const reset = useCallback(() => { @@ -17,11 +17,11 @@ export function Calculator({ active }: WindowProps) { setOperation(null); }, []); - const addInput = useCallback((string) => { + const addInput = useCallback((string: string) => { let hasReset = false; if (secondNumber != null) { if (isIntermediate) { - setFirstNumber(input); + setFirstNumber(parseFloat(input)); setSecondNumber(null); setInput(null); } else { @@ -54,12 +54,10 @@ export function Calculator({ active }: WindowProps) { }, [input, isIntermediate, reset, secondNumber]); const calculate = useCallback((intermediate = false) => { - if (firstNumber == null) { + if (firstNumber != null) { + setSecondNumber(parseFloat(input)); - } else { - setSecondNumber(input); - - const a = parseFloat(firstNumber); + const a = firstNumber; const b = parseFloat(input); let result = 0; @@ -84,11 +82,11 @@ export function Calculator({ active }: WindowProps) { setIsIntermediate(intermediate); }, [firstNumber, input, operation]); - const changeOperation = useCallback((operation) => { + const changeOperation = useCallback((operation: string) => { if (firstNumber != null && secondNumber == null) { calculate(true); } else { - setFirstNumber(input); + setFirstNumber(parseFloat(input)); setSecondNumber(null); setInput(null); } @@ -97,7 +95,7 @@ export function Calculator({ active }: WindowProps) { }, [calculate, firstNumber, input, secondNumber]); useEffect(() => { - const onKeyDown = (event) => { + const onKeyDown = (event: KeyboardEvent) => { if (!active) return; diff --git a/src/components/apps/file-explorer/FileExplorer.tsx b/src/components/apps/file-explorer/FileExplorer.tsx index 3a430bc..b980c3d 100644 --- a/src/components/apps/file-explorer/FileExplorer.tsx +++ b/src/components/apps/file-explorer/FileExplorer.tsx @@ -1,4 +1,4 @@ -import { FC, useCallback, useEffect, useState } from "react"; +import { ChangeEventHandler, FC, KeyboardEventHandler, useCallback, useEffect, useState } from "react"; import { useVirtualRoot } from "../../../hooks/virtual-drive/virtualRootContext"; import styles from "./FileExplorer.module.css"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; @@ -40,10 +40,10 @@ export function FileExplorer({ startPath, selectorMode, Footer, onSelectionChang const virtualRoot = useVirtualRoot(); const [currentDirectory, setCurrentDirectory] = useState(virtualRoot.navigate(startPath ?? "~") as VirtualFolder); - const [path, setPath] = useState(currentDirectory?.path ?? ""); + const [path, setPath] = useState(currentDirectory?.path ?? ""); const windowsManager = useWindowsManager(); const [showHidden] = useState(true); - const { history, stateIndex, pushState, undo, redo, undoAvailable, redoAvailable } = useHistory(currentDirectory.path); + const { history, stateIndex, pushState, undo, redo, undoAvailable, redoAvailable } = useHistory(currentDirectory.path); const { openWindowedModal } = useWindowedModal(); const { onContextMenu: onContextMenuFile } = useContextMenu({ Actions: (props) => @@ -56,29 +56,29 @@ export function FileExplorer({ startPath, selectorMode, Footer, onSelectionChang } file.open(windowsManager); }}/> - { + { file.delete(); }}/> - { + { openWindowedModal({ title: `${file.id} ${TITLE_SEPARATOR} Properties`, iconUrl: file.getIconUrl(), size: new Vector2(400, 500), - Modal: (props) => + Modal: (props: object) => }); }}/> }); const { onContextMenu: onContextMenuFolder } = useContextMenu({ Actions: (props) => - { + { changeDirectory(folder.linkedPath ?? folder.name); }}/> - { + { windowsManager.open(APPS.TERMINAL, { startPath: folder.path }); }}/> - { + { folder.delete(); }}/> @@ -91,7 +91,7 @@ export function FileExplorer({ startPath, selectorMode, Footer, onSelectionChang // } // }); - const changeDirectory = useCallback((path, absolute = false) => { + const changeDirectory = useCallback((path: string, absolute = false) => { if (path == null) return; @@ -119,12 +119,12 @@ export function FileExplorer({ startPath, selectorMode, Footer, onSelectionChang } }, [history, stateIndex, virtualRoot]); - const onPathChange = (event) => { - setPath(event.target.value); + const onPathChange = (event: Event) => { + setPath((event.target as HTMLInputElement).value); }; - const onKeyDown = (event) => { - let value = event.target.value; + const onKeyDown = (event: KeyboardEvent) => { + let value = (event.target as HTMLInputElement).value; if (event.key === "Enter") { if (value === "") @@ -160,7 +160,7 @@ export function FileExplorer({ startPath, selectorMode, Footer, onSelectionChang title="Back" tabIndex={0} className={styles["Icon-button"]} - onClick={undo} + onClick={() => { undo(); }} disabled={!undoAvailable} > @@ -169,7 +169,7 @@ export function FileExplorer({ startPath, selectorMode, Footer, onSelectionChang title="Forward" tabIndex={0} className={styles["Icon-button"]} - onClick={redo} + onClick={() => { redo(); }} disabled={!redoAvailable} > @@ -215,8 +215,8 @@ export function FileExplorer({ startPath, selectorMode, Footer, onSelectionChang aria-label="Path" className={styles["Path-input"]} tabIndex={0} - onChange={onPathChange} - onKeyDown={onKeyDown} + onChange={onPathChange as unknown as ChangeEventHandler} + onKeyDown={onKeyDown as unknown as KeyboardEventHandler} placeholder="Enter a path..." />
} - onReset={(details) => { + onReset={() => { // Reset the state of your app so the error doesn't happen again }} onError={(error) => { diff --git a/src/components/windows/WindowsView.tsx b/src/components/windows/WindowsView.tsx index abbd3f5..dd3f8b3 100644 --- a/src/components/windows/WindowsView.tsx +++ b/src/components/windows/WindowsView.tsx @@ -43,7 +43,7 @@ export const WindowsView: FC = memo(() => { if (windowsManager.startupComplete) return; - let startupAppNames = []; + let startupAppNames: string[] = []; // Get app name and params from URL query const params = getViewportParams(); @@ -54,7 +54,7 @@ export const WindowsView: FC = memo(() => { // Get list of app names from settings file const settings = settingsManager.get(SettingsManager.VIRTUAL_PATHS.apps); - settings.get("startup", (value) => { + void settings.get("startup", (value) => { if (value !== "") { startupAppNames = value?.split(",").concat(startupAppNames); startupAppNames = removeDuplicatesFromArray(startupAppNames); @@ -79,7 +79,7 @@ export const WindowsView: FC = memo(() => { position={position} options={options} minimized={minimized} - toggleMinimized={(event) => { + toggleMinimized={(event: Event) => { event.preventDefault(); event.stopPropagation(); windowsManager.setMinimized(id, !minimized); diff --git a/src/config/apps/textEditor.config.ts b/src/config/apps/textEditor.config.ts index b382a6e..45c8f72 100644 --- a/src/config/apps/textEditor.config.ts +++ b/src/config/apps/textEditor.config.ts @@ -12,7 +12,7 @@ export const CODE_FORMATS = [ "yml" ]; -export const EXTENSION_TO_LANGUAGE = { +export const EXTENSION_TO_LANGUAGE: Record = { "js": "javascript", "jsx": "javascript", "ts": "typescript", diff --git a/src/features/_utils/array.utils.ts b/src/features/_utils/array.utils.ts index 41a03ec..d9c0e40 100644 --- a/src/features/_utils/array.utils.ts +++ b/src/features/_utils/array.utils.ts @@ -1,14 +1,14 @@ -export function removeFromArray(item: any, array: any[]) { +export function removeFromArray(item: Type, array: Type[]) { const index = array.indexOf(item); if (index !== -1) { array.splice(index, 1); } } -export function randomFromArray(array: any[]): any { +export function randomFromArray(array: Type[]): Type { return array[Math.floor(Math.random() * array.length)]; } -export function removeDuplicatesFromArray(array: any[]): any[] { +export function removeDuplicatesFromArray(array: Type[]): Type[] { return array.filter((item, index) => array.indexOf(item) === index); } \ No newline at end of file diff --git a/src/features/_utils/date.utils.ts b/src/features/_utils/date.utils.ts index 5941171..fe78e83 100644 --- a/src/features/_utils/date.utils.ts +++ b/src/features/_utils/date.utils.ts @@ -15,9 +15,9 @@ const TIME_INDICATORS = { * @param maxLength - The maximum amount of units, e.g.: 3 => years, months, days */ export function formatTime(time: number, maxLength: number = 3, allowAffixes: boolean): string { - const result = []; + const result: string[] = []; - const formatResult = (result, inPast) => { + const formatResult = (result: string[], inPast: boolean): string => { if (!allowAffixes) return result.join(", "); @@ -44,8 +44,8 @@ export function formatTime(time: number, maxLength: number = 3, allowAffixes: bo return formatResult(["less than a second"], inPast); } - const units = []; - const unitLabels = { + const units: { amount: number, label: string }[] = []; + const unitLabels: Record = { "s": "seconds", "m": "minutes", "h": "hours", diff --git a/src/features/_utils/event.utils.ts b/src/features/_utils/event.utils.ts index d64828e..f8dda14 100644 --- a/src/features/_utils/event.utils.ts +++ b/src/features/_utils/event.utils.ts @@ -8,7 +8,7 @@ export class EventEmitter { /** * Add event listener for an event */ - on(eventName: Key, callback: (data: any) => void) { + on(eventName: Key, callback: (data: unknown) => void) { if (!this.#events[eventName as string]) { this.#events[eventName as string] = []; } @@ -18,7 +18,7 @@ export class EventEmitter { /** * Remove event listener for an event */ - off(eventName: Key, callback: (data: any) => void) { + off(eventName: Key, callback: (data: unknown) => void) { if (this.#events[eventName as string]) { this.#events[eventName as string] = this.#events[eventName as string].filter( (listener) => listener !== callback @@ -29,7 +29,7 @@ export class EventEmitter { /** * Dispatch event */ - emit(eventName: Key, data?: any) { + emit(eventName: Key, data?: unknown) { if (this.#events[eventName as string]) { this.#events[eventName as string].forEach((listener) => { listener(data); diff --git a/src/features/_utils/number.utils.ts b/src/features/_utils/number.utils.ts index cf1bea7..04850c6 100644 --- a/src/features/_utils/number.utils.ts +++ b/src/features/_utils/number.utils.ts @@ -1,3 +1,3 @@ -export function isValidInteger(number: number | string): number| boolean { +export function isValidInteger(number: number | string): number | boolean { return (typeof number === "number" || parseInt(number) || parseInt(number) === 0); } \ No newline at end of file diff --git a/src/features/apps/appsManager.ts b/src/features/apps/appsManager.ts index 65089be..ae29064 100644 --- a/src/features/apps/appsManager.ts +++ b/src/features/apps/appsManager.ts @@ -38,7 +38,7 @@ export default class AppsManager { ]; static getAppById(id: string): App | null { - let application = null; + let application: App | null = null; this.APPS.forEach((app) => { if (app.id === id) { @@ -54,7 +54,7 @@ export default class AppsManager { * Get the app associated with a file extension */ static getAppByFileExtension(fileExtension: string): App { - let app = null; + let app: App = null; if (IMAGE_FORMATS.includes(fileExtension)) return this.getAppById(APPS.MEDIA_VIEWER); diff --git a/src/features/apps/terminal/commands.ts b/src/features/apps/terminal/commands.ts index 4bd0747..dfb2f5b 100644 --- a/src/features/apps/terminal/commands.ts +++ b/src/features/apps/terminal/commands.ts @@ -1,6 +1,6 @@ import Command from "./command"; -let commands = []; +let commands: Command[] = []; /** * Dynamically import commands @@ -9,7 +9,7 @@ const loadCommands = () => { commands = []; const context = require.context("./commands", false, /\.ts$/); context.keys().forEach((key) => { - const commandModule = context(key); + const commandModule = context(key) as Record; const commandName = Object.keys(commandModule)[0]; const command = commandModule[commandName]; @@ -25,7 +25,7 @@ export default class CommandsManager { static COMMANDS = commands; static find(name: string): Command { - let matchCommand = null; + let matchCommand: Command = null; this.COMMANDS.forEach((command) => { if (command.name === name) { diff --git a/src/features/modals/modal.ts b/src/features/modals/modal.ts index f8fe701..698b1d6 100644 --- a/src/features/modals/modal.ts +++ b/src/features/modals/modal.ts @@ -60,7 +60,7 @@ export default class Modal { this.lastInteraction = Date.now(); } - finish(...args: any[]) { + finish(...args: unknown[]) { if (this.modalsManager == null || this.id == null) return; diff --git a/src/features/settings/settings.ts b/src/features/settings/settings.ts index 7c1be29..750728b 100644 --- a/src/features/settings/settings.ts +++ b/src/features/settings/settings.ts @@ -44,7 +44,7 @@ export class Settings { this.xmlDoc = xmlDoc; } - async write() { + write() { if (!this.file) return; @@ -76,14 +76,16 @@ export class Settings { if (callback) { callback(value); - this.file.on(VirtualFile.EVENT_NAMES.CONTENT_CHANGE, async () => { - await this.read(); - const newValue = await this.get(key); + this.file.on(VirtualFile.EVENT_NAMES.CONTENT_CHANGE, () => { + void (async () => { + await this.read(); + const newValue = await this.get(key); - if (newValue !== value) { - callback(newValue); - value = newValue; - } + if (newValue !== value) { + callback(newValue); + value = newValue; + } + })(); }); } @@ -102,6 +104,6 @@ export class Settings { this.xmlDoc.getElementsByTagName(PARENT_NODE)[0].appendChild(newOption); } - await this.write(); + this.write(); } } \ No newline at end of file diff --git a/src/features/tracking/trackingManager.ts b/src/features/tracking/trackingManager.ts index cd2ce4b..3ec3cb7 100644 --- a/src/features/tracking/trackingManager.ts +++ b/src/features/tracking/trackingManager.ts @@ -1,5 +1,6 @@ import ReactGA from "react-ga4"; import { GA_MEASUREMENT_ID } from "../../config/tracking.config"; +import { UaEventOptions } from "react-ga4/types/ga4"; export class TrackingManager { static initialize() { @@ -7,8 +8,7 @@ export class TrackingManager { ReactGA.initialize(GA_MEASUREMENT_ID); } - /** @type {ReactGA["event"]} */ - static event(options) { + static event(options: UaEventOptions | string) { console.info(options); if (GA_MEASUREMENT_ID == null) diff --git a/src/features/virtual-drive/file/virtualFile.ts b/src/features/virtual-drive/file/virtualFile.ts index f53417e..e2889be 100644 --- a/src/features/virtual-drive/file/virtualFile.ts +++ b/src/features/virtual-drive/file/virtualFile.ts @@ -54,7 +54,7 @@ export class VirtualFile extends VirtualBase { /** * Sets the content of this file and removes the source */ - setContent(content: string | any) { + setContent(content: string) { if (this.content === content || !this.canBeEdited) return; @@ -106,7 +106,7 @@ export class VirtualFile extends VirtualBase { ).catch((error) => { console.error(`Error while reading file with id "${this.id}":`, error); return null; - }); + }) as string; } isFile(): boolean { @@ -143,7 +143,7 @@ export class VirtualFile extends VirtualBase { break; } - return iconUrl; + return iconUrl as string; } getType(): string { diff --git a/src/features/virtual-drive/folder/virtualFolder.ts b/src/features/virtual-drive/folder/virtualFolder.ts index a22fc23..ecbc4a3 100644 --- a/src/features/virtual-drive/folder/virtualFolder.ts +++ b/src/features/virtual-drive/folder/virtualFolder.ts @@ -54,7 +54,7 @@ export class VirtualFolder extends VirtualBase { * Finds and returns a file inside this folder matching a name and extension */ findFile(name: string, extension?: string): VirtualFile | VirtualFileLink { - let resultFile = null; + let resultFile: VirtualFile | VirtualFileLink = null; this.files.forEach((file) => { const matchingName = (file.name === name || (file.alias && file.alias === name)); @@ -71,7 +71,7 @@ export class VirtualFolder extends VirtualBase { * Finds and returns a folder inside this folder matching a name */ findSubFolder(name: string): VirtualFolder | VirtualFolderLink { - let resultFolder = null; + let resultFolder: VirtualFolder | VirtualFolderLink = null; this.subFolders.forEach((folder) => { if (folder.name === name || (folder.alias && folder.alias === name)) { @@ -221,7 +221,7 @@ export class VirtualFolder extends VirtualBase { /** * Removes a file or folder from this folder */ - remove(child: VirtualFile | VirtualFolder | VirtualFolderLink) { + remove(child: VirtualFile | VirtualFileLink | VirtualFolder | VirtualFolderLink) { if (!this.canBeEdited) return; @@ -241,9 +241,9 @@ export class VirtualFolder extends VirtualBase { */ navigate(relativePath: string): VirtualFile | VirtualFolder | null { const segments = relativePath.split("/"); - let currentDirectory: VirtualFile | VirtualFolder = this; + let currentDirectory: VirtualFile | VirtualFolder = this as VirtualFolder; - const getDirectory = (path, isStart) => { + const getDirectory = (path: string, isStart: boolean) => { if (isStart && path === "") { return this.getRoot(); } else if (isStart && Object.keys(this.getRoot().shortcuts).includes(path)) { diff --git a/src/features/virtual-drive/root/defaultData.ts b/src/features/virtual-drive/root/defaultData.ts index 6b881e8..1739098 100644 --- a/src/features/virtual-drive/root/defaultData.ts +++ b/src/features/virtual-drive/root/defaultData.ts @@ -105,7 +105,7 @@ export function loadDefaultData(virtualRoot: VirtualRoot) { }); }); }).createFolder("fonts", (folder) => { - folder.createFolders(["poppins", "roboto-mono"]); + folder.createFolders(["outfit", "roboto-mono"]); }).createFolder("screenshots", (folder) => { folder.createFile("screenshot", "png", (file) => { file.setSource(`${process.env.PUBLIC_URL}/assets/screenshots/screenshot-files-settings-taskbar-desktop.png`); diff --git a/src/features/virtual-drive/root/virtualRoot.ts b/src/features/virtual-drive/root/virtualRoot.ts index aca4b96..a14dab8 100644 --- a/src/features/virtual-drive/root/virtualRoot.ts +++ b/src/features/virtual-drive/root/virtualRoot.ts @@ -1,9 +1,9 @@ import { StorageManager } from "../../storage/storageManager"; -import { VirtualFolderLink } from "../folder/virtualFolderLink"; +import { VirtualFolderLink, VirtualFolderLinkJson } from "../folder/virtualFolderLink"; import { loadDefaultData } from "./defaultData"; import { VirtualFile, VirtualFileJson } from "../file/virtualFile"; import { VirtualFolder } from "../folder"; -import { VirtualFileLink } from "../file/virtualFileLink"; +import { VirtualFileLink, VirtualFileLinkJson } from "../file/virtualFileLink"; import { VirtualFolderJson } from "../folder/virtualFolder"; export interface VirtualRootJson extends VirtualFolderJson { @@ -34,16 +34,16 @@ export class VirtualRoot extends VirtualFolder { if (data == null) return; - let object; + let object: VirtualRootJson | null = null; try { - object = JSON.parse(data); + object = JSON.parse(data) as VirtualRootJson; } catch (error) { console.error(error); } if (object == null) return; - const shortcuts = { ...object.scs }; + const shortcuts = { ...object.scs } as Record; const addFile = ({ nam: name, @@ -52,7 +52,7 @@ export class VirtualRoot extends VirtualFolder { cnt: content, lnk: link, ico: iconUrl, - }: any, parent: VirtualFolder = this) => { + }: VirtualFileJson & VirtualFileLinkJson, parent: VirtualFolder = this) => { if (link) { parent.createFileLink(name, (fileLink: VirtualFileLink) => { fileLink.setLinkedPath(link); @@ -81,7 +81,7 @@ export class VirtualRoot extends VirtualFolder { fls: files, lnk: link, ico: iconUrl, - }: any, parent: VirtualFolder = this) => { + }: VirtualFolderJson & VirtualFolderLinkJson, parent: VirtualFolder = this) => { if (link) { parent.createFolderLink(name, (folderLink: VirtualFolderLink) => { folderLink.setLinkedPath(link); @@ -94,7 +94,7 @@ export class VirtualRoot extends VirtualFolder { parent.createFolder(name, (folder: VirtualFolder) => { if (Object.values(shortcuts).includes(folder.displayPath)) { - let alias; + let alias: string; for (const [key, value] of Object.entries(shortcuts)) { if (value === folder.displayPath) alias = key; @@ -102,12 +102,12 @@ export class VirtualRoot extends VirtualFolder { folder.setAlias(alias); } if (folders != null) { - folders.forEach((subFolder: VirtualFolderJson) => { + folders.forEach((subFolder: VirtualFolderJson & VirtualFolderLinkJson) => { addFolder(subFolder, folder); }); } if (files != null) { - files.forEach((file: VirtualFileJson) => { + files.forEach((file: VirtualFileJson & VirtualFileLinkJson) => { addFile(file, folder); }); } @@ -118,12 +118,12 @@ export class VirtualRoot extends VirtualFolder { }; if (object.fds != null) { - object.fds.forEach((subFolder: VirtualFolderJson) => { + object.fds.forEach((subFolder: VirtualFolderJson & VirtualFolderLinkJson) => { addFolder(subFolder); }); } if (object.fls != null) { - object.fls.forEach((file: VirtualFileJson) => { + object.fls.forEach((file: VirtualFileJson & VirtualFileLinkJson) => { addFile(file); }); } @@ -181,15 +181,15 @@ export class VirtualRoot extends VirtualFolder { } } - static isValidName(name) { + static isValidName(_name: string) { // TO DO } - static isValidFileName(name) { + static isValidFileName(_name: string) { // TO DO } - static isValidFolderName(name) { + static isValidFolderName(_name: string) { // TO DO } @@ -219,9 +219,6 @@ export class VirtualRoot extends VirtualFolder { return object; } - /** - * @returns {string | null} - */ toString(): string | null { const json = this.toJSON(); diff --git a/src/features/virtual-drive/virtualBase.ts b/src/features/virtual-drive/virtualBase.ts index 625453f..e0d4a3f 100644 --- a/src/features/virtual-drive/virtualBase.ts +++ b/src/features/virtual-drive/virtualBase.ts @@ -46,7 +46,7 @@ export class VirtualBase extends EventEmitter { return this;; this.alias = alias; - this.getRoot().addShortcut(alias, this as any); + this.getRoot().addShortcut(alias, this as never); this.confirmChanges(); return this; @@ -100,7 +100,7 @@ export class VirtualBase extends EventEmitter { if (parent == null) return; - parent.remove?.(this as any); + parent.remove?.(this as never); this.confirmChanges(parent.getRoot()); } @@ -114,9 +114,11 @@ export class VirtualBase extends EventEmitter { root?.saveData(); } - open(..._args: any[]): any {} + open(..._args: unknown[]): unknown { + return null; + }; - get path() { + get path(): string { return this.alias ?? this.displayPath; } @@ -177,4 +179,13 @@ export class VirtualBase extends EventEmitter { return object; } + + toString(): string | null { + const json = this.toJSON(); + + if (json == null) + return null; + + return JSON.stringify(json); + } } \ No newline at end of file diff --git a/src/features/windows/windowsManager.ts b/src/features/windows/windowsManager.ts index 823a4e1..c35e8b9 100644 --- a/src/features/windows/windowsManager.ts +++ b/src/features/windows/windowsManager.ts @@ -17,7 +17,7 @@ export interface WindowOptions { isFocused?: boolean; lastInteraction?: number; minimized?: boolean; - [key: string]: any; + [key: string]: unknown; } export default class WindowsManager { @@ -174,8 +174,8 @@ export default class WindowsManager { return active; } - getAppWindowId(appId: string): string { - let windowId = null; + getAppWindowId(appId: string): string | null { + let windowId: string | null = null; Object.values(this.windows).forEach((window) => { if (window.app.id === appId) { diff --git a/src/features/z-index/zIndexManager.ts b/src/features/z-index/zIndexManager.ts index ef7ce1f..8390596 100644 --- a/src/features/z-index/zIndexManager.ts +++ b/src/features/z-index/zIndexManager.ts @@ -14,8 +14,7 @@ export class ZIndexManager extends EventEmitter { static EVENT_NAMES = ZIndexManagerEvents; - /** @type {ZIndexGroup[]} */ - groups = []; + groups: ZIndexGroup[] = []; constructor() { super(); @@ -41,7 +40,7 @@ export class ZIndexManager extends EventEmitter { } } - getIndex(groupIndex, index) { + getIndex(groupIndex: number, index: number) { return this.groups[groupIndex].getIndex(index); } } \ No newline at end of file diff --git a/src/hooks/_utils/history.ts b/src/hooks/_utils/history.ts index 5b9979e..5ac7440 100644 --- a/src/hooks/_utils/history.ts +++ b/src/hooks/_utils/history.ts @@ -1,23 +1,19 @@ import { useState } from "react"; import { clamp } from "../../features/math/clamp"; -/** - * @param {*} initialState - * @returns {{ - * history: *[], - * stateIndex: number, - * pushState: Function, - * undo: Function, - * redo: Function, - * undoAvailable: boolean, - * redoAvailable: boolean - * }} - */ -export function useHistory(initialState) { - const [history, setHistory] = useState(initialState ? [initialState] : []); +export function useHistory(initialState: Type): { + history: Type[]; + stateIndex: number; + pushState: Function; + undo: Function; + redo: Function; + undoAvailable: boolean; + redoAvailable: boolean; +} { + const [history, setHistory] = useState(initialState ? [initialState] : []); const [stateIndex, setStateIndex] = useState(0); - const pushState = (state) => { + const pushState = (state: Type) => { if (state === history[0]) return; @@ -35,7 +31,7 @@ export function useHistory(initialState) { setStateIndex(0); }; - const updateStateIndex = (delta) => { + const updateStateIndex = (delta: number) => { const index = clamp(stateIndex + delta, 0, history.length - 1); if (index === stateIndex) diff --git a/src/hooks/_utils/keyboard.ts b/src/hooks/_utils/keyboard.ts index a5e0829..6e09cc0 100644 --- a/src/hooks/_utils/keyboard.ts +++ b/src/hooks/_utils/keyboard.ts @@ -29,9 +29,9 @@ interface UseShortcutsParams { } export function useShortcuts({ options, shortcuts, useCategories = true }: UseShortcutsParams) { - const [activeKeys, setActiveKeys] = useState([]); + const [activeKeys, setActiveKeys] = useState([]); - const checkShortcuts = useCallback((event, allowExecution = true) => { + const checkShortcuts = useCallback((event: KeyboardEvent, allowExecution = true) => { if (!shortcuts) return; @@ -41,7 +41,7 @@ export function useShortcuts({ options, shortcuts, useCategories = true }: UseSh if (keys.includes("Alt") && !event.altKey) removeFromArray("Alt", keys); - const checkGroup = (group: Record, category?) => { + const checkGroup = (group: Record, category?: string) => { for (const [name, shortcut] of Object.entries(group)) { let active = true; @@ -60,7 +60,7 @@ export function useShortcuts({ options, shortcuts, useCategories = true }: UseSh continue; if (category != null) { - options?.[category]?.[name]?.(); + (options?.[category]?.[name] as Function)?.(); } else { (options?.[name] as Function)?.(); } @@ -69,7 +69,7 @@ export function useShortcuts({ options, shortcuts, useCategories = true }: UseSh if (useCategories) { for (const [category, group] of Object.entries(shortcuts)) { - checkGroup(group, category); + checkGroup(group as Record, category); } } else { checkGroup(shortcuts as Record); @@ -78,7 +78,7 @@ export function useShortcuts({ options, shortcuts, useCategories = true }: UseSh setActiveKeys(keys); }, [activeKeys, options, shortcuts, useCategories]); - const onKeyDown = (event) => { + const onKeyDown = (event: KeyboardEvent) => { const isRepeated = activeKeys.includes(event.key); checkShortcuts(event, isRepeated); @@ -86,7 +86,7 @@ export function useShortcuts({ options, shortcuts, useCategories = true }: UseSh setActiveKeys(activeKeys.concat([event.key])); }; - const onKeyUp = (event) => { + const onKeyUp = (event: KeyboardEvent) => { checkShortcuts(event); if (activeKeys.includes(event.key)) { diff --git a/src/hooks/_utils/mouse.ts b/src/hooks/_utils/mouse.ts index 7addb49..3c14400 100644 --- a/src/hooks/_utils/mouse.ts +++ b/src/hooks/_utils/mouse.ts @@ -1,13 +1,13 @@ import { useEffect } from "react"; -/** - * @param {object} params - * @param {Function} params.onMouseDown - * @param {Function} params.onMouseUp - * @param {Function} params.onClick - * @param {Function} params.onContextMenu - */ -export function useMouseListener({ onMouseDown, onMouseUp, onClick, onContextMenu }) { +interface UseMouseListenerParams { + onMouseDown: EventListener; + onMouseUp: EventListener; + onClick: EventListener; + onContextMenu: EventListener; +} + +export function useMouseListener({ onMouseDown, onMouseUp, onClick, onContextMenu }: UseMouseListenerParams) { useEffect(() => { if (onMouseDown) document.addEventListener("mousedown", onMouseDown); diff --git a/src/hooks/_utils/outsideClick.tsx b/src/hooks/_utils/outsideClick.tsx index 1988db4..5c520a6 100644 --- a/src/hooks/_utils/outsideClick.tsx +++ b/src/hooks/_utils/outsideClick.tsx @@ -20,12 +20,6 @@ function useOutsideClickListener(ref: { current: HTMLElement | null }, callback: }, [ref, callback]); } -/** - * @param {object} props - * @param {Function} props.onOutsideClick - * @param {import("react").ElementType} props.children - */ - interface OutsideClickListenerProps { onOutsideClick: (event: Event) => void; children: ReactNode; diff --git a/src/hooks/_utils/screen.ts b/src/hooks/_utils/screen.ts index 20285fc..3ed8b55 100644 --- a/src/hooks/_utils/screen.ts +++ b/src/hooks/_utils/screen.ts @@ -1,12 +1,9 @@ -import { useEffect, useRef, useState } from "react"; +import { Ref, useEffect, useRef, useState } from "react"; import { TASKBAR_HEIGHT } from "../../config/taskbar.config"; -/** - * @returns {[number, number]} - */ -export function useScreenDimensions() { - const [screenWidth, setScreenWidth] = useState(null); - const [screenHeight, setScreenHeight] = useState(null); +export function useScreenDimensions(): [screenWidth: number, screenHeight: number] { + const [screenWidth, setScreenWidth] = useState(null); + const [screenHeight, setScreenHeight] = useState(null); useEffect(() => { const resizeObserver = new ResizeObserver((event) => { @@ -20,17 +17,12 @@ export function useScreenDimensions() { return [screenWidth, screenHeight]; } -/** - * @param {object} props - * @param {boolean} props.avoidTaskbar - * @returns {{ - * ref, - * initiated: boolean, - * alignLeft: boolean, - * alignTop: boolean - * }} - */ -export function useScreenBounds({ avoidTaskbar = true }) { +export function useScreenBounds({ avoidTaskbar = true }: { avoidTaskbar: boolean; }): { + ref: Ref; + initiated: boolean; + alignLeft: boolean; + alignTop: boolean; +} { const ref = useRef(null); const [initiated, setInitiated] = useState(false); const [alignLeft, setAlignLeft] = useState(false); @@ -41,7 +33,7 @@ export function useScreenBounds({ avoidTaskbar = true }) { if (ref.current == null || screenWidth == null || screenHeight == null) return; - const rect = ref.current.getBoundingClientRect(); + const rect = (ref.current as HTMLElement).getBoundingClientRect(); const maxX = screenWidth; let maxY = screenHeight; diff --git a/src/hooks/_utils/scrollWithShadows.ts b/src/hooks/_utils/scrollWithShadows.ts index 366ab14..707a015 100644 --- a/src/hooks/_utils/scrollWithShadows.ts +++ b/src/hooks/_utils/scrollWithShadows.ts @@ -6,34 +6,39 @@ import { useCallback, useEffect } from "react"; import { useState } from "react"; -/** - * @param {object} options - * @param {React.ElementRef} options.ref - * @param {Boolean=true} options.horizontal - * @param {Boolean=true} options.dynamicOffset - * @param {Number=1} options.dynamicOffsetFactor - * @param {object} options.shadow - * @param {Number=8} options.shadow.offset - * @param {Number=5} options.shadow.blurRadius - * @param {Number=-5} options.shadow.spreadRadius - * @param {object} options.shadow.color - * @param {Number=0} options.shadow.color.r - * @param {Number=0} options.shadow.color.g - * @param {Number=0} options.shadow.color.b - * @param {Number=50} options.shadow.color.a - */ -export function useScrollWithShadow(options) { +interface UseScrollWithShadowParams { + ref?: { current: HTMLElement | null }; + horizontal?: boolean; + dynamicOffset?: boolean; + dynamicOffsetFactor?: number; + shadow?: { + offset?: number; + blurRadius?: number; + spreadRadius?: number; + color?: { + r?: number; + g?: number; + b?: number; + a?: number; + } + } +} + +export function useScrollWithShadow(params: UseScrollWithShadowParams): { + boxShadow: string; + onUpdate: (event: Event) => void; +} { const [initiated, setInitiated] = useState(false); const [scrollStart, setScrollStart] = useState(0); const [scrollLength, setScrollLength] = useState(0); const [clientLength, setClientLength] = useState(0); - if (options == null) - options = {}; - if (options.shadow == null) - options.shadow = {}; - if (options.shadow.color == null) - options.shadow.color = {}; + if (params == null) + params = {}; + if (params.shadow == null) + params.shadow = {}; + if (params.shadow.color == null) + params.shadow.color = {}; const { ref, @@ -51,9 +56,9 @@ export function useScrollWithShadow(options) { a = 50 } } - } = options; + } = params; - const updateValues = useCallback((element) => { + const updateValues = useCallback((element: HTMLElement) => { if (!element) return; @@ -62,8 +67,8 @@ export function useScrollWithShadow(options) { setClientLength(horizontal ? element.clientWidth : element.clientHeight); }, [horizontal]); - const onUpdate = (event) => { - updateValues(event.target); + const onUpdate = (event: Event) => { + updateValues(event.target as HTMLElement); }; useEffect(() => { diff --git a/src/hooks/modals/contextMenu.tsx b/src/hooks/modals/contextMenu.tsx index 88f0d43..537c4e6 100644 --- a/src/hooks/modals/contextMenu.tsx +++ b/src/hooks/modals/contextMenu.tsx @@ -1,4 +1,4 @@ -import { FC, useCallback } from "react"; +import { FC, MouseEvent, useCallback } from "react"; import Vector2 from "../../features/math/vector2"; import Modal from "../../features/modals/modal"; import { ActionsProps, STYLES } from "../../components/actions/Actions"; @@ -13,12 +13,12 @@ export function useContextMenu({ Actions }: UseContextMenuParams) { const modalsManager = useModalsManager(); // Open a new modal when context menu is triggered - const onContextMenu = useCallback((event, params = {}) => { + const onContextMenu = useCallback((event: MouseEvent, params: object = {}) => { event.preventDefault(); event.stopPropagation(); - let positionX = (event?.clientX ?? 0); - let positionY = (event?.clientY ?? 0); + let positionX = event?.clientX ?? 0; + let positionY = event?.clientY ?? 0; if (modalsManager.containerRef?.current) { const containerRect = modalsManager.containerRef.current.getBoundingClientRect(); diff --git a/src/hooks/settings/settingsManagerContext.tsx b/src/hooks/settings/settingsManagerContext.tsx index 23de28f..a06ef04 100644 --- a/src/hooks/settings/settingsManagerContext.tsx +++ b/src/hooks/settings/settingsManagerContext.tsx @@ -1,7 +1,6 @@ import { createContext, FC, ReactNode, useContext } from "react"; import { SettingsManager } from "../../features/settings/settingsManager"; import { useVirtualRoot } from "../virtual-drive/virtualRootContext"; -import { VirtualRoot } from "../../features/virtual-drive/root/virtualRoot"; type SettingsManagerState = SettingsManager | undefined; @@ -12,7 +11,7 @@ const SettingsManagerContext = createContext(undefined); */ export const SettingsManagerProvider: FC<{ children: ReactNode }> = ({ children }) => { const virtualRoot = useVirtualRoot(); - const settingsManager = new SettingsManager(virtualRoot as VirtualRoot); + const settingsManager = new SettingsManager(virtualRoot); return ( diff --git a/src/hooks/virtual-drive/virtualRootContext.tsx b/src/hooks/virtual-drive/virtualRootContext.tsx index 08ab673..d656c0e 100644 --- a/src/hooks/virtual-drive/virtualRootContext.tsx +++ b/src/hooks/virtual-drive/virtualRootContext.tsx @@ -11,9 +11,6 @@ export const VirtualRootProvider: FC<{ children: ReactNode }> = ({ children }) = ; }; -/** - * @returns {VirtualRoot} - */ -export function useVirtualRoot() { +export function useVirtualRoot(): VirtualRoot { return useContext(VirtualRootContext); } \ No newline at end of file diff --git a/src/hooks/z-index/zIndex.ts b/src/hooks/z-index/zIndex.ts index 4854dcf..b0fb8b9 100644 --- a/src/hooks/z-index/zIndex.ts +++ b/src/hooks/z-index/zIndex.ts @@ -2,7 +2,12 @@ import { useEffect, useState } from "react"; import { useZIndexManager } from "./zIndexManagerContext"; import { ZIndexManager } from "../../features/z-index/zIndexManager"; -export function useZIndex({ groupIndex, index }) { +interface UseZIndexParams { + groupIndex: number; + index: number; +} + +export function useZIndex({ groupIndex, index }: UseZIndexParams) { const initialIndex = (groupIndex * 10) + index; const [zIndex, setZIndex] = useState(initialIndex); const zIndexManager = useZIndexManager(); diff --git a/src/index.tsx b/src/index.tsx index 440947c..29e5b82 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -4,11 +4,14 @@ import "./styles/global.css"; import App from "./App"; import reportWebVitals from "./reportWebVitals"; import { ASCII_LOGO, NAME } from "./config/branding.config"; +import { TrackingManager } from "./features/tracking/trackingManager"; export const START_DATE = new Date(); +TrackingManager.initialize(); + // Render app -const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement); +const root = ReactDOM.createRoot(document.getElementById("root")); root.render( ); @@ -22,4 +25,4 @@ console.info(ASCII_LOGO + space + welcomeMessage); // If you want to start measuring performance in your app, pass a function // to log results (for example: reportWebVitals(console.log)) // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals -// reportWebVitals(console.log); \ No newline at end of file +reportWebVitals(() => {}); \ No newline at end of file diff --git a/src/reportWebVitals.ts b/src/reportWebVitals.ts index 45a848b..db3d320 100644 --- a/src/reportWebVitals.ts +++ b/src/reportWebVitals.ts @@ -1,6 +1,8 @@ -const reportWebVitals = (onPerfEntry) => { +import { ReportHandler } from "web-vitals"; + +const reportWebVitals = (onPerfEntry: ReportHandler) => { if (onPerfEntry && onPerfEntry instanceof Function) { - import("web-vitals").then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { + void import("web-vitals").then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { getCLS(onPerfEntry); getFID(onPerfEntry); getFCP(onPerfEntry);