diff --git a/package.json b/package.json index 16315c9..70ff501 100644 --- a/package.json +++ b/package.json @@ -9,12 +9,14 @@ "lint": "next lint" }, "dependencies": { + "@formkit/tempo": "^0.1.2", "@hookform/resolvers": "^3.9.0", "@it-incubator/prettier-config": "^0.1.2", "@radix-ui/react-checkbox": "^1.1.1", "@radix-ui/react-icons": "^1.3.0", "@reduxjs/toolkit": "^2.2.6", "@types/javascript-time-ago": "^2.0.8", + "async-mutex": "^0.5.0", "clsx": "^2.1.1", "javascript-time-ago": "^2.5.10", "next": "14.2.5", @@ -25,6 +27,7 @@ "react-hook-form": "7.52.1", "react-redux": "^9.1.2", "react-time-ago": "^7.3.3", + "sonner": "^1.5.0", "zod": "^3.23.8" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 675100d..89b0c42 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,9 @@ importers: .: dependencies: + '@formkit/tempo': + specifier: ^0.1.2 + version: 0.1.2 '@hookform/resolvers': specifier: ^3.9.0 version: 3.9.0(react-hook-form@7.52.1(react@18.3.1)) @@ -26,6 +29,9 @@ importers: '@types/javascript-time-ago': specifier: ^2.0.8 version: 2.0.8 + async-mutex: + specifier: ^0.5.0 + version: 0.5.0 clsx: specifier: ^2.1.1 version: 2.1.1 @@ -56,6 +62,9 @@ importers: react-time-ago: specifier: ^7.3.3 version: 7.3.3(javascript-time-ago@2.5.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + sonner: + specifier: ^1.5.0 + version: 1.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) zod: specifier: ^3.23.8 version: 3.23.8 @@ -109,6 +118,9 @@ packages: resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@formkit/tempo@0.1.2': + resolution: {integrity: sha512-jNPPbjL8oj7hK3eHX++CwbR6X4GKQt+x00/q4yeXkwynXHGKL27dylYhpEgwrmediPP4y7s0XtN1if/M/JYujg==} + '@hookform/resolvers@3.9.0': resolution: {integrity: sha512-bU0Gr4EepJ/EQsH/IwEzYLsT/PEj5C0ynLQ4m+GSHS+xKH4TfSelhluTgOaoc4kA5s7eCsQbM4wvZLzELmWzUg==} peerDependencies: @@ -509,6 +521,9 @@ packages: ast-types-flow@0.0.8: resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} + async-mutex@0.5.0: + resolution: {integrity: sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA==} + available-typed-arrays@1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} @@ -1577,6 +1592,12 @@ packages: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} + sonner@1.5.0: + resolution: {integrity: sha512-FBjhG/gnnbN6FY0jaNnqZOMmB73R+5IiyYAw8yBj7L54ER7HB3fOSE5OFiQiE2iXWxeXKvg6fIP4LtVppHEdJA==} + peerDependencies: + react: ^18.0.0 + react-dom: ^18.0.0 + source-map-js@1.2.0: resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} engines: {node: '>=0.10.0'} @@ -1815,6 +1836,8 @@ snapshots: '@eslint/js@8.57.0': {} + '@formkit/tempo@0.1.2': {} + '@hookform/resolvers@3.9.0(react-hook-form@7.52.1(react@18.3.1))': dependencies: react-hook-form: 7.52.1(react@18.3.1) @@ -2197,6 +2220,10 @@ snapshots: ast-types-flow@0.0.8: {} + async-mutex@0.5.0: + dependencies: + tslib: 2.6.3 + available-typed-arrays@1.0.7: dependencies: possible-typed-array-names: 1.0.0 @@ -3438,6 +3465,11 @@ snapshots: slash@3.0.0: {} + sonner@1.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + source-map-js@1.2.0: {} stop-iteration-iterator@1.0.0: diff --git a/src/components/textarea.tsx b/src/components/textarea.tsx new file mode 100644 index 0000000..941196a --- /dev/null +++ b/src/components/textarea.tsx @@ -0,0 +1,33 @@ +import { ComponentPropsWithoutRef, ElementRef, forwardRef, useId } from 'react' +import { clsx } from 'clsx' + +export type TextareaProps = ComponentPropsWithoutRef<'textarea'> & { + errorMessage?: string + label?: string +} + +export const Textarea = forwardRef, TextareaProps>( + ({ className, label, errorMessage, id, ...props }, ref) => { + const generatedId = useId() + const finalId = id ?? generatedId + + return ( +
+ {!!label && ( + + )} +