Skip to content

Commit

Permalink
chore: implement portal inside button component #2025
Browse files Browse the repository at this point in the history
  • Loading branch information
marek-mihok authored and mturoci committed Sep 6, 2023
1 parent ab32afb commit 3f00a90
Showing 1 changed file with 51 additions and 39 deletions.
90 changes: 51 additions & 39 deletions ui/src/copyable_text.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,22 @@ export interface CopyableText {
height?: S
}

type CopyButton = { value: S, anchorElement: HTMLElement | undefined, showOnHoverOnly?: B }
type CopyButton = {
/** Text to be copied to clipboard. */
value: S,
/** The element to which the copy button is attached. */
anchorElement: HTMLElement | undefined,
/** Show copy button only on hover. */
showOnHoverOnly?: B,
/** Use portal if ClipboardCopyButton is not direct child of the anchor element. */
portal?: B
}

export const ClipboardCopyButton = ({ value, anchorElement, showOnHoverOnly = false }: CopyButton) => {
export const ClipboardCopyButton = ({ value, anchorElement, showOnHoverOnly = false, portal = false }: CopyButton) => {
const
timeoutRef = React.useRef<U>(),
[copied, setCopied] = React.useState(false),
onClick = async () => {
onClick = React.useCallback(async () => {
if (!anchorElement) return
try {
if (document.queryCommandSupported('copy')) {
Expand All @@ -84,21 +93,29 @@ export const ClipboardCopyButton = ({ value, anchorElement, showOnHoverOnly = fa

setCopied(true)
timeoutRef.current = window.setTimeout(() => setCopied(false), 2000)
}
}, [anchorElement, value]),
CopyButton = React.useMemo(() => <Fluent.PrimaryButton
id='copybutton'
title='Copy to clipboard'
onClick={onClick}
iconProps={{ iconName: copied ? 'CheckMark' : 'Copy' }}
className={clas(css.btn, copied ? css.copiedBtn : '', showOnHoverOnly ? css.animate : '', showOnHoverOnly ? '' : css.visible)}
/>, [copied, onClick, showOnHoverOnly])

React.useEffect(() => {
if (showOnHoverOnly && anchorElement) anchorElement.classList.add(css.hover)
}, [anchorElement, showOnHoverOnly])
if (!anchorElement) return
if (portal) {
ReactDOM.render(
ReactDOM.createPortal(CopyButton, anchorElement),
document.createElement('div')
)
}
if (showOnHoverOnly) anchorElement.classList.add(css.hover)
}, [CopyButton, anchorElement, portal, showOnHoverOnly])

React.useEffect(() => () => window.clearTimeout(timeoutRef.current), [])

return (<Fluent.PrimaryButton
id='copybutton'
title='Copy to clipboard'
onClick={onClick}
iconProps={{ iconName: copied ? 'CheckMark' : 'Copy' }}
className={clas(css.btn, copied ? css.copiedBtn : '', showOnHoverOnly ? css.animate : '', showOnHoverOnly ? '' : css.visible)}
/>)
return portal ? null : CopyButton
}

export const XCopyableText = ({ model }: { model: CopyableText }) => {
Expand All @@ -111,32 +128,27 @@ export const XCopyableText = ({ model }: { model: CopyableText }) => {
if (inputEl) setInputEl(inputEl)
}, [])

React.useEffect(() => {
if (!inputEl) return
ReactDOM.render(
ReactDOM.createPortal(<ClipboardCopyButton value={value} anchorElement={inputEl} showOnHoverOnly={!!multiline} />, inputEl),
document.createElement('div')
)
}, [inputEl, multiline, value])

return (
<Fluent.TextField
data-test={name}
// Temporary solution which will be replaced with ref once TextField is converted to a function component.
elementRef={domRef}
value={value}
multiline={multiline}
label={label}
styles={{
root: {
...heightStyle,
textFieldRoot: { position: 'relative', width: pc(100) },
},
wrapper: heightStyle,
fieldGroup: heightStyle || { minHeight: height },
field: { ...heightStyle, height, resize: multiline ? 'vertical' : 'none', },
}}
readOnly
/>
<>
<Fluent.TextField
data-test={name}
// Temporary solution which will be replaced with ref once TextField is converted to a function component.
elementRef={domRef}
value={value}
multiline={multiline}
label={label}
styles={{
root: {
...heightStyle,
textFieldRoot: { position: 'relative', width: pc(100) },
},
wrapper: heightStyle,
fieldGroup: heightStyle || { minHeight: height },
field: { ...heightStyle, height, resize: multiline ? 'vertical' : 'none', },
}}
readOnly
/>
<ClipboardCopyButton value={value} anchorElement={inputEl} showOnHoverOnly={!!multiline} portal />
</>
)
}

0 comments on commit 3f00a90

Please sign in to comment.