mirror of
https://github.com/Shadowfita/docmost.git
synced 2025-11-09 20:12:00 +10:00
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:
@ -1,14 +1,14 @@
|
|||||||
import React, { ReactNode } from 'react';
|
import React, { ReactNode, useState } from "react";
|
||||||
import {
|
import {
|
||||||
ActionIcon,
|
ActionIcon,
|
||||||
Popover,
|
Popover,
|
||||||
Button,
|
Button,
|
||||||
useMantineColorScheme,
|
useMantineColorScheme,
|
||||||
} from '@mantine/core';
|
} from "@mantine/core";
|
||||||
import { useDisclosure } from '@mantine/hooks';
|
import { useClickOutside, useDisclosure, useWindowEvent } from "@mantine/hooks";
|
||||||
import { Suspense } from 'react';
|
import { Suspense } from "react";
|
||||||
|
const Picker = React.lazy(() => import("@emoji-mart/react"));
|
||||||
const Picker = React.lazy(() => import('@emoji-mart/react'));
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
export interface EmojiPickerInterface {
|
export interface EmojiPickerInterface {
|
||||||
onEmojiSelect: (emoji: any) => void;
|
onEmojiSelect: (emoji: any) => void;
|
||||||
@ -23,8 +23,26 @@ function EmojiPicker({
|
|||||||
removeEmojiAction,
|
removeEmojiAction,
|
||||||
readOnly,
|
readOnly,
|
||||||
}: EmojiPickerInterface) {
|
}: EmojiPickerInterface) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const [opened, handlers] = useDisclosure(false);
|
const [opened, handlers] = useDisclosure(false);
|
||||||
const { colorScheme } = useMantineColorScheme();
|
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) => {
|
const handleEmojiSelect = (emoji) => {
|
||||||
onEmojiSelect(emoji);
|
onEmojiSelect(emoji);
|
||||||
@ -43,16 +61,17 @@ function EmojiPicker({
|
|||||||
width={332}
|
width={332}
|
||||||
position="bottom"
|
position="bottom"
|
||||||
disabled={readOnly}
|
disabled={readOnly}
|
||||||
|
closeOnEscape={true}
|
||||||
>
|
>
|
||||||
<Popover.Target>
|
<Popover.Target ref={setTarget}>
|
||||||
<ActionIcon c="gray" variant="transparent" onClick={handlers.toggle}>
|
<ActionIcon c="gray" variant="transparent" onClick={handlers.toggle}>
|
||||||
{icon}
|
{icon}
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
</Popover.Target>
|
</Popover.Target>
|
||||||
<Popover.Dropdown bg="000" style={{ border: 'none' }}>
|
<Popover.Dropdown bg="000" style={{ border: "none" }} ref={setDropdown}>
|
||||||
<Suspense fallback={null}>
|
<Suspense fallback={null}>
|
||||||
<Picker
|
<Picker
|
||||||
data={async () => (await import('@emoji-mart/data')).default}
|
data={async () => (await import("@emoji-mart/data")).default}
|
||||||
onEmojiSelect={handleEmojiSelect}
|
onEmojiSelect={handleEmojiSelect}
|
||||||
perLine={8}
|
perLine={8}
|
||||||
skinTonePosition="search"
|
skinTonePosition="search"
|
||||||
@ -64,14 +83,14 @@ function EmojiPicker({
|
|||||||
c="gray"
|
c="gray"
|
||||||
size="xs"
|
size="xs"
|
||||||
style={{
|
style={{
|
||||||
position: 'absolute',
|
position: "absolute",
|
||||||
zIndex: 2,
|
zIndex: 2,
|
||||||
bottom: '1rem',
|
bottom: "1rem",
|
||||||
right: '1rem',
|
right: "1rem",
|
||||||
}}
|
}}
|
||||||
onClick={handleRemoveEmoji}
|
onClick={handleRemoveEmoji}
|
||||||
>
|
>
|
||||||
Remove
|
{t("Remove")}
|
||||||
</Button>
|
</Button>
|
||||||
</Popover.Dropdown>
|
</Popover.Dropdown>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
|||||||
@ -15,7 +15,8 @@ import {
|
|||||||
IconChevronDown,
|
IconChevronDown,
|
||||||
IconChevronRight,
|
IconChevronRight,
|
||||||
IconDotsVertical,
|
IconDotsVertical,
|
||||||
IconFileDescription, IconFileExport,
|
IconFileDescription,
|
||||||
|
IconFileExport,
|
||||||
IconLink,
|
IconLink,
|
||||||
IconPlus,
|
IconPlus,
|
||||||
IconPointFilled,
|
IconPointFilled,
|
||||||
@ -140,13 +141,13 @@ export default function SpaceTree({ spaceId, readOnly }: SpaceTreeProps) {
|
|||||||
flatTreeItems = [
|
flatTreeItems = [
|
||||||
...flatTreeItems,
|
...flatTreeItems,
|
||||||
...children.filter(
|
...children.filter(
|
||||||
(child) => !flatTreeItems.some((item) => item.id === child.id)
|
(child) => !flatTreeItems.some((item) => item.id === child.id),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchPromises = ancestors.map((ancestor) =>
|
const fetchPromises = ancestors.map((ancestor) =>
|
||||||
fetchAndUpdateChildren(ancestor)
|
fetchAndUpdateChildren(ancestor),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Wait for all fetch operations to complete
|
// Wait for all fetch operations to complete
|
||||||
@ -160,7 +161,7 @@ export default function SpaceTree({ spaceId, readOnly }: SpaceTreeProps) {
|
|||||||
const updatedTree = appendNodeChildren(
|
const updatedTree = appendNodeChildren(
|
||||||
data,
|
data,
|
||||||
rootChild.id,
|
rootChild.id,
|
||||||
rootChild.children
|
rootChild.children,
|
||||||
);
|
);
|
||||||
setData(updatedTree);
|
setData(updatedTree);
|
||||||
|
|
||||||
@ -255,7 +256,7 @@ function Node({ node, style, dragHandle, tree }: NodeRendererProps<any>) {
|
|||||||
const updatedTreeData = appendNodeChildren(
|
const updatedTreeData = appendNodeChildren(
|
||||||
treeData,
|
treeData,
|
||||||
node.data.id,
|
node.data.id,
|
||||||
childrenTree
|
childrenTree,
|
||||||
);
|
);
|
||||||
|
|
||||||
setTreeData(updatedTreeData);
|
setTreeData(updatedTreeData);
|
||||||
@ -468,9 +469,7 @@ function NodeMenu({ node, treeApi }: NodeMenuProps) {
|
|||||||
|
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
c="red"
|
c="red"
|
||||||
leftSection={
|
leftSection={<IconTrash size={16} />}
|
||||||
<IconTrash size={16} />
|
|
||||||
}
|
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|||||||
Reference in New Issue
Block a user