mirror of https://github.com/acid-info/lsd.git
refactor: refactor breadcrumb component
This commit is contained in:
parent
9c97071103
commit
4cb6e5a541
|
@ -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',
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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`,
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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'
|
||||||
|
|
Loading…
Reference in New Issue