Fix curveEditorPopover overwriting existing curve (#151)
* Fix curveEditorPopover overwriting existing curve * Fix existing curve overwrite, other reactivity
This commit is contained in:
parent
417233a7c6
commit
cd9d03076b
2 changed files with 36 additions and 18 deletions
|
@ -102,6 +102,7 @@ const NoResultsFoundContainer = styled.div`
|
|||
`
|
||||
|
||||
enum TextInputMode {
|
||||
init,
|
||||
user,
|
||||
auto,
|
||||
}
|
||||
|
@ -153,14 +154,16 @@ const CurveEditorPopover: React.FC<IProps> = (props) => {
|
|||
inputRef.current?.focus()
|
||||
}, [inputRef.current])
|
||||
|
||||
const [inputValue, setInputValue] = useState<string>('')
|
||||
const [inputValue, setInputValue] = useState<string>(
|
||||
cssCubicBezierArgsFromHandles(easing),
|
||||
)
|
||||
|
||||
const onInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setTextInputMode(TextInputMode.user)
|
||||
setInputValue(e.target.value)
|
||||
|
||||
const maybeHandles = handlesFromCssCubicBezierArgs(inputValue)
|
||||
if (maybeHandles) setEdit(inputValue)
|
||||
const maybeHandles = handlesFromCssCubicBezierArgs(e.target.value)
|
||||
if (maybeHandles) setEdit(e.target.value)
|
||||
}
|
||||
const onSearchKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {
|
||||
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
|
||||
// changes so that the user's search is preserved.
|
||||
const [textInputMode, setTextInputMode] = useState<TextInputMode>(
|
||||
TextInputMode.auto,
|
||||
TextInputMode.init,
|
||||
)
|
||||
useEffect(() => {
|
||||
if (textInputMode === TextInputMode.auto)
|
||||
|
@ -191,7 +194,9 @@ const CurveEditorPopover: React.FC<IProps> = (props) => {
|
|||
}, [trackData])
|
||||
|
||||
// `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.
|
||||
const [preview, setPreview] = useState<CSSCubicBezierArgsString | null>(null)
|
||||
|
||||
|
@ -214,18 +219,22 @@ const CurveEditorPopover: React.FC<IProps> = (props) => {
|
|||
|
||||
////// Preset reactivity //////
|
||||
const displayedPresets = useMemo(() => {
|
||||
const presetSearchResults = fuzzy.filter(inputValue, EASING_PRESETS, {
|
||||
extract: (el) => el.label,
|
||||
})
|
||||
const isInputValueAQuery = /^[A-Za-z]/.test(inputValue)
|
||||
|
||||
return isInputValueAQuery
|
||||
? presetSearchResults.map((result) => result.original)
|
||||
: EASING_PRESETS
|
||||
if (isInputValueAQuery) {
|
||||
return fuzzy
|
||||
.filter(inputValue, EASING_PRESETS, {
|
||||
extract: (el) => el.label,
|
||||
})
|
||||
.map((result) => result.original)
|
||||
} else {
|
||||
return EASING_PRESETS
|
||||
}
|
||||
}, [inputValue])
|
||||
// Use the first preset in the search when the displayed presets change
|
||||
useEffect(() => {
|
||||
if (displayedPresets[0]) setEdit(displayedPresets[0].value)
|
||||
if (textInputMode === TextInputMode.user && displayedPresets[0])
|
||||
setEdit(displayedPresets[0].value)
|
||||
}, [displayedPresets])
|
||||
|
||||
////// Option grid specification and reactivity //////
|
||||
|
@ -243,8 +252,10 @@ const CurveEditorPopover: React.FC<IProps> = (props) => {
|
|||
setPreview(item.value)
|
||||
const onEasingOptionMouseOut = () => setPreview(null)
|
||||
const onSelectEasingOption = (item: {label: string; value: string}) => {
|
||||
setTextInputMode(TextInputMode.auto)
|
||||
setEdit(item.value)
|
||||
setTempValue(tempTransaction, props, cur, next, item.value)
|
||||
props.onRequestClose()
|
||||
|
||||
return Outcome.Handled
|
||||
}
|
||||
|
||||
// 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
|
||||
maybePresetEl?.focus()
|
||||
setEdit(grid.currentSelection.value)
|
||||
const isInputValueAQuery = /^[A-Za-z]/.test(inputValue)
|
||||
if (!isInputValueAQuery) {
|
||||
setInputValue(grid.currentSelection.value)
|
||||
}
|
||||
}
|
||||
}, [grid.currentSelection])
|
||||
|
||||
|
|
|
@ -14,13 +14,13 @@ type UIOptionGridOptions<Item> = {
|
|||
items: Item[]
|
||||
/** display of items */
|
||||
renderItem: (value: {
|
||||
select(): void
|
||||
select(e?: Event): void
|
||||
/** data item */
|
||||
item: Item
|
||||
/** arrow key nav */
|
||||
isSelected: boolean
|
||||
}) => React.ReactNode
|
||||
onSelectItem(item: Item): void
|
||||
onSelectItem(item: Item): Outcome
|
||||
/** Set a callback for what to do if we try to leave the grid */
|
||||
canVerticleExit?: (exitSide: 'top' | 'bottom') => Outcome
|
||||
}
|
||||
|
@ -98,9 +98,12 @@ export function useUIOptionGrid<T>(
|
|||
options.renderItem({
|
||||
isSelected: idx === selectionIndex,
|
||||
item,
|
||||
select() {
|
||||
select(e) {
|
||||
setSelectionIndex(idx)
|
||||
options.onSelectItem(item)
|
||||
if (options.onSelectItem(item) === Outcome.Handled) {
|
||||
e?.preventDefault()
|
||||
e?.stopPropagation()
|
||||
}
|
||||
},
|
||||
}),
|
||||
),
|
||||
|
|
Loading…
Reference in a new issue