@@ -2,50 +2,8 @@ import * as React from 'react';
2
2
import styled , { css } from 'styled-components' ;
3
3
import palette from '../../lib/styles/palette' ;
4
4
import transitions from '../../lib/styles/transitions' ;
5
-
6
- const TagInputBlock = styled . div `
7
- color : ${ palette . gray8 } ;
8
- font-size : 1.125rem ;
9
- margin-bottom : 4rem ;
10
- display : flex;
11
- flex-wrap : wrap;
12
- [contenteditable = 'true' ]: empty : before {
13
- content : attr (placeholder);
14
- display : block; /* For Firefox */
15
- color : ${ palette . gray5 } ;
16
- }
17
- ` ;
18
- const StyledInput = styled . input `
19
- display : inline-flex;
20
- outline : none;
21
- cursor : text;
22
- font-size : 1.125rem ;
23
- line-height : 2rem ;
24
- margin-bottom : 0.75rem ;
25
- min-width : 8rem ;
26
- border : none;
27
- ` ;
28
-
29
- const Tag = styled . div `
30
- color : ${ palette . gray9 } ;
31
- font-size : 1rem ;
32
- display : inline-flex;
33
- align-items : center;
34
- height : 2rem ;
35
- border-radius : 1rem ;
36
- padding-left : 1rem ;
37
- padding-right : 1rem ;
38
- background : ${ palette . gray1 } ;
39
- color : ${ palette . teal7 } ;
40
- margin-right : 0.75rem ;
41
- transition : ease-in 0.125s ;
42
- cursor : pointer;
43
- & : hover {
44
- opacity : 0.6 ;
45
- }
46
- margin-bottom : 0.75rem ;
47
- animation : ${ transitions . popIn } 0.125s forwards ease-in-out;
48
- ` ;
5
+ import media , { mediaQuery } from '../../lib/styles/media' ;
6
+ import { useTransition , animated } from 'react-spring' ;
49
7
50
8
export interface TagInputProps {
51
9
ref ?: React . RefObject < HTMLDivElement > ;
@@ -59,24 +17,6 @@ const TagItem: React.FC<{
59
17
return < Tag onClick = { onClick } > { children } </ Tag > ;
60
18
} ;
61
19
62
- const Help = styled . div < { visible : boolean } > `
63
- display: block;
64
- width: 100%;
65
- font-size: 0.875rem;
66
- color: ${ palette . gray7 } ;
67
- transition: ease-in 0.125s;
68
- opacity: 0;
69
- & > .inside {
70
- margin-top: 0.5rem;
71
- position: absolute;
72
- }
73
- ${ props =>
74
- props . visible &&
75
- css `
76
- opacity : 1 ;
77
- ` }
78
- ` ;
79
-
80
20
const { useState, useCallback, useEffect, useRef } = React ;
81
21
const TagInput : React . FC < TagInputProps > = ( { onChange, tags : initialTags } ) => {
82
22
const [ tags , setTags ] = useState < string [ ] > ( initialTags ) ;
@@ -170,15 +110,110 @@ const TagInput: React.FC<TagInputProps> = ({ onChange, tags: initialTags }) => {
170
110
onFocus = { ( ) => setFocus ( true ) }
171
111
onBlur = { ( ) => setFocus ( false ) }
172
112
/>
173
- < Help visible = { focus } >
174
- < div className = "inside" >
175
- 쉼표 혹은 엔터를 입력하여 태그를 등록 할 수 있습니다.
176
- < br />
177
- 등록된 태그를 클릭하면 삭제됩니다.
178
- </ div >
179
- </ Help >
113
+ < Help focus = { focus } />
180
114
</ TagInputBlock >
181
115
) ;
182
116
} ;
183
117
118
+ function Help ( { focus } : { focus : boolean } ) {
119
+ const transitions = useTransition ( focus , null , {
120
+ from : { opacity : 0 , transform : 'translateY(-1rem)' } ,
121
+ enter : { opacity : 1 , transform : 'translateY(0rem)' } ,
122
+ leave : { opacity : 0 , transform : 'translateY(-1rem)' } ,
123
+ config : {
124
+ tension : 350 ,
125
+ friction : 22 ,
126
+ } ,
127
+ } ) ;
128
+
129
+ return (
130
+ < HelpBlock >
131
+ { transitions . map ( ( { item, key, props } ) =>
132
+ item ? (
133
+ < animated . div className = "inside" style = { props } key = { key } >
134
+ 쉼표 혹은 엔터를 입력하여 태그를 등록 할 수 있습니다.
135
+ < br />
136
+ 등록된 태그를 클릭하면 삭제됩니다.
137
+ </ animated . div >
138
+ ) : null ,
139
+ ) }
140
+ </ HelpBlock >
141
+ ) ;
142
+ }
143
+
144
+ const HelpBlock = styled . div `
145
+ display: block;
146
+ width: 100%;
147
+
148
+ color: ${ palette . gray7 } ;
149
+ transition: ease-in 0.125s;
150
+
151
+ & > .inside {
152
+ position: absolute;
153
+ background: ${ palette . gray8 } ;
154
+ color: white;
155
+ padding: 0.75rem;
156
+ z-index: 20;
157
+ line-height: 1.5;
158
+ font-size: 0.75rem;
159
+ }
160
+ ` ;
161
+
162
+ const TagInputBlock = styled . div `
163
+ color: ${ palette . gray8 } ;
164
+ font-size: 1.125rem;
165
+
166
+ display: flex;
167
+ flex-wrap: wrap;
168
+ [contenteditable='true']:empty:before {
169
+ content: attr(placeholder);
170
+ display: block; /* For Firefox */
171
+ color: ${ palette . gray5 } ;
172
+ }
173
+ ` ;
174
+ const StyledInput = styled . input `
175
+ display: inline-flex;
176
+ outline: none;
177
+ cursor: text;
178
+ font-size: 1.125rem;
179
+ line-height: 2rem;
180
+ ${ mediaQuery ( 767 ) } {
181
+ line-height: 1.5rem;
182
+ font-size: 0.75rem;
183
+ }
184
+ margin-bottom: 0.75rem;
185
+ min-width: 8rem;
186
+ border: none;
187
+ ` ;
188
+
189
+ const Tag = styled . div `
190
+ color: ${ palette . gray9 } ;
191
+ font-size: 1rem;
192
+ display: inline-flex;
193
+ align-items: center;
194
+ height: 2rem;
195
+ border-radius: 1rem;
196
+ padding-left: 1rem;
197
+ padding-right: 1rem;
198
+ background: ${ palette . gray1 } ;
199
+ color: ${ palette . teal7 } ;
200
+ margin-right: 0.75rem;
201
+ transition: ease-in 0.125s;
202
+ cursor: pointer;
203
+ &:hover {
204
+ opacity: 0.6;
205
+ }
206
+ margin-bottom: 0.75rem;
207
+ animation: ${ transitions . popIn } 0.125s forwards ease-in-out;
208
+ ${ mediaQuery ( 767 ) } {
209
+ height: 1.5rem;
210
+ font-size: 0.75rem;
211
+ border-radius: 0.75rem;
212
+ padding-left: 0.75rem;
213
+ padding-right: 0.75rem;
214
+ margin-right: 0.5rem;
215
+ margin-bottom: 0.5rem;
216
+ }
217
+ ` ;
218
+
184
219
export default TagInput ;
0 commit comments