mirror of
https://github.com/datahub-project/datahub.git
synced 2025-11-08 23:43:04 +00:00
65 lines
2.3 KiB
TypeScript
65 lines
2.3 KiB
TypeScript
import { useRemirrorContext } from '@remirror/react';
|
|
import { ActionKind, AutocompleteAction, FromTo } from 'prosemirror-autocomplete';
|
|
import { useCallback, useEffect, useState } from 'react';
|
|
|
|
import { DataHubMentionsExtension } from '@components/components/Editor/extensions/mentions/DataHubMentionsExtension';
|
|
|
|
type State = {
|
|
active: boolean;
|
|
range?: FromTo;
|
|
filter?: string;
|
|
};
|
|
|
|
type UseDataHubMentionsProps<T> = {
|
|
items?: T[];
|
|
onEnter?(item: T): boolean;
|
|
};
|
|
|
|
/**
|
|
* This hook is a helper utility to read actions from prosemirror-autocomplete, allowing components
|
|
* to react to these changes accordingly. It provides the postional and query metadata of the currently
|
|
* active autocomplete menu. In addition, this hooks stores the selected index triggered
|
|
* when using the arrow keys to navigate the autocomplete menu.
|
|
*/
|
|
export function useDataHubMentions<Item = any>(props: UseDataHubMentionsProps<Item>) {
|
|
const [index, selectedIndex] = useState(0);
|
|
const rmrCtx = useRemirrorContext();
|
|
const ext = rmrCtx.getExtension(DataHubMentionsExtension);
|
|
const [state, setState] = useState<State>({ active: false });
|
|
const { items, onEnter } = props;
|
|
|
|
const handleEvents = useCallback(
|
|
(action: AutocompleteAction) => {
|
|
const active = !(action.kind === ActionKind.close || action.kind === ActionKind.enter);
|
|
setState({ active, range: action.range, filter: action.filter });
|
|
|
|
if (!items) {
|
|
return false;
|
|
}
|
|
|
|
const maxIndex = items.length - 1;
|
|
|
|
switch (action.kind) {
|
|
case ActionKind.enter:
|
|
return onEnter?.(items[index]) || true;
|
|
case ActionKind.up:
|
|
selectedIndex((i) => (i - 1 < 0 ? maxIndex : i - 1));
|
|
return true;
|
|
case ActionKind.down:
|
|
selectedIndex((i) => (i + 1 > maxIndex ? 0 : i + 1));
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
},
|
|
[items, onEnter, selectedIndex, index],
|
|
);
|
|
|
|
useEffect(() => {
|
|
const eventHandler = ext.addHandler('handleEvents', handleEvents);
|
|
return () => eventHandler();
|
|
}, [ext, handleEvents]);
|
|
|
|
return { ...state, selectedIndex: index };
|
|
}
|