refactor(v4.0.0-alpha): beginning of a new era

This commit is contained in:
Amruth Pillai
2023-11-05 12:31:42 +01:00
parent 0ba6a444e2
commit 22933bd412
505 changed files with 81829 additions and 0 deletions
+18
View File
@@ -0,0 +1,18 @@
{
"extends": ["plugin:@nx/react", "../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.ts", "*.tsx"],
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
"rules": {}
}
]
}
+16
View File
@@ -0,0 +1,16 @@
{
"name": "@reactive-resume/hooks",
"version": "0.0.1",
"private": false,
"main": "./index.js",
"types": "./index.d.ts",
"publishConfig": {
"access": "public"
},
"exports": {
".": {
"import": "./index.mjs",
"require": "./index.js"
}
}
}
+40
View File
@@ -0,0 +1,40 @@
{
"name": "hooks",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "libs/hooks/src",
"projectType": "library",
"tags": ["frontend"],
"targets": {
"lint": {
"executor": "@nx/eslint:lint",
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": ["libs/hooks/**/*.{ts,tsx,js,jsx}"]
}
},
"build": {
"executor": "@nx/vite:build",
"outputs": ["{options.outputPath}"],
"defaultConfiguration": "production",
"options": {
"outputPath": "dist/libs/hooks"
},
"configurations": {
"development": {
"mode": "development"
},
"production": {
"mode": "production"
}
}
},
"test": {
"executor": "@nx/vite:test",
"outputs": ["{options.reportsDirectory}"],
"options": {
"passWithNoTests": true,
"reportsDirectory": "../../coverage/libs/hooks"
}
}
}
}
+25
View File
@@ -0,0 +1,25 @@
import { breakpoints } from "@reactive-resume/utils";
import { useMemo } from "react";
import { useBreakpoint as _useBreakpoint } from "use-breakpoint";
export const useBreakpoint = () => {
const { breakpoint, minWidth, maxWidth } = _useBreakpoint(breakpoints);
const { isMobile, isTablet, isDesktop } = useMemo(() => {
return {
isMobile: breakpoint === "xs" || breakpoint === "sm" || breakpoint === "md",
isTablet: breakpoint === "sm" || breakpoint === "md",
isDesktop: breakpoint === "lg" || breakpoint === "xl" || breakpoint === "2xl",
};
}, [breakpoint]);
return {
breakpoint,
minWidth,
maxWidth,
isMobile,
isTablet,
isDesktop,
devicePixelRatio: window.devicePixelRatio,
};
};
+37
View File
@@ -0,0 +1,37 @@
import { createContext, useContext } from "react";
import { useFormContext } from "react-hook-form";
import { FieldPath, FieldValues } from "react-hook-form";
type FormFieldContextValue<
TFieldValues extends FieldValues = FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
> = { name: TName };
export const FormFieldContext = createContext<FormFieldContextValue>({} as FormFieldContextValue);
type FormItemContextValue = { id: string };
export const FormItemContext = createContext<FormItemContextValue>({} as FormItemContextValue);
export const useFormField = () => {
const fieldContext = useContext(FormFieldContext);
const itemContext = useContext(FormItemContext);
const { getFieldState, formState } = useFormContext();
const fieldState = getFieldState(fieldContext.name, formState);
if (!fieldContext) {
throw new Error("useFormField should be used within <FormField>");
}
const { id } = itemContext;
return {
id,
name: fieldContext.name,
formItemId: `${id}-form-item`,
formDescriptionId: `${id}-form-item-description`,
formMessageId: `${id}-form-item-message`,
...fieldState,
};
};
@@ -0,0 +1,39 @@
import { useEffect } from "react";
export const usePasswordToggle = (formRef: React.RefObject<HTMLElement | null>) => {
// Show Password on "Control" Key Down
useEffect(() => {
const onKeyDown = (event: KeyboardEvent) => {
if (event.key === "Control") {
formRef.current
?.querySelector<HTMLInputElement>('input[name="password"]')
?.setAttribute("type", "text");
}
};
window.addEventListener("keydown", onKeyDown);
return () => {
window.removeEventListener("keydown", onKeyDown);
};
}, [formRef]);
// Hide Password on "Control" Key Up
useEffect(() => {
const onKeyUp = (event: KeyboardEvent) => {
if (event.key === "Control") {
formRef.current
?.querySelector<HTMLInputElement>('input[name="password"]')
?.setAttribute("type", "password");
}
};
window.addEventListener("keyup", onKeyUp);
return () => {
window.removeEventListener("keyup", onKeyUp);
};
}, [formRef]);
return;
};
+54
View File
@@ -0,0 +1,54 @@
import { type Dispatch, type SetStateAction, useEffect, useState } from "react";
import { useLocalStorage, useMediaQuery, useUpdateEffect } from "usehooks-ts";
const COLOR_SCHEME_QUERY = "(prefers-color-scheme: dark)";
type Theme = "system" | "dark" | "light";
interface UseThemeOutput {
theme: Theme;
isDarkMode: boolean;
toggleTheme: () => void;
setTheme: Dispatch<SetStateAction<Theme>>;
}
export const useTheme = (): UseThemeOutput => {
const isDarkOS = useMediaQuery(COLOR_SCHEME_QUERY);
const [isDarkMode, setDarkMode] = useState<boolean>(isDarkOS);
const [theme, setTheme] = useLocalStorage<Theme>("theme", "system");
useUpdateEffect(() => {
if (theme === "system") setDarkMode(isDarkOS);
}, [isDarkOS]);
useEffect(() => {
switch (theme) {
case "light":
setDarkMode(false);
break;
case "system":
setDarkMode(isDarkOS);
break;
case "dark":
setDarkMode(true);
break;
}
}, [theme, isDarkOS]);
function toggleTheme() {
const toggleDict: Record<Theme, Theme> = {
light: "system",
system: "dark",
dark: "light",
};
setTheme((prevMode) => toggleDict[prevMode]);
}
return {
theme,
setTheme,
isDarkMode,
toggleTheme,
};
};
+4
View File
@@ -0,0 +1,4 @@
export * from "./hooks/use-breakpoint";
export * from "./hooks/use-form-field";
export * from "./hooks/use-password-toggle";
export * from "./hooks/use-theme";
+21
View File
@@ -0,0 +1,21 @@
{
"compilerOptions": {
"jsx": "react-jsx",
"allowJs": false,
"esModuleInterop": false,
"allowSyntheticDefaultImports": true,
"strict": true,
"types": ["vite/client", "vitest"]
},
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.lib.json"
},
{
"path": "./tsconfig.spec.json"
}
],
"extends": "../../tsconfig.base.json"
}
+23
View File
@@ -0,0 +1,23 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"types": [
"node",
"@nx/react/typings/cssmodule.d.ts",
"@nx/react/typings/image.d.ts",
"vite/client"
]
},
"exclude": [
"**/*.spec.ts",
"**/*.test.ts",
"**/*.spec.tsx",
"**/*.test.tsx",
"**/*.spec.js",
"**/*.test.js",
"**/*.spec.jsx",
"**/*.test.jsx"
],
"include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx", "src/index.ts.bak"]
}
+19
View File
@@ -0,0 +1,19 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"types": ["vitest/globals", "vitest/importMeta", "vite/client", "node", "vitest"]
},
"include": [
"vite.config.ts",
"src/**/*.test.ts",
"src/**/*.spec.ts",
"src/**/*.test.tsx",
"src/**/*.spec.tsx",
"src/**/*.test.js",
"src/**/*.spec.js",
"src/**/*.test.jsx",
"src/**/*.spec.jsx",
"src/**/*.d.ts"
]
}
+42
View File
@@ -0,0 +1,42 @@
/// <reference types='vitest' />
import { nxViteTsPaths } from "@nx/vite/plugins/nx-tsconfig-paths.plugin";
import react from "@vitejs/plugin-react-swc";
import * as path from "path";
import { defineConfig, splitVendorChunkPlugin } from "vite";
import dts from "vite-plugin-dts";
export default defineConfig({
cacheDir: "../../node_modules/.vite/hooks",
plugins: [
react(),
nxViteTsPaths(),
splitVendorChunkPlugin(),
dts({
entryRoot: "src",
tsconfigPath: path.join(__dirname, "tsconfig.lib.json"),
}),
],
build: {
lib: {
entry: "src/index.ts",
name: "hooks",
fileName: "index",
formats: ["es", "cjs"],
},
rollupOptions: {
external: [/^react.*/, "react-hook-form", "use-breakpoint", "usehooks-ts"],
},
},
test: {
globals: true,
cache: {
dir: "../../node_modules/.vitest",
},
environment: "jsdom",
include: ["src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
},
});