Skip to content

Commit

Permalink
Migrate Overlay component with scss (#1949)
Browse files Browse the repository at this point in the history
<!--
  How to write a good PR title:
- Follow [the Conventional Commits
specification](https://www.conventionalcommits.org/en/v1.0.0/).
  - Give as much context as necessary and as little as possible
  - Prefix it with [WIP] while it’s a work in progress
-->

## Self Checklist

- [x] I wrote a PR title in **English** and added an appropriate
**label** to the PR.
- [x] I wrote the commit message in **English** and to follow [**the
Conventional Commits
specification**](https://www.conventionalcommits.org/en/v1.0.0/).
- [x] I [added the
**changeset**](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md)
about the changes that needed to be released. (or didn't have to)
- [x] I wrote or updated **documentation** related to the changes. (or
didn't have to)
- [x] I wrote or updated **tests** related to the changes. (or didn't
have to)
- [x] I tested the changes in various browsers. (or didn't have to)
  - Windows: Chrome, Edge, (Optional) Firefox
  - macOS: Chrome, Edge, Safari, (Optional) Firefox

## Related Issue
<!-- Please link to issue if one exists -->

- #1733

## Summary
<!-- Please brief explanation of the changes made -->

Migrate `Overlay` component with scss

## Details
<!-- Please elaborate description of the changes -->

SCSS 마이그레이션 외 아래와 같은 점들을 변경했습니다.

- as 및 interpolation 관련 속성을 제거합니다
- 컴포넌트 리팩토링
  - 내부 컴포넌트의 useMemo 제거
  - prop 순서 정렬
  - 함수의 noop 기본값 제거
- 스타일 관련 테스트 제거
- 스토리에서 styled 사용을 제거하고, 단순한 Primary 테스트 하나만 남깁니다.
- 마이너: 공용 elevation css module의 클래스명이 잘못되어있던 부분을 수정합니다.

### Footnotes

- 새로 구현하고 싶었으나... 리팩토링의 범위를 한참 뛰어넘는다고 생각하여 진행하지 않았습니다. 
- 다음 버전의 디자인 시스템에서 스펙 잘 정의하고, 그 때는
[floating-ui](https://floating-ui.com/)같은 라이브러리를 사용하여 재구현(혹은 새로운 컴포넌트
구현)하면 높은 퀄리티의 컴포넌트를 손쉽게 구현할 수 있어 좋을 거 같아요.

### Breaking change? (Yes/No)
<!-- If Yes, please describe the impact and migration path for users -->

Yes
  • Loading branch information
sungik-choi authored Jan 29, 2024
1 parent c687ed9 commit a7dad85
Show file tree
Hide file tree
Showing 12 changed files with 222 additions and 525 deletions.
9 changes: 9 additions & 0 deletions .changeset/curly-poets-decide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@channel.io/bezier-react": major
---

**Breaking Changes: Property updates in `Overlay` component**

- No longer support `as` and `interpolation` property. Replace any usage of `interpolation` property with appropriate `style` or `className` implementations.
- No longer support `containerInterpolation` property. Replace any usage of `containerInterpolation` property with appropriate `containerStyle` or `containerClassName` implementations.
- No longer support `wrapperTestId` property.
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ describe('Select', () => {

await user.click(body)

expect(dropdown).not.toBeVisible()
expect(dropdown).toHaveClass('hidden')
})
})
})
32 changes: 32 additions & 0 deletions packages/bezier-react/src/components/Overlay/Overlay.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
.OverlayContainer {
position: fixed;
z-index: var(--z-index-overlay);
inset: 0;

width: 100%;
height: 100%;

&:where(.hidden) {
pointer-events: none;
}
}

.OverlayWrapper {
position: relative;
z-index: var(--z-index-base);
width: 100%;
height: 100%;
}

.Overlay {
position: absolute;
z-index: var(--z-index-overlay);

&:where(.hidden) {
opacity: 0;
}

&:where(.transition) {
transition: top var(--transition-s), opacity var(--transition-s);
}
}
287 changes: 54 additions & 233 deletions packages/bezier-react/src/components/Overlay/Overlay.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,18 @@ import React, {
import {
type Meta,
type StoryFn,
type StoryObj,
} from '@storybook/react'

import { styled } from '~/src/foundation'
import { isBoolean } from '~/src/utils/type'

import Overlay from './Overlay'
import type OverlayProps from './Overlay.types'
import { Button } from '~/src/components/Button'

import { Overlay } from './Overlay'
import type { OverlayProps } from './Overlay.types'
import { OverlayPosition } from './Overlay.types'

const meta: Meta<OverlayProps & {
containerWidth: number
containerHeight: number
} & {
targetTop: number
targetLeft: number
}> = {
const meta: Meta<OverlayProps> = {
component: Overlay,
argTypes: {
position: {
Expand Down Expand Up @@ -63,246 +60,70 @@ const meta: Meta<OverlayProps & {
step: 1,
},
},
containerWidth: {
control: {
type: 'range',
min: 100,
max: 1000,
step: 20,
},
},
containerHeight: {
control: {
type: 'range',
min: 100,
max: 1000,
step: 20,
},
},
targetTop: {
control: {
type: 'range',
min: 100,
max: 1000,
step: 20,
},
},
targetLeft: {
control: {
type: 'range',
min: 100,
max: 1000,
step: 20,
},
},
},
}
export default meta

interface ContainerProps {
containerWidth?: number
containerHeight?: number
}

interface TargetProps {
targetTop?: number
targetLeft?: number
}

const Container = styled.div<ContainerProps>`
position: relative;
width: ${({ containerWidth }) => containerWidth ?? 600}px;
height: ${({ containerHeight }) => containerHeight ?? 500}px;
overflow: hidden;
border: 1px solid ${props => props.foundation?.theme?.['bg-black-dark']};
`

const Wrapper = styled.div`
display: flex;
width: 100%;
height: 100%;
`

const Target = styled.div<TargetProps>`
position: absolute;
top: ${({ targetTop }) => targetTop ?? 200}px;
left: ${({ targetLeft }) => targetLeft ?? 200}px;
display: flex;
align-items: center;
justify-content: center;
width: 70px;
height: 40px;
background-color: ${props => props.foundation?.theme?.['bg-black-dark']};
border-radius: 4px;
`

const Children = styled.div`
width: 250px;
height: 150px;
overflow-y: scroll;
background-color: ${props => props.foundation?.theme?.['bg-black-dark']};
border-radius: 4px;
`

const ScrollContent = styled.div`
box-sizing: border-box;
width: 250px;
height: 350px;
padding: 5px;
color: white;
`

const OverlayTemplate: React.FC<OverlayProps & ContainerProps & TargetProps> = ({
const Template: StoryFn<OverlayProps> = ({
show: showProp,
children,
containerWidth,
containerHeight,
targetTop,
targetLeft,
...rests
...rest
}) => {
const containerRef = useRef<any>(null)
const targetRef = useRef<any>(null)
const [show, setShow] = useState(false)
const containerRef = useRef<HTMLDivElement | null>(null)
const targetRef = useRef<HTMLButtonElement | null>(null)

useEffect(function syncShow() {
if (isBoolean(showProp)) {
setShow(showProp)
}
}, [showProp])

return (
<Container
containerWidth={containerWidth}
containerHeight={containerHeight}
<div
ref={containerRef}
style={{
position: 'relative',
width: 300,
height: 300,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
<Wrapper>
<Target
targetTop={targetTop}
targetLeft={targetLeft}
ref={targetRef}
>
target
</Target>
<Overlay
{...rests}
target={targetRef.current}
container={containerRef.current}
>
{ children }
</Overlay>
</Wrapper>
</Container>
<Button
ref={targetRef}
text="Click me!"
onClick={() => setShow(true)}
/>

<Overlay
show={show}
style={{
width: 200,
height: 200,
backgroundColor: 'var(--bg-white-high)',
borderRadius: 'var(--radius-8)',
boxShadow: 'var(--ev-3)',
}}
target={targetRef.current}
container={containerRef.current}
onHide={() => setShow(false)}
{...rest}
>
{ children }
</Overlay>
</div>
)
}

const Template: StoryFn = (props) => (
<OverlayTemplate {...props}>
<Children>
<ScrollContent>
{
`Lorem Ipsum is simply dummy text of the printing and typesetting
industry. Lorem Ipsum has been the industry's standard dummy text
ever since the 1500s, when an unknown printer took a galley of type
and scrambled it to make a type specimen book. It has survived not
only five centuries, but also the leap into electronic typesetting,
remaining essentially unchanged. It was popularised in the 1960s
with the release of Letraset sheets containing Lorem Ipsum passages,
and more recently with desktop publishing software like Aldus PageMaker
including versions of Lorem Ipsum.`
}
</ScrollContent>
</Children>
</OverlayTemplate>
)

export const Primary = {
export const Primary: StoryObj<OverlayProps> = {
render: Template,

args: {
show: false,
position: OverlayPosition.BottomCenter,
marginX: 0,
marginY: 0,
keepInContainer: false,
withTransition: false,
marginY: 6,
},
}

const StressTestTemplate: StoryFn<OverlayProps> = (props) => {
const targetRef = useRef<any>()
const containerRef = useRef<any>()
const [, reload] = useState(0)

useEffect(() => {
setInterval(() => {
reload((prev) => prev + 1)
}, 100)
}, [])

return (
<OverlayTemplate
{...props}
// 실제 값은 변하지 않지만, 100ms의 매 렌더링마다 참조가 변하고 있다.
containerStyle={{ opacity: 1 }}
target={targetRef.current}
container={containerRef.current}
>
<Children>
<ScrollContent>
{
`Lorem Ipsum is simply dummy text of the printing and typesetting
industry. Lorem Ipsum has been the industry's standard dummy text
ever since the 1500s, when an unknown printer took a galley of type
and scrambled it to make a type specimen book. It has survived not
only five centuries, but also the leap into electronic typesetting,
remaining essentially unchanged. It was popularised in the 1960s
with the release of Letraset sheets containing Lorem Ipsum passages,
and more recently with desktop publishing software like Aldus PageMaker
including versions of Lorem Ipsum.`
}
</ScrollContent>
</Children>
</OverlayTemplate>
)
}

export const StressTest = {
render: StressTestTemplate,

args: {
enableClickOutside: false,
},
}

const ChangeableChildrenTemplate: StoryFn<OverlayProps> = (props) => {
const [items, setItems] = useState<number[]>([])

const addItem = React.useCallback(() => {
setItems([...items, Math.random()])
}, [items])

return (
<>
<button type="button" onClick={addItem}>Add</button>
<div>
<OverlayTemplate {...props}>
<Children>
{ items.map((item) => (
<div key={item}>
{ item }
</div>
)) }
</Children>
</OverlayTemplate>
</div>
</>
)
}

export const ChangeableChildren = {
render: ChangeableChildrenTemplate,
export default meta

args: {
show: false,
position: OverlayPosition.BottomCenter,
marginX: 0,
marginY: 0,
keepInContainer: false,
withTransition: false,
enableClickOutside: true,
},
}
Loading

0 comments on commit a7dad85

Please sign in to comment.