Skip to content

Commit

Permalink
Refactor remaining Documentation components to TS
Browse files Browse the repository at this point in the history
  • Loading branch information
psdcoder committed Apr 7, 2020
1 parent 5a8821a commit bc25fec
Show file tree
Hide file tree
Showing 35 changed files with 1,297 additions and 1,287 deletions.
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,17 @@
"@types/classnames": "^2.2.10",
"@types/isomorphic-fetch": "^0.0.35",
"@types/lodash.includes": "^4.3.6",
"@types/lodash.startcase": "^4.4.6",
"@types/lodash.throttle": "^4.1.6",
"@types/lodash.topairs": "^4.3.6",
"@types/promise-polyfill": "^6.0.3",
"@types/react": "^16.9.27",
"@types/react-collapse": "^5.0.0",
"@types/react-dom": "^16.9.6",
"@types/react-helmet": "^5.0.15",
"@types/react-popover": "^0.5.3",
"@types/react-slick": "^0.23.4",
"@types/rehype-react": "^4.0.0",
"@types/styled-components": "^5.0.1",
"@types/vfile-message": "^1.0.1",
"@typescript-eslint/eslint-plugin": "^2.24.0",
Expand Down
6 changes: 6 additions & 0 deletions src/components/Documentation/Layout/styles.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
}

.side {
flex-shrink: 0;
width: 280px;
background-color: var(--color-light-blue);

Expand Down Expand Up @@ -103,5 +104,10 @@
.content {
display: flex;
flex-direction: row;
max-width: calc(100% - 280px);
background-color: #fff;

@media (--xs-scr) {
max-width: 100%;
}
}
133 changes: 133 additions & 0 deletions src/components/Documentation/Markdown/Tooltip/DesktopView/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import React, { useRef, useState, useEffect } from 'react'
import cn from 'classnames'
import ReactMarkdown from 'react-markdown'
import throttle from 'lodash.throttle'

import Portal from '../Portal'
import { getHeaderHeight } from '../../../../../utils/scroll'
import styles from './styles.module.css'

interface IDesktopViewProps {
description: string
header: string
text: React.ReactNode
}

interface ITooltipPosition {
left: number
top: number
arrow: ['l' | 'r', 't' | 'b']
}

const ARROW_SIZE = 10

const getPosition = (toggle: Element, tooltip: Element): ITooltipPosition => {
const toggleRect = toggle.getBoundingClientRect()
const tooltipRect = tooltip.getBoundingClientRect()
const windowWidth = document.documentElement.clientWidth
const headerHeight = getHeaderHeight()
const result: ITooltipPosition = { left: 0, top: 0, arrow: ['l', 'b'] }

if (windowWidth - tooltipRect.width > toggleRect.left) {
result.left = toggleRect.left
} else {
result.left = toggleRect.left + toggleRect.width - tooltipRect.width
result.arrow[0] = 'r'
}

if (toggleRect.top > tooltipRect.height + ARROW_SIZE + headerHeight) {
result.top = toggleRect.top - tooltipRect.height - ARROW_SIZE
} else {
result.top = toggleRect.top + toggleRect.height + ARROW_SIZE
result.arrow[1] = 't'
}

return result
}

const DesktopView: React.SFC<IDesktopViewProps> = ({
description,
header,
text
}) => {
const timeoutRef = useRef<number | undefined>()
const toggleRef = useRef<HTMLSpanElement>(null)
const tooltipRef = useRef<HTMLDivElement>(null)
const [tooltipPosition, setPosition] = useState<
ITooltipPosition | undefined
>()
const [isVisible, setVisible] = useState(false)
const calcPosition = () => {
if (!tooltipRef.current || !toggleRef.current) {
return
}

setPosition(getPosition(toggleRef.current, tooltipRef.current))
}
const throttledCalcPosition = throttle(calcPosition, 50)
const show = () => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current)
timeoutRef.current = undefined
}

setVisible(true)
}
const hide = () => {
timeoutRef.current = window.setTimeout(() => setVisible(false), 100)
}

useEffect(() => {
document.addEventListener('scroll', throttledCalcPosition)
window.addEventListener('resize', throttledCalcPosition)

return () => {
document.removeEventListener('scroll', throttledCalcPosition)
window.removeEventListener('resize', throttledCalcPosition)
}
}, [])
useEffect(() => {
if (!tooltipRef.current) {
return
}

calcPosition()
}, [isVisible, tooltipRef.current])

return (
<>
{isVisible && (
<Portal>
<div
ref={tooltipRef}
className={cn(
styles.tooltip,
tooltipPosition?.arrow && styles.calculated,
tooltipPosition?.arrow && styles[tooltipPosition.arrow.join('')]
)}
style={tooltipPosition}
onMouseOver={show}
onMouseLeave={hide}
onFocus={show}
onBlur={hide}
>
<div className={styles.tooltipHeader}>{header}</div>
<ReactMarkdown className="markdown-body" source={description} />
</div>
</Portal>
)}
<span
ref={toggleRef}
className={styles.highlightedText}
onMouseOver={show}
onMouseLeave={hide}
onFocus={show}
onBlur={hide}
>
{text}
</span>
</>
)
}

export default DesktopView
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
.highlightedText {
border-bottom: 1px black dotted;
}

.tooltip {
position: absolute;
display: none;
width: 400px;
padding: 8px 10px;
border: 1px solid var(--color-lighter-blue);
border-radius: 3px;
color: var(--color-black);
background-color: #fff;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);

&.calculated {
display: block;
}

&::after {
position: absolute;
content: '';
display: block;
height: 10px;
width: 10px;
border: none;
border-top: 1px solid var(--color-lighter-blue);
border-left: 2px solid var(--color-lighter-blue);
transform: rotate(90deg);
background-color: #fff;
}

&.lt::after,
&.rt::after {
top: -7px;
border-top-width: 2px;
border-left-width: 1px;
transform: rotate(45deg);
}

&.lt::after {
left: 27px;
}

&.rt::after {
right: 27px;
}

&.lb::after,
&.rb::after {
top: 100%;
margin-top: -4px;
transform: rotate(-135deg);
}

&.lb::after {
left: 27px;
}

&.rb::after {
right: 27px;
}
}

.tooltipHeader {
font-size: 1.3em;
font-weight: bold;
}
79 changes: 79 additions & 0 deletions src/components/Documentation/Markdown/Tooltip/MobileView/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import React, { useState } from 'react'
import cn from 'classnames'
import ReactMarkdown from 'react-markdown'

import Portal from '../Portal'

import styles from './styles.module.css'

interface IMobileViewProps {
description: string
header: string
text: React.ReactNode
}

const MobileView: React.SFC<IMobileViewProps> = ({
description,
header,
text
}) => {
const [isVisible, setVisible] = useState(false)
const openTooltip = (e: React.MouseEvent<HTMLSpanElement>) => {
e.stopPropagation()
setVisible(true)
}
const onOpenKeyDown = (e: React.KeyboardEvent) => {
if (e.which === 13 || e.which === 32) {
setVisible(true)
}
}
const closeTooltip = (e: React.MouseEvent<HTMLDivElement>) => {
e.stopPropagation()
setVisible(false)
}
const onCloseKeyDown = (e: React.KeyboardEvent) => {
if (e.which === 13 || e.which === 32) {
setVisible(false)
}
}

return (
<>
<span
className={styles.highlightedText}
onClick={openTooltip}
onKeyDown={onOpenKeyDown}
role="button"
tabIndex={0}
>
{text}
</span>
{isVisible && (
<Portal>
{/* eslint-disable jsx-a11y/no-static-element-interactions*/}
{/* eslint-disable jsx-a11y/click-events-have-key-events */}
<div className={styles.modalBackground} onClick={closeTooltip}>
{/* eslint-enable jsx-a11y/no-static-element-interactions*/}
{/* eslint-enable jsx-a11y/click-events-have-key-events */}
<div className={styles.modalContent}>
<div
className={styles.closeContainer}
onClick={closeTooltip}
onKeyPress={onCloseKeyDown}
role="button"
tabIndex={0}
>
<div className={cn(styles.closeLine, styles.first)} />
<div className={cn(styles.closeLine, styles.second)} />
</div>
<h5 className={styles.modalHeader}>{header}</h5>
<ReactMarkdown className="markdown-body" source={description} />
</div>
</div>
</Portal>
)}
</>
)
}

export default MobileView
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
.highlightedText {
border-bottom: 1px black dotted;
}

.modalBackground {
height: 100vh;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
background-color: rgba(0, 0, 0, 0.4);
}

.closeContainer {
float: right;
margin: 2px 10px 0 0;
}

.closeLine {
position: absolute;
height: 23px;
width: 2px;
background-color: black;

&.first {
transform: rotate(-45deg);
}

&.second {
transform: rotate(45deg);
}
}

.modalContent {
width: 80%;
padding: 8px 10px;
border: 1px solid var(--color-light-blue);
border-radius: 3px;
background-color: #fff;
}

.modalHeader {
font-size: 1.3em;
font-weight: bold;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import ReactDOM from 'react-dom'

const Portal: React.SFC<{ children: React.ReactNode }> = ({ children }) =>
ReactDOM.createPortal(
children,
document.getElementById('portal') as HTMLElement
)

export default Portal
Loading

0 comments on commit bc25fec

Please sign in to comment.