Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate ListItem component with scss #1925

Merged
merged 37 commits into from
Jan 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
4de16e3
feat(list-item): add scss module
sungik-choi Jan 17, 2024
e832fbe
feat(list-item): apply scss module and refactor (rm useMemo, etc.)
sungik-choi Jan 17, 2024
69614bf
feat(list-item): rm unused props
sungik-choi Jan 17, 2024
a1e5d82
refactor(list-item): clean up type
sungik-choi Jan 17, 2024
73d13db
feat(list-item): apply missing additional style props
sungik-choi Jan 17, 2024
87a49e1
feat(list-item): implement useAdjacentElementBorderRadius via css :ha…
sungik-choi Jan 17, 2024
0982ef5
refactor(list-item): rm unused files
sungik-choi Jan 17, 2024
67b2749
refactor(list-item): split link element and inline component
sungik-choi Jan 17, 2024
b29ebf7
feat(list-item): rm unnecessary active conditional logic, inline useC…
sungik-choi Jan 17, 2024
598ba76
feat(list-item): add width 100% style
sungik-choi Jan 17, 2024
487db6f
refactor(list-item): inline variable
sungik-choi Jan 17, 2024
04193d2
refactor(list-item): fix html element type
sungik-choi Jan 17, 2024
95523df
feat(list-item): refine tyeps
sungik-choi Jan 17, 2024
5f7b065
refactor(list-item): inline testid
sungik-choi Jan 17, 2024
6475413
refactor(list-item): apply named export
sungik-choi Jan 17, 2024
18517ae
refactor(list-item): inline link component
sungik-choi Jan 17, 2024
ddefe40
feat(list-item): revert element type changing (div -> button)
sungik-choi Jan 17, 2024
5fc3949
fix(list-item): fix invalid selector
sungik-choi Jan 17, 2024
522636f
test(list-item): simplify story
sungik-choi Jan 17, 2024
829473b
fix(list-item): rm unnecessary focus logic
sungik-choi Jan 17, 2024
763e57c
test(list-item): cleanup unit tests
sungik-choi Jan 17, 2024
30c4e60
test: update snapshot
sungik-choi Jan 17, 2024
fac5cf7
refactor(list-item): rm unnecessary default value
sungik-choi Jan 17, 2024
e31a6df
feat(list-item): rm activeClassName prop and enhance type
sungik-choi Jan 18, 2024
069e127
refactor(props): rm unncessary props from ActivatableProps
sungik-choi Jan 18, 2024
ab666cc
feat(list-item): rm unnecessary additional stylable props
sungik-choi Jan 18, 2024
88f120b
fix(list-item): rename size the same as figma
sungik-choi Jan 18, 2024
1bb458b
fix(list-item): fix xl typo size the same as figma
sungik-choi Jan 18, 2024
2f46dd6
feat(list-item): rm name, leftIcon prop, change onClick prop type and…
sungik-choi Jan 18, 2024
5c7764d
chore(changeset): add
sungik-choi Jan 18, 2024
9b59ce4
feat(list-item): change element type to cover a variety of cases
sungik-choi Jan 18, 2024
f4033bd
fix: type error
sungik-choi Jan 18, 2024
0cbc20b
fix: type error
sungik-choi Jan 18, 2024
2fc2643
Merge branch 'alpha' into feat/scss-list-item
sungik-choi Jan 19, 2024
c842b41
fix(list-item): fix new line component styling
sungik-choi Jan 19, 2024
07d70c2
fix(list-item): fix style
sungik-choi Jan 19, 2024
7db374f
test(list-item): add composition story
sungik-choi Jan 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .changeset/cuddly-crews-matter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
"@channel.io/bezier-react": major
---

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

- No longer support `interpolation` property. Replace any usage of `interpolation` property with appropriate `style` or `className` implementations.
- No longer support `iconStyle`, `iconClassName`, `iconInterpolation`, `contentStyle`, `contentClassName` and `contentInterpolation`. This decision was made to reduce excessive flexibility in the interface.
- No longer support `leftIcon` property. Removed for consistency with other component interfaces. Replace it to `leftContent`.
- No longer support `name` property. The second argument (name) of `onClick` is also removed. If you need an identifier, combine functions outside of the component.
- No longer support `hide`, `nested`, `optionKey` and `disableIconActive` property. Removed because it is a legacy property. Replace `hide` property with conditional rendering.
- The size changes according to the `ListItemSize`. This is a change to unify the design. Please change it like below.
- `ListItemSize.S` -> `ListItemSize.XS`
- `ListItemSize.M` -> `ListItemSize.S`
- `ListItemSize.L` -> `ListItemSize.M`
- `ListItemSize.XL` -> `ListItemSize.L`

**Minor Changes:**

- Fix incorrect text size for `XL`(now `L`) size.
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ export const UsageComposite: StoryObj<{}> = {
</LegacyStackItem>
<LegacyStackItem>
<ListItem
leftIcon={TagIcon}
leftContent={TagIcon}
content="KR/Product"
rightContent={(
<LegacyHStack>
Expand All @@ -295,7 +295,7 @@ export const UsageComposite: StoryObj<{}> = {
</LegacyStackItem>
<LegacyStackItem>
<ListItem
leftIcon={TagIcon}
leftContent={TagIcon}
content="KR/Design"
rightContent={(
<LegacyHStack>
Expand Down
159 changes: 159 additions & 0 deletions packages/bezier-react/src/components/ListItem/ListItem.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
.ListItemLeftIcon {
transition: color var(--transition-m);
}

.ListItem {
all: unset;

cursor: pointer;

display: flex;
align-items: center;

text-decoration: none;

transition: background-color var(--transition-s);

&:where(.variant-monochrome) {
color: var(--txt-black-darkest);

& :where(.ListItemLeftIcon) {
color: var(--txt-black-dark);
}
}

&:where(.size-xs) {
padding: 4px 6px;
border-radius: var(--radius-6);
}

&:where(.size-s) {
padding: 6px;
border-radius: var(--radius-6);
}

&:where(.size-m) {
padding: 8px 6px;
border-radius: var(--radius-8);
}

&:where(.size-l) {
padding: 10px 6px;
border-radius: var(--radius-12);
}

&:where(.disabled) {
cursor: default;
opacity: var(--opacity-disabled);
}

&:where(:not(.disabled, .active)) {
&:where(.focused, :focus-visible) {
background-color: var(--bg-black-lighter);
}

&:where(:hover) {
background-color: var(--bg-black-lighter);
}
}

&:where(.active) {
color: var(--bgtxt-blue-normal);
background-color: var(--bgtxt-blue-lightest);

&:where(.focused, :focus-visible) {
background-color: var(--bgtxt-blue-lighter);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기는 기존과 다른 스타일링 같습니다. active && focused 일 때 --bgtxt-blue-lightest 이었습니다

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ListItem을 interactive content(button)으로 변경해보는 시도를 하다가 넣었던 스타일인데, 다시 div로 되돌리기로 결정해서 이전과 동일하게 제거하면 되겠네요

Copy link
Collaborator

@yangwooseong yangwooseong Jan 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기만 다시 봐주시면 될것같습니다! 말씀하신대로 div 라서 focused 인터페이스가 조금 이상한거같은데 사용하는 곳이 은근 있네요..

}

& :where(.ListItemLeftIcon) {
color: var(--bgtxt-blue-normal);
}

/* NOTE: When multiple adjacent elements are active, it naturally stitches the border together. */
/* stylelint-disable selector-max-specificity */
&:has(+ .ListItem.active) {
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
}

& + .ListItem.active {
border-top-left-radius: 0;
border-top-right-radius: 0;
}
/* stylelint-enable selector-max-specificity */
}
Comment on lines +72 to +84
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

기존 훅이 하던 부분


&.variant-blue {
color: var(--bgtxt-blue-normal);

& :where(.ListItemLeftIcon) {
color: var(--bgtxt-blue-normal);
}
}

&.variant-red {
color: var(--bgtxt-red-normal);

& :where(.ListItemLeftIcon) {
color: var(--bgtxt-red-normal);
}
}

&.variant-green {
color: var(--bgtxt-green-normal);

& :where(.ListItemLeftIcon) {
color: var(--bgtxt-green-normal);
}
}

&.variant-cobalt {
color: var(--bgtxt-cobalt-normal);

& :where(.ListItemLeftIcon) {
color: var(--bgtxt-cobalt-normal);
}
}
}

.ListItemContent {
display: grid;
grid-template-columns: fit-content(100%) minmax(0, 1fr);
width: 100%;
}

.ListItemRightContent {
display: flex;
margin-left: 8px;
white-space: nowrap;
}

.ListItemTitle {
display: flex;
grid-column: 2;
grid-row: 1;
align-items: center;

& * {
transition: color var(--transition-s);
}
}

.ListItemDescription {
display: flex;
grid-column: 2;
grid-row: 2;
align-items: center;

width: 100%;
margin-top: 2px;
}

.ListItemLeftContent {
display: flex;
grid-column: 1;
grid-row: 1;
align-items: center;

margin-right: 8px;
}
105 changes: 22 additions & 83 deletions packages/bezier-react/src/components/ListItem/ListItem.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
import React, {
useMemo,
useState,
} from 'react'
import React, { useState } from 'react'

import { InboxIcon } from '@channel.io/bezier-icons'
import {
Expand All @@ -10,126 +7,68 @@ import {
type StoryObj,
} from '@storybook/react'

import { compact } from '~/src/utils/array'
import { range } from '~/src/utils/number'

import ListItem from './ListItem'
import type ListItemProps from './ListItem.types'
import { ListItem } from './ListItem'
import {
type ListItemProps,
ListItemSize,
ListItemVariant,
} from './ListItem.types'

const meta: Meta<typeof ListItem> = {
component: ListItem,
}
export default meta

interface ArgTypes extends ListItemProps {
width: number
}

const Template: StoryFn<ArgTypes> = ({ width, ...listItemProps }) => (
<div style={{ width }}>
<ListItem optionKey="menu-item-0" {...listItemProps} />
const Template: StoryFn<ListItemProps> = (props) => (
<div style={{ width: 400 }}>
<ListItem {...props} />
</div>
)

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

args: {
width: 388,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

프로덕션 모드에선 args를 추가하지 않아도 전부 나오므로 제거함

size: ListItemSize.M,
size: ListItemSize.S,
content: '상담이 열릴 때',
description:
'고객이 첫 메시지를 보내거나, 매니저가 상담을 다시 열거나, 자동으로 리오픈되면 트리거됩니다.',
rightContent: '',
leftIcon: InboxIcon,
leftContent: InboxIcon,
active: false,
focused: false,
disableIconActive: false,
descriptionMaxLines: 0,
href: '',
},

argTypes: {
width: {
control: {
type: 'range',
min: 50,
max: 500,
step: 1,
},
},
disabled: { control: { type: 'boolean' } },
variant: {
control: {
type: 'radio',
},
options: [...Object.values(ListItemVariant)],
},
active: { control: { type: 'boolean' } },
size: {
control: {
type: 'select',
},
options: ListItemSize,
},
description: '고객이 첫 메시지를 보내거나, 매니저가 상담을 다시 열거나, 자동으로 리오픈되면 트리거됩니다.',
descriptionMaxLines: 2,
},
}

interface CompositionProps {
listRange: number
}
const list = range(0, 10)

const CompositionTemplate = ({ listRange }: CompositionProps) => {
const [activeIndex, setActiveIndex] = useState<Set<number>>(() => {
const randomActiveIndex = Array.from(Array(listRange).keys()).map((index) => (Math.random() < 0.5 ? index : null))
return new Set(compact<number>([...randomActiveIndex]))
})
const CompositionTemplate = () => {
const [activeIndex, setActiveIndex] = useState<Set<number>>(new Set([0, 1, 2, 4]))

const isActive = (index: number) => activeIndex.has(index)

const toggleActive = (index: number) => setActiveIndex((prevSet) => {
if (prevSet.has(index)) {
prevSet.delete(index)
return new Set(Array.from(prevSet))
return new Set(prevSet)
}
return new Set(Array.from(prevSet.add(index)))
return new Set(prevSet.add(index))
})

const list = useMemo(() => Array.from(Array(listRange).keys()), [listRange])

return (
<div>
<div style={{ width: 200 }}>
{ list.map((index) => (
<ListItem
key={index}
className={isActive(index) ? 'active' : undefined}
optionKey={`menu-item-${index}`}
active={isActive(index)}
onClick={() => toggleActive(index)}
content={`이것은 ${index}번 아이템입니다.`}
content="Click me!"
/>
)) }
</div>
)
}

export const Composition: StoryObj<CompositionProps> = {
export const Composition: StoryObj = {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

composition 은 있어도 되지 않을까요? 여러개 붙어있을 때 border-radius 가 0인지 보여주는 게 좋아보입니다!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

기존 스토리에 추가해보도록 할게요

render: CompositionTemplate,

args: {
listRange: 10,
},

argTypes: {
listRange: {
control: {
type: 'range',
min: 2,
max: 20,
},
},
},
}

export default meta
Loading