Refactor Quickstart component

The previous implementation was hidding the irrelevant lines via data-props and dynamically generated CSS. This created problems with Next and was also hard to follow. CSS was used to do what React is supposed to handle.

The new implementation simplfy filters the list of children (React elements) via their props.
This commit is contained in:
Marcus Blättermann 2022-12-13 07:04:27 +01:00
parent 4b315d1c4c
commit 04ec2c0e93
No known key found for this signature in database
GPG Key ID: A1E1F04008AC450D

View File

@ -1,4 +1,4 @@
import React, { Fragment, useState, useEffect, useRef } from 'react' import React, { Fragment, useState, useEffect, useRef, Children } from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import classNames from 'classnames' import classNames from 'classnames'
import { window, document } from 'browser-monads' import { window, document } from 'browser-monads'
@ -36,7 +36,6 @@ const Quickstart = ({
const isClient = typeof window !== 'undefined' const isClient = typeof window !== 'undefined'
const supportsCopy = isClient && document.queryCommandSupported('copy') const supportsCopy = isClient && document.queryCommandSupported('copy')
const showCopy = supportsCopy && copy const showCopy = supportsCopy && copy
const [styles, setStyles] = useState({})
const [checked, setChecked] = useState({}) const [checked, setChecked] = useState({})
const [initialized, setInitialized] = useState(false) const [initialized, setInitialized] = useState(false)
const [copySuccess, setCopySuccess] = useState(false) const [copySuccess, setCopySuccess] = useState(false)
@ -57,14 +56,6 @@ const Quickstart = ({
copyToClipboard(copyAreaRef, setCopySuccess) copyToClipboard(copyAreaRef, setCopySuccess)
} }
const getCss = (id, checkedOptions) => {
const checkedForId = checkedOptions[id] || []
const exclude = checkedForId
.map((value) => `:not([data-quickstart-${id}="${value}"])`)
.join('')
return `[data-quickstart-results]>[data-quickstart-${id}]${exclude} {display: none}`
}
useEffect(() => { useEffect(() => {
window.dispatchEvent(new Event('resize')) // scroll position for progress window.dispatchEvent(new Event('resize')) // scroll position for progress
if (!initialized) { if (!initialized) {
@ -74,16 +65,25 @@ const Quickstart = ({
[id]: options.filter((option) => option.checked).map(({ id }) => id), [id]: options.filter((option) => option.checked).map(({ id }) => id),
})) }))
) )
const initialStyles = Object.assign(
{},
...data.map(({ id }) => ({ [id]: getCss(id, initialChecked) }))
)
setChecked(initialChecked) setChecked(initialChecked)
setStyles(initialStyles)
setInitialized(true) setInitialized(true)
} }
}, [data, initialized]) }, [data, initialized])
const isRelevant = (child) => {
if (typeof child === 'string' || child.type !== QS) {
return true
}
return data.every((itemData) => {
return (
!child.props[itemData.id] ||
!checked[itemData.id] ||
checked[itemData.id].includes(child.props[itemData.id])
)
})
}
return !data.length ? null : ( return !data.length ? null : (
<Container id={id}> <Container id={id}>
<div <div
@ -117,10 +117,6 @@ const Quickstart = ({
const dropdownGetter = showDropdown[id] || (() => true) const dropdownGetter = showDropdown[id] || (() => true)
return hidden ? null : ( return hidden ? null : (
<div key={id} data-quickstart-group={id} className={classes['group']}> <div key={id} data-quickstart-group={id} className={classes['group']}>
<style data-quickstart-style={id} scoped>
{styles[id] ||
`[data-quickstart-results]>[data-quickstart-${id}] { display: none }`}
</style>
<div className={classes['legend']}> <div className={classes['legend']}>
{title} {title}
{help && ( {help && (
@ -147,10 +143,6 @@ const Quickstart = ({
), ),
} }
setChecked(newChecked) setChecked(newChecked)
setStyles({
...styles,
[id]: getCss(id, newChecked),
})
setterFunc(newChecked[id]) setterFunc(newChecked[id])
}} }}
type={optionType} type={optionType}
@ -231,7 +223,7 @@ const Quickstart = ({
data-quickstart-results="" data-quickstart-results=""
ref={contentRef} ref={contentRef}
> >
{children} {Children.toArray(children).flat().filter(isRelevant)}
</code> </code>
<menu className={classes['menu']}> <menu className={classes['menu']}>
@ -295,17 +287,7 @@ const QS = ({ children, prompt = 'bash', divider = false, comment = false, ...pr
[classes['divider']]: !!divider, [classes['divider']]: !!divider,
[classes['comment']]: !!comment, [classes['comment']]: !!comment,
}) })
const attrs = Object.assign( return <span className={qsClassNames}>{children}</span>
{},
...Object.keys(props).map((key) => ({
[`data-quickstart-${key}`]: props[key],
}))
)
return (
<span className={qsClassNames} {...attrs}>
{children}
</span>
)
} }
export { Quickstart, QS } export { Quickstart, QS }