diff --git a/packages/app/src/features/register/molecules/ProfileInputs/index.tsx b/packages/app/src/features/register/molecules/ProfileInputs/index.tsx
index 33ad6a8f..b045d9cb 100644
--- a/packages/app/src/features/register/molecules/ProfileInputs/index.tsx
+++ b/packages/app/src/features/register/molecules/ProfileInputs/index.tsx
@@ -1,4 +1,4 @@
-import { Input, Profile, Select, SearchInput } from '@sms/shared'
+import { Input, Profile, Select, SearchInput, Textarea } from '@sms/shared'
import { InputColumn, FormWrapper } from '@features/register/atoms'
import { RegisterFormType } from '@features/register/type'
import {
@@ -57,13 +57,12 @@ const ProfileInputs = ({
/>
- resetField('introduce')}
placeholder='1줄 자기소개 입력'
/>
diff --git a/packages/app/src/features/register/molecules/ProjectsInput/index.tsx b/packages/app/src/features/register/molecules/ProjectsInput/index.tsx
index cab3f6d9..ff8647bd 100644
--- a/packages/app/src/features/register/molecules/ProjectsInput/index.tsx
+++ b/packages/app/src/features/register/molecules/ProjectsInput/index.tsx
@@ -5,7 +5,7 @@ import {
FourImageInputs,
IconImageInput,
} from '@features/register/atoms'
-import { Input, SearchInput, MultiMonthPicker } from '@sms/shared'
+import { Input, SearchInput, MultiMonthPicker, Textarea } from '@sms/shared'
import { RegisterFormType } from '@features/register/type'
import * as Icon from '@sms/shared/src/icons'
import {
@@ -115,7 +115,7 @@ const ProjectsInput = ({
-
- theme.body2}
color: var(--N40);
+ white-space: pre-line;
`
export const LinkWrapper = styled(Link)`
diff --git a/packages/shared/package.json b/packages/shared/package.json
index 1b11c9d4..726086cc 100644
--- a/packages/shared/package.json
+++ b/packages/shared/package.json
@@ -32,6 +32,7 @@
"@emotion/react": "^11.10.6",
"@emotion/styled": "^11.10.6",
"next": "13.3.0",
- "react-hook-form": "^7.43.9"
+ "react-hook-form": "^7.43.9",
+ "react-textarea-autosize": "^8.5.3"
}
}
diff --git a/packages/shared/src/atoms/Textarea/index.stories.ts b/packages/shared/src/atoms/Textarea/index.stories.ts
new file mode 100644
index 00000000..c8ccd90a
--- /dev/null
+++ b/packages/shared/src/atoms/Textarea/index.stories.ts
@@ -0,0 +1,14 @@
+import { Meta, StoryObj } from '@storybook/react'
+import Textarea from './index'
+
+const config: Meta = {
+ title: 'Textarea',
+ component: Textarea,
+ args: { error: 'ofweji', placeholder: 'hello' },
+}
+
+export default config
+
+type Story = StoryObj
+
+export const Primary: Story = {}
diff --git a/packages/shared/src/atoms/Textarea/index.tsx b/packages/shared/src/atoms/Textarea/index.tsx
new file mode 100644
index 00000000..d542d009
--- /dev/null
+++ b/packages/shared/src/atoms/Textarea/index.tsx
@@ -0,0 +1,22 @@
+import { TextareaAutosizeProps } from 'react-textarea-autosize'
+import { forwardRef } from 'react'
+import * as S from './style'
+
+interface Props extends TextareaAutosizeProps {
+ error?: string
+}
+
+const Textarea = forwardRef(
+ ({ error, ...props }, ref) => {
+ return (
+
+
+ {error && {error}}
+
+ )
+ }
+)
+
+Textarea.displayName = 'Textarea'
+
+export default Textarea
diff --git a/packages/shared/src/atoms/Textarea/style.ts b/packages/shared/src/atoms/Textarea/style.ts
new file mode 100644
index 00000000..cfc65778
--- /dev/null
+++ b/packages/shared/src/atoms/Textarea/style.ts
@@ -0,0 +1,36 @@
+import TextareaAutosize from 'react-textarea-autosize'
+import styled from '@emotion/styled'
+
+export const Wrapper = styled.div`
+ display: flex;
+ flex-direction: column;
+`
+
+export const TextareaField = styled(TextareaAutosize)`
+ ${({ theme }) => theme.body1}
+ width: 100%;
+ border: 1px solid transparent;
+ border-radius: 0.5rem;
+ padding: 0.75rem;
+ resize: none;
+ outline: none;
+ background: var(--N10);
+ transition: 0.2s;
+
+ ::placeholder {
+ color: var(--N30);
+ }
+
+ :hover {
+ border: 1px solid var(--P1);
+ }
+ :focus {
+ border: 1px solid var(--P2);
+ }
+`
+
+export const Error = styled.div`
+ ${({ theme }) => theme.caption1}
+ color: var(--ERROR);
+ margin-top: 0.5rem;
+`
diff --git a/packages/shared/src/atoms/index.ts b/packages/shared/src/atoms/index.ts
index 33755cf5..bf44ac6b 100644
--- a/packages/shared/src/atoms/index.ts
+++ b/packages/shared/src/atoms/index.ts
@@ -17,3 +17,4 @@ export { default as Checkbox } from './Checkbox'
export { default as Toast } from './Toast'
export { default as ImageInput } from './ImageInput'
export { default as MonthPicker } from './MonthPicker'
+export { default as Textarea } from './Textarea'
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index cdd59ec0..afe18bd9 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -137,6 +137,9 @@ importers:
react-hook-form:
specifier: ^7.43.9
version: 7.43.9(react@18.2.0)
+ react-textarea-autosize:
+ specifier: ^8.5.3
+ version: 8.5.3(@types/react@18.0.33)(react@18.2.0)
devDependencies:
'@babel/preset-env':
specifier: ^7.21.4
@@ -8475,6 +8478,20 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
+ /react-textarea-autosize@8.5.3(@types/react@18.0.33)(react@18.2.0):
+ resolution: {integrity: sha512-XT1024o2pqCuZSuBt9FwHlaDeNtVrtCXu0Rnz88t1jUGheCLa3PhjE1GH8Ctm2axEtvdCl5SUHYschyQ0L5QHQ==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0
+ dependencies:
+ '@babel/runtime': 7.21.0
+ react: 18.2.0
+ use-composed-ref: 1.3.0(react@18.2.0)
+ use-latest: 1.2.1(@types/react@18.0.33)(react@18.2.0)
+ transitivePeerDependencies:
+ - '@types/react'
+ dev: false
+
/react@18.2.0:
resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==}
engines: {node: '>=0.10.0'}
@@ -9661,6 +9678,41 @@ packages:
punycode: 2.3.0
dev: true
+ /use-composed-ref@1.3.0(react@18.2.0):
+ resolution: {integrity: sha512-GLMG0Jc/jiKov/3Ulid1wbv3r54K9HlMW29IWcDFPEqFkSO2nS0MuefWgMJpeHQ9YJeXDL3ZUF+P3jdXlZX/cQ==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0
+ dependencies:
+ react: 18.2.0
+ dev: false
+
+ /use-isomorphic-layout-effect@1.1.2(@types/react@18.0.33)(react@18.2.0):
+ resolution: {integrity: sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@types/react': 18.0.33
+ react: 18.2.0
+ dev: false
+
+ /use-latest@1.2.1(@types/react@18.0.33)(react@18.2.0):
+ resolution: {integrity: sha512-xA+AVm/Wlg3e2P/JiItTziwS7FK92LWrDB0p+hgXloIMuVCeJJ8v6f0eeHyPZaJrM+usM1FkFfbNCrJGs8A/zw==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@types/react': 18.0.33
+ react: 18.2.0
+ use-isomorphic-layout-effect: 1.1.2(@types/react@18.0.33)(react@18.2.0)
+ dev: false
+
/use-resize-observer@9.1.0(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-R25VqO9Wb3asSD4eqtcxk8sJalvIOYBqS8MNZlpDSQ4l4xMQxC/J7Id9HoTqPq8FwULIn0PVW+OAqF2dyYbjow==}
peerDependencies: