import classnames from 'classnames'; import { memo, useEffect, useMemo, useState } from 'react'; import type { GenericCompletionOption } from './Editor/genericCompletion'; import { IconButton } from './IconButton'; import { Input } from './Input'; import { VStack } from './Stacks'; interface Props { pairs: Pair[]; onChange: (pairs: Pair[]) => void; className?: string; } interface Pair { name: string; value: string; } interface PairContainer { pair: Pair; id: string; } export const PairEditor = memo(function PairEditor({ pairs: originalPairs, className, onChange, }: Props) { const newPairContainer = (): PairContainer => { return { pair: { name: '', value: '' }, id: Math.random().toString() }; }; const [pairs, setPairs] = useState(() => { // Remove empty headers on initial render const nonEmpty = originalPairs.filter((h) => !(h.name === '' && h.value === '')); const pairs = nonEmpty.map((h) => ({ pair: h, id: Math.random().toString() })); return [...pairs, newPairContainer()]; }); const setPairsAndSave = (fn: (pairs: PairContainer[]) => PairContainer[]) => { setPairs((oldPairs) => { const pairs = fn(oldPairs).map((p) => p.pair); onChange(pairs); return fn(oldPairs); }); }; const handleChangeHeader = (pair: PairContainer) => { setPairsAndSave((pairs) => pairs.map((p) => (pair.id !== p.id ? p : pair))); }; // Ensure there's always at least one pair useEffect(() => { if (pairs.length === 0) { setPairs((pairs) => [...pairs, newPairContainer()]); } }, [pairs]); const handleDelete = (pair: PairContainer) => { setPairsAndSave((oldPairs) => oldPairs.filter((p) => p.id !== pair.id)); }; return (
{pairs.map((p, i) => { const isLast = i === pairs.length - 1; return ( { if (isLast) { setPairs((pairs) => [...pairs, newPairContainer()]); } }} onDelete={isLast ? undefined : handleDelete} /> ); })}
); }); const FormRow = memo(function FormRow({ pairContainer, onChange, onDelete, onFocus, isLast, }: { pairContainer: PairContainer; onChange: (pair: PairContainer) => void; onDelete?: (pair: PairContainer) => void; onFocus?: () => void; isLast?: boolean; }) { const { id } = pairContainer; const valueOptions = useMemo(() => { if (pairContainer.pair.name.toLowerCase() === 'content-type') { return [ { label: 'application/json', type: 'constant' }, { label: 'text/xml', type: 'constant' }, { label: 'text/html', type: 'constant' }, ]; } return undefined; }, [pairContainer.pair.value]); return (
onChange({ id, pair: { name, value: pairContainer.pair.value } })} onFocus={onFocus} placeholder={isLast ? 'new name' : 'name'} useEditor={{ useTemplating: true, autocompleteOptions: [{ label: 'Content-Type', type: 'constant' }], }} /> onChange({ id, pair: { name: pairContainer.pair.name, value } })} onFocus={onFocus} placeholder={isLast ? 'new value' : 'value'} useEditor={{ useTemplating: true, autocompleteOptions: valueOptions }} /> {onDelete ? ( onDelete(pairContainer)} tabIndex={-1} className={classnames('opacity-0 group-hover:opacity-100')} /> ) : ( )}
); });