diff --git a/apps/frontend/app/auth/layout.tsx b/apps/frontend/app/auth/layout.tsx new file mode 100644 index 0000000..271b593 --- /dev/null +++ b/apps/frontend/app/auth/layout.tsx @@ -0,0 +1,7 @@ +export default function AuthLayout({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ); +} diff --git a/apps/frontend/app/auth/login/page.tsx b/apps/frontend/app/auth/login/page.tsx new file mode 100644 index 0000000..5099a8f --- /dev/null +++ b/apps/frontend/app/auth/login/page.tsx @@ -0,0 +1 @@ +export { LoginPage as default } from 'pages/login'; diff --git a/apps/frontend/app/auth/register/page.tsx b/apps/frontend/app/auth/register/page.tsx new file mode 100644 index 0000000..7210324 --- /dev/null +++ b/apps/frontend/app/auth/register/page.tsx @@ -0,0 +1 @@ +export { RegisterPage as default } from 'pages/register'; diff --git a/apps/frontend/next-env.d.ts b/apps/frontend/next-env.d.ts index c05d9f7..cdb6b7b 100644 --- a/apps/frontend/next-env.d.ts +++ b/apps/frontend/next-env.d.ts @@ -1,7 +1,7 @@ /// /// /// -import './.next/types/routes.d.ts'; +import './.next/dev/types/routes.d.ts'; // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/apps/frontend/src/pages/login/index.ts b/apps/frontend/src/pages/login/index.ts new file mode 100644 index 0000000..270ae4d --- /dev/null +++ b/apps/frontend/src/pages/login/index.ts @@ -0,0 +1 @@ +export { default as LoginPage } from './ui/LoginPage'; diff --git a/apps/frontend/src/pages/login/model/loginSchema.ts b/apps/frontend/src/pages/login/model/loginSchema.ts new file mode 100644 index 0000000..079bc1c --- /dev/null +++ b/apps/frontend/src/pages/login/model/loginSchema.ts @@ -0,0 +1,8 @@ +import { z } from 'zod'; + +export const formSchema = z.object({ + email: z.email('Неверный формат email'), + password: z.string().min(6, 'Минимум 6 символов').max(32, 'Слишком длинный пароль'), +}); + +export type FormState = z.infer; diff --git a/apps/frontend/src/pages/login/ui/LoginForm.tsx b/apps/frontend/src/pages/login/ui/LoginForm.tsx new file mode 100644 index 0000000..8169580 --- /dev/null +++ b/apps/frontend/src/pages/login/ui/LoginForm.tsx @@ -0,0 +1,57 @@ +'use client'; +import Link from 'next/link'; +import { useForm } from 'react-hook-form'; +import { zodResolver } from '@hookform/resolvers/zod'; +import { formSchema, FormState } from '../model/loginSchema'; +import { Input } from 'shared/ui/input'; +import { Button } from 'shared/ui'; +import { Field, FieldDescription, FieldLabel } from 'shared/ui/field'; + +export function LoginForm() { + const { + register, + handleSubmit, + reset, + formState: { errors }, + } = useForm({ + resolver: zodResolver(formSchema), + mode: 'onChange', + }); + const onSubmit = (data: FormState): void => { + console.log(data); + reset(); + }; + return ( + + + + Почта + + {errors.email && ( + {errors.email.message} + )} + + + + Пароль + + Забыли пароль? + + + + + + {errors.password && ( + + {errors.password.message} + + )} + + + Войти + + ); +} diff --git a/apps/frontend/src/pages/login/ui/LoginPage.tsx b/apps/frontend/src/pages/login/ui/LoginPage.tsx new file mode 100644 index 0000000..120a3c9 --- /dev/null +++ b/apps/frontend/src/pages/login/ui/LoginPage.tsx @@ -0,0 +1,21 @@ +'use client'; +import { LoginForm } from './LoginForm'; +import Link from 'next/link'; +export default function LoginPage() { + return ( + + # Task-tracker + + С возвращением + + + + Нет аккаунта? + + Зарегистрироваться + + + + + ); +} diff --git a/apps/frontend/src/pages/register/index.ts b/apps/frontend/src/pages/register/index.ts new file mode 100644 index 0000000..4498c04 --- /dev/null +++ b/apps/frontend/src/pages/register/index.ts @@ -0,0 +1 @@ +export { default as RegisterPage } from './ui/RegisterPage'; diff --git a/apps/frontend/src/pages/register/model/registerSchema.ts b/apps/frontend/src/pages/register/model/registerSchema.ts new file mode 100644 index 0000000..7bed4e8 --- /dev/null +++ b/apps/frontend/src/pages/register/model/registerSchema.ts @@ -0,0 +1,9 @@ +import { z } from 'zod'; + +export const formSchema = z.object({ + email: z.email('Неверный формат email'), + name: z.string().min(2, 'Слишком короткое имя').max(15, 'Слишком длинное имя'), + password: z.string().min(6, 'Минимум 6 символов').max(32, 'Слишком длинный пароль'), +}); + +export type FormState = z.infer; diff --git a/apps/frontend/src/pages/register/ui/RegisterForm.tsx b/apps/frontend/src/pages/register/ui/RegisterForm.tsx new file mode 100644 index 0000000..612438b --- /dev/null +++ b/apps/frontend/src/pages/register/ui/RegisterForm.tsx @@ -0,0 +1,54 @@ +'use client'; + +import { useForm } from 'react-hook-form'; +import { zodResolver } from '@hookform/resolvers/zod'; +import { Input } from 'shared/ui/input'; +import { formSchema, FormState } from '../model/registerSchema'; +import { Field, FieldDescription, FieldLabel } from 'shared/ui/field'; +import { Button } from 'shared/ui'; + +export function RegisterForm() { + const { + register, + handleSubmit, + reset, + formState: { errors }, + } = useForm({ + resolver: zodResolver(formSchema), + mode: 'onChange', + }); + const onSubmit = (data: FormState): void => { + console.log(data); + reset(); + }; + return ( + + + + Почта + + {errors.email && ( + {errors.email.message} + )} + + + Имя + + {errors.name && ( + + {errors.name.message} + + )} + + + Пароль + + {errors.password && ( + {errors.password.message} + )} + + + Зарегистрироваться + + ); +} diff --git a/apps/frontend/src/pages/register/ui/RegisterPage.tsx b/apps/frontend/src/pages/register/ui/RegisterPage.tsx new file mode 100644 index 0000000..8d3a162 --- /dev/null +++ b/apps/frontend/src/pages/register/ui/RegisterPage.tsx @@ -0,0 +1,12 @@ +'use client'; +import { RegisterForm } from './RegisterForm'; + +export default function RegisterPage() { + return ( + + # Task-tracker + С возвращением + + + ); +} diff --git a/apps/frontend/src/shared/ui/field.tsx b/apps/frontend/src/shared/ui/field.tsx new file mode 100644 index 0000000..4bef5e0 --- /dev/null +++ b/apps/frontend/src/shared/ui/field.tsx @@ -0,0 +1,222 @@ +import { useMemo } from 'react'; +import { cva, type VariantProps } from 'class-variance-authority'; + +import { cn } from 'shared/lib'; +import { Label } from 'shared/ui/label'; +import { Separator } from 'shared/ui/separator'; + +function FieldSet({ className, ...props }: React.ComponentProps<'fieldset'>) { + return ( + [data-slot=checkbox-group]]:gap-3 has-[>[data-slot=radio-group]]:gap-3', + className + )} + {...props} + /> + ); +} + +function FieldLegend({ + className, + variant = 'legend', + ...props +}: React.ComponentProps<'legend'> & { variant?: 'legend' | 'label' }) { + return ( + + ); +} + +function FieldGroup({ className, ...props }: React.ComponentProps<'div'>) { + return ( + + ); +} + +const fieldVariants = cva('group/field flex w-full gap-2 data-[invalid=true]:text-destructive', { + variants: { + orientation: { + vertical: 'flex-col *:w-full [&>.sr-only]:w-auto', + horizontal: + 'flex-row items-center has-[>[data-slot=field-content]]:items-start *:data-[slot=field-label]:flex-auto has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px', + responsive: + 'flex-col *:w-full @md/field-group:flex-row @md/field-group:items-center @md/field-group:*:w-auto @md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:*:data-[slot=field-label]:flex-auto [&>.sr-only]:w-auto @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px', + }, + }, + defaultVariants: { + orientation: 'vertical', + }, +}); + +function Field({ + className, + orientation = 'vertical', + ...props +}: React.ComponentProps<'div'> & VariantProps) { + return ( + + ); +} + +function FieldContent({ className, ...props }: React.ComponentProps<'div'>) { + return ( + + ); +} + +function FieldLabel({ className, ...props }: React.ComponentProps) { + return ( + [data-slot=field]]:rounded-lg has-[>[data-slot=field]]:border *:data-[slot=field]:p-2.5 dark:has-data-checked:border-primary/20 dark:has-data-checked:bg-primary/10', + 'has-[>[data-slot=field]]:w-full has-[>[data-slot=field]]:flex-col', + className + )} + {...props} + /> + ); +} + +function FieldTitle({ className, ...props }: React.ComponentProps<'div'>) { + return ( + + ); +} + +function FieldDescription({ className, ...props }: React.ComponentProps<'p'>) { + return ( + a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary', + className + )} + {...props} + /> + ); +} + +function FieldSeparator({ + children, + className, + ...props +}: React.ComponentProps<'div'> & { + children?: React.ReactNode; +}) { + return ( + + + {children && ( + + {children} + + )} + + ); +} + +function FieldError({ + className, + children, + errors, + ...props +}: React.ComponentProps<'div'> & { + errors?: Array<{ message?: string } | undefined>; +}) { + const content = useMemo(() => { + if (children) { + return children; + } + + if (!errors?.length) { + return null; + } + + const uniqueErrors = [...new Map(errors.map((error) => [error?.message, error])).values()]; + + if (uniqueErrors?.length == 1) { + return uniqueErrors[0]?.message; + } + + return ( + + {uniqueErrors.map((error, index) => error?.message && {error.message})} + + ); + }, [children, errors]); + + if (!content) { + return null; + } + + return ( + + {content} + + ); +} + +export { + Field, + FieldLabel, + FieldDescription, + FieldError, + FieldGroup, + FieldLegend, + FieldSeparator, + FieldSet, + FieldContent, + FieldTitle, +}; diff --git a/apps/frontend/src/shared/ui/input.tsx b/apps/frontend/src/shared/ui/input.tsx new file mode 100644 index 0000000..045827f --- /dev/null +++ b/apps/frontend/src/shared/ui/input.tsx @@ -0,0 +1,19 @@ +import * as React from 'react'; + +import { cn } from 'shared/lib'; + +function Input({ className, type, ...props }: React.ComponentProps<'input'>) { + return ( + + ); +} + +export { Input }; diff --git a/apps/frontend/src/shared/ui/label.tsx b/apps/frontend/src/shared/ui/label.tsx new file mode 100644 index 0000000..cba4f8b --- /dev/null +++ b/apps/frontend/src/shared/ui/label.tsx @@ -0,0 +1,19 @@ +import * as React from 'react'; +import { Label as LabelPrimitive } from 'radix-ui'; + +import { cn } from 'shared/lib'; + +function Label({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +export { Label }; diff --git a/apps/frontend/src/shared/ui/separator.tsx b/apps/frontend/src/shared/ui/separator.tsx new file mode 100644 index 0000000..21281a5 --- /dev/null +++ b/apps/frontend/src/shared/ui/separator.tsx @@ -0,0 +1,28 @@ +'use client'; + +import * as React from 'react'; +import { Separator as SeparatorPrimitive } from 'radix-ui'; + +import { cn } from 'shared/lib'; + +function Separator({ + className, + orientation = 'horizontal', + decorative = true, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +export { Separator }; diff --git a/eslint.config.mjs b/eslint.config.mjs index ae40151..ed485af 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,6 +1,40 @@ -import eslint from '@eslint/js'; -import { defineConfig } from 'eslint/config'; +import js from '@eslint/js'; import tseslint from 'typescript-eslint'; -import prettier from 'eslint-config-prettier'; +import importPlugin from 'eslint-plugin-import'; +import unusedImports from 'eslint-plugin-unused-imports'; +import prettier from 'eslint-plugin-prettier'; +import globals from 'globals'; // Добавили для работы окружений -export default defineConfig(eslint.configs.recommended, tseslint.configs.recommended, prettier); +export default [ + js.configs.recommended, + ...tseslint.configs.recommended, + + { + files: ['**/*.{ts,tsx}'], + languageOptions: { + parser: tseslint.parser, + parserOptions: { + project: ['./tsconfig.json'], + }, + globals: { + ...globals.es2021, + }, + }, + }, + { + plugins: { + import: importPlugin, + 'unused-imports': unusedImports, + prettier, + }, + rules: { + 'no-unused-vars': 'off', + '@typescript-eslint/no-unused-vars': 'off', + 'unused-imports/no-unused-imports': 'error', + }, + }, + + { + ignores: ['node_modules', 'dist', '.next', 'build', '**/jest.config.ts', '**/*.config.ts'], + }, +]; diff --git a/package.json b/package.json index f638aea..783fba6 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,13 @@ "@types/node": "^25.0.0", "eslint": "^9.39.2", "eslint-config-prettier": "^10.1.8", + "eslint-plugin-import": "^2.32.0", + "eslint-plugin-n": "^17.24.0", + "eslint-plugin-prettier": "^5.5.5", + "eslint-plugin-react": "^7.37.5", + "eslint-plugin-react-hooks": "^7.0.1", + "eslint-plugin-unused-imports": "^4.4.1", + "globals": "^17.3.0", "husky": "^9.1.7", "lint-staged": "^16.3.1", "prettier": "^3.0.0", diff --git a/packages/shared-types/package.json b/packages/shared-types/package.json index e6c379b..42a0273 100644 --- a/packages/shared-types/package.json +++ b/packages/shared-types/package.json @@ -5,12 +5,6 @@ "description": "", "main": "index.js", "scripts": { - "build": "echo 'No build step'", - "typecheck": "tsc --noEmit", - "lint": "eslint", - "lint:fix": "eslint --fix", - "format": "prettier --write .", - "format:check": "prettier --check .", "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a3be911..96443b2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,6 +20,27 @@ importers: eslint-config-prettier: specifier: ^10.1.8 version: 10.1.8(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-import: + specifier: ^2.32.0 + version: 2.32.0(@typescript-eslint/parser@8.56.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-n: + specifier: ^17.24.0 + version: 17.24.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint-plugin-prettier: + specifier: ^5.5.5 + version: 5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))(prettier@3.8.1) + eslint-plugin-react: + specifier: ^7.37.5 + version: 7.37.5(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-react-hooks: + specifier: ^7.0.1 + version: 7.0.1(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-unused-imports: + specifier: ^4.4.1 + version: 4.4.1(@typescript-eslint/eslint-plugin@8.56.0(@typescript-eslint/parser@8.56.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)) + globals: + specifier: ^17.3.0 + version: 17.3.0 husky: specifier: ^9.1.7 version: 9.1.7 @@ -3535,6 +3556,12 @@ packages: engines: {node: '>=6.0'} hasBin: true + eslint-compat-utils@0.5.1: + resolution: {integrity: sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==} + engines: {node: '>=12'} + peerDependencies: + eslint: '>=6.0.0' + eslint-config-next@16.1.6: resolution: {integrity: sha512-vKq40io2B0XtkkNDYyleATwblNt8xuh3FWp8SpSz3pt7P01OkBFlKsJZ2mWt5WsCySlDQLckb1zMY9yE9Qy0LA==} peerDependencies: @@ -3587,6 +3614,12 @@ packages: eslint-import-resolver-webpack: optional: true + eslint-plugin-es-x@7.8.0: + resolution: {integrity: sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + eslint: '>=8' + eslint-plugin-import@2.32.0: resolution: {integrity: sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==} engines: {node: '>=4'} @@ -3603,6 +3636,26 @@ packages: peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 + eslint-plugin-n@17.24.0: + resolution: {integrity: sha512-/gC7/KAYmfNnPNOb3eu8vw+TdVnV0zhdQwexsw6FLXbhzroVj20vRn2qL8lDWDGnAQ2J8DhdfvXxX9EoxvERvw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: '>=8.23.0' + + eslint-plugin-prettier@5.5.5: + resolution: {integrity: sha512-hscXkbqUZ2sPithAuLm5MXL+Wph+U7wHngPBv9OMWwlP8iaflyxpjTYZkmdgB4/vPIhemRlBEoLrH7UC1n7aUw==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + '@types/eslint': '>=8.0.0' + eslint: '>=8.0.0' + eslint-config-prettier: '>= 7.0.0 <10.0.0 || >=10.1.0' + prettier: '>=3.0.0' + peerDependenciesMeta: + '@types/eslint': + optional: true + eslint-config-prettier: + optional: true + eslint-plugin-react-hooks@7.0.1: resolution: {integrity: sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==} engines: {node: '>=18'} @@ -3615,6 +3668,15 @@ packages: peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 + eslint-plugin-unused-imports@4.4.1: + resolution: {integrity: sha512-oZGYUz1X3sRMGUB+0cZyK2VcvRX5lm/vB56PgNNcU+7ficUCKm66oZWKUubXWnOuPjQ8PvmXtCViXBMONPe7tQ==} + peerDependencies: + '@typescript-eslint/eslint-plugin': ^8.0.0-0 || ^7.0.0 || ^6.0.0 || ^5.0.0 + eslint: ^10.0.0 || ^9.0.0 || ^8.0.0 + peerDependenciesMeta: + '@typescript-eslint/eslint-plugin': + optional: true + eslint-scope@5.1.1: resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} engines: {node: '>=8.0.0'} @@ -3739,6 +3801,9 @@ packages: fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + fast-glob@3.3.1: resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} engines: {node: '>=8.6.0'} @@ -3990,6 +4055,10 @@ packages: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} + globals@15.15.0: + resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==} + engines: {node: '>=18'} + globals@16.4.0: resolution: {integrity: sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==} engines: {node: '>=18'} @@ -4006,6 +4075,9 @@ packages: resolution: {integrity: sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==} engines: {node: '>=18'} + globrex@0.1.2: + resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} + gonzales-pe@4.3.0: resolution: {integrity: sha512-otgSPpUmdWJ43VXyiNgEYE4luzHCL2pz4wQ0OnDluC6Eg4Ko3Vexy/SrSynglw/eR+OhkzmqFCZa/OFa/RgAOQ==} engines: {node: '>=0.6.0'} @@ -5356,6 +5428,10 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} + prettier-linter-helpers@1.0.1: + resolution: {integrity: sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==} + engines: {node: '>=6.0.0'} + prettier@3.8.1: resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} engines: {node: '>=14'} @@ -6060,6 +6136,11 @@ packages: peerDependencies: typescript: '>=4.8.4' + ts-declaration-location@1.0.7: + resolution: {integrity: sha512-EDyGAwH1gO0Ausm9gV6T2nUvBgXT5kGoCMJPllOaooZ+4VvJiKBdZE7wK18N1deEowhcUptS+5GXZK8U/fvpwA==} + peerDependencies: + typescript: '>=4.0.0' + ts-jest@29.4.6: resolution: {integrity: sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA==} engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0} @@ -10097,6 +10178,11 @@ snapshots: optionalDependencies: source-map: 0.6.1 + eslint-compat-utils@0.5.1(eslint@9.39.2(jiti@2.6.1)): + dependencies: + eslint: 9.39.2(jiti@2.6.1) + semver: 7.7.4 + eslint-config-next@16.1.6(@typescript-eslint/parser@8.56.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): dependencies: '@next/eslint-plugin-next': 16.1.6 @@ -10155,6 +10241,13 @@ snapshots: transitivePeerDependencies: - supports-color + eslint-plugin-es-x@7.8.0(eslint@9.39.2(jiti@2.6.1)): + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) + '@eslint-community/regexpp': 4.12.2 + eslint: 9.39.2(jiti@2.6.1) + eslint-compat-utils: 0.5.1(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.56.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)): dependencies: '@rtsao/scc': 1.1.0 @@ -10203,6 +10296,31 @@ snapshots: safe-regex-test: 1.1.0 string.prototype.includes: 2.0.1 + eslint-plugin-n@17.24.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) + enhanced-resolve: 5.19.0 + eslint: 9.39.2(jiti@2.6.1) + eslint-plugin-es-x: 7.8.0(eslint@9.39.2(jiti@2.6.1)) + get-tsconfig: 4.13.6 + globals: 15.15.0 + globrex: 0.1.2 + ignore: 5.3.2 + semver: 7.7.4 + ts-declaration-location: 1.0.7(typescript@5.9.3) + transitivePeerDependencies: + - typescript + + eslint-plugin-prettier@5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))(prettier@3.8.1): + dependencies: + eslint: 9.39.2(jiti@2.6.1) + prettier: 3.8.1 + prettier-linter-helpers: 1.0.1 + synckit: 0.11.12 + optionalDependencies: + '@types/eslint': 9.6.1 + eslint-config-prettier: 10.1.8(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-react-hooks@7.0.1(eslint@9.39.2(jiti@2.6.1)): dependencies: '@babel/core': 7.29.0 @@ -10236,6 +10354,12 @@ snapshots: string.prototype.matchall: 4.0.12 string.prototype.repeat: 1.0.0 + eslint-plugin-unused-imports@4.4.1(@typescript-eslint/eslint-plugin@8.56.0(@typescript-eslint/parser@8.56.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)): + dependencies: + eslint: 9.39.2(jiti@2.6.1) + optionalDependencies: + '@typescript-eslint/eslint-plugin': 8.56.0(@typescript-eslint/parser@8.56.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint-scope@5.1.1: dependencies: esrecurse: 4.3.0 @@ -10417,6 +10541,8 @@ snapshots: fast-deep-equal@3.1.3: {} + fast-diff@1.3.0: {} + fast-glob@3.3.1: dependencies: '@nodelib/fs.stat': 2.0.5 @@ -10729,6 +10855,8 @@ snapshots: globals@14.0.0: {} + globals@15.15.0: {} + globals@16.4.0: {} globals@17.3.0: {} @@ -10747,6 +10875,8 @@ snapshots: slash: 5.1.0 unicorn-magic: 0.3.0 + globrex@0.1.2: {} + gonzales-pe@4.3.0: dependencies: minimist: 1.2.8 @@ -12237,6 +12367,10 @@ snapshots: prelude-ls@1.2.1: {} + prettier-linter-helpers@1.0.1: + dependencies: + fast-diff: 1.3.0 + prettier@3.8.1: {} pretty-format@30.2.0: @@ -13134,6 +13268,11 @@ snapshots: dependencies: typescript: 5.9.3 + ts-declaration-location@1.0.7(typescript@5.9.3): + dependencies: + picomatch: 4.0.3 + typescript: 5.9.3 + ts-jest@29.4.6(@babel/core@7.29.0)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.29.0))(jest-util@30.2.0)(jest@30.2.0(@types/node@25.2.3)(ts-node@10.9.2(@types/node@25.2.3)(typescript@5.9.3)))(typescript@5.9.3): dependencies: bs-logger: 0.2.6
Нет аккаунта?
a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary', + className + )} + {...props} + /> + ); +} + +function FieldSeparator({ + children, + className, + ...props +}: React.ComponentProps<'div'> & { + children?: React.ReactNode; +}) { + return ( +