Skip to content

Commit 5971b85

Browse files
committed
remove tippy
1 parent a809189 commit 5971b85

3 files changed

Lines changed: 77 additions & 84 deletions

File tree

packages/ra-input-rich-text/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@
5555
"react": "^18.3.1",
5656
"react-dom": "^18.3.1",
5757
"react-hook-form": "^7.65.0",
58-
"tippy.js": "^6.3.7",
5958
"typescript": "^5.1.3",
6059
"zshy": "^0.5.0"
6160
},

packages/ra-input-rich-text/src/RichTextInput.stories.tsx

Lines changed: 76 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import fakeRestDataProvider from 'ra-data-fakerest';
2222
import { Routes, Route } from 'react-router-dom';
2323
import Mention from '@tiptap/extension-mention';
2424
import { Editor, ReactRenderer } from '@tiptap/react';
25-
import tippy, { Instance as TippyInstance } from 'tippy.js';
25+
import { computePosition, flip, shift, offset } from '@floating-ui/dom';
2626
import {
2727
DefaultEditorOptions,
2828
RichTextInput,
@@ -375,59 +375,48 @@ export const CustomOptions = () => (
375375
</TestMemoryRouter>
376376
);
377377

378-
const MentionList = React.forwardRef<
379-
MentionListRef,
380-
{
381-
items: string[];
382-
command: (props: { id: string }) => void;
383-
}
384-
>((props, ref) => {
378+
const MentionList = (props: {
379+
items: string[];
380+
command: (props: { id: string }) => void;
381+
onKeyDownRef: React.MutableRefObject<
382+
((props: { event: KeyboardEvent }) => boolean) | null
383+
>;
384+
}) => {
385385
const [selectedIndex, setSelectedIndex] = React.useState(0);
386386

387387
const selectItem = index => {
388388
const item = props.items[index];
389+
console.log('selectItem', index, item, props.command);
389390

390391
if (item) {
391392
props.command({ id: item });
392393
}
393394
};
394395

395-
const upHandler = () => {
396-
setSelectedIndex(
397-
(selectedIndex + props.items.length - 1) % props.items.length
398-
);
399-
};
400-
401-
const downHandler = () => {
402-
setSelectedIndex((selectedIndex + 1) % props.items.length);
403-
};
404-
405-
const enterHandler = () => {
406-
selectItem(selectedIndex);
407-
};
408-
409396
React.useEffect(() => setSelectedIndex(0), [props.items]);
410397

411-
React.useImperativeHandle(ref, () => ({
412-
onKeyDown: ({ event }) => {
398+
React.useEffect(() => {
399+
props.onKeyDownRef.current = ({ event }) => {
413400
if (event.key === 'ArrowUp') {
414-
upHandler();
401+
setSelectedIndex(
402+
i => (i + props.items.length - 1) % props.items.length
403+
);
415404
return true;
416405
}
417406

418407
if (event.key === 'ArrowDown') {
419-
downHandler();
408+
setSelectedIndex(i => (i + 1) % props.items.length);
420409
return true;
421410
}
422411

423412
if (event.key === 'Enter') {
424-
enterHandler();
413+
selectItem(selectedIndex);
425414
return true;
426415
}
427416

428417
return false;
429-
},
430-
}));
418+
};
419+
});
431420

432421
return (
433422
<Paper>
@@ -438,7 +427,11 @@ const MentionList = React.forwardRef<
438427
dense
439428
selected={index === selectedIndex}
440429
key={index}
441-
onClick={() => selectItem(index)}
430+
onMouseDown={e => {
431+
console.log('onMouseDown', index);
432+
e.preventDefault();
433+
selectItem(index);
434+
}}
442435
>
443436
{item}
444437
</ListItemButton>
@@ -451,10 +444,6 @@ const MentionList = React.forwardRef<
451444
</List>
452445
</Paper>
453446
);
454-
});
455-
456-
type MentionListRef = {
457-
onKeyDown: (props: { event: React.KeyboardEvent }) => boolean;
458447
};
459448
const suggestions = tags => {
460449
return {
@@ -467,75 +456,90 @@ const suggestions = tags => {
467456
},
468457

469458
render: () => {
470-
let component: ReactRenderer<MentionListRef>;
471-
let popup: TippyInstance[];
459+
let component: ReactRenderer;
460+
let floatingEl: HTMLElement;
461+
const onKeyDownRef: React.MutableRefObject<
462+
((props: { event: KeyboardEvent }) => boolean) | null
463+
> = { current: null };
464+
465+
const updatePosition = (clientRect: () => DOMRect) => {
466+
if (!floatingEl) return;
467+
const virtualEl = {
468+
getBoundingClientRect: clientRect,
469+
};
470+
computePosition(virtualEl, floatingEl, {
471+
placement: 'bottom-start',
472+
middleware: [offset(8), flip(), shift()],
473+
}).then(({ x, y }) => {
474+
Object.assign(floatingEl.style, {
475+
left: `${x}px`,
476+
top: `${y}px`,
477+
});
478+
});
479+
};
472480

473481
return {
474482
onStart: props => {
475483
component = new ReactRenderer(MentionList, {
476-
props,
484+
props: { ...props, onKeyDownRef },
477485
editor: props.editor,
478486
});
479487

480-
if (!props.clientRect) {
481-
return;
482-
}
488+
floatingEl = document.createElement('div');
489+
floatingEl.style.position = 'absolute';
490+
floatingEl.style.zIndex = '1300';
491+
floatingEl.addEventListener('mousedown', e =>
492+
e.preventDefault()
493+
);
494+
floatingEl.appendChild(component.element);
495+
props.editor.view.dom.parentElement.appendChild(floatingEl);
483496

484-
popup = tippy('body', {
485-
getReferenceClientRect: props.clientRect,
486-
appendTo: () => document.body,
487-
content: component.element,
488-
showOnCreate: true,
489-
interactive: true,
490-
trigger: 'manual',
491-
placement: 'bottom-start',
492-
});
497+
if (props.clientRect) {
498+
updatePosition(props.clientRect);
499+
}
493500
},
494501

495502
onUpdate(props) {
496503
if (component) {
497-
component.updateProps(props);
498-
}
499-
500-
if (!props.clientRect) {
501-
return;
504+
component.updateProps({ ...props, onKeyDownRef });
502505
}
503506

504-
if (popup && popup[0]) {
505-
popup[0].setProps({
506-
getReferenceClientRect: props.clientRect,
507-
});
507+
if (props.clientRect) {
508+
updatePosition(props.clientRect);
508509
}
509510
},
510511

511512
onKeyDown(props) {
512-
if (popup && popup[0] && props.event.key === 'Escape') {
513-
popup[0].hide();
514-
513+
console.log(
514+
'suggestion onKeyDown',
515+
props.event.key,
516+
'ref:',
517+
!!onKeyDownRef.current
518+
);
519+
if (props.event.key === 'Escape') {
520+
if (floatingEl) {
521+
floatingEl.style.display = 'none';
522+
}
515523
return true;
516524
}
517525

518-
if (!component.ref) {
526+
if (!onKeyDownRef.current) {
519527
return false;
520528
}
521529

522-
return component.ref.onKeyDown(props);
530+
return onKeyDownRef.current(props);
523531
},
524532

525533
onExit() {
534+
onKeyDownRef.current = null;
526535
queueMicrotask(() => {
527-
if (popup && popup[0] && !popup[0].state.isDestroyed) {
528-
popup[0].destroy();
529-
}
530536
if (component) {
531537
component.destroy();
532538
}
533-
// Remove references to the old popup and component upon destruction/exit.
534-
// (This should prevent redundant calls to `popup.destroy()`, which Tippy
535-
// warns in the console is a sign of a memory leak, as the `suggestion`
536-
// plugin seems to call `onExit` both when a suggestion menu is closed after
537-
// a user chooses an option, *and* when the editor itself is destroyed.)
538-
popup = undefined;
539+
if (floatingEl && floatingEl.parentNode) {
540+
floatingEl.parentNode.removeChild(floatingEl);
541+
}
542+
floatingEl = undefined;
539543
component = undefined;
540544
});
541545
},

yarn.lock

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5115,7 +5115,7 @@ __metadata:
51155115
languageName: node
51165116
linkType: hard
51175117

5118-
"@popperjs/core@npm:^2.11.8, @popperjs/core@npm:^2.9.0":
5118+
"@popperjs/core@npm:^2.11.8":
51195119
version: 2.11.8
51205120
resolution: "@popperjs/core@npm:2.11.8"
51215121
checksum: 4681e682abc006d25eb380d0cf3efc7557043f53b6aea7a5057d0d1e7df849a00e281cd8ea79c902a35a414d7919621fc2ba293ecec05f413598e0b23d5a1e63
@@ -20991,7 +20991,6 @@ __metadata:
2099120991
react: "npm:^18.3.1"
2099220992
react-dom: "npm:^18.3.1"
2099320993
react-hook-form: "npm:^7.65.0"
20994-
tippy.js: "npm:^6.3.7"
2099520994
typescript: "npm:^5.1.3"
2099620995
zshy: "npm:^0.5.0"
2099720996
peerDependencies:
@@ -24212,15 +24211,6 @@ __metadata:
2421224211
languageName: node
2421324212
linkType: hard
2421424213

24215-
"tippy.js@npm:^6.3.7":
24216-
version: 6.3.7
24217-
resolution: "tippy.js@npm:6.3.7"
24218-
dependencies:
24219-
"@popperjs/core": "npm:^2.9.0"
24220-
checksum: ec3677beb8caec791ee1f715663f28f42d60e0f7250074a047d13d5e6db95fdb6d26d8a3ac16cecb4ebcaf33ae919dbc889cf97948d115e8d3c81518c911b379
24221-
languageName: node
24222-
linkType: hard
24223-
2422424214
"tldts-core@npm:^6.1.86":
2422524215
version: 6.1.86
2422624216
resolution: "tldts-core@npm:6.1.86"

0 commit comments

Comments
 (0)