Skip to content

Commit 693a44c

Browse files
authored
Navigation 리팩토링 (#57)
* Scroll Wrapper 를 옵셔널 하게 변경 * Title dom 구조 수정 * Text 스펙 변경 대응 * Navigation 최하단에 마진 40px 를 강제로 추가 * Scroll ref prop 추가
1 parent 44b6b42 commit 693a44c

File tree

5 files changed

+115
-30
lines changed

5 files changed

+115
-30
lines changed

src/layout/Navigation/Navigation.stories.tsx

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ export const WithGNB = () => {
8080
This is GNB
8181
</GNB>
8282
<Navigation
83+
withScroll
8384
title={text('navigation title', '고객 연락처')}
8485
fixedTitle={boolean('fixed title', false)}
8586
maxWidth={number('max width', 540)}
@@ -125,3 +126,66 @@ export const WithGNB = () => {
125126
</div>
126127
)
127128
}
129+
130+
export const ProgrammaticScroll = () => {
131+
const scrollAreaRef = useRef<HTMLDivElement | null>(null)
132+
const firstMilestone = useRef<HTMLDivElement | null>(null)
133+
const secondMilestone = useRef<HTMLDivElement | null>(null)
134+
const scrollToTop = useCallback(() => {
135+
scrollAreaRef.current.scrollTop = 0
136+
}, [])
137+
138+
const scrollToBottom = useCallback(() => {
139+
scrollAreaRef.current.scrollTop = scrollAreaRef.current.scrollHeight
140+
}, [])
141+
142+
return (
143+
<div
144+
style={{ display: 'flex', height: '100%' }}
145+
>
146+
<ThemeProvider theme={LightTheme}>
147+
<Navigation
148+
scrollRef={scrollAreaRef}
149+
withScroll
150+
>
151+
<div
152+
style={{
153+
position: 'relative',
154+
height: 15000,
155+
}}
156+
>
157+
<div style={{ position: 'absolute', top: 0 }}>
158+
Hi, This is TOP!
159+
</div>
160+
161+
<div
162+
ref={firstMilestone}
163+
style={{ position: 'absolute', top: 3000 }}
164+
>
165+
1st Milestone
166+
</div>
167+
168+
<div
169+
ref={secondMilestone}
170+
style={{ position: 'absolute', top: 8000 }}
171+
>
172+
2nd Milestone
173+
</div>
174+
175+
<div style={{ position: 'absolute', bottom: 0 }}>
176+
Oh hello, This is BOTTOM!
177+
</div>
178+
</div>
179+
</Navigation>
180+
<div>
181+
<button type="button" onClick={scrollToTop}>
182+
Go to Top
183+
</button>
184+
<button type="button" onClick={scrollToBottom}>
185+
Go to Bottom
186+
</button>
187+
</div>
188+
</ThemeProvider>
189+
</div>
190+
)
191+
}

src/layout/Navigation/Navigation.styled.ts

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,40 +6,49 @@ import NavigationProps from './Navigation.types'
66

77
export const StyledNavigation = styled.div<NavigationProps>`
88
position: relative;
9+
display: flex;
10+
flex-direction: column;
911
flex: none;
1012
height: 100%;
1113
user-select: ${props => (props.isDragging ? 'none' : 'auto')};
1214
width: ${props => props.width}px;
1315
background-color: ${props => props.theme?.colors?.background1};
1416
box-shadow: inset -1px 0 0 0 ${props => props.theme?.colors?.background2};
1517
transition: background-color 200ms ease-in-out, width 200ms;
18+
overflow: hidden;
1619
`
1720

18-
interface StyledHandleProps {
19-
disable: boolean
21+
interface StyledContentWrapperProps {
22+
scroll?: boolean
2023
}
2124

22-
export const StyledContentWrapper = styled.div`
25+
export const StyledContentWrapper = styled.div<StyledContentWrapperProps>`
2326
width: 100%;
2427
height: 100%;
2528
overflow-x: hidden;
26-
overflow-y: scroll;
29+
overflow-y: ${props => (props.scroll ? 'auto' : 'hidden')};
30+
31+
& > *:last-child {
32+
margin-bottom: 40px !important;
33+
}
2734
`
2835

2936
interface StyledTitleWrapperProps {
30-
sticky: boolean
37+
fixed?: boolean
3138
}
3239

3340
export const StyledTitleWrapper = styled.div<StyledTitleWrapperProps>`
34-
position: ${props => (props.sticky ? 'sticky' : 'initial')};
35-
top: 0;
3641
width: 100%;
3742
height: 75px;
3843
padding: 18px 18px 21px;
3944
box-sizing: border-box;
4045
background-color: ${props => props.theme?.colors?.background1};
4146
`
4247

48+
interface StyledHandleProps {
49+
disable: boolean
50+
}
51+
4352
export const StyledHandle = styled.div<StyledHandleProps>`
4453
position: absolute;
4554
top: 0;

src/layout/Navigation/Navigation.test.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ describe('Navigation Test >', () => {
2222
}
2323
})
2424

25-
const renderNavigation = () => render(<Navigation {...props} />)
25+
const renderNavigation = (optionalProps?: NavigationProps) =>
26+
render(<Navigation {...props} {...optionalProps}/>)
2627

2728
it('Navigation should be initialized with mininal width', () => {
2829
const { getByTestId } = renderNavigation()
@@ -39,14 +40,14 @@ describe('Navigation Test >', () => {
3940
})
4041

4142
it('Navigation can be scrolled in y-axis', () => {
42-
const { getByTestId } = renderNavigation()
43+
const { getByTestId } = renderNavigation({ withScroll: true })
4344
const renderedNav = getByTestId(NAV_SCROLL_TEST_ID)
4445

45-
expect(renderedNav).toHaveStyle('overflow-y: scroll')
46+
expect(renderedNav).toHaveStyle('overflow-y: auto')
4647
})
4748

4849
it('Navigation hide overflowed contents on x-axis', () => {
49-
const { getByTestId } = renderNavigation()
50+
const { getByTestId } = renderNavigation({ withScroll: true })
5051
const renderedNav = getByTestId(NAV_SCROLL_TEST_ID)
5152

5253
expect(renderedNav).toHaveStyle('overflow-x: hidden')

src/layout/Navigation/Navigation.tsx

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,13 @@ export const NAV_SCROLL_TEST_ID = 'ch-design-system-nav-scroll'
2424

2525
function Navigation(
2626
{
27+
scrollRef,
2728
testId,
2829
style,
2930
className,
3031
title,
3132
fixedTitle = false,
33+
withScroll = false,
3234
width = 240,
3335
minWidth = 240,
3436
maxWidth = 540,
@@ -97,28 +99,32 @@ function Navigation(
9799
data-testid={testId}
98100
isDragging={isDragging}
99101
>
102+
{ (title && fixedTitle) && (
103+
<StyledTitleWrapper fixed>
104+
<Text
105+
bold
106+
typo={Typography.Size24}
107+
>
108+
{ title }
109+
</Text>
110+
</StyledTitleWrapper>
111+
) }
100112
<StyledContentWrapper
113+
ref={scrollRef}
114+
scroll={withScroll}
101115
data-testid={NAV_SCROLL_TEST_ID}
102116
>
103-
<div>
104-
{ /**
105-
* FIXME: Safari 에서 sticky 가 제대로 동작하지 않는 버그가 있어서,
106-
* 이를 해결하기 위해 추가한 임시 div 입니다.
107-
* 추후 제거 요망.
108-
*
109-
* 참고: https://stackoverflow.com/questions/57934803/workaround-for-a-safari-position-sticky-webkit-sticky-bug
110-
* */ }
111-
{ title && (
112-
<StyledTitleWrapper sticky={fixedTitle}>
113-
<Text
114-
bold
115-
typo={Typography.Size24}
116-
content={title}
117-
/>
118-
</StyledTitleWrapper>
119-
) }
120-
{ children }
121-
</div>
117+
{ (title && !fixedTitle) && (
118+
<StyledTitleWrapper>
119+
<Text
120+
bold
121+
typo={Typography.Size24}
122+
>
123+
{ title }
124+
</Text>
125+
</StyledTitleWrapper>
126+
) }
127+
{ children }
122128
</StyledContentWrapper>
123129
<StyledHandle
124130
disable={disableResize}

src/layout/Navigation/Navigation.types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
1+
/* External dependencies */
2+
import { Ref } from 'react'
3+
14
/* Internal dependencies */
25
import { ChildrenComponentProps } from '../../types/ComponentProps'
36

47
export default interface NavigationProps extends Omit<ChildrenComponentProps, 'as'> {
8+
scrollRef?: Ref<HTMLDivElement>
59
title?: string
610
fixedTitle?: boolean
11+
withScroll?: boolean
712
width?: number
813
minWidth?: number
914
maxWidth?: number

0 commit comments

Comments
 (0)