refactor: upgrade tiptap dependencies and enhance toolbar functionality

- Updated Tiptap dependencies to version 3.x, including core, extensions, and starter kit.
- Added Link extension to the editor for hyperlink support.
- Refactored ToolBar component to utilize useEditorState for better state management.
- Enhanced toolbar with additional heading options (H5, H6) and improved button states for formatting actions.
- Added a button to clear all marks in the editor.
This commit is contained in:
Marco Pedone 2025-08-06 15:03:05 +02:00
parent 0ea14d0650
commit 7a50ba4147
5 changed files with 423 additions and 4866 deletions

View file

@ -1,5 +1,4 @@
NEW IDEA TODOS: NEW IDEA TODOS:
//TODO predere privacy policy sito vecchio e adattarla
- trigger pag sucecss event from ordini tab and gen payment button in order detail - trigger pag sucecss event from ordini tab and gen payment button in order detail

File diff suppressed because it is too large Load diff

View file

@ -32,10 +32,12 @@
"@tanstack/react-query": "^5.74.4", "@tanstack/react-query": "^5.74.4",
"@tanstack/react-table": "^8.21.3", "@tanstack/react-table": "^8.21.3",
"@tanstack/react-virtual": "^3.13.12", "@tanstack/react-virtual": "^3.13.12",
"@tiptap/extension-underline": "^2.23.0", "@tiptap/core": "^3.0.9",
"@tiptap/pm": "^2.25.0", "@tiptap/extension-link": "^3.0.9",
"@tiptap/react": "^2.23.0", "@tiptap/extension-underline": "^3.0.9",
"@tiptap/starter-kit": "^2.25.0", "@tiptap/pm": "^3.0.9",
"@tiptap/react": "^3.0.9",
"@tiptap/starter-kit": "^3.0.9",
"@trpc/client": "^11.1.0", "@trpc/client": "^11.1.0",
"@trpc/next": "^11.4.3", "@trpc/next": "^11.4.3",
"@trpc/react-query": "^11.1.0", "@trpc/react-query": "^11.1.0",

View file

@ -2,6 +2,7 @@
import { useEditor, EditorContent } from "@tiptap/react"; import { useEditor, EditorContent } from "@tiptap/react";
import StarterKit from "@tiptap/starter-kit"; import StarterKit from "@tiptap/starter-kit";
import Underline from "@tiptap/extension-underline"; import Underline from "@tiptap/extension-underline";
import Link from "@tiptap/extension-link";
import ToolBar from "~/components/tip-tap/toolbar"; import ToolBar from "~/components/tip-tap/toolbar";
function Tiptap({ function Tiptap({
value, value,
@ -13,7 +14,13 @@ function Tiptap({
id: string; id: string;
}) { }) {
const editor = useEditor({ const editor = useEditor({
extensions: [StarterKit, Underline], extensions: [
StarterKit,
Underline,
Link.configure({
defaultProtocol: "https",
}),
],
content: value, content: value,
editorProps: { editorProps: {
attributes: { attributes: {
@ -27,6 +34,10 @@ function Tiptap({
immediatelyRender: false, immediatelyRender: false,
}); });
if (!editor) {
return null;
}
return ( return (
<div <div
className="flex h-full min-h-[250px] w-full flex-col justify-stretch" className="flex h-full min-h-[250px] w-full flex-col justify-stretch"

View file

@ -1,12 +1,15 @@
"use client"; "use client";
import { type Editor } from "@tiptap/react"; import { useEditorState, type Editor } from "@tiptap/react";
import { import {
Bold, Bold,
BrushCleaning,
Heading1, Heading1,
Heading2, Heading2,
Heading3, Heading3,
Heading4, Heading4,
Heading5,
Heading6,
Italic, Italic,
List, List,
ListOrdered, ListOrdered,
@ -21,26 +24,47 @@ import {
import { Toggle } from "~/components/ui/toggle"; import { Toggle } from "~/components/ui/toggle";
import { Button } from "~/components/ui/button"; import { Button } from "~/components/ui/button";
type Props = { function ToolBar({ editor }: { editor: Editor }) {
editor: Editor | null; const editorState = useEditorState({
}; editor,
selector: (ctx) => {
function ToolBar({ editor }: Props) { return {
if (!editor) { isBold: ctx.editor.isActive("bold") ?? false,
return null; canBold: ctx.editor.can().chain().toggleBold().run() ?? false,
} isItalic: ctx.editor.isActive("italic") ?? false,
canItalic: ctx.editor.can().chain().toggleItalic().run() ?? false,
isUnderline: ctx.editor.isActive("underline") ?? false,
canUnderline: ctx.editor.can().chain().toggleUnderline().run() ?? false,
isStrike: ctx.editor.isActive("strike") ?? false,
canStrike: ctx.editor.can().chain().toggleStrike().run() ?? false,
canClearMarks: ctx.editor.can().chain().unsetAllMarks().run() ?? false,
isParagraph: ctx.editor.isActive("paragraph") ?? false,
isHeading1: ctx.editor.isActive("heading", { level: 1 }) ?? false,
isHeading2: ctx.editor.isActive("heading", { level: 2 }) ?? false,
isHeading3: ctx.editor.isActive("heading", { level: 3 }) ?? false,
isHeading4: ctx.editor.isActive("heading", { level: 4 }) ?? false,
isHeading5: ctx.editor.isActive("heading", { level: 5 }) ?? false,
isHeading6: ctx.editor.isActive("heading", { level: 6 }) ?? false,
isBulletList: ctx.editor.isActive("bulletList") ?? false,
isOrderedList: ctx.editor.isActive("orderedList") ?? false,
isBlockquote: ctx.editor.isActive("blockquote") ?? false,
canUndo: ctx.editor.can().chain().undo().run() ?? false,
canRedo: ctx.editor.can().chain().redo().run() ?? false,
};
},
});
return ( return (
<div className="border-input my-2 flex flex-wrap gap-3 rounded-lg border p-1"> <div className="border-input my-2 flex flex-wrap gap-3 rounded-lg border p-1">
<Toggle <Toggle
onPressedChange={() => editor.chain().focus().setParagraph().run()} onPressedChange={() => editor.chain().focus().setParagraph().run()}
pressed={editor.isActive("paragraph")} pressed={editorState.isParagraph}
> >
<Text className="size-4" /> <Text className="size-4" />
</Toggle> </Toggle>
<Toggle <Toggle
size="sm" size="sm"
pressed={editor.isActive("heading", { level: 1 })} pressed={editorState.isHeading1}
onPressedChange={() => onPressedChange={() =>
editor.chain().focus().toggleHeading({ level: 1 }).run() editor.chain().focus().toggleHeading({ level: 1 }).run()
} }
@ -49,7 +73,7 @@ function ToolBar({ editor }: Props) {
</Toggle> </Toggle>
<Toggle <Toggle
size="sm" size="sm"
pressed={editor.isActive("heading", { level: 2 })} pressed={editorState.isHeading2}
onPressedChange={() => onPressedChange={() =>
editor.chain().focus().toggleHeading({ level: 2 }).run() editor.chain().focus().toggleHeading({ level: 2 }).run()
} }
@ -58,7 +82,7 @@ function ToolBar({ editor }: Props) {
</Toggle> </Toggle>
<Toggle <Toggle
size="sm" size="sm"
pressed={editor.isActive("heading", { level: 3 })} pressed={editorState.isHeading3}
onPressedChange={() => onPressedChange={() =>
editor.chain().focus().toggleHeading({ level: 3 }).run() editor.chain().focus().toggleHeading({ level: 3 }).run()
} }
@ -67,59 +91,81 @@ function ToolBar({ editor }: Props) {
</Toggle> </Toggle>
<Toggle <Toggle
size="sm" size="sm"
pressed={editor.isActive("heading", { level: 4 })} pressed={editorState.isHeading4}
onPressedChange={() => onPressedChange={() =>
editor.chain().focus().toggleHeading({ level: 4 }).run() editor.chain().focus().toggleHeading({ level: 4 }).run()
} }
> >
<Heading4 className="size-4" /> <Heading4 className="size-4" />
</Toggle> </Toggle>
<Toggle
size="sm"
pressed={editorState.isHeading5}
onPressedChange={() =>
editor.chain().focus().toggleHeading({ level: 5 }).run()
}
>
<Heading5 className="size-4" />
</Toggle>
<Toggle
size="sm"
pressed={editorState.isHeading6}
onPressedChange={() =>
editor.chain().focus().toggleHeading({ level: 6 }).run()
}
>
<Heading6 className="size-4" />
</Toggle>
<Toggle <Toggle
size="sm" size="sm"
pressed={editor.isActive("bold")} pressed={editorState.isBold}
disabled={!editorState.canBold}
onPressedChange={() => editor.chain().focus().toggleBold().run()} onPressedChange={() => editor.chain().focus().toggleBold().run()}
> >
<Bold className="size-4" /> <Bold className="size-4" />
</Toggle> </Toggle>
<Toggle <Toggle
size="sm" size="sm"
pressed={editor.isActive("italic")} pressed={editorState.isItalic}
disabled={!editorState.canItalic}
onPressedChange={() => editor.chain().focus().toggleItalic().run()} onPressedChange={() => editor.chain().focus().toggleItalic().run()}
> >
<Italic className="size-4" /> <Italic className="size-4" />
</Toggle> </Toggle>
<Toggle <Toggle
size="sm" size="sm"
pressed={editor.isActive("underline")} pressed={editorState.isUnderline}
disabled={!editorState.canUnderline}
onPressedChange={() => editor.chain().focus().toggleUnderline().run()} onPressedChange={() => editor.chain().focus().toggleUnderline().run()}
> >
<Underline className="size-4" /> <Underline className="size-4" />
</Toggle> </Toggle>
<Toggle <Toggle
size="sm" size="sm"
pressed={editor.isActive("strike")} pressed={editorState.isStrike}
disabled={!editorState.canStrike}
onPressedChange={() => editor.chain().focus().toggleStrike().run()} onPressedChange={() => editor.chain().focus().toggleStrike().run()}
> >
<StrikethroughIcon className="size-4" /> <StrikethroughIcon className="size-4" />
</Toggle> </Toggle>
<Toggle <Toggle
size="sm" size="sm"
pressed={editor.isActive("bulletList")} pressed={editorState.isBulletList}
onPressedChange={() => editor.chain().focus().toggleBulletList().run()} onPressedChange={() => editor.chain().focus().toggleBulletList().run()}
> >
<List className="size-4" /> <List className="size-4" />
</Toggle> </Toggle>
<Toggle <Toggle
size="sm" size="sm"
pressed={editor.isActive("orderedList")} pressed={editorState.isOrderedList}
onPressedChange={() => editor.chain().focus().toggleOrderedList().run()} onPressedChange={() => editor.chain().focus().toggleOrderedList().run()}
> >
<ListOrdered className="size-4" /> <ListOrdered className="size-4" />
</Toggle> </Toggle>
<Toggle <Toggle
size="sm" size="sm"
pressed={editor.isActive("blockquote")} pressed={editorState.isBlockquote}
onPressedChange={() => editor.chain().focus().toggleBlockquote().run()} onPressedChange={() => editor.chain().focus().toggleBlockquote().run()}
> >
<Quote className="size-4" /> <Quote className="size-4" />
@ -138,10 +184,19 @@ function ToolBar({ editor }: Props) {
> >
Hard break Hard break
</Button> </Button>
<Button
variant="ghost"
type="button"
disabled={!editorState.canClearMarks}
onClick={() => editor.chain().focus().unsetAllMarks().run()}
>
<BrushCleaning className="size-4" />
</Button>
<Button <Button
variant="ghost" variant="ghost"
type="button" type="button"
disabled={!editorState.canUndo}
onClick={() => editor.chain().focus().undo().run()} onClick={() => editor.chain().focus().undo().run()}
> >
<Undo className="size-4" /> <Undo className="size-4" />
@ -149,6 +204,7 @@ function ToolBar({ editor }: Props) {
<Button <Button
variant="ghost" variant="ghost"
type="button" type="button"
disabled={!editorState.canRedo}
onClick={() => editor.chain().focus().redo().run()} onClick={() => editor.chain().focus().redo().run()}
> >
<Redo className="size-4" /> <Redo className="size-4" />