import React, { Fragment, useState, useEffect, useRef, Children } from 'react' import PropTypes from 'prop-types' import classNames from 'classnames' import { window, document } from 'browser-monads' import Section from './section' import Icon from './icon' import { H2 } from './typography' import { copyToClipboard } from './copy' import classes from '../styles/quickstart.module.sass' function getNewChecked(optionId, checkedForId, multiple) { if (!multiple) return [optionId] if (checkedForId.includes(optionId)) return checkedForId.filter((opt) => opt !== optionId) return [...checkedForId, optionId] } const Quickstart = ({ data = [], title, description, copy = true, download, rawContent = null, id = 'quickstart', setters = {}, showDropdown = {}, hidePrompts, small, codeLang, Container = Section, children, }) => { const contentRef = useRef() const copyAreaRef = useRef() const isClient = typeof window !== 'undefined' const supportsCopy = isClient && document.queryCommandSupported('copy') const showCopy = supportsCopy && copy const [checked, setChecked] = useState({}) const [initialized, setInitialized] = useState(false) const [copySuccess, setCopySuccess] = useState(false) const [otherState, setOtherState] = useState({}) const setOther = (id, value) => setOtherState({ ...otherState, [id]: value }) const getRawContent = (ref) => { if (rawContent !== null) return rawContent if (ref.current && ref.current.childNodes) { // Select all currently visible nodes (spans and text nodes) const result = [...ref.current.childNodes].filter((el) => el.offsetParent !== null) return result.map((el) => el.textContent).join('\n') } return '' } const onClickCopy = () => { copyAreaRef.current.value = getRawContent(contentRef) copyToClipboard(copyAreaRef, setCopySuccess) } useEffect(() => { window.dispatchEvent(new Event('resize')) // scroll position for progress if (!initialized) { const initialChecked = Object.assign( {}, ...data.map(({ id, options = [] }) => ({ [id]: options.filter((option) => option.checked).map(({ id }) => id), })) ) setChecked(initialChecked) setInitialized(true) } }, [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 : (
{title && (

{title}

)} {description &&

{description}

} {data.map( ({ id, title, options = [], dropdown = [], defaultValue, multiple, other, help, hidden, }) => { // Optional function that's called with the value const setterFunc = setters[id] || (() => {}) // Check if dropdown should be shown const dropdownGetter = showDropdown[id] || (() => true) return hidden ? null : (
{title} {help && ( {' '} )}
{options.map((option) => { const optionType = multiple ? 'checkbox' : 'radio' const checkedForId = checked[id] || [] return ( { const newChecked = { ...checked, [id]: getNewChecked( option.id, checkedForId, multiple ), } setChecked(newChecked) setterFunc(newChecked[id]) }} type={optionType} className={classNames( classes['input'], classes[optionType] )} name={id} id={`quickstart-${option.id}`} value={option.id} checked={checkedForId.includes(option.id)} /> ) })} {!!dropdown.length && ( )} {other && otherState[id] && ( setterFunc(target.value)} /> )}
) } )}
                    
                        {Children.toArray(children).flat().filter(isRelevant)}
                    

                    
                        {showCopy && (
                            
                        )}
                        {download && (
                            
                                
                            
                        )}
                    
                
{showCopy && (