mirror of
https://github.com/inventree/InvenTree.git
synced 2026-09-02 19:08:47 +00:00
Support tables
This commit is contained in:
@@ -83,6 +83,7 @@
|
|||||||
"@tiptap/core": "^3.23.6",
|
"@tiptap/core": "^3.23.6",
|
||||||
"@tiptap/extension-image": "^3.23.6",
|
"@tiptap/extension-image": "^3.23.6",
|
||||||
"@tiptap/extension-link": "^3.23.6",
|
"@tiptap/extension-link": "^3.23.6",
|
||||||
|
"@tiptap/extension-table": "^3.23.6",
|
||||||
"@tiptap/pm": "^3.23.6",
|
"@tiptap/pm": "^3.23.6",
|
||||||
"@tiptap/react": "^3.23.6",
|
"@tiptap/react": "^3.23.6",
|
||||||
"@tiptap/starter-kit": "^3.23.6",
|
"@tiptap/starter-kit": "^3.23.6",
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ import '@mantine/tiptap/styles.css';
|
|||||||
import { useHotkeys } from '@mantine/hooks';
|
import { useHotkeys } from '@mantine/hooks';
|
||||||
import { notifications } from '@mantine/notifications';
|
import { notifications } from '@mantine/notifications';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { useEditor } from '@tiptap/react';
|
import { TableKit } from '@tiptap/extension-table';
|
||||||
|
import { useEditor, useEditorState } from '@tiptap/react';
|
||||||
import StarterKit from '@tiptap/starter-kit';
|
import StarterKit from '@tiptap/starter-kit';
|
||||||
import DOMPurify from 'dompurify';
|
import DOMPurify from 'dompurify';
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
@@ -35,12 +36,22 @@ import {
|
|||||||
Tooltip
|
Tooltip
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import {
|
import {
|
||||||
|
IconArrowMerge,
|
||||||
IconCirclePlus,
|
IconCirclePlus,
|
||||||
|
IconColumnInsertLeft,
|
||||||
|
IconColumnInsertRight,
|
||||||
|
IconColumnRemove,
|
||||||
IconDeviceFloppy,
|
IconDeviceFloppy,
|
||||||
IconInfoCircle,
|
IconInfoCircle,
|
||||||
IconPhoto,
|
IconPhoto,
|
||||||
IconReload,
|
IconReload,
|
||||||
IconStar
|
IconRowInsertBottom,
|
||||||
|
IconRowInsertTop,
|
||||||
|
IconRowRemove,
|
||||||
|
IconStar,
|
||||||
|
IconTableOff,
|
||||||
|
IconTablePlus,
|
||||||
|
IconTableRow
|
||||||
} from '@tabler/icons-react';
|
} from '@tabler/icons-react';
|
||||||
import { useShallow } from 'zustand/react/shallow';
|
import { useShallow } from 'zustand/react/shallow';
|
||||||
import { formatDate } from '../../defaults/formatters';
|
import { formatDate } from '../../defaults/formatters';
|
||||||
@@ -150,6 +161,9 @@ export default function NotesEditor({
|
|||||||
const src = await uploadFileRef.current(file);
|
const src = await uploadFileRef.current(file);
|
||||||
return { src, 'data-keep-ratio': true };
|
return { src, 'data-keep-ratio': true };
|
||||||
}
|
}
|
||||||
|
}),
|
||||||
|
TableKit.configure({
|
||||||
|
table: { resizable: true, renderWrapper: true, cellMinWidth: 50 }
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
content: '',
|
content: '',
|
||||||
@@ -233,6 +247,11 @@ export default function NotesEditor({
|
|||||||
[user, modelType, notesQuery]
|
[user, modelType, notesQuery]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const isInTable = useEditorState({
|
||||||
|
editor,
|
||||||
|
selector: ({ editor: e }) => e?.isActive('table') ?? false
|
||||||
|
});
|
||||||
|
|
||||||
// Sync editor editable state when permissions change
|
// Sync editor editable state when permissions change
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
editor?.setEditable(canEdit);
|
editor?.setEditable(canEdit);
|
||||||
@@ -466,6 +485,118 @@ export default function NotesEditor({
|
|||||||
)}
|
)}
|
||||||
</FileButton>
|
</FileButton>
|
||||||
</RichTextEditor.ControlsGroup>
|
</RichTextEditor.ControlsGroup>
|
||||||
|
<RichTextEditor.ControlsGroup>
|
||||||
|
<RichTextEditor.Control
|
||||||
|
onClick={() =>
|
||||||
|
editor
|
||||||
|
?.chain()
|
||||||
|
.focus()
|
||||||
|
.insertTable({
|
||||||
|
rows: 3,
|
||||||
|
cols: 3,
|
||||||
|
withHeaderRow: true
|
||||||
|
})
|
||||||
|
.run()
|
||||||
|
}
|
||||||
|
aria-label={t`Insert table`}
|
||||||
|
title={t`Insert table`}
|
||||||
|
>
|
||||||
|
<IconTablePlus size='0.9rem' />
|
||||||
|
</RichTextEditor.Control>
|
||||||
|
</RichTextEditor.ControlsGroup>
|
||||||
|
</RichTextEditor.Toolbar>
|
||||||
|
)}
|
||||||
|
{canEdit && isInTable && (
|
||||||
|
<RichTextEditor.Toolbar>
|
||||||
|
<RichTextEditor.ControlsGroup>
|
||||||
|
<RichTextEditor.Control
|
||||||
|
onClick={() =>
|
||||||
|
editor?.chain().focus().addColumnBefore().run()
|
||||||
|
}
|
||||||
|
aria-label={t`Add column before`}
|
||||||
|
title={t`Add column before`}
|
||||||
|
>
|
||||||
|
<IconColumnInsertLeft size='0.9rem' />
|
||||||
|
</RichTextEditor.Control>
|
||||||
|
<RichTextEditor.Control
|
||||||
|
onClick={() =>
|
||||||
|
editor?.chain().focus().addColumnAfter().run()
|
||||||
|
}
|
||||||
|
aria-label={t`Add column after`}
|
||||||
|
title={t`Add column after`}
|
||||||
|
>
|
||||||
|
<IconColumnInsertRight size='0.9rem' />
|
||||||
|
</RichTextEditor.Control>
|
||||||
|
<RichTextEditor.Control
|
||||||
|
onClick={() =>
|
||||||
|
editor?.chain().focus().deleteColumn().run()
|
||||||
|
}
|
||||||
|
aria-label={t`Delete column`}
|
||||||
|
title={t`Delete column`}
|
||||||
|
>
|
||||||
|
<IconColumnRemove size='0.9rem' />
|
||||||
|
</RichTextEditor.Control>
|
||||||
|
</RichTextEditor.ControlsGroup>
|
||||||
|
<RichTextEditor.ControlsGroup>
|
||||||
|
<RichTextEditor.Control
|
||||||
|
onClick={() =>
|
||||||
|
editor?.chain().focus().addRowBefore().run()
|
||||||
|
}
|
||||||
|
aria-label={t`Add row before`}
|
||||||
|
title={t`Add row before`}
|
||||||
|
>
|
||||||
|
<IconRowInsertTop size='0.9rem' />
|
||||||
|
</RichTextEditor.Control>
|
||||||
|
<RichTextEditor.Control
|
||||||
|
onClick={() =>
|
||||||
|
editor?.chain().focus().addRowAfter().run()
|
||||||
|
}
|
||||||
|
aria-label={t`Add row after`}
|
||||||
|
title={t`Add row after`}
|
||||||
|
>
|
||||||
|
<IconRowInsertBottom size='0.9rem' />
|
||||||
|
</RichTextEditor.Control>
|
||||||
|
<RichTextEditor.Control
|
||||||
|
onClick={() =>
|
||||||
|
editor?.chain().focus().deleteRow().run()
|
||||||
|
}
|
||||||
|
aria-label={t`Delete row`}
|
||||||
|
title={t`Delete row`}
|
||||||
|
>
|
||||||
|
<IconRowRemove size='0.9rem' />
|
||||||
|
</RichTextEditor.Control>
|
||||||
|
</RichTextEditor.ControlsGroup>
|
||||||
|
<RichTextEditor.ControlsGroup>
|
||||||
|
<RichTextEditor.Control
|
||||||
|
onClick={() =>
|
||||||
|
editor?.chain().focus().mergeOrSplit().run()
|
||||||
|
}
|
||||||
|
aria-label={t`Merge or split cells`}
|
||||||
|
title={t`Merge or split cells`}
|
||||||
|
>
|
||||||
|
<IconArrowMerge size='0.9rem' />
|
||||||
|
</RichTextEditor.Control>
|
||||||
|
<RichTextEditor.Control
|
||||||
|
onClick={() =>
|
||||||
|
editor?.chain().focus().toggleHeaderRow().run()
|
||||||
|
}
|
||||||
|
aria-label={t`Toggle header row`}
|
||||||
|
title={t`Toggle header row`}
|
||||||
|
>
|
||||||
|
<IconTableRow size='0.9rem' />
|
||||||
|
</RichTextEditor.Control>
|
||||||
|
</RichTextEditor.ControlsGroup>
|
||||||
|
<RichTextEditor.ControlsGroup>
|
||||||
|
<RichTextEditor.Control
|
||||||
|
onClick={() =>
|
||||||
|
editor?.chain().focus().deleteTable().run()
|
||||||
|
}
|
||||||
|
aria-label={t`Delete table`}
|
||||||
|
title={t`Delete table`}
|
||||||
|
>
|
||||||
|
<IconTableOff size='0.9rem' />
|
||||||
|
</RichTextEditor.Control>
|
||||||
|
</RichTextEditor.ControlsGroup>
|
||||||
</RichTextEditor.Toolbar>
|
</RichTextEditor.Toolbar>
|
||||||
)}
|
)}
|
||||||
<RichTextEditor.Content />
|
<RichTextEditor.Content />
|
||||||
|
|||||||
@@ -2110,6 +2110,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-3.23.6.tgz#b68e8df11c8c24c82d8c292ff94bc962f3cec871"
|
resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-3.23.6.tgz#b68e8df11c8c24c82d8c292ff94bc962f3cec871"
|
||||||
integrity sha512-oF7FEZ37f15aCe5kPgzGDYf/m+hr7VdQ/Ko/Hds/UM9pX7AG1fdtmRrl6wqkRqDM/incZaC/AQR2/Dpo2VCNGQ==
|
integrity sha512-oF7FEZ37f15aCe5kPgzGDYf/m+hr7VdQ/Ko/Hds/UM9pX7AG1fdtmRrl6wqkRqDM/incZaC/AQR2/Dpo2VCNGQ==
|
||||||
|
|
||||||
|
"@tiptap/extension-table@^3.23.6":
|
||||||
|
version "3.23.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tiptap/extension-table/-/extension-table-3.23.6.tgz#757a4d14f472fd4735ff5bab35da72402b0bced4"
|
||||||
|
integrity sha512-XbhZXjhsS6AP7ThoZxjAnNs+NiR81YRori25l6E+ORqB7quiPkIXOAi5h4AIpkn/CYIqze6ere11lWsYpDjtaQ==
|
||||||
|
|
||||||
"@tiptap/extension-text@^3.13.0":
|
"@tiptap/extension-text@^3.13.0":
|
||||||
version "3.23.4"
|
version "3.23.4"
|
||||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-3.23.4.tgz#1ab44d78d34c746f97100ff34cc28e0914231eaa"
|
resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-3.23.4.tgz#1ab44d78d34c746f97100ff34cc28e0914231eaa"
|
||||||
|
|||||||
Reference in New Issue
Block a user