mirror of https://github.com/fantasticit/think.git
improve bubble-menu placement
This commit is contained in:
parent
b2a485e513
commit
1d32808335
|
@ -19,9 +19,8 @@ export interface BubbleMenuPluginProps {
|
||||||
to?: number;
|
to?: number;
|
||||||
}) => boolean)
|
}) => boolean)
|
||||||
| null;
|
| null;
|
||||||
renderContainerSelector?: string;
|
|
||||||
matchRenderContainer?: (node: HTMLElement) => boolean;
|
|
||||||
getRenderContainer?: (node: HTMLElement) => HTMLElement;
|
getRenderContainer?: (node: HTMLElement) => HTMLElement;
|
||||||
|
defaultAnimation?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BubbleMenuViewProps = BubbleMenuPluginProps & {
|
export type BubbleMenuViewProps = BubbleMenuPluginProps & {
|
||||||
|
@ -43,6 +42,8 @@ export class BubbleMenuView {
|
||||||
|
|
||||||
public getRenderContainer?: BubbleMenuPluginProps['getRenderContainer'];
|
public getRenderContainer?: BubbleMenuPluginProps['getRenderContainer'];
|
||||||
|
|
||||||
|
public defaultAnimation?: BubbleMenuPluginProps['defaultAnimation'];
|
||||||
|
|
||||||
public shouldShow: Exclude<BubbleMenuPluginProps['shouldShow'], null> = ({ view, state, from, to }) => {
|
public shouldShow: Exclude<BubbleMenuPluginProps['shouldShow'], null> = ({ view, state, from, to }) => {
|
||||||
const { doc, selection } = state;
|
const { doc, selection } = state;
|
||||||
const { empty } = selection;
|
const { empty } = selection;
|
||||||
|
@ -59,11 +60,20 @@ export class BubbleMenuView {
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor({ editor, element, view, tippyOptions = {}, shouldShow, getRenderContainer }: BubbleMenuViewProps) {
|
constructor({
|
||||||
|
editor,
|
||||||
|
element,
|
||||||
|
view,
|
||||||
|
tippyOptions = {},
|
||||||
|
shouldShow,
|
||||||
|
getRenderContainer,
|
||||||
|
defaultAnimation = true,
|
||||||
|
}: BubbleMenuViewProps) {
|
||||||
this.editor = editor;
|
this.editor = editor;
|
||||||
this.element = element;
|
this.element = element;
|
||||||
this.view = view;
|
this.view = view;
|
||||||
this.getRenderContainer = getRenderContainer;
|
this.getRenderContainer = getRenderContainer;
|
||||||
|
this.defaultAnimation = defaultAnimation;
|
||||||
|
|
||||||
if (shouldShow) {
|
if (shouldShow) {
|
||||||
this.shouldShow = shouldShow;
|
this.shouldShow = shouldShow;
|
||||||
|
@ -133,7 +143,13 @@ export class BubbleMenuView {
|
||||||
placement: 'top',
|
placement: 'top',
|
||||||
hideOnClick: 'toggle',
|
hideOnClick: 'toggle',
|
||||||
...Object.assign(
|
...Object.assign(
|
||||||
{ zIndex: 999, duration: 200, animation: 'shift-toward-subtle', moveTransition: 'transform 0.2s ease-in-out' },
|
{
|
||||||
|
zIndex: 999,
|
||||||
|
duration: 200,
|
||||||
|
...(this.defaultAnimation
|
||||||
|
? { animation: 'shift-toward-subtle', moveTransition: 'transform 0.2s ease-in-out' }
|
||||||
|
: {}),
|
||||||
|
},
|
||||||
this.tippyOptions
|
this.tippyOptions
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
@ -159,8 +175,10 @@ export class BubbleMenuView {
|
||||||
|
|
||||||
// support for CellSelections
|
// support for CellSelections
|
||||||
const { ranges } = selection;
|
const { ranges } = selection;
|
||||||
|
const cursorAt = selection.$anchor.pos;
|
||||||
const from = Math.min(...ranges.map((range) => range.$from.pos));
|
const from = Math.min(...ranges.map((range) => range.$from.pos));
|
||||||
const to = Math.max(...ranges.map((range) => range.$to.pos));
|
const to = Math.max(...ranges.map((range) => range.$to.pos));
|
||||||
|
const placement = Math.abs(cursorAt - to) <= Math.abs(cursorAt - from) ? 'bottom' : 'top';
|
||||||
const domAtPos = view.domAtPos(from).node as HTMLElement;
|
const domAtPos = view.domAtPos(from).node as HTMLElement;
|
||||||
const nodeDOM = view.nodeDOM(from) as HTMLElement;
|
const nodeDOM = view.nodeDOM(from) as HTMLElement;
|
||||||
const node = nodeDOM || domAtPos;
|
const node = nodeDOM || domAtPos;
|
||||||
|
@ -183,6 +201,7 @@ export class BubbleMenuView {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.tippy?.setProps({
|
this.tippy?.setProps({
|
||||||
|
placement,
|
||||||
getReferenceClientRect: () => {
|
getReferenceClientRect: () => {
|
||||||
let toMountNode = null;
|
let toMountNode = null;
|
||||||
|
|
||||||
|
|
|
@ -25,9 +25,8 @@ export const BubbleMenu: React.FC<BubbleMenuProps> = (props) => {
|
||||||
editor,
|
editor,
|
||||||
tippyOptions = {},
|
tippyOptions = {},
|
||||||
shouldShow = null,
|
shouldShow = null,
|
||||||
// renderContainerSelector,
|
|
||||||
// matchRenderContainer,
|
|
||||||
getRenderContainer,
|
getRenderContainer,
|
||||||
|
defaultAnimation,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const plugin = BubbleMenuPlugin({
|
const plugin = BubbleMenuPlugin({
|
||||||
|
@ -36,9 +35,8 @@ export const BubbleMenu: React.FC<BubbleMenuProps> = (props) => {
|
||||||
element,
|
element,
|
||||||
tippyOptions,
|
tippyOptions,
|
||||||
shouldShow,
|
shouldShow,
|
||||||
// renderContainerSelector,
|
|
||||||
// matchRenderContainer,
|
|
||||||
getRenderContainer,
|
getRenderContainer,
|
||||||
|
defaultAnimation,
|
||||||
});
|
});
|
||||||
|
|
||||||
editor.registerPlugin(plugin);
|
editor.registerPlugin(plugin);
|
||||||
|
|
|
@ -65,6 +65,7 @@ export const Text = ({ editor }) => {
|
||||||
pluginKey="text-bubble-menu"
|
pluginKey="text-bubble-menu"
|
||||||
shouldShow={shouldShow}
|
shouldShow={shouldShow}
|
||||||
tippyOptions={{ maxWidth: 'calc(100vw - 100px)' }}
|
tippyOptions={{ maxWidth: 'calc(100vw - 100px)' }}
|
||||||
|
defaultAnimation={false}
|
||||||
>
|
>
|
||||||
<Space spacing={4}>
|
<Space spacing={4}>
|
||||||
<Bold editor={editor} />
|
<Bold editor={editor} />
|
||||||
|
|
Loading…
Reference in New Issue