refactor: refactor breadcrumb component

This commit is contained in:
jinhojang6 2023-02-16 01:10:18 +09:00
parent 9c97071103
commit 4cb6e5a541
No known key found for this signature in database
GPG Key ID: 0E7AA62CB0D9E6F3
8 changed files with 67 additions and 104 deletions

View File

@ -2,15 +2,7 @@ export const breadcrumbClasses = {
root: `lsd-breadcrumb`, root: `lsd-breadcrumb`,
list: `lsd-breadcrumb-list`, list: `lsd-breadcrumb-list`,
trigger: `lsd-breadcrumb-trigger`,
triggerLabel: `lsd-breadcrumb-trigger__label`,
triggerIcons: `lsd-breadcrumb-trigger-icons`,
triggerIcon: `lsd-breadcrumb-trigger-icons__icon`,
triggerMenuIcon: `lsd-breadcrumb-trigger-icons__menu-icon`,
listBox: 'lsd-breadcrumb-list-box', listBox: 'lsd-breadcrumb-list-box',
listBoxLarge: 'lsd-breadcrumb-list-box-large',
listBoxMedium: 'lsd-breadcrumb-list-box-medium',
open: 'lsd-breadcrumb--open', open: 'lsd-breadcrumb--open',
disabled: 'lsd-breadcrumb--disabled', disabled: 'lsd-breadcrumb--disabled',

View File

@ -11,13 +11,6 @@ export default {
value: ['small', 'medium', 'large'], value: ['small', 'medium', 'large'],
}, },
}, },
maxItems: {
control: {
type: 'number',
min: 2,
max: 6,
},
},
}, },
} as Meta } as Meta

View File

@ -26,21 +26,12 @@ export const BreadcrumbStyles = css`
display: flex; display: flex;
flex-direction: column; flex-direction: column;
max-height: 400px; max-height: 400px;
max-width: 148px;
overflow: auto; overflow: auto;
border: 1px solid rgb(var(--lsd-border-primary)); border: 1px solid rgb(var(--lsd-border-primary));
margin-top: 10px; margin-top: 10px;
margin-left: 20px;
position: absolute; position: absolute;
} width: auto !important;
// Portal cannot be ralatively positioned
.${breadcrumbClasses.listBoxLarge} {
margin-left: 92px;
}
// Portal cannot be ralatively positioned
.${breadcrumbClasses.listBoxMedium} {
margin-left: 82px;
} }
.${breadcrumbClasses.listBox} > a { .${breadcrumbClasses.listBox} > a {

View File

@ -39,8 +39,29 @@ export const Breadcrumb: React.FC<BreadcrumbProps> & {
options = [], options = [],
...props ...props
}) => { }) => {
const ref = useRef<HTMLUListElement>(null) const ellipsisRef = useRef<HTMLLIElement>(null)
const [open, setOpen] = useState(false) const [open, setOpen] = useState<boolean>(false)
maxItems = Math.max(1, Math.min(maxItems || 1, options.length))
const [root, ...rest] = options
const [collapsed, visible] = !ellipsis
? [[], rest]
: [
rest.slice(0, rest.length - maxItems + 1),
rest.slice(rest.length - maxItems + 1),
]
const renderItems = (items: BreadcrumbOption[]) =>
items.map((item, idx) => (
<BreadcrumbItem
key={idx}
current={idx === visible.length - 1}
label={item.value}
size={size}
link={item.link}
/>
))
const onTrigger = () => { const onTrigger = () => {
!disabled && setOpen((value) => !value) !disabled && setOpen((value) => !value)
@ -61,64 +82,33 @@ export const Breadcrumb: React.FC<BreadcrumbProps> & {
open && breadcrumbClasses.open, open && breadcrumbClasses.open,
)} )}
> >
<ul ref={ref} className={breadcrumbClasses.list}> <ul className={breadcrumbClasses.list}>
{!ellipsis || maxItems === options.length {root && renderItems([root])}
? options.map((opt, idx) => ( {collapsed.length > 0 && (
<BreadcrumbItem <BreadcrumbItem
current={idx === options.length - 1} ellipsisRef={ellipsisRef}
label={opt.value} size={size}
size={size} label={'...'}
link={opt.link} onClick={onTrigger}
/> />
)) )}
: options.map((opt, idx) => { {renderItems(visible)}
if (idx === 1)
return (
<BreadcrumbItem
size={size}
label={'...'}
onClick={onTrigger}
/>
)
else if (
maxItems &&
maxItems > 1 &&
maxItems < options.length &&
idx > 1 &&
idx < options.length - maxItems + 1
)
return null
else
return (
<BreadcrumbItem
current={idx === options.length - 1}
label={opt.value}
size={size}
link={opt.link}
/>
)
})}
</ul> </ul>
{ellipsis && maxItems && ( {ellipsisRef?.current != null && ellipsis && maxItems && (
<Portal id="breadcrumb"> <Portal id="breadcrumb">
<ListBox <ListBox
handleRef={ref} handleRef={ellipsisRef}
open={open} open={open}
onClose={() => setOpen(false)} onClose={() => setOpen(false)}
className={clsx( className={clsx(breadcrumbClasses.listBox)}
breadcrumbClasses.listBox,
size === 'large'
? breadcrumbClasses.listBoxLarge
: breadcrumbClasses.listBoxMedium,
)}
> >
{options.slice(1, options.length - maxItems + 1).map((opt) => ( {collapsed.map((opt) => (
<Typography <Typography
color="primary" color="primary"
component="a" component="a"
href={opt.link} href={opt.link}
variant={size === 'large' ? 'label1' : 'label2'} variant={size === 'large' ? 'label1' : 'label2'}
className={breadcrumbItemClasses.listElementLink} className={breadcrumbItemClasses.elementLink}
> >
{opt.value} {opt.value}
</Typography> </Typography>

View File

@ -1,13 +1,9 @@
export const breadcrumbItemClasses = { export const breadcrumbItemClasses = {
root: `lsd-breadcrumb-item`, root: `lsd-breadcrumb-item`,
label: `lsd-breadcrumb-item__label`,
listElement: `lsd-breadcrumb-item-list-element`, element: `lsd-breadcrumb-item-element`,
listElementCurrentPage: `lsd-breadcrumb-item-list-element-current-page`, elementCurrentPage: `lsd-breadcrumb-item-element--current-page`,
listElementLink: `lsd-breadcrumb-item-list-element__link`, elementLink: `lsd-breadcrumb-item-element-link`,
disabled: 'lsd-breadcrumb-item--disabled',
selected: 'lsd-breadcrumb-item--selected',
small: `lsd-breadcrumb-item--small`, small: `lsd-breadcrumb-item--small`,
medium: `lsd-breadcrumb-item--medium`, medium: `lsd-breadcrumb-item--medium`,

View File

@ -12,22 +12,22 @@ export const BreadcrumbItemStyles = css`
content: '/'; content: '/';
} }
.${breadcrumbItemClasses.listElement} { .${breadcrumbItemClasses.element} {
list-style-type: none; list-style-type: none;
} }
.${breadcrumbItemClasses.listElementLink} { .${breadcrumbItemClasses.elementLink} {
text-decoration: none; text-decoration: none;
cursor: pointer; cursor: pointer;
} }
.${breadcrumbItemClasses.listElementCurrentPage} { .${breadcrumbItemClasses.elementCurrentPage} {
border: 1px solid #000000; border: 1px solid rgb(var(--lsd-border-primary));
padding: 4px 12px; padding: 4px 12px;
} }
.${breadcrumbClasses.root}:not(.${breadcrumbClasses.disabled}) { .${breadcrumbClasses.root}:not(.${breadcrumbClasses.disabled}) {
.${breadcrumbItemClasses.listElementLink} { .${breadcrumbItemClasses.elementLink} {
&:hover, &:hover,
&:focus { &:focus {
text-decoration: underline; text-decoration: underline;
@ -35,13 +35,6 @@ export const BreadcrumbItemStyles = css`
} }
} }
.${breadcrumbItemClasses.label} {
}
.${breadcrumbItemClasses.disabled} {
opacity: 0.34;
}
.${breadcrumbItemClasses.small} { .${breadcrumbItemClasses.small} {
padding: 6px 10px; padding: 6px 10px;
} }

View File

@ -10,31 +10,37 @@ export type BreadcrumbItemProps = React.HTMLAttributes<HTMLDivElement> & {
current?: boolean current?: boolean
disabled?: boolean disabled?: boolean
selected?: boolean selected?: boolean
ellipsisRef?: React.RefObject<HTMLLIElement>
onClick?: () => void onClick?: () => void
} }
export const BreadcrumbItem: React.FC<BreadcrumbItemProps> & { export const BreadcrumbItem: React.FC<BreadcrumbItemProps> & {
classes: typeof breadcrumbItemClasses classes: typeof breadcrumbItemClasses
} = ({ label, link, size = 'large', current, onClick, selected }) => { } = ({
label,
link,
size = 'large',
current,
selected,
ellipsisRef,
onClick,
}) => {
return ( return (
<li <li
className={clsx(breadcrumbItemClasses.listElement)} className={clsx(breadcrumbItemClasses.element)}
aria-selected={selected ? 'true' : 'false'} aria-selected={selected ? 'true' : 'false'}
onClick={onClick} onClick={onClick}
ref={ellipsisRef}
> >
<Typography <Typography
color="primary" color="primary"
component="a" component="a"
href={link} href={link}
variant={size === 'large' ? 'label1' : 'label2'} variant={size === 'large' ? 'label1' : 'label2'}
className={ className={clsx(
current breadcrumbItemClasses.elementLink,
? clsx( current && breadcrumbItemClasses.elementCurrentPage,
breadcrumbItemClasses.listElementLink, )}
breadcrumbItemClasses.listElementCurrentPage,
)
: breadcrumbItemClasses.listElementLink
}
> >
{label} {label}
</Typography> </Typography>

View File

@ -7,3 +7,5 @@ export * from './components/ListBox'
export * from './components/TabItem' export * from './components/TabItem'
export * from './components/Tabs' export * from './components/Tabs'
export * from './components/Theme' export * from './components/Theme'
export * from './components/Breadcrumb'
export * from './components/BreadcrumbItem'