Instantly share code, notes, and snippets.
Last active
April 12, 2021 21:17
-
Star
(0)
0
You must be signed in to star a gist -
Fork
(0)
0
You must be signed in to fork a gist
-
Save erickvieira/52038ce9ccf8208a55cb5c31506b7fcd to your computer and use it in GitHub Desktop.
AntD TagsCloud Component with StyledComponents
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react'; | |
import styled, { css } from 'styled-components'; | |
export interface TagsWrapperProps extends React.HTMLAttributes<HTMLDivElement> { | |
collapsed?: boolean; | |
uncollapsedHeight?: number | string; | |
} | |
const handleCollapse = (props: TagsWrapperProps) => css` | |
max-height: ${props.collapsed | |
? '22px' | |
: typeof props.uncollapsedHeight === 'string' | |
? props.uncollapsedHeight | |
: `${props.uncollapsedHeight}em`}; | |
overflow: ${props.collapsed ? 'hidden' : 'auto'}; | |
`; | |
export const TagsWrapper = styled.div.attrs((props: TagsWrapperProps) => ({ | |
...props, | |
collapsed: props.collapsed ?? false | |
}))` | |
flex: 1; | |
${handleCollapse} | |
transition: all 0.3s ease-in-out; | |
`; | |
export interface TagsCloudContentProps | |
extends React.HTMLAttributes<HTMLDivElement> { | |
showToggler?: boolean; | |
} | |
const handleShowToggle = (props: TagsCloudContentProps) => { | |
if (props.showToggler) { | |
return css` | |
margin-right: 32px; | |
position: relative; | |
& > .tags-cloud-toggler { | |
position: absolute; | |
bottom: 0; | |
left: calc(100% - 32px); | |
} | |
`; | |
} | |
}; | |
export const TagsCloudContent = styled.div.attrs( | |
(props: TagsCloudContentProps) => ({ | |
...props, | |
showToggler: props.showToggler ?? false | |
}) | |
)` | |
margin: 8px 0; | |
display: flex; | |
align-items: center; | |
width: 100%; | |
${handleShowToggle} | |
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { useCallback, useLayoutEffect, useRef, useState } from 'react'; | |
import { TagsWrapper, TagsCloudContent } from './TagsCloud.styled'; | |
import { Button } from 'antd'; | |
let defaultTogglerOffset: string | number = 'calc(100% - 32px)'; | |
export interface TagsCloudProps extends React.HTMLAttributes<HTMLDivElement> { | |
wrapperProps?: React.HTMLAttributes<HTMLDivElement>; | |
children: React.ReactNode; | |
tagsSelector?: string; | |
uncollapsedHeight?: string | number; | |
} | |
function TagsCloud({ | |
wrapperProps = {}, | |
children, | |
tagsSelector = '.ant-tag', | |
uncollapsedHeight = '12em', | |
...contentProps | |
}: TagsCloudProps) { | |
const [collapsed, setCollapsed] = useState(false); | |
const [shotToggler, setShowToggler] = useState(false); | |
const [togglerOffset, setTogglerOffset] = useState<string | number>( | |
defaultTogglerOffset | |
); | |
const tagsWrapperRef = useRef() as React.MutableRefObject<HTMLDivElement>; | |
useLayoutEffect(() => { | |
if (tagsWrapperRef?.current) { | |
const wrapperWidth = tagsWrapperRef.current.clientWidth; | |
const renderedTags = Array.from( | |
tagsWrapperRef.current.querySelectorAll(tagsSelector) | |
); | |
if (renderedTags.length === 0) return; | |
let childrenTotalWidth = 0; | |
let childDOMRect: DOMRect; | |
for (const index in renderedTags) { | |
childDOMRect = renderedTags[index].getBoundingClientRect(); | |
childrenTotalWidth += childDOMRect.width; | |
console.log({ | |
childrenTotalWidth, | |
wrapperWidth, | |
childDomRect: childDOMRect | |
}); | |
if (childrenTotalWidth > wrapperWidth) { | |
setCollapsed(true); | |
setShowToggler(true); | |
defaultTogglerOffset = childrenTotalWidth - childDOMRect.width + 8; | |
setTogglerOffset(defaultTogglerOffset); | |
break; | |
} | |
} | |
} | |
}, [tagsWrapperRef]); | |
const toggle = useCallback(() => { | |
if (collapsed) { | |
const lastTag = tagsWrapperRef.current.querySelector( | |
`${tagsSelector}:last-child` | |
); | |
setTogglerOffset(lastTag!.getBoundingClientRect().left + 20); | |
} else setTogglerOffset(defaultTogglerOffset); | |
setCollapsed(!collapsed); | |
}, [collapsed]); | |
return ( | |
<TagsCloudContent | |
{...contentProps} | |
className={`tags-cloud ${contentProps.className ?? ''}`} | |
showToggler={shotToggler}> | |
<TagsWrapper | |
{...wrapperProps} | |
ref={tagsWrapperRef} | |
collapsed={collapsed} | |
uncollapsedHeight={uncollapsedHeight}> | |
{children} | |
</TagsWrapper> | |
{shotToggler && ( | |
<Button | |
className="tags-cloud-toggler" | |
size="small" | |
type="link" | |
shape="circle" | |
onClick={toggle} | |
style={{ left: togglerOffset }}> | |
{collapsed ? '+' : '-'} | |
</Button> | |
)} | |
</TagsCloudContent> | |
); | |
} | |
export default TagsCloud; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment