diff --git a/packages/common/src/hooks/index.ts b/packages/common/src/hooks/index.ts
new file mode 100644
index 000000000..e6c2ba36b
--- /dev/null
+++ b/packages/common/src/hooks/index.ts
@@ -0,0 +1,20 @@
+/*
+This file is part of the Notesnook project (https://notesnook.com/)
+
+Copyright (C) 2023 Streetwriters (Private) Limited
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+export * from "./use-time-ago";
diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts
index 33c0564df..768b5a19a 100644
--- a/packages/common/src/index.ts
+++ b/packages/common/src/index.ts
@@ -18,10 +18,5 @@ along with this program. If not, see .
*/
export * from "./database";
-
-export * from "./utils/file";
-export * from "./utils/number";
-export * from "./utils/total-notes";
-export * from "./utils/time";
-
-export * from "./hooks/use-time-ago";
+export * from "./utils";
+export * from "./hooks";
diff --git a/packages/common/src/utils/debounce.ts b/packages/common/src/utils/debounce.ts
new file mode 100644
index 000000000..19658081d
--- /dev/null
+++ b/packages/common/src/utils/debounce.ts
@@ -0,0 +1,71 @@
+/*
+This file is part of the Notesnook project (https://notesnook.com/)
+
+Copyright (C) 2023 Streetwriters (Private) Limited
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+/* eslint-disable @typescript-eslint/no-explicit-any */
+
+interface DebouncedFunction<
+ Args extends any[],
+ F extends (...args: Args) => any
+> {
+ (this: ThisParameterType, ...args: Args & Parameters): void;
+}
+
+interface DebouncedFunctionWithId<
+ Args extends any[],
+ F extends (...args: Args) => any
+> {
+ (
+ this: ThisParameterType,
+ id: string | number,
+ ...args: Args & Parameters
+ ): void;
+}
+
+export function debounce void>(
+ func: F,
+ waitFor: number
+): DebouncedFunction {
+ let timeout: number | null;
+
+ return (...args: Args) => {
+ if (timeout) clearTimeout(timeout);
+ timeout = setTimeout(() => func(...args), waitFor) as unknown as number;
+ };
+}
+
+export function debounceWithId<
+ Args extends any[],
+ F extends (...args: Args) => void
+>(func: F, waitFor: number): DebouncedFunctionWithId {
+ let timeout: number | null;
+ let debounceId: string | number | null = null;
+
+ return (id: string | number, ...args: Parameters) => {
+ if (timeout && id === debounceId) clearTimeout(timeout);
+ debounceId = id;
+ timeout = setTimeout(() => {
+ func(...args);
+ }, waitFor) as unknown as number;
+ };
+}
+
+const DEBOUNCE_TIMEOUTS: Record = {};
+export function inlineDebounce(id: string, func: () => void, waitFor: number) {
+ clearTimeout(DEBOUNCE_TIMEOUTS[id]);
+ DEBOUNCE_TIMEOUTS[id] = setTimeout(func, waitFor);
+}
diff --git a/packages/common/src/utils/index.ts b/packages/common/src/utils/index.ts
new file mode 100644
index 000000000..d2a7cd928
--- /dev/null
+++ b/packages/common/src/utils/index.ts
@@ -0,0 +1,26 @@
+/*
+This file is part of the Notesnook project (https://notesnook.com/)
+
+Copyright (C) 2023 Streetwriters (Private) Limited
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+export * from "./file";
+export * from "./number";
+export * from "./total-notes";
+export * from "./time";
+export * from "./debounce";
+export * from "./random";
+export * from "./string";
diff --git a/packages/common/src/utils/random.ts b/packages/common/src/utils/random.ts
new file mode 100644
index 000000000..f7949e4f5
--- /dev/null
+++ b/packages/common/src/utils/random.ts
@@ -0,0 +1,27 @@
+/*
+This file is part of the Notesnook project (https://notesnook.com/)
+
+Copyright (C) 2023 Streetwriters (Private) Limited
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+function getRandom(min: number, max: number) {
+ return Math.round(Math.random() * (max - min) + min);
+}
+
+function getRandomArbitrary(min: number, max: number) {
+ return Math.random() * (max - min) + min;
+}
+export { getRandom, getRandomArbitrary };
diff --git a/packages/common/src/utils/string.ts b/packages/common/src/utils/string.ts
new file mode 100644
index 000000000..3e8702b7a
--- /dev/null
+++ b/packages/common/src/utils/string.ts
@@ -0,0 +1,83 @@
+/*
+This file is part of the Notesnook project (https://notesnook.com/)
+
+Copyright (C) 2023 Streetwriters (Private) Limited
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+export type TitleCase<
+ T extends string,
+ D extends string = " "
+> = string extends T
+ ? never
+ : T extends `${infer F}${D}${infer R}`
+ ? `${Capitalize}${D}${TitleCase}`
+ : Capitalize;
+
+type Separator = " " | "-" | "_";
+
+export type CamelCase =
+ T extends `${Separator}${infer Suffix}`
+ ? CamelCase
+ : T extends `${infer Prefix}${Separator}`
+ ? CamelCase
+ : T extends `${infer Prefix}${Separator}${infer Suffix}`
+ ? CamelCase<`${Prefix}${Capitalize}`>
+ : T;
+
+type KebabCaseHelper<
+ S,
+ Acc extends string = ""
+> = S extends `${infer C}${infer T}`
+ ? KebabCaseHelper<
+ T extends Uncapitalize ? T : Uncapitalize,
+ `${Acc}${Lowercase}${T extends Uncapitalize ? "" : "-"}`
+ >
+ : Acc;
+
+export type KebabCase = KebabCaseHelper;
+
+const SingularPluralPairs = {
+ note: "notes",
+ notebook: "notebooks",
+ topic: "topics",
+ attachment: "attachments",
+ reminder: "reminders",
+ file: "files",
+ tag: "tags",
+ item: "items"
+};
+
+export function pluralize(
+ count: number | null | undefined | false,
+ key: keyof typeof SingularPluralPairs
+): string {
+ return !count || count > 1
+ ? `${count} ${SingularPluralPairs[key]}`
+ : `${count} ${key}`;
+}
+
+export function toTitleCase(str: T): TitleCase | "" {
+ if (!str || !str[0]) {
+ return "";
+ }
+ return (str[0].toUpperCase() + str.substring(1)) as TitleCase;
+}
+
+export function toCamelCase(str: T): CamelCase {
+ return str.replace(/-(.{1})/gm, (_str, letter) => {
+ return letter.toUpperCase();
+ }) as CamelCase;
+}