Fix: Ensure only one emoji list appears (#572)

* Fix: Ensure only one emoji list appears

* fix: refactor logic

* remove unused file node-id-atoms

* small fix

* align with Mantine UI

* close emoji picker on escape

* translate string

---------

Co-authored-by: Philipinho <16838612+Philipinho@users.noreply.github.com>
This commit is contained in:
Naifer 2025-01-15 17:07:26 +01:00 committed by GitHub
parent 59b514fa26
commit f7efb6c2c9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 39 additions and 21 deletions

View File

@ -1,14 +1,14 @@
import React, { ReactNode } from 'react';
import React, { ReactNode, useState } from "react";
import {
ActionIcon,
Popover,
Button,
useMantineColorScheme,
} from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';
import { Suspense } from 'react';
const Picker = React.lazy(() => import('@emoji-mart/react'));
} from "@mantine/core";
import { useClickOutside, useDisclosure, useWindowEvent } from "@mantine/hooks";
import { Suspense } from "react";
const Picker = React.lazy(() => import("@emoji-mart/react"));
import { useTranslation } from "react-i18next";
export interface EmojiPickerInterface {
onEmojiSelect: (emoji: any) => void;
@ -23,8 +23,26 @@ function EmojiPicker({
removeEmojiAction,
readOnly,
}: EmojiPickerInterface) {
const { t } = useTranslation();
const [opened, handlers] = useDisclosure(false);
const { colorScheme } = useMantineColorScheme();
const [target, setTarget] = useState<HTMLElement | null>(null);
const [dropdown, setDropdown] = useState<HTMLDivElement | null>(null);
useClickOutside(
() => handlers.close(),
["mousedown", "touchstart"],
[dropdown, target],
);
// We need this because the default Mantine popover closeOnEscape does not work
useWindowEvent("keydown", (event) => {
if (opened && event.key === "Escape") {
event.stopPropagation();
event.preventDefault();
handlers.close();
}
});
const handleEmojiSelect = (emoji) => {
onEmojiSelect(emoji);
@ -43,16 +61,17 @@ function EmojiPicker({
width={332}
position="bottom"
disabled={readOnly}
closeOnEscape={true}
>
<Popover.Target>
<Popover.Target ref={setTarget}>
<ActionIcon c="gray" variant="transparent" onClick={handlers.toggle}>
{icon}
</ActionIcon>
</Popover.Target>
<Popover.Dropdown bg="000" style={{ border: 'none' }}>
<Popover.Dropdown bg="000" style={{ border: "none" }} ref={setDropdown}>
<Suspense fallback={null}>
<Picker
data={async () => (await import('@emoji-mart/data')).default}
data={async () => (await import("@emoji-mart/data")).default}
onEmojiSelect={handleEmojiSelect}
perLine={8}
skinTonePosition="search"
@ -64,14 +83,14 @@ function EmojiPicker({
c="gray"
size="xs"
style={{
position: 'absolute',
position: "absolute",
zIndex: 2,
bottom: '1rem',
right: '1rem',
bottom: "1rem",
right: "1rem",
}}
onClick={handleRemoveEmoji}
>
Remove
{t("Remove")}
</Button>
</Popover.Dropdown>
</Popover>

View File

@ -15,7 +15,8 @@ import {
IconChevronDown,
IconChevronRight,
IconDotsVertical,
IconFileDescription, IconFileExport,
IconFileDescription,
IconFileExport,
IconLink,
IconPlus,
IconPointFilled,
@ -140,13 +141,13 @@ export default function SpaceTree({ spaceId, readOnly }: SpaceTreeProps) {
flatTreeItems = [
...flatTreeItems,
...children.filter(
(child) => !flatTreeItems.some((item) => item.id === child.id)
(child) => !flatTreeItems.some((item) => item.id === child.id),
),
];
};
const fetchPromises = ancestors.map((ancestor) =>
fetchAndUpdateChildren(ancestor)
fetchAndUpdateChildren(ancestor),
);
// Wait for all fetch operations to complete
@ -160,7 +161,7 @@ export default function SpaceTree({ spaceId, readOnly }: SpaceTreeProps) {
const updatedTree = appendNodeChildren(
data,
rootChild.id,
rootChild.children
rootChild.children,
);
setData(updatedTree);
@ -255,7 +256,7 @@ function Node({ node, style, dragHandle, tree }: NodeRendererProps<any>) {
const updatedTreeData = appendNodeChildren(
treeData,
node.data.id,
childrenTree
childrenTree,
);
setTreeData(updatedTreeData);
@ -468,9 +469,7 @@ function NodeMenu({ node, treeApi }: NodeMenuProps) {
<Menu.Item
c="red"
leftSection={
<IconTrash size={16} />
}
leftSection={<IconTrash size={16} />}
onClick={(e) => {
e.preventDefault();
e.stopPropagation();