Fix curveEditorPopover overwriting existing curve (#151)

* Fix curveEditorPopover overwriting existing curve

* Fix existing curve overwrite, other reactivity
This commit is contained in:
Elliot 2022-05-10 13:14:32 -04:00 committed by GitHub
parent 417233a7c6
commit cd9d03076b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 36 additions and 18 deletions

View file

@ -102,6 +102,7 @@ const NoResultsFoundContainer = styled.div`
` `
enum TextInputMode { enum TextInputMode {
init,
user, user,
auto, auto,
} }
@ -153,14 +154,16 @@ const CurveEditorPopover: React.FC<IProps> = (props) => {
inputRef.current?.focus() inputRef.current?.focus()
}, [inputRef.current]) }, [inputRef.current])
const [inputValue, setInputValue] = useState<string>('') const [inputValue, setInputValue] = useState<string>(
cssCubicBezierArgsFromHandles(easing),
)
const onInputChange = (e: React.ChangeEvent<HTMLInputElement>) => { const onInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setTextInputMode(TextInputMode.user) setTextInputMode(TextInputMode.user)
setInputValue(e.target.value) setInputValue(e.target.value)
const maybeHandles = handlesFromCssCubicBezierArgs(inputValue) const maybeHandles = handlesFromCssCubicBezierArgs(e.target.value)
if (maybeHandles) setEdit(inputValue) if (maybeHandles) setEdit(e.target.value)
} }
const onSearchKeyDown = (e: KeyboardEvent<HTMLInputElement>) => { const onSearchKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {
setTextInputMode(TextInputMode.user) setTextInputMode(TextInputMode.user)
@ -183,7 +186,7 @@ const CurveEditorPopover: React.FC<IProps> = (props) => {
// in user mode, the text input field does not update when the curve // in user mode, the text input field does not update when the curve
// changes so that the user's search is preserved. // changes so that the user's search is preserved.
const [textInputMode, setTextInputMode] = useState<TextInputMode>( const [textInputMode, setTextInputMode] = useState<TextInputMode>(
TextInputMode.auto, TextInputMode.init,
) )
useEffect(() => { useEffect(() => {
if (textInputMode === TextInputMode.auto) if (textInputMode === TextInputMode.auto)
@ -191,7 +194,9 @@ const CurveEditorPopover: React.FC<IProps> = (props) => {
}, [trackData]) }, [trackData])
// `edit` keeps track of the current edited state of the curve. // `edit` keeps track of the current edited state of the curve.
const [edit, setEdit] = useState<CSSCubicBezierArgsString | null>(null) const [edit, setEdit] = useState<CSSCubicBezierArgsString | null>(
cssCubicBezierArgsFromHandles(easing),
)
// `preview` is used when hovering over a curve to preview it. // `preview` is used when hovering over a curve to preview it.
const [preview, setPreview] = useState<CSSCubicBezierArgsString | null>(null) const [preview, setPreview] = useState<CSSCubicBezierArgsString | null>(null)
@ -214,18 +219,22 @@ const CurveEditorPopover: React.FC<IProps> = (props) => {
////// Preset reactivity ////// ////// Preset reactivity //////
const displayedPresets = useMemo(() => { const displayedPresets = useMemo(() => {
const presetSearchResults = fuzzy.filter(inputValue, EASING_PRESETS, {
extract: (el) => el.label,
})
const isInputValueAQuery = /^[A-Za-z]/.test(inputValue) const isInputValueAQuery = /^[A-Za-z]/.test(inputValue)
return isInputValueAQuery if (isInputValueAQuery) {
? presetSearchResults.map((result) => result.original) return fuzzy
: EASING_PRESETS .filter(inputValue, EASING_PRESETS, {
extract: (el) => el.label,
})
.map((result) => result.original)
} else {
return EASING_PRESETS
}
}, [inputValue]) }, [inputValue])
// Use the first preset in the search when the displayed presets change // Use the first preset in the search when the displayed presets change
useEffect(() => { useEffect(() => {
if (displayedPresets[0]) setEdit(displayedPresets[0].value) if (textInputMode === TextInputMode.user && displayedPresets[0])
setEdit(displayedPresets[0].value)
}, [displayedPresets]) }, [displayedPresets])
////// Option grid specification and reactivity ////// ////// Option grid specification and reactivity //////
@ -243,8 +252,10 @@ const CurveEditorPopover: React.FC<IProps> = (props) => {
setPreview(item.value) setPreview(item.value)
const onEasingOptionMouseOut = () => setPreview(null) const onEasingOptionMouseOut = () => setPreview(null)
const onSelectEasingOption = (item: {label: string; value: string}) => { const onSelectEasingOption = (item: {label: string; value: string}) => {
setTextInputMode(TextInputMode.auto) setTempValue(tempTransaction, props, cur, next, item.value)
setEdit(item.value) props.onRequestClose()
return Outcome.Handled
} }
// A map to store all html elements corresponding to easing options // A map to store all html elements corresponding to easing options
@ -316,6 +327,10 @@ const CurveEditorPopover: React.FC<IProps> = (props) => {
optionsRef.current?.[grid.currentSelection.label]?.current optionsRef.current?.[grid.currentSelection.label]?.current
maybePresetEl?.focus() maybePresetEl?.focus()
setEdit(grid.currentSelection.value) setEdit(grid.currentSelection.value)
const isInputValueAQuery = /^[A-Za-z]/.test(inputValue)
if (!isInputValueAQuery) {
setInputValue(grid.currentSelection.value)
}
} }
}, [grid.currentSelection]) }, [grid.currentSelection])

View file

@ -14,13 +14,13 @@ type UIOptionGridOptions<Item> = {
items: Item[] items: Item[]
/** display of items */ /** display of items */
renderItem: (value: { renderItem: (value: {
select(): void select(e?: Event): void
/** data item */ /** data item */
item: Item item: Item
/** arrow key nav */ /** arrow key nav */
isSelected: boolean isSelected: boolean
}) => React.ReactNode }) => React.ReactNode
onSelectItem(item: Item): void onSelectItem(item: Item): Outcome
/** Set a callback for what to do if we try to leave the grid */ /** Set a callback for what to do if we try to leave the grid */
canVerticleExit?: (exitSide: 'top' | 'bottom') => Outcome canVerticleExit?: (exitSide: 'top' | 'bottom') => Outcome
} }
@ -98,9 +98,12 @@ export function useUIOptionGrid<T>(
options.renderItem({ options.renderItem({
isSelected: idx === selectionIndex, isSelected: idx === selectionIndex,
item, item,
select() { select(e) {
setSelectionIndex(idx) setSelectionIndex(idx)
options.onSelectItem(item) if (options.onSelectItem(item) === Outcome.Handled) {
e?.preventDefault()
e?.stopPropagation()
}
}, },
}), }),
), ),