1import { css } from '@emotion/core'; 2import * as React from 'react'; 3 4import { AdditionalProps } from '~/common/headingManager'; 5import PermalinkIcon from '~/components/icons/Permalink'; 6import withHeadingManager from '~/components/page-higher-order/withHeadingManager'; 7 8type BaseProps = { 9 component: any; 10 className?: string; 11}; 12 13type EnhancedProps = { 14 children: React.ReactNode; 15 nestingLevel?: number; 16 additionalProps?: AdditionalProps; 17 customIconStyle?: React.CSSProperties; 18 id?: string; 19}; 20 21class Permalink extends React.Component<BaseProps> { 22 render() { 23 const { component, className, children, ...rest } = this.props; 24 return React.cloneElement( 25 component, 26 { 27 className: [className, component.props.className || ''].join(' '), 28 ...rest, 29 }, 30 children 31 ); 32 } 33} 34 35const STYLES_CONTAINER = css` 36 position: relative; 37 38 .anchor-icon { 39 cursor: pointer; 40 position: absolute; 41 top: 8px; 42 width: 20px; 43 height: 20px; 44 visibility: hidden; 45 } 46 47 :hover { 48 .anchor-icon { 49 visibility: visible; 50 } 51 } 52`; 53 54const STYLES_CONTAINER_ANCHOR = css` 55 position: absolute; 56 top: 0; 57 left: -24px; 58 width: 20px; 59 height: 20px; 60`; 61 62const STYLES_CONTAINER_TARGET = css` 63 display: block; 64 position: absolute; 65 top: -100px; 66 visibility: hidden; 67`; 68 69/** 70 * Props: 71 * - children: Title or component containing title text 72 * - nestingLevel: Sidebar heading level override 73 * - additionalProps: Additional properties passed to component 74 */ 75export default withHeadingManager<EnhancedProps>(props => { 76 // NOTE(jim): Not the greatest way to generate permalinks. 77 // for now I've shortened the length of permalinks. 78 const component = props.children as JSX.Element; 79 const children = component.props.children || ''; 80 81 let permalinkKey = props.id; 82 83 const heading = props.headingManager.addHeading( 84 children, 85 props.nestingLevel, 86 props.additionalProps 87 ); 88 89 if (!permalinkKey) { 90 permalinkKey = heading.slug; 91 } 92 93 return ( 94 <Permalink component={component} data-components-heading> 95 <div css={STYLES_CONTAINER} ref={heading.ref}> 96 <span id={permalinkKey} css={STYLES_CONTAINER_TARGET} /> 97 <a 98 style={props.customIconStyle} 99 href={'#' + permalinkKey} 100 className="permalink" 101 css={STYLES_CONTAINER_ANCHOR}> 102 <PermalinkIcon /> 103 </a> 104 <div className="permalink-child">{children}</div> 105 </div> 106 </Permalink> 107 ); 108}); 109