mirror of
https://github.com/idrainformatica/PecFlow.git
synced 2026-06-16 12:45:42 +02:00
vboxes fix
This commit is contained in:
+858
-3
@@ -2150,6 +2150,12 @@
|
||||
"integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@remirror/core-constants": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@remirror/core-constants/-/core-constants-3.0.0.tgz",
|
||||
"integrity": "sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@remix-run/router": {
|
||||
"version": "1.23.2",
|
||||
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.2.tgz",
|
||||
@@ -2180,6 +2186,20 @@
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz",
|
||||
"integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@tanstack/query-core": {
|
||||
"version": "5.91.0",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.91.0.tgz",
|
||||
@@ -2233,6 +2253,505 @@
|
||||
"react": "^18 || ^19"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/core": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/core/-/core-3.20.4.tgz",
|
||||
"integrity": "sha512-3i/DG89TFY/b34T5P+j35UcjYuB5d3+9K8u6qID+iUqNPiza015HPIZLuPfE5elNwVdV3EXIoPo0LLeBLgXXAg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/pm": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-blockquote": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-3.20.4.tgz",
|
||||
"integrity": "sha512-9sskyyhYj2oKat//lyZVXCp9YrPt4oJAZnGHYWXS0xlskjsLElrfKKlM4vpbhGss3VrhQRoEGqWLnIaJYPF1zw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-bold": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-3.20.4.tgz",
|
||||
"integrity": "sha512-Md7/mNAeJCY+VLJc8JRGI+8XkVPKiOGB1NgqQPdh3aYtxXQDChQOZoJEQl6TuudDxZ85bLZB67NjZlx3jo8/0g==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-bubble-menu": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-3.20.4.tgz",
|
||||
"integrity": "sha512-EXywPlI8wjPcAb8ozymgVhjtMjFrnhtoyNTy8ZcObdpUi5CdO9j892Y7aPbKe5hLhlDpvJk7rMfir4FFKEmfng==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@floating-ui/dom": "^1.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4",
|
||||
"@tiptap/pm": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-bullet-list": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-3.20.4.tgz",
|
||||
"integrity": "sha512-1RTGrur1EKoxfnLZ3M6xeNj8GITAz74jH2DHGcjLsd2Xr7Q7BozGaIq6GkkvKguMwbI1zCOxTHFCpUETXAIQQA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extension-list": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-code": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-3.20.4.tgz",
|
||||
"integrity": "sha512-7j8Hi964bH1SZ9oLdZC1fkqWz27mliSDV7M8lmL/M14+Qw42D/VOAKS4Aw9OCFtHMlTsjLR6qsoVxL8Lpkt6NA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-code-block": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-3.20.4.tgz",
|
||||
"integrity": "sha512-Zlw3FrXTy01+o1yISeX/LC+iJeHA+ym602bMXGmtA6lyl7QSOSO7WExweJ6xeJGhbCjldwT5al6fkRAs8iGJZg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4",
|
||||
"@tiptap/pm": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-color": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-color/-/extension-color-3.20.4.tgz",
|
||||
"integrity": "sha512-+OT9wWEJnqoWmzfqPYt0oWm8LZcH+D44Z3jA2TNzBj4tLGQ2YPxN2SyS12AlRi7MuguVT7utFy7qDXrfir8eUA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extension-text-style": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-document": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-3.20.4.tgz",
|
||||
"integrity": "sha512-zF1CIFVLt8MfSpWWnPwtGyxPOsT0xYM2qJKcXf2yZcTG37wDKmUi6heG53vGigIavbQlLaAFvs+1mNdOu2x/0A==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-dropcursor": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-3.20.4.tgz",
|
||||
"integrity": "sha512-TgMwvZ8myXYdmd6bUV7qkpZXv7ZUiSmX/8eo+iPEzYo2CnDLAGvDKgC50nfq/g87SDvfBgPuAiBfFvsMQQWaTw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extensions": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-floating-menu": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-3.20.4.tgz",
|
||||
"integrity": "sha512-AaPTFhoO8DBIElJyd/RTVJjkctvJuL+GHURX0npbtTxXq5HXbebVwf2ARNR7jMd/GThsmBaNJiGxZg4A2oeDqQ==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@floating-ui/dom": "^1.0.0",
|
||||
"@tiptap/core": "^3.20.4",
|
||||
"@tiptap/pm": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-font-family": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-font-family/-/extension-font-family-3.20.4.tgz",
|
||||
"integrity": "sha512-u5HjpNVBK7N9glR4Sz/HyVvTTAprEiion0oyyBWPBlgZvLrJta0zNvhfwG9ZUoubvqou3fBRbZwVosfonN2fAw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extension-text-style": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-gapcursor": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-3.20.4.tgz",
|
||||
"integrity": "sha512-JJ6f1iQ1e0s4kISgq55U3UYGwWV/N9f0PYMtB6e3L+SBQjXnywaLK0g6vfN6IvTCC2vdIuqeSOX8VlSO97sJLw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extensions": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-hard-break": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-3.20.4.tgz",
|
||||
"integrity": "sha512-gJbq58d8zB1gzyqVEopowej5CpW4/Fpg6oGJvlZxaCukqd0gJRWGC89K+jE62YA1Td4sfcKrekKvN7jm2y/ZUg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-heading": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-3.20.4.tgz",
|
||||
"integrity": "sha512-xsnkmTGggJc5P2iCwS1lv8KFG31xC/GNPJKoi/3UH67j/lKDhA3AdtshsLeyv2FKtTtYDb8oV0IqzHB1MM6a7w==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-horizontal-rule": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-3.20.4.tgz",
|
||||
"integrity": "sha512-y6joCi49haAA0bo3EGUY+dWUMHH1GPUc84hxrBY/0pMs+Bn+kQ1+DQJErZDTWGJrlHPWU/yekBZT72SNdp0DNA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4",
|
||||
"@tiptap/pm": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-italic": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-3.20.4.tgz",
|
||||
"integrity": "sha512-4ZqiWr7cmqPFux8tj1ZLiYytyWf343IvQemNX6AvVWvscrJcrfj3YX4Le2BA0RW3A3M6RpLQXXozuF8vxYFDeQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-link": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-link/-/extension-link-3.20.4.tgz",
|
||||
"integrity": "sha512-JNDSkWrVdb8NSvbQXwHWvK5tCMbTWwOHFOweknQZ1JPK4dei9FJVofYQaHyW4bJBdcCjds3NZSnXE8DM9iAWmg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"linkifyjs": "^4.3.2"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4",
|
||||
"@tiptap/pm": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-list": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-list/-/extension-list-3.20.4.tgz",
|
||||
"integrity": "sha512-X+5plTKhOioNcQ4KsAFJJSb/3+zR8Xhdpow4HzXtoV1KcbdDey1fhZdpsfkbrzCL0s6/wAgwZuAchCK7HujurQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4",
|
||||
"@tiptap/pm": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-list-item": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-3.20.4.tgz",
|
||||
"integrity": "sha512-QoTc5RACXaZF+vIIBBxjGO7D0oWFUDgBKJCpvUZ0CoGGKosnfe4a9I5THFyLj4201cf0oUqgf1oZhTqETGxlVw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extension-list": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-list-keymap": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-list-keymap/-/extension-list-keymap-3.20.4.tgz",
|
||||
"integrity": "sha512-RIqXM649+8IP7p/KVfaGlJiwjCylm1m6OPlaoM3K8O7oEOGRQzNeexexECCD2jsXRxew4E+vBNMD2orXqJmu8A==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extension-list": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-ordered-list": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-3.20.4.tgz",
|
||||
"integrity": "sha512-3budNL8BgBon3TcXZ4hjT0YpFvx1Ka3uSIECKDxHgES+OQcR+6cagxSb60gFEccf3Dr0PIwcVTY6g14lC1qKRQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extension-list": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-paragraph": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-3.20.4.tgz",
|
||||
"integrity": "sha512-lm6fOScWuZAF/Sfp97igUwFd3L1QHIVLAWP5NVdh0DTLrEIt4rMBmsww+yOpMQRhvz2uTgMbMXynrimhzi/QVw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-placeholder": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-placeholder/-/extension-placeholder-3.20.4.tgz",
|
||||
"integrity": "sha512-GB0KWtqm83YHG8cnqBLijvUBm+xvLfQHDfFRRH2fb3EzH3eIsM9jKRC31ADT27RSV1zVpHMFGcP3/pWpdrN1Lw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extensions": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-strike": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-3.20.4.tgz",
|
||||
"integrity": "sha512-It1Px9uDGTsVqyyg6cy7DigLoenljpQwqdI0jssM7QclZrHnsrye9fZxBBiiuCzzV1305MxKgHvratkHwqmVNA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-text": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-3.20.4.tgz",
|
||||
"integrity": "sha512-jchJcBZixDEO2J66Zx5dchsI2mA6IYsROqF8P1poxL4ienH7RVQRCTsBNnSfIeOtREKKWeOU/tEs5fcpvvGwIQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-text-align": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-text-align/-/extension-text-align-3.20.4.tgz",
|
||||
"integrity": "sha512-6ZuRyClIyCimXu+S5LQ54DueEsYg5VOVOmubOVbG+WAjM9svn9Z8gv2sNDah2yEqXrX06B02zYcSyMiD7CHbfA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-text-style": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-text-style/-/extension-text-style-3.20.4.tgz",
|
||||
"integrity": "sha512-PvW0Ja7ahWpo4bRuR8YCCVv4PH8lXjzhzlBAa4bMbsumOg+GbhX8Su7fwqd+IIPrHqfPXz9HTBMApSfzP6/08A==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-underline": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-underline/-/extension-underline-3.20.4.tgz",
|
||||
"integrity": "sha512-0OjMc3FDujX16G+jhvqcY/mLot8SrNtDu8ggUwNLAfiI/QIvMVgk7giFD71DATC/4Nb8i/iwAEegTD8MxBIXCg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extensions": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extensions/-/extensions-3.20.4.tgz",
|
||||
"integrity": "sha512-8p6hVT65DjuQjtEdlH6ewX9SOJHlVQAOee3sWIJQmeJNRnZNvqPIBLleebUqDiljNTpxBv6s6QWkSTKgf3btwg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4",
|
||||
"@tiptap/pm": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/pm": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-3.20.4.tgz",
|
||||
"integrity": "sha512-rCHYSBToilBEuI6PtjziHDdRkABH/XqwJ7dG4Amn/SD3yGiZKYCiEApQlTUS2zZeo8DsLeuqqqB4vEOeD4OEPg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-changeset": "^2.3.0",
|
||||
"prosemirror-collab": "^1.3.1",
|
||||
"prosemirror-commands": "^1.6.2",
|
||||
"prosemirror-dropcursor": "^1.8.1",
|
||||
"prosemirror-gapcursor": "^1.3.2",
|
||||
"prosemirror-history": "^1.4.1",
|
||||
"prosemirror-inputrules": "^1.4.0",
|
||||
"prosemirror-keymap": "^1.2.2",
|
||||
"prosemirror-markdown": "^1.13.1",
|
||||
"prosemirror-menu": "^1.2.4",
|
||||
"prosemirror-model": "^1.24.1",
|
||||
"prosemirror-schema-basic": "^1.2.3",
|
||||
"prosemirror-schema-list": "^1.5.0",
|
||||
"prosemirror-state": "^1.4.3",
|
||||
"prosemirror-tables": "^1.6.4",
|
||||
"prosemirror-trailing-node": "^3.0.0",
|
||||
"prosemirror-transform": "^1.10.2",
|
||||
"prosemirror-view": "^1.38.1"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/react": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/react/-/react-3.20.4.tgz",
|
||||
"integrity": "sha512-1B8iWsHWwb5TeyVaUs8BRPzwWo4PsLQcl03urHaz0zTJ8DauopqvxzV3+lem1OkzRHn7wnrapDvwmIGoROCaQw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/use-sync-external-store": "^0.0.6",
|
||||
"fast-equals": "^5.3.3",
|
||||
"use-sync-external-store": "^1.4.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@tiptap/extension-bubble-menu": "^3.20.4",
|
||||
"@tiptap/extension-floating-menu": "^3.20.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4",
|
||||
"@tiptap/pm": "^3.20.4",
|
||||
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"@types/react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/starter-kit": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/starter-kit/-/starter-kit-3.20.4.tgz",
|
||||
"integrity": "sha512-WcyK6hsTl8eBsQhQ+d9Sq8fYZKOYdL+D45MyH3hz583elXqJlW3h3JPFYb0o87gddGxn8Mm57OA/gA1zEdeDMw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tiptap/core": "^3.20.4",
|
||||
"@tiptap/extension-blockquote": "^3.20.4",
|
||||
"@tiptap/extension-bold": "^3.20.4",
|
||||
"@tiptap/extension-bullet-list": "^3.20.4",
|
||||
"@tiptap/extension-code": "^3.20.4",
|
||||
"@tiptap/extension-code-block": "^3.20.4",
|
||||
"@tiptap/extension-document": "^3.20.4",
|
||||
"@tiptap/extension-dropcursor": "^3.20.4",
|
||||
"@tiptap/extension-gapcursor": "^3.20.4",
|
||||
"@tiptap/extension-hard-break": "^3.20.4",
|
||||
"@tiptap/extension-heading": "^3.20.4",
|
||||
"@tiptap/extension-horizontal-rule": "^3.20.4",
|
||||
"@tiptap/extension-italic": "^3.20.4",
|
||||
"@tiptap/extension-link": "^3.20.4",
|
||||
"@tiptap/extension-list": "^3.20.4",
|
||||
"@tiptap/extension-list-item": "^3.20.4",
|
||||
"@tiptap/extension-list-keymap": "^3.20.4",
|
||||
"@tiptap/extension-ordered-list": "^3.20.4",
|
||||
"@tiptap/extension-paragraph": "^3.20.4",
|
||||
"@tiptap/extension-strike": "^3.20.4",
|
||||
"@tiptap/extension-text": "^3.20.4",
|
||||
"@tiptap/extension-underline": "^3.20.4",
|
||||
"@tiptap/extensions": "^3.20.4",
|
||||
"@tiptap/pm": "^3.20.4"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/babel__core": {
|
||||
"version": "7.20.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
|
||||
@@ -2285,6 +2804,28 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/linkify-it": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz",
|
||||
"integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/markdown-it": {
|
||||
"version": "14.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz",
|
||||
"integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/linkify-it": "^5",
|
||||
"@types/mdurl": "^2"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/mdurl": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz",
|
||||
"integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.19.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.15.tgz",
|
||||
@@ -2299,14 +2840,12 @@
|
||||
"version": "15.7.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz",
|
||||
"integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==",
|
||||
"devOptional": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "18.3.28",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.28.tgz",
|
||||
"integrity": "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
@@ -2317,12 +2856,17 @@
|
||||
"version": "18.3.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz",
|
||||
"integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@types/react": "^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/use-sync-external-store": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz",
|
||||
"integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@vitejs/plugin-react": {
|
||||
"version": "4.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz",
|
||||
@@ -2485,6 +3029,12 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||
"license": "Python-2.0"
|
||||
},
|
||||
"node_modules/aria-hidden": {
|
||||
"version": "1.2.6",
|
||||
"resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz",
|
||||
@@ -2803,6 +3353,12 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/crelt": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz",
|
||||
"integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cssesc": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
|
||||
@@ -2910,6 +3466,18 @@
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/entities": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
||||
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/es-define-property": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||
@@ -3011,6 +3579,18 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/escape-string-regexp": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/estree-walker": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
|
||||
@@ -3031,6 +3611,15 @@
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-equals": {
|
||||
"version": "5.4.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.4.0.tgz",
|
||||
"integrity": "sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-glob": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
|
||||
@@ -3396,6 +3985,21 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/linkify-it": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz",
|
||||
"integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"uc.micro": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/linkifyjs": {
|
||||
"version": "4.3.2",
|
||||
"resolved": "https://registry.npmjs.org/linkifyjs/-/linkifyjs-4.3.2.tgz",
|
||||
"integrity": "sha512-NT1CJtq3hHIreOianA8aSXn6Cw0JzYOuDQbOrSPe7gqFnCpKP++MQe3ODgO3oh2GJFORkAAdqredOa60z63GbA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
@@ -3444,6 +4048,23 @@
|
||||
"@jridgewell/sourcemap-codec": "^1.5.5"
|
||||
}
|
||||
},
|
||||
"node_modules/markdown-it": {
|
||||
"version": "14.1.1",
|
||||
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.1.tgz",
|
||||
"integrity": "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"argparse": "^2.0.1",
|
||||
"entities": "^4.4.0",
|
||||
"linkify-it": "^5.0.0",
|
||||
"mdurl": "^2.0.0",
|
||||
"punycode.js": "^2.3.1",
|
||||
"uc.micro": "^2.1.0"
|
||||
},
|
||||
"bin": {
|
||||
"markdown-it": "bin/markdown-it.mjs"
|
||||
}
|
||||
},
|
||||
"node_modules/math-intrinsics": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||
@@ -3453,6 +4074,12 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/mdurl": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz",
|
||||
"integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/merge2": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
||||
@@ -3573,6 +4200,12 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/orderedmap": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/orderedmap/-/orderedmap-2.1.1.tgz",
|
||||
"integrity": "sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/path-parse": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
||||
@@ -3832,12 +4465,216 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/prosemirror-changeset": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-changeset/-/prosemirror-changeset-2.4.0.tgz",
|
||||
"integrity": "sha512-LvqH2v7Q2SF6yxatuPP2e8vSUKS/L+xAU7dPDC4RMyHMhZoGDfBC74mYuyYF4gLqOEG758wajtyhNnsTkuhvng==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-transform": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-collab": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-collab/-/prosemirror-collab-1.3.1.tgz",
|
||||
"integrity": "sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-state": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-commands": {
|
||||
"version": "1.7.1",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.7.1.tgz",
|
||||
"integrity": "sha512-rT7qZnQtx5c0/y/KlYaGvtG411S97UaL6gdp6RIZ23DLHanMYLyfGBV5DtSnZdthQql7W+lEVbpSfwtO8T+L2w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-model": "^1.0.0",
|
||||
"prosemirror-state": "^1.0.0",
|
||||
"prosemirror-transform": "^1.10.2"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-dropcursor": {
|
||||
"version": "1.8.2",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-dropcursor/-/prosemirror-dropcursor-1.8.2.tgz",
|
||||
"integrity": "sha512-CCk6Gyx9+Tt2sbYk5NK0nB1ukHi2ryaRgadV/LvyNuO3ena1payM2z6Cg0vO1ebK8cxbzo41ku2DE5Axj1Zuiw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-state": "^1.0.0",
|
||||
"prosemirror-transform": "^1.1.0",
|
||||
"prosemirror-view": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-gapcursor": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-gapcursor/-/prosemirror-gapcursor-1.4.1.tgz",
|
||||
"integrity": "sha512-pMdYaEnjNMSwl11yjEGtgTmLkR08m/Vl+Jj443167p9eB3HVQKhYCc4gmHVDsLPODfZfjr/MmirsdyZziXbQKw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-keymap": "^1.0.0",
|
||||
"prosemirror-model": "^1.0.0",
|
||||
"prosemirror-state": "^1.0.0",
|
||||
"prosemirror-view": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-history": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-history/-/prosemirror-history-1.5.0.tgz",
|
||||
"integrity": "sha512-zlzTiH01eKA55UAf1MEjtssJeHnGxO0j4K4Dpx+gnmX9n+SHNlDqI2oO1Kv1iPN5B1dm5fsljCfqKF9nFL6HRg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-state": "^1.2.2",
|
||||
"prosemirror-transform": "^1.0.0",
|
||||
"prosemirror-view": "^1.31.0",
|
||||
"rope-sequence": "^1.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-inputrules": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-inputrules/-/prosemirror-inputrules-1.5.1.tgz",
|
||||
"integrity": "sha512-7wj4uMjKaXWAQ1CDgxNzNtR9AlsuwzHfdFH1ygEHA2KHF2DOEaXl1CJfNPAKCg9qNEh4rum975QLaCiQPyY6Fw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-state": "^1.0.0",
|
||||
"prosemirror-transform": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-keymap": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-keymap/-/prosemirror-keymap-1.2.3.tgz",
|
||||
"integrity": "sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-state": "^1.0.0",
|
||||
"w3c-keyname": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-markdown": {
|
||||
"version": "1.13.4",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-markdown/-/prosemirror-markdown-1.13.4.tgz",
|
||||
"integrity": "sha512-D98dm4cQ3Hs6EmjK500TdAOew4Z03EV71ajEFiWra3Upr7diytJsjF4mPV2dW+eK5uNectiRj0xFxYI9NLXDbw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/markdown-it": "^14.0.0",
|
||||
"markdown-it": "^14.0.0",
|
||||
"prosemirror-model": "^1.25.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-menu": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-menu/-/prosemirror-menu-1.3.0.tgz",
|
||||
"integrity": "sha512-TImyPXCHPcDsSka2/lwJ6WjTASr4re/qWq1yoTTuLOqfXucwF6VcRa2LWCkM/EyTD1UO3CUwiH8qURJoWJRxwg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"crelt": "^1.0.0",
|
||||
"prosemirror-commands": "^1.0.0",
|
||||
"prosemirror-history": "^1.0.0",
|
||||
"prosemirror-state": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-model": {
|
||||
"version": "1.25.4",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.25.4.tgz",
|
||||
"integrity": "sha512-PIM7E43PBxKce8OQeezAs9j4TP+5yDpZVbuurd1h5phUxEKIu+G2a+EUZzIC5nS1mJktDJWzbqS23n1tsAf5QA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"orderedmap": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-schema-basic": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-schema-basic/-/prosemirror-schema-basic-1.2.4.tgz",
|
||||
"integrity": "sha512-ELxP4TlX3yr2v5rM7Sb70SqStq5NvI15c0j9j/gjsrO5vaw+fnnpovCLEGIcpeGfifkuqJwl4fon6b+KdrODYQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-model": "^1.25.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-schema-list": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.5.1.tgz",
|
||||
"integrity": "sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-model": "^1.0.0",
|
||||
"prosemirror-state": "^1.0.0",
|
||||
"prosemirror-transform": "^1.7.3"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-state": {
|
||||
"version": "1.4.4",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.4.4.tgz",
|
||||
"integrity": "sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-model": "^1.0.0",
|
||||
"prosemirror-transform": "^1.0.0",
|
||||
"prosemirror-view": "^1.27.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-tables": {
|
||||
"version": "1.8.5",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-tables/-/prosemirror-tables-1.8.5.tgz",
|
||||
"integrity": "sha512-V/0cDCsHKHe/tfWkeCmthNUcEp1IVO3p6vwN8XtwE9PZQLAZJigbw3QoraAdfJPir4NKJtNvOB8oYGKRl+t0Dw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-keymap": "^1.2.3",
|
||||
"prosemirror-model": "^1.25.4",
|
||||
"prosemirror-state": "^1.4.4",
|
||||
"prosemirror-transform": "^1.10.5",
|
||||
"prosemirror-view": "^1.41.4"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-trailing-node": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-trailing-node/-/prosemirror-trailing-node-3.0.0.tgz",
|
||||
"integrity": "sha512-xiun5/3q0w5eRnGYfNlW1uU9W6x5MoFKWwq/0TIRgt09lv7Hcser2QYV8t4muXbEr+Fwo0geYn79Xs4GKywrRQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@remirror/core-constants": "3.0.0",
|
||||
"escape-string-regexp": "^4.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"prosemirror-model": "^1.22.1",
|
||||
"prosemirror-state": "^1.4.2",
|
||||
"prosemirror-view": "^1.33.8"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-transform": {
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.11.0.tgz",
|
||||
"integrity": "sha512-4I7Ce4KpygXb9bkiPS3hTEk4dSHorfRw8uI0pE8IhxlK2GXsqv5tIA7JUSxtSu7u8APVOTtbUBxTmnHIxVkIJw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-model": "^1.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-view": {
|
||||
"version": "1.41.7",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.41.7.tgz",
|
||||
"integrity": "sha512-jUwKNCEIGiqdvhlS91/2QAg21e4dfU5bH2iwmSDQeosXJgKF7smG0YSplOWK0cjSNgIqXe7VXqo7EIfUFJdt3w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-model": "^1.20.0",
|
||||
"prosemirror-state": "^1.0.0",
|
||||
"prosemirror-transform": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/punycode.js": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
|
||||
"integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/qrcode.react": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/qrcode.react/-/qrcode.react-4.2.0.tgz",
|
||||
@@ -4137,6 +4974,12 @@
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/rope-sequence": {
|
||||
"version": "1.3.4",
|
||||
"resolved": "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.4.tgz",
|
||||
"integrity": "sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/run-parallel": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
|
||||
@@ -4450,6 +5293,12 @@
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/uc.micro": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
|
||||
"integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "6.21.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
||||
@@ -4696,6 +5545,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/w3c-keyname": {
|
||||
"version": "2.2.8",
|
||||
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
|
||||
"integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/why-is-node-running": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz",
|
||||
|
||||
Generated
+854
-3
@@ -21,6 +21,16 @@
|
||||
"@radix-ui/react-tooltip": "^1.1.3",
|
||||
"@tanstack/react-query": "^5.56.2",
|
||||
"@tanstack/react-query-devtools": "^5.56.2",
|
||||
"@tiptap/extension-color": "^3.20.4",
|
||||
"@tiptap/extension-font-family": "^3.20.4",
|
||||
"@tiptap/extension-link": "^3.20.4",
|
||||
"@tiptap/extension-placeholder": "^3.20.4",
|
||||
"@tiptap/extension-text-align": "^3.20.4",
|
||||
"@tiptap/extension-text-style": "^3.20.4",
|
||||
"@tiptap/extension-underline": "^3.20.4",
|
||||
"@tiptap/pm": "^3.20.4",
|
||||
"@tiptap/react": "^3.20.4",
|
||||
"@tiptap/starter-kit": "^3.20.4",
|
||||
"axios": "^1.7.9",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.1.1",
|
||||
@@ -2569,6 +2579,12 @@
|
||||
"integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@remirror/core-constants": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@remirror/core-constants/-/core-constants-3.0.0.tgz",
|
||||
"integrity": "sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@remix-run/router": {
|
||||
"version": "1.23.2",
|
||||
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.2.tgz",
|
||||
@@ -2988,6 +3004,505 @@
|
||||
"react": "^18 || ^19"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/core": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/core/-/core-3.20.4.tgz",
|
||||
"integrity": "sha512-3i/DG89TFY/b34T5P+j35UcjYuB5d3+9K8u6qID+iUqNPiza015HPIZLuPfE5elNwVdV3EXIoPo0LLeBLgXXAg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/pm": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-blockquote": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-3.20.4.tgz",
|
||||
"integrity": "sha512-9sskyyhYj2oKat//lyZVXCp9YrPt4oJAZnGHYWXS0xlskjsLElrfKKlM4vpbhGss3VrhQRoEGqWLnIaJYPF1zw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-bold": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-3.20.4.tgz",
|
||||
"integrity": "sha512-Md7/mNAeJCY+VLJc8JRGI+8XkVPKiOGB1NgqQPdh3aYtxXQDChQOZoJEQl6TuudDxZ85bLZB67NjZlx3jo8/0g==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-bubble-menu": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-3.20.4.tgz",
|
||||
"integrity": "sha512-EXywPlI8wjPcAb8ozymgVhjtMjFrnhtoyNTy8ZcObdpUi5CdO9j892Y7aPbKe5hLhlDpvJk7rMfir4FFKEmfng==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@floating-ui/dom": "^1.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4",
|
||||
"@tiptap/pm": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-bullet-list": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-3.20.4.tgz",
|
||||
"integrity": "sha512-1RTGrur1EKoxfnLZ3M6xeNj8GITAz74jH2DHGcjLsd2Xr7Q7BozGaIq6GkkvKguMwbI1zCOxTHFCpUETXAIQQA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extension-list": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-code": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-3.20.4.tgz",
|
||||
"integrity": "sha512-7j8Hi964bH1SZ9oLdZC1fkqWz27mliSDV7M8lmL/M14+Qw42D/VOAKS4Aw9OCFtHMlTsjLR6qsoVxL8Lpkt6NA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-code-block": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-3.20.4.tgz",
|
||||
"integrity": "sha512-Zlw3FrXTy01+o1yISeX/LC+iJeHA+ym602bMXGmtA6lyl7QSOSO7WExweJ6xeJGhbCjldwT5al6fkRAs8iGJZg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4",
|
||||
"@tiptap/pm": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-color": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-color/-/extension-color-3.20.4.tgz",
|
||||
"integrity": "sha512-+OT9wWEJnqoWmzfqPYt0oWm8LZcH+D44Z3jA2TNzBj4tLGQ2YPxN2SyS12AlRi7MuguVT7utFy7qDXrfir8eUA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extension-text-style": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-document": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-3.20.4.tgz",
|
||||
"integrity": "sha512-zF1CIFVLt8MfSpWWnPwtGyxPOsT0xYM2qJKcXf2yZcTG37wDKmUi6heG53vGigIavbQlLaAFvs+1mNdOu2x/0A==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-dropcursor": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-3.20.4.tgz",
|
||||
"integrity": "sha512-TgMwvZ8myXYdmd6bUV7qkpZXv7ZUiSmX/8eo+iPEzYo2CnDLAGvDKgC50nfq/g87SDvfBgPuAiBfFvsMQQWaTw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extensions": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-floating-menu": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-3.20.4.tgz",
|
||||
"integrity": "sha512-AaPTFhoO8DBIElJyd/RTVJjkctvJuL+GHURX0npbtTxXq5HXbebVwf2ARNR7jMd/GThsmBaNJiGxZg4A2oeDqQ==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@floating-ui/dom": "^1.0.0",
|
||||
"@tiptap/core": "^3.20.4",
|
||||
"@tiptap/pm": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-font-family": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-font-family/-/extension-font-family-3.20.4.tgz",
|
||||
"integrity": "sha512-u5HjpNVBK7N9glR4Sz/HyVvTTAprEiion0oyyBWPBlgZvLrJta0zNvhfwG9ZUoubvqou3fBRbZwVosfonN2fAw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extension-text-style": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-gapcursor": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-3.20.4.tgz",
|
||||
"integrity": "sha512-JJ6f1iQ1e0s4kISgq55U3UYGwWV/N9f0PYMtB6e3L+SBQjXnywaLK0g6vfN6IvTCC2vdIuqeSOX8VlSO97sJLw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extensions": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-hard-break": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-3.20.4.tgz",
|
||||
"integrity": "sha512-gJbq58d8zB1gzyqVEopowej5CpW4/Fpg6oGJvlZxaCukqd0gJRWGC89K+jE62YA1Td4sfcKrekKvN7jm2y/ZUg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-heading": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-3.20.4.tgz",
|
||||
"integrity": "sha512-xsnkmTGggJc5P2iCwS1lv8KFG31xC/GNPJKoi/3UH67j/lKDhA3AdtshsLeyv2FKtTtYDb8oV0IqzHB1MM6a7w==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-horizontal-rule": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-3.20.4.tgz",
|
||||
"integrity": "sha512-y6joCi49haAA0bo3EGUY+dWUMHH1GPUc84hxrBY/0pMs+Bn+kQ1+DQJErZDTWGJrlHPWU/yekBZT72SNdp0DNA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4",
|
||||
"@tiptap/pm": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-italic": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-3.20.4.tgz",
|
||||
"integrity": "sha512-4ZqiWr7cmqPFux8tj1ZLiYytyWf343IvQemNX6AvVWvscrJcrfj3YX4Le2BA0RW3A3M6RpLQXXozuF8vxYFDeQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-link": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-link/-/extension-link-3.20.4.tgz",
|
||||
"integrity": "sha512-JNDSkWrVdb8NSvbQXwHWvK5tCMbTWwOHFOweknQZ1JPK4dei9FJVofYQaHyW4bJBdcCjds3NZSnXE8DM9iAWmg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"linkifyjs": "^4.3.2"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4",
|
||||
"@tiptap/pm": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-list": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-list/-/extension-list-3.20.4.tgz",
|
||||
"integrity": "sha512-X+5plTKhOioNcQ4KsAFJJSb/3+zR8Xhdpow4HzXtoV1KcbdDey1fhZdpsfkbrzCL0s6/wAgwZuAchCK7HujurQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4",
|
||||
"@tiptap/pm": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-list-item": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-3.20.4.tgz",
|
||||
"integrity": "sha512-QoTc5RACXaZF+vIIBBxjGO7D0oWFUDgBKJCpvUZ0CoGGKosnfe4a9I5THFyLj4201cf0oUqgf1oZhTqETGxlVw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extension-list": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-list-keymap": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-list-keymap/-/extension-list-keymap-3.20.4.tgz",
|
||||
"integrity": "sha512-RIqXM649+8IP7p/KVfaGlJiwjCylm1m6OPlaoM3K8O7oEOGRQzNeexexECCD2jsXRxew4E+vBNMD2orXqJmu8A==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extension-list": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-ordered-list": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-3.20.4.tgz",
|
||||
"integrity": "sha512-3budNL8BgBon3TcXZ4hjT0YpFvx1Ka3uSIECKDxHgES+OQcR+6cagxSb60gFEccf3Dr0PIwcVTY6g14lC1qKRQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extension-list": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-paragraph": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-3.20.4.tgz",
|
||||
"integrity": "sha512-lm6fOScWuZAF/Sfp97igUwFd3L1QHIVLAWP5NVdh0DTLrEIt4rMBmsww+yOpMQRhvz2uTgMbMXynrimhzi/QVw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-placeholder": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-placeholder/-/extension-placeholder-3.20.4.tgz",
|
||||
"integrity": "sha512-GB0KWtqm83YHG8cnqBLijvUBm+xvLfQHDfFRRH2fb3EzH3eIsM9jKRC31ADT27RSV1zVpHMFGcP3/pWpdrN1Lw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extensions": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-strike": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-3.20.4.tgz",
|
||||
"integrity": "sha512-It1Px9uDGTsVqyyg6cy7DigLoenljpQwqdI0jssM7QclZrHnsrye9fZxBBiiuCzzV1305MxKgHvratkHwqmVNA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-text": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-3.20.4.tgz",
|
||||
"integrity": "sha512-jchJcBZixDEO2J66Zx5dchsI2mA6IYsROqF8P1poxL4ienH7RVQRCTsBNnSfIeOtREKKWeOU/tEs5fcpvvGwIQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-text-align": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-text-align/-/extension-text-align-3.20.4.tgz",
|
||||
"integrity": "sha512-6ZuRyClIyCimXu+S5LQ54DueEsYg5VOVOmubOVbG+WAjM9svn9Z8gv2sNDah2yEqXrX06B02zYcSyMiD7CHbfA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-text-style": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-text-style/-/extension-text-style-3.20.4.tgz",
|
||||
"integrity": "sha512-PvW0Ja7ahWpo4bRuR8YCCVv4PH8lXjzhzlBAa4bMbsumOg+GbhX8Su7fwqd+IIPrHqfPXz9HTBMApSfzP6/08A==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-underline": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-underline/-/extension-underline-3.20.4.tgz",
|
||||
"integrity": "sha512-0OjMc3FDujX16G+jhvqcY/mLot8SrNtDu8ggUwNLAfiI/QIvMVgk7giFD71DATC/4Nb8i/iwAEegTD8MxBIXCg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extensions": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extensions/-/extensions-3.20.4.tgz",
|
||||
"integrity": "sha512-8p6hVT65DjuQjtEdlH6ewX9SOJHlVQAOee3sWIJQmeJNRnZNvqPIBLleebUqDiljNTpxBv6s6QWkSTKgf3btwg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4",
|
||||
"@tiptap/pm": "^3.20.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/pm": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-3.20.4.tgz",
|
||||
"integrity": "sha512-rCHYSBToilBEuI6PtjziHDdRkABH/XqwJ7dG4Amn/SD3yGiZKYCiEApQlTUS2zZeo8DsLeuqqqB4vEOeD4OEPg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-changeset": "^2.3.0",
|
||||
"prosemirror-collab": "^1.3.1",
|
||||
"prosemirror-commands": "^1.6.2",
|
||||
"prosemirror-dropcursor": "^1.8.1",
|
||||
"prosemirror-gapcursor": "^1.3.2",
|
||||
"prosemirror-history": "^1.4.1",
|
||||
"prosemirror-inputrules": "^1.4.0",
|
||||
"prosemirror-keymap": "^1.2.2",
|
||||
"prosemirror-markdown": "^1.13.1",
|
||||
"prosemirror-menu": "^1.2.4",
|
||||
"prosemirror-model": "^1.24.1",
|
||||
"prosemirror-schema-basic": "^1.2.3",
|
||||
"prosemirror-schema-list": "^1.5.0",
|
||||
"prosemirror-state": "^1.4.3",
|
||||
"prosemirror-tables": "^1.6.4",
|
||||
"prosemirror-trailing-node": "^3.0.0",
|
||||
"prosemirror-transform": "^1.10.2",
|
||||
"prosemirror-view": "^1.38.1"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/react": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/react/-/react-3.20.4.tgz",
|
||||
"integrity": "sha512-1B8iWsHWwb5TeyVaUs8BRPzwWo4PsLQcl03urHaz0zTJ8DauopqvxzV3+lem1OkzRHn7wnrapDvwmIGoROCaQw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/use-sync-external-store": "^0.0.6",
|
||||
"fast-equals": "^5.3.3",
|
||||
"use-sync-external-store": "^1.4.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@tiptap/extension-bubble-menu": "^3.20.4",
|
||||
"@tiptap/extension-floating-menu": "^3.20.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^3.20.4",
|
||||
"@tiptap/pm": "^3.20.4",
|
||||
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"@types/react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/starter-kit": {
|
||||
"version": "3.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/starter-kit/-/starter-kit-3.20.4.tgz",
|
||||
"integrity": "sha512-WcyK6hsTl8eBsQhQ+d9Sq8fYZKOYdL+D45MyH3hz583elXqJlW3h3JPFYb0o87gddGxn8Mm57OA/gA1zEdeDMw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tiptap/core": "^3.20.4",
|
||||
"@tiptap/extension-blockquote": "^3.20.4",
|
||||
"@tiptap/extension-bold": "^3.20.4",
|
||||
"@tiptap/extension-bullet-list": "^3.20.4",
|
||||
"@tiptap/extension-code": "^3.20.4",
|
||||
"@tiptap/extension-code-block": "^3.20.4",
|
||||
"@tiptap/extension-document": "^3.20.4",
|
||||
"@tiptap/extension-dropcursor": "^3.20.4",
|
||||
"@tiptap/extension-gapcursor": "^3.20.4",
|
||||
"@tiptap/extension-hard-break": "^3.20.4",
|
||||
"@tiptap/extension-heading": "^3.20.4",
|
||||
"@tiptap/extension-horizontal-rule": "^3.20.4",
|
||||
"@tiptap/extension-italic": "^3.20.4",
|
||||
"@tiptap/extension-link": "^3.20.4",
|
||||
"@tiptap/extension-list": "^3.20.4",
|
||||
"@tiptap/extension-list-item": "^3.20.4",
|
||||
"@tiptap/extension-list-keymap": "^3.20.4",
|
||||
"@tiptap/extension-ordered-list": "^3.20.4",
|
||||
"@tiptap/extension-paragraph": "^3.20.4",
|
||||
"@tiptap/extension-strike": "^3.20.4",
|
||||
"@tiptap/extension-text": "^3.20.4",
|
||||
"@tiptap/extension-underline": "^3.20.4",
|
||||
"@tiptap/extensions": "^3.20.4",
|
||||
"@tiptap/pm": "^3.20.4"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/babel__core": {
|
||||
"version": "7.20.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
|
||||
@@ -3040,6 +3555,28 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/linkify-it": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz",
|
||||
"integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/markdown-it": {
|
||||
"version": "14.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz",
|
||||
"integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/linkify-it": "^5",
|
||||
"@types/mdurl": "^2"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/mdurl": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz",
|
||||
"integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.19.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.15.tgz",
|
||||
@@ -3054,14 +3591,12 @@
|
||||
"version": "15.7.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz",
|
||||
"integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==",
|
||||
"devOptional": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "18.3.28",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.28.tgz",
|
||||
"integrity": "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
@@ -3072,12 +3607,17 @@
|
||||
"version": "18.3.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz",
|
||||
"integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@types/react": "^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/use-sync-external-store": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz",
|
||||
"integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@vitejs/plugin-react": {
|
||||
"version": "4.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz",
|
||||
@@ -3240,6 +3780,12 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||
"license": "Python-2.0"
|
||||
},
|
||||
"node_modules/aria-hidden": {
|
||||
"version": "1.2.6",
|
||||
"resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz",
|
||||
@@ -3558,6 +4104,12 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/crelt": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz",
|
||||
"integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cssesc": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
|
||||
@@ -3665,6 +4217,18 @@
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/entities": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
||||
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/es-define-property": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||
@@ -3766,6 +4330,18 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/escape-string-regexp": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/estree-walker": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
|
||||
@@ -3786,6 +4362,15 @@
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-equals": {
|
||||
"version": "5.4.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.4.0.tgz",
|
||||
"integrity": "sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-glob": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
|
||||
@@ -4166,6 +4751,21 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/linkify-it": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz",
|
||||
"integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"uc.micro": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/linkifyjs": {
|
||||
"version": "4.3.2",
|
||||
"resolved": "https://registry.npmjs.org/linkifyjs/-/linkifyjs-4.3.2.tgz",
|
||||
"integrity": "sha512-NT1CJtq3hHIreOianA8aSXn6Cw0JzYOuDQbOrSPe7gqFnCpKP++MQe3ODgO3oh2GJFORkAAdqredOa60z63GbA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
@@ -4214,6 +4814,23 @@
|
||||
"@jridgewell/sourcemap-codec": "^1.5.5"
|
||||
}
|
||||
},
|
||||
"node_modules/markdown-it": {
|
||||
"version": "14.1.1",
|
||||
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.1.tgz",
|
||||
"integrity": "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"argparse": "^2.0.1",
|
||||
"entities": "^4.4.0",
|
||||
"linkify-it": "^5.0.0",
|
||||
"mdurl": "^2.0.0",
|
||||
"punycode.js": "^2.3.1",
|
||||
"uc.micro": "^2.1.0"
|
||||
},
|
||||
"bin": {
|
||||
"markdown-it": "bin/markdown-it.mjs"
|
||||
}
|
||||
},
|
||||
"node_modules/math-intrinsics": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||
@@ -4223,6 +4840,12 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/mdurl": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz",
|
||||
"integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/merge2": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
||||
@@ -4343,6 +4966,12 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/orderedmap": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/orderedmap/-/orderedmap-2.1.1.tgz",
|
||||
"integrity": "sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/path-parse": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
||||
@@ -4602,12 +5231,216 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/prosemirror-changeset": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-changeset/-/prosemirror-changeset-2.4.0.tgz",
|
||||
"integrity": "sha512-LvqH2v7Q2SF6yxatuPP2e8vSUKS/L+xAU7dPDC4RMyHMhZoGDfBC74mYuyYF4gLqOEG758wajtyhNnsTkuhvng==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-transform": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-collab": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-collab/-/prosemirror-collab-1.3.1.tgz",
|
||||
"integrity": "sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-state": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-commands": {
|
||||
"version": "1.7.1",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.7.1.tgz",
|
||||
"integrity": "sha512-rT7qZnQtx5c0/y/KlYaGvtG411S97UaL6gdp6RIZ23DLHanMYLyfGBV5DtSnZdthQql7W+lEVbpSfwtO8T+L2w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-model": "^1.0.0",
|
||||
"prosemirror-state": "^1.0.0",
|
||||
"prosemirror-transform": "^1.10.2"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-dropcursor": {
|
||||
"version": "1.8.2",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-dropcursor/-/prosemirror-dropcursor-1.8.2.tgz",
|
||||
"integrity": "sha512-CCk6Gyx9+Tt2sbYk5NK0nB1ukHi2ryaRgadV/LvyNuO3ena1payM2z6Cg0vO1ebK8cxbzo41ku2DE5Axj1Zuiw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-state": "^1.0.0",
|
||||
"prosemirror-transform": "^1.1.0",
|
||||
"prosemirror-view": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-gapcursor": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-gapcursor/-/prosemirror-gapcursor-1.4.1.tgz",
|
||||
"integrity": "sha512-pMdYaEnjNMSwl11yjEGtgTmLkR08m/Vl+Jj443167p9eB3HVQKhYCc4gmHVDsLPODfZfjr/MmirsdyZziXbQKw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-keymap": "^1.0.0",
|
||||
"prosemirror-model": "^1.0.0",
|
||||
"prosemirror-state": "^1.0.0",
|
||||
"prosemirror-view": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-history": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-history/-/prosemirror-history-1.5.0.tgz",
|
||||
"integrity": "sha512-zlzTiH01eKA55UAf1MEjtssJeHnGxO0j4K4Dpx+gnmX9n+SHNlDqI2oO1Kv1iPN5B1dm5fsljCfqKF9nFL6HRg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-state": "^1.2.2",
|
||||
"prosemirror-transform": "^1.0.0",
|
||||
"prosemirror-view": "^1.31.0",
|
||||
"rope-sequence": "^1.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-inputrules": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-inputrules/-/prosemirror-inputrules-1.5.1.tgz",
|
||||
"integrity": "sha512-7wj4uMjKaXWAQ1CDgxNzNtR9AlsuwzHfdFH1ygEHA2KHF2DOEaXl1CJfNPAKCg9qNEh4rum975QLaCiQPyY6Fw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-state": "^1.0.0",
|
||||
"prosemirror-transform": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-keymap": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-keymap/-/prosemirror-keymap-1.2.3.tgz",
|
||||
"integrity": "sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-state": "^1.0.0",
|
||||
"w3c-keyname": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-markdown": {
|
||||
"version": "1.13.4",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-markdown/-/prosemirror-markdown-1.13.4.tgz",
|
||||
"integrity": "sha512-D98dm4cQ3Hs6EmjK500TdAOew4Z03EV71ajEFiWra3Upr7diytJsjF4mPV2dW+eK5uNectiRj0xFxYI9NLXDbw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/markdown-it": "^14.0.0",
|
||||
"markdown-it": "^14.0.0",
|
||||
"prosemirror-model": "^1.25.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-menu": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-menu/-/prosemirror-menu-1.3.0.tgz",
|
||||
"integrity": "sha512-TImyPXCHPcDsSka2/lwJ6WjTASr4re/qWq1yoTTuLOqfXucwF6VcRa2LWCkM/EyTD1UO3CUwiH8qURJoWJRxwg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"crelt": "^1.0.0",
|
||||
"prosemirror-commands": "^1.0.0",
|
||||
"prosemirror-history": "^1.0.0",
|
||||
"prosemirror-state": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-model": {
|
||||
"version": "1.25.4",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.25.4.tgz",
|
||||
"integrity": "sha512-PIM7E43PBxKce8OQeezAs9j4TP+5yDpZVbuurd1h5phUxEKIu+G2a+EUZzIC5nS1mJktDJWzbqS23n1tsAf5QA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"orderedmap": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-schema-basic": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-schema-basic/-/prosemirror-schema-basic-1.2.4.tgz",
|
||||
"integrity": "sha512-ELxP4TlX3yr2v5rM7Sb70SqStq5NvI15c0j9j/gjsrO5vaw+fnnpovCLEGIcpeGfifkuqJwl4fon6b+KdrODYQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-model": "^1.25.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-schema-list": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.5.1.tgz",
|
||||
"integrity": "sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-model": "^1.0.0",
|
||||
"prosemirror-state": "^1.0.0",
|
||||
"prosemirror-transform": "^1.7.3"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-state": {
|
||||
"version": "1.4.4",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.4.4.tgz",
|
||||
"integrity": "sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-model": "^1.0.0",
|
||||
"prosemirror-transform": "^1.0.0",
|
||||
"prosemirror-view": "^1.27.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-tables": {
|
||||
"version": "1.8.5",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-tables/-/prosemirror-tables-1.8.5.tgz",
|
||||
"integrity": "sha512-V/0cDCsHKHe/tfWkeCmthNUcEp1IVO3p6vwN8XtwE9PZQLAZJigbw3QoraAdfJPir4NKJtNvOB8oYGKRl+t0Dw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-keymap": "^1.2.3",
|
||||
"prosemirror-model": "^1.25.4",
|
||||
"prosemirror-state": "^1.4.4",
|
||||
"prosemirror-transform": "^1.10.5",
|
||||
"prosemirror-view": "^1.41.4"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-trailing-node": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-trailing-node/-/prosemirror-trailing-node-3.0.0.tgz",
|
||||
"integrity": "sha512-xiun5/3q0w5eRnGYfNlW1uU9W6x5MoFKWwq/0TIRgt09lv7Hcser2QYV8t4muXbEr+Fwo0geYn79Xs4GKywrRQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@remirror/core-constants": "3.0.0",
|
||||
"escape-string-regexp": "^4.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"prosemirror-model": "^1.22.1",
|
||||
"prosemirror-state": "^1.4.2",
|
||||
"prosemirror-view": "^1.33.8"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-transform": {
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.11.0.tgz",
|
||||
"integrity": "sha512-4I7Ce4KpygXb9bkiPS3hTEk4dSHorfRw8uI0pE8IhxlK2GXsqv5tIA7JUSxtSu7u8APVOTtbUBxTmnHIxVkIJw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-model": "^1.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-view": {
|
||||
"version": "1.41.7",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.41.7.tgz",
|
||||
"integrity": "sha512-jUwKNCEIGiqdvhlS91/2QAg21e4dfU5bH2iwmSDQeosXJgKF7smG0YSplOWK0cjSNgIqXe7VXqo7EIfUFJdt3w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-model": "^1.20.0",
|
||||
"prosemirror-state": "^1.0.0",
|
||||
"prosemirror-transform": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/punycode.js": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
|
||||
"integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/qrcode.react": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/qrcode.react/-/qrcode.react-4.2.0.tgz",
|
||||
@@ -4907,6 +5740,12 @@
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/rope-sequence": {
|
||||
"version": "1.3.4",
|
||||
"resolved": "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.4.tgz",
|
||||
"integrity": "sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/run-parallel": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
|
||||
@@ -5220,6 +6059,12 @@
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/uc.micro": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
|
||||
"integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "6.21.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
||||
@@ -5481,6 +6326,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/w3c-keyname": {
|
||||
"version": "2.2.8",
|
||||
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
|
||||
"integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/why-is-node-running": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz",
|
||||
|
||||
+25
-15
@@ -13,7 +13,31 @@
|
||||
"test:e2e": "playwright test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@radix-ui/react-avatar": "^1.1.1",
|
||||
"@radix-ui/react-dialog": "^1.1.2",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.2",
|
||||
"@radix-ui/react-label": "^2.1.0",
|
||||
"@radix-ui/react-scroll-area": "^1.2.0",
|
||||
"@radix-ui/react-select": "^2.1.2",
|
||||
"@radix-ui/react-separator": "^1.1.0",
|
||||
"@radix-ui/react-slot": "^1.1.0",
|
||||
"@radix-ui/react-switch": "^1.1.1",
|
||||
"@radix-ui/react-tabs": "^1.1.1",
|
||||
"@radix-ui/react-tooltip": "^1.1.3",
|
||||
"@tanstack/react-query": "^5.56.2",
|
||||
"@tanstack/react-query-devtools": "^5.56.2",
|
||||
"@tiptap/extension-color": "^3.20.4",
|
||||
"@tiptap/extension-font-family": "^3.20.4",
|
||||
"@tiptap/extension-link": "^3.20.4",
|
||||
"@tiptap/extension-placeholder": "^3.20.4",
|
||||
"@tiptap/extension-text-align": "^3.20.4",
|
||||
"@tiptap/extension-text-style": "^3.20.4",
|
||||
"@tiptap/extension-underline": "^3.20.4",
|
||||
"@tiptap/pm": "^3.20.4",
|
||||
"@tiptap/react": "^3.20.4",
|
||||
"@tiptap/starter-kit": "^3.20.4",
|
||||
"axios": "^1.7.9",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.1.1",
|
||||
"date-fns": "^3.6.0",
|
||||
"lucide-react": "^0.441.0",
|
||||
@@ -24,21 +48,7 @@
|
||||
"react-hot-toast": "^2.4.1",
|
||||
"react-router-dom": "^6.26.2",
|
||||
"tailwind-merge": "^2.5.2",
|
||||
"zustand": "^5.0.0",
|
||||
"@tanstack/react-query": "^5.56.2",
|
||||
"@tanstack/react-query-devtools": "^5.56.2",
|
||||
"@radix-ui/react-dialog": "^1.1.2",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.2",
|
||||
"@radix-ui/react-label": "^2.1.0",
|
||||
"@radix-ui/react-select": "^2.1.2",
|
||||
"@radix-ui/react-separator": "^1.1.0",
|
||||
"@radix-ui/react-slot": "^1.1.0",
|
||||
"@radix-ui/react-switch": "^1.1.1",
|
||||
"@radix-ui/react-tabs": "^1.1.1",
|
||||
"@radix-ui/react-tooltip": "^1.1.3",
|
||||
"@radix-ui/react-avatar": "^1.1.1",
|
||||
"@radix-ui/react-scroll-area": "^1.2.0",
|
||||
"class-variance-authority": "^0.7.0"
|
||||
"zustand": "^5.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.47.2",
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
import apiClient from './client'
|
||||
import type {
|
||||
LabelCreate,
|
||||
LabelResponse,
|
||||
LabelUpdate,
|
||||
MessageBulkLabelRequest,
|
||||
MessageBulkLabelResponse,
|
||||
MessageLabelAddRequest,
|
||||
MessageLabelRemoveRequest,
|
||||
MessageLabelSetRequest,
|
||||
} from '@/types/api.types'
|
||||
|
||||
export const labelsApi = {
|
||||
// ─── CRUD Tag ─────────────────────────────────────────────────────────────
|
||||
|
||||
list: () =>
|
||||
apiClient.get<LabelResponse[]>('/labels').then((r) => r.data),
|
||||
|
||||
create: (data: LabelCreate) =>
|
||||
apiClient.post<LabelResponse>('/labels', data).then((r) => r.data),
|
||||
|
||||
update: (id: string, data: LabelUpdate) =>
|
||||
apiClient.patch<LabelResponse>(`/labels/${id}`, data).then((r) => r.data),
|
||||
|
||||
delete: (id: string) =>
|
||||
apiClient.delete(`/labels/${id}`).then((r) => r.data),
|
||||
|
||||
// ─── Tag su singolo messaggio ─────────────────────────────────────────────
|
||||
|
||||
getMessageLabels: (messageId: string) =>
|
||||
apiClient
|
||||
.get<LabelResponse[]>(`/messages/${messageId}/labels`)
|
||||
.then((r) => r.data),
|
||||
|
||||
/** Sostituisce tutti i tag di un messaggio. */
|
||||
setMessageLabels: (messageId: string, data: MessageLabelSetRequest) =>
|
||||
apiClient
|
||||
.put<LabelResponse[]>(`/messages/${messageId}/labels`, data)
|
||||
.then((r) => r.data),
|
||||
|
||||
/** Aggiunge tag a un messaggio senza rimuovere quelli esistenti. */
|
||||
addMessageLabels: (messageId: string, data: MessageLabelAddRequest) =>
|
||||
apiClient
|
||||
.post<LabelResponse[]>(`/messages/${messageId}/labels/add`, data)
|
||||
.then((r) => r.data),
|
||||
|
||||
/** Rimuove specifici tag da un messaggio. */
|
||||
removeMessageLabels: (messageId: string, data: MessageLabelRemoveRequest) =>
|
||||
apiClient
|
||||
.post<LabelResponse[]>(`/messages/${messageId}/labels/remove`, data)
|
||||
.then((r) => r.data),
|
||||
|
||||
// ─── Bulk ─────────────────────────────────────────────────────────────────
|
||||
|
||||
bulkLabels: (data: MessageBulkLabelRequest) =>
|
||||
apiClient
|
||||
.post<MessageBulkLabelResponse>('/messages/bulk-labels', data)
|
||||
.then((r) => r.data),
|
||||
}
|
||||
@@ -69,8 +69,25 @@ export const messagesApi = {
|
||||
getAttachments: (id: string) =>
|
||||
apiClient.get<AttachmentResponse[]>(`/messages/${id}/attachments`).then((r) => r.data),
|
||||
|
||||
getAttachmentUrl: (messageId: string, attachmentId: string) =>
|
||||
`/api/v1/messages/${messageId}/attachments/${attachmentId}/download`,
|
||||
/**
|
||||
* Scarica un allegato autenticato e lo salva localmente.
|
||||
* Utilizza apiClient (con Bearer token) per evitare il 401 che si ottiene
|
||||
* navigando direttamente verso l'URL con un <a href>.
|
||||
*/
|
||||
downloadAttachment: async (messageId: string, attachmentId: string, filename: string): Promise<void> => {
|
||||
const response = await apiClient.get(
|
||||
`/messages/${messageId}/attachments/${attachmentId}/download`,
|
||||
{ responseType: 'blob' },
|
||||
)
|
||||
const blobUrl = window.URL.createObjectURL(new Blob([response.data]))
|
||||
const anchor = document.createElement('a')
|
||||
anchor.href = blobUrl
|
||||
anchor.setAttribute('download', filename)
|
||||
document.body.appendChild(anchor)
|
||||
anchor.click()
|
||||
anchor.remove()
|
||||
window.URL.revokeObjectURL(blobUrl)
|
||||
},
|
||||
|
||||
getReceipts: (id: string) =>
|
||||
apiClient.get<MessageResponse[]>(`/messages/${id}/receipts`).then((r) => r.data),
|
||||
|
||||
@@ -12,10 +12,33 @@ export interface SendJobFilters {
|
||||
status?: string
|
||||
}
|
||||
|
||||
/** Payload esteso per l'invio multipart (include body_html) */
|
||||
export interface SendPecMultipartRequest extends SendPecRequest {
|
||||
body_html?: string
|
||||
}
|
||||
|
||||
export const sendApi = {
|
||||
/** Invio PEC semplice (JSON, senza allegati) – retrocompatibile */
|
||||
send: (data: SendPecRequest) =>
|
||||
apiClient.post<SendJobResponse>('/send', data).then((r) => r.data),
|
||||
|
||||
/**
|
||||
* Invio PEC con allegati tramite multipart/form-data.
|
||||
*
|
||||
* Il campo `data` viene serializzato come JSON string;
|
||||
* i file vengono appesi come `attachments[]`.
|
||||
*/
|
||||
sendMultipart: (data: SendPecMultipartRequest, files: File[] = []) => {
|
||||
const formData = new FormData()
|
||||
formData.append('data', JSON.stringify(data))
|
||||
files.forEach((file) => formData.append('attachments', file))
|
||||
return apiClient
|
||||
.post<SendJobResponse>('/send/multipart', formData, {
|
||||
headers: { 'Content-Type': 'multipart/form-data' },
|
||||
})
|
||||
.then((r) => r.data)
|
||||
},
|
||||
|
||||
listJobs: (filters: SendJobFilters = {}) =>
|
||||
apiClient.get<SendJobListResponse>('/send/jobs', { params: filters }).then((r) => r.data),
|
||||
|
||||
|
||||
@@ -0,0 +1,517 @@
|
||||
/**
|
||||
* RichTextEditor – editor di testo ricco in stile Roundcube.
|
||||
*
|
||||
* Usa TipTap (ProseMirror) con estensioni per:
|
||||
* - Formattazione testo: grassetto, corsivo, sottolineato, barrato
|
||||
* - Colore testo (palette + picker custom)
|
||||
* - Titoli H1/H2/H3
|
||||
* - Elenchi puntati, numerati, citazioni
|
||||
* - Allineamento testo
|
||||
* - Collegamento ipertestuale
|
||||
* - Undo/Redo
|
||||
* - Rimuovi formattazione
|
||||
*/
|
||||
|
||||
import { useEditor, EditorContent } from '@tiptap/react'
|
||||
import StarterKit from '@tiptap/starter-kit'
|
||||
import UnderlineExt from '@tiptap/extension-underline'
|
||||
import TextAlign from '@tiptap/extension-text-align'
|
||||
import Link from '@tiptap/extension-link'
|
||||
import Placeholder from '@tiptap/extension-placeholder'
|
||||
import { TextStyle } from '@tiptap/extension-text-style'
|
||||
import Color from '@tiptap/extension-color'
|
||||
import { useEffect, useCallback, useState, useRef } from 'react'
|
||||
import {
|
||||
Bold,
|
||||
Italic,
|
||||
Underline,
|
||||
Strikethrough,
|
||||
AlignLeft,
|
||||
AlignCenter,
|
||||
AlignRight,
|
||||
AlignJustify,
|
||||
List,
|
||||
ListOrdered,
|
||||
Quote,
|
||||
Link as LinkIcon,
|
||||
Link2Off,
|
||||
Undo2,
|
||||
Redo2,
|
||||
Baseline,
|
||||
Eraser,
|
||||
} from 'lucide-react'
|
||||
|
||||
// ─── Tipi ────────────────────────────────────────────────────────────────────
|
||||
|
||||
interface RichTextEditorProps {
|
||||
value: string
|
||||
onChange: (html: string) => void
|
||||
placeholder?: string
|
||||
minHeight?: string
|
||||
}
|
||||
|
||||
// ─── Palette colori ───────────────────────────────────────────────────────────
|
||||
|
||||
const COLOR_PALETTE = [
|
||||
// Grigi
|
||||
'#000000', '#434343', '#666666', '#999999', '#b7b7b7', '#cccccc', '#d9d9d9', '#ffffff',
|
||||
// Vivaci
|
||||
'#ff0000', '#ff9900', '#ffff00', '#00ff00', '#00ffff', '#4a86e8', '#9900ff', '#ff00ff',
|
||||
// Chiari
|
||||
'#f4cccc', '#fce5cd', '#fff2cc', '#d9ead3', '#d0e0e3', '#cfe2f3', '#d9d2e9', '#ead1dc',
|
||||
// Standard
|
||||
'#ea4335', '#fbbc04', '#34a853', '#4285f4', '#9334e6', '#c2185b', '#e65100', '#00838f',
|
||||
]
|
||||
|
||||
// ─── Sub-componenti toolbar ───────────────────────────────────────────────────
|
||||
|
||||
interface ToolbarButtonProps {
|
||||
onClick: () => void
|
||||
isActive?: boolean
|
||||
disabled?: boolean
|
||||
title: string
|
||||
children: React.ReactNode
|
||||
}
|
||||
|
||||
function ToolbarButton({ onClick, isActive, disabled, title, children }: ToolbarButtonProps) {
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
title={title}
|
||||
disabled={disabled}
|
||||
onClick={onClick}
|
||||
className={[
|
||||
'flex items-center justify-center w-7 h-7 rounded text-sm transition-colors select-none',
|
||||
isActive
|
||||
? 'bg-primary/15 text-primary'
|
||||
: 'text-foreground hover:bg-muted',
|
||||
disabled ? 'opacity-40 cursor-not-allowed' : 'cursor-pointer',
|
||||
].join(' ')}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
function ToolbarSeparator() {
|
||||
return <div className="w-px h-5 bg-border mx-0.5 flex-shrink-0" />
|
||||
}
|
||||
|
||||
// ─── Color Picker ─────────────────────────────────────────────────────────────
|
||||
|
||||
interface ColorPickerProps {
|
||||
currentColor?: string
|
||||
onSelect: (color: string) => void
|
||||
onClose: () => void
|
||||
}
|
||||
|
||||
function ColorPicker({ currentColor, onSelect, onClose }: ColorPickerProps) {
|
||||
const ref = useRef<HTMLDivElement>(null)
|
||||
|
||||
useEffect(() => {
|
||||
const handler = (e: MouseEvent) => {
|
||||
if (ref.current && !ref.current.contains(e.target as Node)) {
|
||||
onClose()
|
||||
}
|
||||
}
|
||||
// Delay to avoid closing immediately on the button click that opened us
|
||||
const timer = setTimeout(() => document.addEventListener('mousedown', handler), 50)
|
||||
return () => {
|
||||
clearTimeout(timer)
|
||||
document.removeEventListener('mousedown', handler)
|
||||
}
|
||||
}, [onClose])
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className="absolute z-50 top-full left-0 mt-1 p-2.5 bg-background border rounded-lg shadow-xl min-w-max"
|
||||
>
|
||||
<div className="text-xs text-muted-foreground mb-1.5 font-medium">Colore testo</div>
|
||||
<div className="grid grid-cols-8 gap-1 mb-2">
|
||||
{COLOR_PALETTE.map((color) => (
|
||||
<button
|
||||
key={color}
|
||||
type="button"
|
||||
className={[
|
||||
'w-5 h-5 rounded-sm border transition-transform hover:scale-110',
|
||||
currentColor === color ? 'ring-2 ring-primary ring-offset-1' : 'border-border/40',
|
||||
].join(' ')}
|
||||
style={{ backgroundColor: color }}
|
||||
onClick={() => { onSelect(color); onClose() }}
|
||||
title={color}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div className="flex items-center gap-2 pt-1.5 border-t">
|
||||
<label className="text-xs text-muted-foreground">Personalizzato:</label>
|
||||
<input
|
||||
type="color"
|
||||
className="w-7 h-6 rounded cursor-pointer border border-border"
|
||||
defaultValue={currentColor || '#000000'}
|
||||
onChange={(e) => onSelect(e.target.value)}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
className="text-xs text-muted-foreground hover:text-foreground underline ml-auto"
|
||||
onClick={() => { onSelect(''); onClose() }}
|
||||
>
|
||||
Rimuovi
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// ─── Link Dialog ──────────────────────────────────────────────────────────────
|
||||
|
||||
interface LinkDialogProps {
|
||||
currentUrl?: string
|
||||
onConfirm: (url: string) => void
|
||||
onRemove: () => void
|
||||
onClose: () => void
|
||||
}
|
||||
|
||||
function LinkDialog({ currentUrl, onConfirm, onRemove, onClose }: LinkDialogProps) {
|
||||
const [url, setUrl] = useState(currentUrl || 'https://')
|
||||
const ref = useRef<HTMLDivElement>(null)
|
||||
const inputRef = useRef<HTMLInputElement>(null)
|
||||
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => inputRef.current?.focus(), 50)
|
||||
const handler = (e: MouseEvent) => {
|
||||
if (ref.current && !ref.current.contains(e.target as Node)) onClose()
|
||||
}
|
||||
setTimeout(() => document.addEventListener('mousedown', handler), 50)
|
||||
return () => {
|
||||
clearTimeout(timer)
|
||||
document.removeEventListener('mousedown', handler)
|
||||
}
|
||||
}, [onClose])
|
||||
|
||||
const confirm = useCallback(() => {
|
||||
if (url && url !== 'https://') {
|
||||
onConfirm(url.startsWith('http') ? url : `https://${url}`)
|
||||
}
|
||||
onClose()
|
||||
}, [url, onConfirm, onClose])
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className="absolute z-50 top-full left-0 mt-1 p-3 bg-background border rounded-lg shadow-xl w-80"
|
||||
>
|
||||
<div className="text-xs text-muted-foreground mb-2 font-medium">
|
||||
{currentUrl ? 'Modifica collegamento' : 'Inserisci collegamento'}
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<input
|
||||
ref={inputRef}
|
||||
type="url"
|
||||
value={url}
|
||||
onChange={(e) => setUrl(e.target.value)}
|
||||
placeholder="https://esempio.it"
|
||||
className="flex-1 text-sm border rounded px-2 py-1.5 focus:outline-none focus:ring-1 focus:ring-ring bg-background"
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') confirm()
|
||||
if (e.key === 'Escape') onClose()
|
||||
}}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
className="px-3 py-1.5 bg-primary text-primary-foreground rounded text-sm font-medium hover:bg-primary/90"
|
||||
onClick={confirm}
|
||||
>
|
||||
OK
|
||||
</button>
|
||||
{currentUrl && (
|
||||
<button
|
||||
type="button"
|
||||
className="p-1.5 bg-destructive/10 text-destructive rounded hover:bg-destructive/20"
|
||||
onClick={() => { onRemove(); onClose() }}
|
||||
title="Rimuovi collegamento"
|
||||
>
|
||||
<Link2Off className="h-4 w-4" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// ─── Toolbar principale ───────────────────────────────────────────────────────
|
||||
|
||||
interface ToolbarProps {
|
||||
editor: ReturnType<typeof useEditor>
|
||||
}
|
||||
|
||||
function Toolbar({ editor }: ToolbarProps) {
|
||||
const [showColorPicker, setShowColorPicker] = useState(false)
|
||||
const [showLinkDialog, setShowLinkDialog] = useState(false)
|
||||
const colorRef = useRef<HTMLDivElement>(null)
|
||||
const linkRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
if (!editor) return null
|
||||
|
||||
const currentColor = editor.getAttributes('textStyle').color as string | undefined
|
||||
const currentLinkUrl = editor.getAttributes('link').href as string | undefined
|
||||
|
||||
return (
|
||||
<div className="flex flex-wrap items-center gap-0.5 p-1.5 bg-muted/40 border-b overflow-x-auto">
|
||||
|
||||
{/* Undo / Redo */}
|
||||
<ToolbarButton
|
||||
onClick={() => editor.chain().focus().undo().run()}
|
||||
disabled={!editor.can().undo()}
|
||||
title="Annulla (Ctrl+Z)"
|
||||
>
|
||||
<Undo2 className="h-3.5 w-3.5" />
|
||||
</ToolbarButton>
|
||||
<ToolbarButton
|
||||
onClick={() => editor.chain().focus().redo().run()}
|
||||
disabled={!editor.can().redo()}
|
||||
title="Ripeti (Ctrl+Y)"
|
||||
>
|
||||
<Redo2 className="h-3.5 w-3.5" />
|
||||
</ToolbarButton>
|
||||
|
||||
<ToolbarSeparator />
|
||||
|
||||
{/* Formattazione di base */}
|
||||
<ToolbarButton
|
||||
onClick={() => editor.chain().focus().toggleBold().run()}
|
||||
isActive={editor.isActive('bold')}
|
||||
title="Grassetto (Ctrl+B)"
|
||||
>
|
||||
<Bold className="h-3.5 w-3.5" />
|
||||
</ToolbarButton>
|
||||
<ToolbarButton
|
||||
onClick={() => editor.chain().focus().toggleItalic().run()}
|
||||
isActive={editor.isActive('italic')}
|
||||
title="Corsivo (Ctrl+I)"
|
||||
>
|
||||
<Italic className="h-3.5 w-3.5" />
|
||||
</ToolbarButton>
|
||||
<ToolbarButton
|
||||
onClick={() => editor.chain().focus().toggleUnderline().run()}
|
||||
isActive={editor.isActive('underline')}
|
||||
title="Sottolineato (Ctrl+U)"
|
||||
>
|
||||
<Underline className="h-3.5 w-3.5" />
|
||||
</ToolbarButton>
|
||||
<ToolbarButton
|
||||
onClick={() => editor.chain().focus().toggleStrike().run()}
|
||||
isActive={editor.isActive('strike')}
|
||||
title="Barrato"
|
||||
>
|
||||
<Strikethrough className="h-3.5 w-3.5" />
|
||||
</ToolbarButton>
|
||||
|
||||
<ToolbarSeparator />
|
||||
|
||||
{/* Colore testo */}
|
||||
<div className="relative" ref={colorRef}>
|
||||
<ToolbarButton
|
||||
onClick={() => setShowColorPicker((v) => !v)}
|
||||
isActive={showColorPicker}
|
||||
title="Colore testo"
|
||||
>
|
||||
<span className="flex flex-col items-center leading-none">
|
||||
<Baseline className="h-3 w-3" />
|
||||
<span
|
||||
className="block h-[3px] w-4 rounded-sm mt-0.5"
|
||||
style={{ backgroundColor: currentColor || '#000000' }}
|
||||
/>
|
||||
</span>
|
||||
</ToolbarButton>
|
||||
{showColorPicker && (
|
||||
<ColorPicker
|
||||
currentColor={currentColor}
|
||||
onSelect={(color) => {
|
||||
if (color) {
|
||||
editor.chain().focus().setColor(color).run()
|
||||
} else {
|
||||
editor.chain().focus().unsetColor().run()
|
||||
}
|
||||
}}
|
||||
onClose={() => setShowColorPicker(false)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Rimuovi formattazione */}
|
||||
<ToolbarButton
|
||||
onClick={() => editor.chain().focus().clearNodes().unsetAllMarks().run()}
|
||||
title="Rimuovi formattazione"
|
||||
>
|
||||
<Eraser className="h-3.5 w-3.5" />
|
||||
</ToolbarButton>
|
||||
|
||||
<ToolbarSeparator />
|
||||
|
||||
{/* Titoli */}
|
||||
<ToolbarButton
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 1 }).run()}
|
||||
isActive={editor.isActive('heading', { level: 1 })}
|
||||
title="Titolo 1"
|
||||
>
|
||||
<span className="text-[11px] font-bold leading-none">H1</span>
|
||||
</ToolbarButton>
|
||||
<ToolbarButton
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 2 }).run()}
|
||||
isActive={editor.isActive('heading', { level: 2 })}
|
||||
title="Titolo 2"
|
||||
>
|
||||
<span className="text-[11px] font-bold leading-none">H2</span>
|
||||
</ToolbarButton>
|
||||
<ToolbarButton
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 3 }).run()}
|
||||
isActive={editor.isActive('heading', { level: 3 })}
|
||||
title="Titolo 3"
|
||||
>
|
||||
<span className="text-[11px] font-bold leading-none">H3</span>
|
||||
</ToolbarButton>
|
||||
|
||||
<ToolbarSeparator />
|
||||
|
||||
{/* Elenchi */}
|
||||
<ToolbarButton
|
||||
onClick={() => editor.chain().focus().toggleBulletList().run()}
|
||||
isActive={editor.isActive('bulletList')}
|
||||
title="Elenco puntato"
|
||||
>
|
||||
<List className="h-3.5 w-3.5" />
|
||||
</ToolbarButton>
|
||||
<ToolbarButton
|
||||
onClick={() => editor.chain().focus().toggleOrderedList().run()}
|
||||
isActive={editor.isActive('orderedList')}
|
||||
title="Elenco numerato"
|
||||
>
|
||||
<ListOrdered className="h-3.5 w-3.5" />
|
||||
</ToolbarButton>
|
||||
<ToolbarButton
|
||||
onClick={() => editor.chain().focus().toggleBlockquote().run()}
|
||||
isActive={editor.isActive('blockquote')}
|
||||
title="Citazione"
|
||||
>
|
||||
<Quote className="h-3.5 w-3.5" />
|
||||
</ToolbarButton>
|
||||
|
||||
<ToolbarSeparator />
|
||||
|
||||
{/* Allineamento */}
|
||||
<ToolbarButton
|
||||
onClick={() => editor.chain().focus().setTextAlign('left').run()}
|
||||
isActive={editor.isActive({ textAlign: 'left' })}
|
||||
title="Allinea a sinistra"
|
||||
>
|
||||
<AlignLeft className="h-3.5 w-3.5" />
|
||||
</ToolbarButton>
|
||||
<ToolbarButton
|
||||
onClick={() => editor.chain().focus().setTextAlign('center').run()}
|
||||
isActive={editor.isActive({ textAlign: 'center' })}
|
||||
title="Centra"
|
||||
>
|
||||
<AlignCenter className="h-3.5 w-3.5" />
|
||||
</ToolbarButton>
|
||||
<ToolbarButton
|
||||
onClick={() => editor.chain().focus().setTextAlign('right').run()}
|
||||
isActive={editor.isActive({ textAlign: 'right' })}
|
||||
title="Allinea a destra"
|
||||
>
|
||||
<AlignRight className="h-3.5 w-3.5" />
|
||||
</ToolbarButton>
|
||||
<ToolbarButton
|
||||
onClick={() => editor.chain().focus().setTextAlign('justify').run()}
|
||||
isActive={editor.isActive({ textAlign: 'justify' })}
|
||||
title="Giustifica"
|
||||
>
|
||||
<AlignJustify className="h-3.5 w-3.5" />
|
||||
</ToolbarButton>
|
||||
|
||||
<ToolbarSeparator />
|
||||
|
||||
{/* Link */}
|
||||
<div className="relative" ref={linkRef}>
|
||||
<ToolbarButton
|
||||
onClick={() => setShowLinkDialog((v) => !v)}
|
||||
isActive={editor.isActive('link') || showLinkDialog}
|
||||
title={editor.isActive('link') ? 'Modifica collegamento' : 'Inserisci collegamento'}
|
||||
>
|
||||
<LinkIcon className="h-3.5 w-3.5" />
|
||||
</ToolbarButton>
|
||||
{showLinkDialog && (
|
||||
<LinkDialog
|
||||
currentUrl={currentLinkUrl}
|
||||
onConfirm={(url) =>
|
||||
editor.chain().focus().extendMarkRange('link').setLink({ href: url }).run()
|
||||
}
|
||||
onRemove={() => editor.chain().focus().unsetLink().run()}
|
||||
onClose={() => setShowLinkDialog(false)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// ─── Componente principale ────────────────────────────────────────────────────
|
||||
|
||||
export function RichTextEditor({
|
||||
value,
|
||||
onChange,
|
||||
placeholder = 'Scrivi il testo della PEC...',
|
||||
minHeight = '260px',
|
||||
}: RichTextEditorProps) {
|
||||
const editor = useEditor({
|
||||
extensions: [
|
||||
StarterKit.configure({
|
||||
heading: { levels: [1, 2, 3] },
|
||||
}),
|
||||
UnderlineExt,
|
||||
TextStyle,
|
||||
Color,
|
||||
TextAlign.configure({
|
||||
types: ['heading', 'paragraph'],
|
||||
defaultAlignment: 'left',
|
||||
}),
|
||||
Link.configure({
|
||||
openOnClick: false,
|
||||
HTMLAttributes: {
|
||||
class: 'rte-link',
|
||||
rel: 'noopener noreferrer',
|
||||
},
|
||||
}),
|
||||
Placeholder.configure({ placeholder }),
|
||||
],
|
||||
content: value,
|
||||
onUpdate: ({ editor }) => {
|
||||
onChange(editor.getHTML())
|
||||
},
|
||||
editorProps: {
|
||||
attributes: {
|
||||
class: 'rte-content focus:outline-none',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
// Sync da valore esterno (es. modifica replyTo dopo il mount)
|
||||
useEffect(() => {
|
||||
if (editor && !editor.isDestroyed && value !== editor.getHTML()) {
|
||||
editor.commands.setContent(value, { emitUpdate: false })
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [value])
|
||||
|
||||
return (
|
||||
<div className="border rounded-md overflow-hidden focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2 bg-background">
|
||||
<Toolbar editor={editor} />
|
||||
<EditorContent
|
||||
editor={editor}
|
||||
style={{ minHeight }}
|
||||
className="px-4 py-3 overflow-y-auto"
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* TagBadge – badge colorato per un singolo tag/label.
|
||||
*
|
||||
* Mostra il nome del tag con il colore di sfondo configurato.
|
||||
* Se `onRemove` è fornito, mostra un pulsante × per rimuovere il tag.
|
||||
*/
|
||||
import { X } from 'lucide-react'
|
||||
import { cn } from '@/lib/utils'
|
||||
import type { LabelResponse } from '@/types/api.types'
|
||||
|
||||
// Colore di default quando il tag non ha colore configurato
|
||||
const DEFAULT_COLOR = '#6b7280'
|
||||
|
||||
/**
|
||||
* Calcola il colore del testo (bianco o nero) in base alla luminosità
|
||||
* del colore di sfondo per garantire un contrasto leggibile.
|
||||
*/
|
||||
function getTextColor(hexColor: string): string {
|
||||
const hex = hexColor.replace('#', '')
|
||||
const r = parseInt(hex.substring(0, 2), 16)
|
||||
const g = parseInt(hex.substring(2, 4), 16)
|
||||
const b = parseInt(hex.substring(4, 6), 16)
|
||||
// Formula luminosità relativa (WCAG)
|
||||
const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255
|
||||
return luminance > 0.5 ? '#1f2937' : '#ffffff'
|
||||
}
|
||||
|
||||
interface TagBadgeProps {
|
||||
label: LabelResponse
|
||||
onRemove?: () => void
|
||||
size?: 'sm' | 'md'
|
||||
className?: string
|
||||
}
|
||||
|
||||
export function TagBadge({ label, onRemove, size = 'sm', className }: TagBadgeProps) {
|
||||
const bgColor = label.color || DEFAULT_COLOR
|
||||
const textColor = getTextColor(bgColor)
|
||||
|
||||
return (
|
||||
<span
|
||||
className={cn(
|
||||
'inline-flex items-center gap-1 rounded-full font-medium transition-all',
|
||||
size === 'sm' ? 'px-2 py-0.5 text-xs' : 'px-2.5 py-1 text-sm',
|
||||
className,
|
||||
)}
|
||||
style={{ backgroundColor: bgColor, color: textColor }}
|
||||
title={label.name}
|
||||
>
|
||||
<span className="truncate max-w-[120px]">{label.name}</span>
|
||||
{onRemove && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
onRemove()
|
||||
}}
|
||||
className="flex-shrink-0 rounded-full p-0.5 hover:opacity-70 transition-opacity"
|
||||
style={{ color: textColor }}
|
||||
aria-label={`Rimuovi tag ${label.name}`}
|
||||
>
|
||||
<X className="h-3 w-3" />
|
||||
</button>
|
||||
)}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* TagBadgeList – mostra una lista compatta di tag badge.
|
||||
* Se ci sono più tag del limite `maxVisible`, mostra un badge "+N".
|
||||
*/
|
||||
interface TagBadgeListProps {
|
||||
labels: LabelResponse[]
|
||||
onRemove?: (labelId: string) => void
|
||||
maxVisible?: number
|
||||
size?: 'sm' | 'md'
|
||||
className?: string
|
||||
}
|
||||
|
||||
export function TagBadgeList({
|
||||
labels,
|
||||
onRemove,
|
||||
maxVisible = 3,
|
||||
size = 'sm',
|
||||
className,
|
||||
}: TagBadgeListProps) {
|
||||
if (!labels || labels.length === 0) return null
|
||||
|
||||
const visible = labels.slice(0, maxVisible)
|
||||
const overflow = labels.length - maxVisible
|
||||
|
||||
return (
|
||||
<div className={cn('flex items-center gap-1 flex-wrap', className)}>
|
||||
{visible.map((label) => (
|
||||
<TagBadge
|
||||
key={label.id}
|
||||
label={label}
|
||||
onRemove={onRemove ? () => onRemove(label.id) : undefined}
|
||||
size={size}
|
||||
/>
|
||||
))}
|
||||
{overflow > 0 && (
|
||||
<span
|
||||
className="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-muted text-muted-foreground"
|
||||
title={labels
|
||||
.slice(maxVisible)
|
||||
.map((l) => l.name)
|
||||
.join(', ')}
|
||||
>
|
||||
+{overflow}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,392 @@
|
||||
/**
|
||||
* TagSelector – pannello di selezione/creazione tag per messaggi.
|
||||
*
|
||||
* Modalità d'uso:
|
||||
* - single: apre un Dialog per impostare i tag di un singolo messaggio
|
||||
* - bulk: apre un Dialog per aggiungere o rimuovere tag da più messaggi
|
||||
*
|
||||
* Funzionalità:
|
||||
* - Lista tutti i tag del tenant con checkbox
|
||||
* - Ricerca/filtro tag
|
||||
* - Crea nuovi tag con nome e colore (solo per admin)
|
||||
* - Mostra anteprima del badge colorato
|
||||
*/
|
||||
import { useState, useMemo } from 'react'
|
||||
import { Plus, Search, Tag, Check, Trash2 } from 'lucide-react'
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import { Button } from '@/components/ui/Button'
|
||||
import { Input } from '@/components/ui/Input'
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogFooter,
|
||||
} from '@/components/ui/Dialog'
|
||||
import { TagBadge } from './TagBadge'
|
||||
import { labelsApi } from '@/api/labels.api'
|
||||
import { getErrorMessage } from '@/api/client'
|
||||
import { useAuth } from '@/hooks/useAuth'
|
||||
import { cn } from '@/lib/utils'
|
||||
import type { LabelResponse } from '@/types/api.types'
|
||||
|
||||
// ─── Tavolozza colori predefiniti ─────────────────────────────────────────────
|
||||
|
||||
const PRESET_COLORS = [
|
||||
'#ef4444', // rosso
|
||||
'#f97316', // arancione
|
||||
'#eab308', // giallo
|
||||
'#22c55e', // verde
|
||||
'#14b8a6', // teal
|
||||
'#3b82f6', // blu
|
||||
'#8b5cf6', // viola
|
||||
'#ec4899', // rosa
|
||||
'#6b7280', // grigio
|
||||
'#78716c', // marrone
|
||||
]
|
||||
|
||||
// ─── Tipi ──────────────────────────────────────────────────────────────────────
|
||||
|
||||
interface TagSelectorSingleProps {
|
||||
mode: 'single'
|
||||
open: boolean
|
||||
onClose: () => void
|
||||
/** ID dei tag attualmente assegnati al messaggio */
|
||||
currentLabelIds: string[]
|
||||
/** Chiamata quando l'utente conferma la selezione */
|
||||
onApply: (labelIds: string[]) => void
|
||||
isApplying?: boolean
|
||||
}
|
||||
|
||||
interface TagSelectorBulkProps {
|
||||
mode: 'bulk'
|
||||
open: boolean
|
||||
onClose: () => void
|
||||
/** Numero di messaggi selezionati (per info nell'UI) */
|
||||
messageCount: number
|
||||
/** Chiamata con i label selezionati e l'azione (add/remove) */
|
||||
onApply: (labelIds: string[], action: 'add' | 'remove') => void
|
||||
isApplying?: boolean
|
||||
}
|
||||
|
||||
type TagSelectorProps = TagSelectorSingleProps | TagSelectorBulkProps
|
||||
|
||||
// ─── Componente principale ────────────────────────────────────────────────────
|
||||
|
||||
export function TagSelector(props: TagSelectorProps) {
|
||||
const { open, onClose, onApply, isApplying } = props
|
||||
const { user } = useAuth()
|
||||
const isAdmin = user?.role === 'admin' || user?.role === 'super_admin'
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
// Stato selezione (per single: IDs scelti; per bulk: IDs da applicare)
|
||||
const [selectedIds, setSelectedIds] = useState<Set<string>>(
|
||||
props.mode === 'single' ? new Set(props.currentLabelIds) : new Set(),
|
||||
)
|
||||
const [searchQuery, setSearchQuery] = useState('')
|
||||
const [showCreate, setShowCreate] = useState(false)
|
||||
const [newName, setNewName] = useState('')
|
||||
const [newColor, setNewColor] = useState(PRESET_COLORS[5]) // blu default
|
||||
|
||||
// Reset dello stato all'apertura
|
||||
const handleOpenChange = (isOpen: boolean) => {
|
||||
if (!isOpen) {
|
||||
setSearchQuery('')
|
||||
setShowCreate(false)
|
||||
setNewName('')
|
||||
setNewColor(PRESET_COLORS[5])
|
||||
if (props.mode === 'bulk') {
|
||||
setSelectedIds(new Set())
|
||||
}
|
||||
onClose()
|
||||
} else if (props.mode === 'single') {
|
||||
setSelectedIds(new Set(props.currentLabelIds))
|
||||
}
|
||||
}
|
||||
|
||||
// Carica lista tag del tenant
|
||||
const { data: allLabels = [], isLoading } = useQuery({
|
||||
queryKey: ['labels'],
|
||||
queryFn: labelsApi.list,
|
||||
staleTime: 5 * 60 * 1000,
|
||||
enabled: open,
|
||||
})
|
||||
|
||||
// Tag filtrati per ricerca
|
||||
const filteredLabels = useMemo(() => {
|
||||
if (!searchQuery.trim()) return allLabels
|
||||
const q = searchQuery.toLowerCase()
|
||||
return allLabels.filter((l) => l.name.toLowerCase().includes(q))
|
||||
}, [allLabels, searchQuery])
|
||||
|
||||
// Crea nuovo tag
|
||||
const createMutation = useMutation<LabelResponse, Error, void>({
|
||||
mutationFn: () => labelsApi.create({ name: newName.trim(), color: newColor }),
|
||||
onSuccess: (newLabel) => {
|
||||
queryClient.invalidateQueries({ queryKey: ['labels'] })
|
||||
setSelectedIds((prev) => new Set([...prev, newLabel.id]))
|
||||
setNewName('')
|
||||
setShowCreate(false)
|
||||
toast.success(`Tag "${newLabel.name}" creato`)
|
||||
},
|
||||
onError: (error) => toast.error(getErrorMessage(error)),
|
||||
})
|
||||
|
||||
// Elimina tag
|
||||
const deleteMutation = useMutation({
|
||||
mutationFn: (id: string) => labelsApi.delete(id),
|
||||
onSuccess: (_, deletedId) => {
|
||||
queryClient.invalidateQueries({ queryKey: ['labels'] })
|
||||
setSelectedIds((prev) => {
|
||||
const next = new Set(prev)
|
||||
next.delete(deletedId)
|
||||
return next
|
||||
})
|
||||
toast.success('Tag eliminato')
|
||||
},
|
||||
onError: (error) => toast.error(getErrorMessage(error)),
|
||||
})
|
||||
|
||||
const toggleLabel = (id: string) => {
|
||||
setSelectedIds((prev) => {
|
||||
const next = new Set(prev)
|
||||
if (next.has(id)) next.delete(id)
|
||||
else next.add(id)
|
||||
return next
|
||||
})
|
||||
}
|
||||
|
||||
const handleApplySingle = () => {
|
||||
if (props.mode === 'single') {
|
||||
onApply(Array.from(selectedIds))
|
||||
}
|
||||
}
|
||||
|
||||
const handleApplyBulk = (action: 'add' | 'remove') => {
|
||||
if (props.mode === 'bulk') {
|
||||
onApply(Array.from(selectedIds), action)
|
||||
}
|
||||
}
|
||||
|
||||
const canConfirm = selectedIds.size > 0
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={handleOpenChange}>
|
||||
<DialogContent className="max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="flex items-center gap-2">
|
||||
<Tag className="h-5 w-5 text-primary" />
|
||||
{props.mode === 'single' ? 'Gestisci tag' : `Assegna tag a ${props.mode === 'bulk' ? props.messageCount : ''} messaggi`}
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
|
||||
<div className="space-y-4">
|
||||
{/* Ricerca tag */}
|
||||
<div className="relative">
|
||||
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
|
||||
<Input
|
||||
placeholder="Cerca tag…"
|
||||
className="pl-9 h-9"
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
autoFocus
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Lista tag */}
|
||||
<div className="max-h-60 overflow-y-auto space-y-1 rounded-lg border bg-muted/20 p-2">
|
||||
{isLoading ? (
|
||||
<div className="flex items-center justify-center py-4">
|
||||
<div className="h-5 w-5 animate-spin rounded-full border-2 border-primary border-t-transparent" />
|
||||
</div>
|
||||
) : filteredLabels.length === 0 ? (
|
||||
<p className="text-xs text-muted-foreground text-center py-4">
|
||||
{searchQuery ? 'Nessun tag trovato' : 'Nessun tag disponibile'}
|
||||
</p>
|
||||
) : (
|
||||
filteredLabels.map((label) => (
|
||||
<LabelRow
|
||||
key={label.id}
|
||||
label={label}
|
||||
isSelected={selectedIds.has(label.id)}
|
||||
onToggle={() => toggleLabel(label.id)}
|
||||
onDelete={isAdmin ? () => deleteMutation.mutate(label.id) : undefined}
|
||||
isDeleting={deleteMutation.isPending && deleteMutation.variables === label.id}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Crea nuovo tag (admin only) */}
|
||||
{isAdmin && (
|
||||
<div className="border rounded-lg overflow-hidden">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowCreate(!showCreate)}
|
||||
className="w-full flex items-center gap-2 px-3 py-2 text-sm text-left hover:bg-muted/50 transition-colors"
|
||||
>
|
||||
<Plus className="h-4 w-4 text-primary flex-shrink-0" />
|
||||
<span className="text-primary font-medium">Crea nuovo tag</span>
|
||||
</button>
|
||||
|
||||
{showCreate && (
|
||||
<div className="px-3 pb-3 pt-1 border-t bg-muted/10 space-y-3">
|
||||
<Input
|
||||
placeholder="Nome tag…"
|
||||
value={newName}
|
||||
onChange={(e) => setNewName(e.target.value)}
|
||||
className="h-8 text-sm"
|
||||
maxLength={100}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter' && newName.trim()) createMutation.mutate()
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Selettore colore */}
|
||||
<div className="space-y-1.5">
|
||||
<p className="text-xs text-muted-foreground">Colore</p>
|
||||
<div className="flex items-center gap-2 flex-wrap">
|
||||
{PRESET_COLORS.map((color) => (
|
||||
<button
|
||||
key={color}
|
||||
type="button"
|
||||
onClick={() => setNewColor(color)}
|
||||
className={cn(
|
||||
'h-6 w-6 rounded-full border-2 transition-all',
|
||||
newColor === color
|
||||
? 'border-foreground scale-110'
|
||||
: 'border-transparent hover:scale-105',
|
||||
)}
|
||||
style={{ backgroundColor: color }}
|
||||
title={color}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Anteprima badge */}
|
||||
{newName.trim() && (
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xs text-muted-foreground">Anteprima:</span>
|
||||
<TagBadge
|
||||
label={{ id: 'preview', tenant_id: '', name: newName.trim(), color: newColor }}
|
||||
size="sm"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Button
|
||||
size="sm"
|
||||
className="w-full h-8"
|
||||
disabled={!newName.trim()}
|
||||
onClick={() => createMutation.mutate()}
|
||||
isLoading={createMutation.isPending}
|
||||
>
|
||||
Crea tag
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Footer azioni */}
|
||||
<DialogFooter className="flex-col gap-2 sm:flex-row">
|
||||
<Button variant="outline" onClick={() => handleOpenChange(false)} className="sm:order-first">
|
||||
Annulla
|
||||
</Button>
|
||||
|
||||
{props.mode === 'single' ? (
|
||||
<Button
|
||||
onClick={handleApplySingle}
|
||||
isLoading={isApplying}
|
||||
>
|
||||
Applica tag
|
||||
</Button>
|
||||
) : (
|
||||
<div className="flex gap-2 flex-1 sm:justify-end">
|
||||
<Button
|
||||
variant="outline"
|
||||
disabled={!canConfirm}
|
||||
onClick={() => handleApplyBulk('remove')}
|
||||
isLoading={isApplying}
|
||||
className="flex-1 sm:flex-none"
|
||||
>
|
||||
Rimuovi
|
||||
</Button>
|
||||
<Button
|
||||
disabled={!canConfirm}
|
||||
onClick={() => handleApplyBulk('add')}
|
||||
isLoading={isApplying}
|
||||
className="flex-1 sm:flex-none"
|
||||
>
|
||||
Aggiungi
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
// ─── Riga singolo label nella lista ──────────────────────────────────────────
|
||||
|
||||
interface LabelRowProps {
|
||||
label: LabelResponse
|
||||
isSelected: boolean
|
||||
onToggle: () => void
|
||||
onDelete?: () => void
|
||||
isDeleting?: boolean
|
||||
}
|
||||
|
||||
function LabelRow({ label, isSelected, onToggle, onDelete, isDeleting }: LabelRowProps) {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'flex items-center gap-2 px-2 py-1.5 rounded cursor-pointer hover:bg-muted/50 transition-colors group',
|
||||
isSelected && 'bg-primary/5',
|
||||
)}
|
||||
onClick={onToggle}
|
||||
>
|
||||
{/* Checkbox */}
|
||||
<div
|
||||
className={cn(
|
||||
'h-4 w-4 rounded border-2 flex items-center justify-center flex-shrink-0 transition-colors',
|
||||
isSelected
|
||||
? 'bg-primary border-primary text-primary-foreground'
|
||||
: 'border-muted-foreground/40',
|
||||
)}
|
||||
>
|
||||
{isSelected && <Check className="h-3 w-3" />}
|
||||
</div>
|
||||
|
||||
{/* Badge con colore */}
|
||||
<TagBadge label={label} size="sm" className="pointer-events-none" />
|
||||
|
||||
{/* Spacer */}
|
||||
<div className="flex-1" />
|
||||
|
||||
{/* Pulsante elimina (solo admin, visibile su hover) */}
|
||||
{onDelete && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
onDelete()
|
||||
}}
|
||||
className={cn(
|
||||
'p-1 rounded hover:bg-destructive/10 text-muted-foreground hover:text-destructive transition-all',
|
||||
isDeleting ? 'opacity-50 pointer-events-none' : 'opacity-0 group-hover:opacity-100',
|
||||
)}
|
||||
title="Elimina tag"
|
||||
aria-label={`Elimina tag ${label.name}`}
|
||||
>
|
||||
<Trash2 className="h-3.5 w-3.5" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -82,6 +82,82 @@
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
/* ─── Rich Text Editor (TipTap / ProseMirror) ─────────────────────────────── */
|
||||
|
||||
.rte-content {
|
||||
outline: none;
|
||||
min-height: inherit;
|
||||
line-height: 1.6;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
/* Placeholder */
|
||||
.rte-content p.is-editor-empty:first-child::before {
|
||||
content: attr(data-placeholder);
|
||||
color: hsl(var(--muted-foreground));
|
||||
float: left;
|
||||
height: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Tipografia */
|
||||
.rte-content h1 { font-size: 1.6rem; font-weight: 700; margin: 0.6rem 0 0.3rem; line-height: 1.3; }
|
||||
.rte-content h2 { font-size: 1.3rem; font-weight: 600; margin: 0.5rem 0 0.25rem; line-height: 1.3; }
|
||||
.rte-content h3 { font-size: 1.1rem; font-weight: 600; margin: 0.4rem 0 0.2rem; line-height: 1.3; }
|
||||
.rte-content p { margin: 0.2rem 0; }
|
||||
.rte-content p + p { margin-top: 0.4rem; }
|
||||
|
||||
/* Elenchi */
|
||||
.rte-content ul { list-style-type: disc; padding-left: 1.5rem; margin: 0.3rem 0; }
|
||||
.rte-content ol { list-style-type: decimal; padding-left: 1.5rem; margin: 0.3rem 0; }
|
||||
.rte-content li { margin: 0.15rem 0; }
|
||||
|
||||
/* Citazione */
|
||||
.rte-content blockquote {
|
||||
border-left: 3px solid hsl(var(--border));
|
||||
padding-left: 0.85rem;
|
||||
color: hsl(var(--muted-foreground));
|
||||
margin: 0.4rem 0;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* Link */
|
||||
.rte-content a.rte-link,
|
||||
.rte-content a {
|
||||
color: hsl(var(--primary));
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
.rte-content a:hover { opacity: 0.8; }
|
||||
|
||||
/* Codice */
|
||||
.rte-content code {
|
||||
background: hsl(var(--muted));
|
||||
padding: 0.1rem 0.3rem;
|
||||
border-radius: 0.25rem;
|
||||
font-family: ui-monospace, monospace;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
.rte-content pre {
|
||||
background: hsl(222 47% 11%);
|
||||
color: hsl(210 40% 96%);
|
||||
padding: 0.75rem 1rem;
|
||||
border-radius: 0.375rem;
|
||||
overflow-x: auto;
|
||||
margin: 0.4rem 0;
|
||||
}
|
||||
.rte-content pre code { background: none; color: inherit; padding: 0; }
|
||||
|
||||
/* Separatore orizzontale */
|
||||
.rte-content hr {
|
||||
border: none;
|
||||
border-top: 1px solid hsl(var(--border));
|
||||
margin: 0.6rem 0;
|
||||
}
|
||||
|
||||
/* Selezione testo */
|
||||
.rte-content .ProseMirror-selectednode { outline: 2px solid hsl(var(--primary)); }
|
||||
|
||||
/* Badge PEC stati */
|
||||
.pec-badge-draft { @apply bg-gray-100 text-gray-700 border-gray-200; }
|
||||
.pec-badge-queued { @apply bg-yellow-100 text-yellow-700 border-yellow-200; }
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { useState } from 'react'
|
||||
import { useState, useRef } from 'react'
|
||||
import { useNavigate, useLocation } from 'react-router-dom'
|
||||
import { useForm, useFieldArray } from 'react-hook-form'
|
||||
import { Send, X, Plus, ArrowLeft, AlertCircle } from 'lucide-react'
|
||||
import { Send, X, Plus, ArrowLeft, AlertCircle, Paperclip, Upload } from 'lucide-react'
|
||||
import { useQuery, useMutation } from '@tanstack/react-query'
|
||||
import toast from 'react-hot-toast'
|
||||
import { Button } from '@/components/ui/Button'
|
||||
import { Input } from '@/components/ui/Input'
|
||||
import { Label } from '@/components/ui/Label'
|
||||
import { RichTextEditor } from '@/components/RichTextEditor/RichTextEditor'
|
||||
import { sendApi } from '@/api/send.api'
|
||||
import { mailboxesApi } from '@/api/mailboxes.api'
|
||||
import { getErrorMessage } from '@/api/client'
|
||||
@@ -17,7 +18,22 @@ interface ComposeFormValues {
|
||||
to_addresses: { value: string }[]
|
||||
cc_addresses: { value: string }[]
|
||||
subject: string
|
||||
body_text: string
|
||||
}
|
||||
|
||||
const MAX_FILE_SIZE = 20 * 1024 * 1024 // 20 MB
|
||||
|
||||
function formatFileSize(bytes: number): string {
|
||||
if (bytes < 1024) return `${bytes} B`
|
||||
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`
|
||||
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`
|
||||
}
|
||||
|
||||
/** Estrae testo semplice dall'HTML del rich editor per la parte text/plain dell'email */
|
||||
function htmlToText(html: string): string {
|
||||
if (!html || html === '<p></p>') return ''
|
||||
const div = document.createElement('div')
|
||||
div.innerHTML = html
|
||||
return div.textContent || div.innerText || ''
|
||||
}
|
||||
|
||||
export function ComposePage() {
|
||||
@@ -25,6 +41,27 @@ export function ComposePage() {
|
||||
const location = useLocation()
|
||||
const replyTo = location.state?.replyTo as MessageResponse | undefined
|
||||
const [showCc, setShowCc] = useState(false)
|
||||
const fileInputRef = useRef<HTMLInputElement>(null)
|
||||
|
||||
// Corpo HTML (gestito da TipTap)
|
||||
const [bodyHtml, setBodyHtml] = useState<string>(() => {
|
||||
if (!replyTo) return ''
|
||||
const date = new Date(
|
||||
replyTo.received_at || replyTo.created_at
|
||||
).toLocaleDateString('it-IT')
|
||||
return [
|
||||
'<p></p>',
|
||||
'<p></p>',
|
||||
'<hr>',
|
||||
`<p><strong>In risposta al messaggio del ${date}</strong></p>`,
|
||||
`<p>Da: ${replyTo.from_address || ''}</p>`,
|
||||
`<p>A: ${replyTo.to_addresses?.join(', ') || ''}</p>`,
|
||||
`<p>Oggetto: ${replyTo.subject || ''}</p>`,
|
||||
].join('')
|
||||
})
|
||||
|
||||
// Allegati
|
||||
const [attachments, setAttachments] = useState<File[]>([])
|
||||
|
||||
const {
|
||||
register,
|
||||
@@ -34,12 +71,11 @@ export function ComposePage() {
|
||||
} = useForm<ComposeFormValues>({
|
||||
defaultValues: {
|
||||
mailbox_id: replyTo?.mailbox_id || '',
|
||||
to_addresses: replyTo ? [{ value: replyTo.from_address || '' }] : [{ value: '' }],
|
||||
to_addresses: replyTo
|
||||
? [{ value: replyTo.from_address || '' }]
|
||||
: [{ value: '' }],
|
||||
cc_addresses: [],
|
||||
subject: replyTo ? `Re: ${replyTo.subject || ''}` : '',
|
||||
body_text: replyTo
|
||||
? `\n\n---\nIn risposta al messaggio del ${new Date(replyTo.received_at || replyTo.created_at).toLocaleDateString('it-IT')}\nDa: ${replyTo.from_address || ''}\nA: ${replyTo.to_addresses?.join(', ') || ''}\nOggetto: ${replyTo.subject || ''}`
|
||||
: '',
|
||||
},
|
||||
})
|
||||
|
||||
@@ -62,7 +98,10 @@ export function ComposePage() {
|
||||
})
|
||||
|
||||
const sendMutation = useMutation({
|
||||
mutationFn: sendApi.send,
|
||||
mutationFn: (args: {
|
||||
data: Parameters<typeof sendApi.sendMultipart>[0]
|
||||
files: File[]
|
||||
}) => sendApi.sendMultipart(args.data, args.files),
|
||||
onSuccess: (job) => {
|
||||
toast.success(`PEC inviata! Job ID: ${job.id.slice(0, 8)}...`)
|
||||
navigate('/sent')
|
||||
@@ -72,8 +111,29 @@ export function ComposePage() {
|
||||
},
|
||||
})
|
||||
|
||||
const onSubmit = async (data: ComposeFormValues) => {
|
||||
const toAddresses = data.to_addresses
|
||||
// ── Gestione allegati ──────────────────────────────────────────────────────
|
||||
|
||||
const handleFileAdd = (files: FileList | null) => {
|
||||
if (!files) return
|
||||
const valid: File[] = []
|
||||
for (const file of Array.from(files)) {
|
||||
if (file.size > MAX_FILE_SIZE) {
|
||||
toast.error(`"${file.name}" supera il limite di 20 MB`)
|
||||
} else {
|
||||
valid.push(file)
|
||||
}
|
||||
}
|
||||
if (valid.length) setAttachments((prev) => [...prev, ...valid])
|
||||
}
|
||||
|
||||
const removeAttachment = (idx: number) => {
|
||||
setAttachments((prev) => prev.filter((_, i) => i !== idx))
|
||||
}
|
||||
|
||||
// ── Submit ─────────────────────────────────────────────────────────────────
|
||||
|
||||
const onSubmit = async (formData: ComposeFormValues) => {
|
||||
const toAddresses = formData.to_addresses
|
||||
.map((t) => t.value.trim())
|
||||
.filter((v) => v.length > 0)
|
||||
|
||||
@@ -83,14 +143,18 @@ export function ComposePage() {
|
||||
}
|
||||
|
||||
await sendMutation.mutateAsync({
|
||||
mailbox_id: data.mailbox_id,
|
||||
to_addresses: toAddresses,
|
||||
cc_addresses: data.cc_addresses
|
||||
.map((c) => c.value.trim())
|
||||
.filter((v) => v.length > 0),
|
||||
subject: data.subject,
|
||||
body_text: data.body_text,
|
||||
reply_to_message_id: replyTo?.id,
|
||||
data: {
|
||||
mailbox_id: formData.mailbox_id,
|
||||
to_addresses: toAddresses,
|
||||
cc_addresses: formData.cc_addresses
|
||||
.map((c) => c.value.trim())
|
||||
.filter((v) => v.length > 0),
|
||||
subject: formData.subject,
|
||||
body_text: htmlToText(bodyHtml),
|
||||
body_html: bodyHtml,
|
||||
reply_to_message_id: replyTo?.id,
|
||||
},
|
||||
files: attachments,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -99,28 +163,29 @@ export function ComposePage() {
|
||||
return (
|
||||
<div className="flex flex-col h-full">
|
||||
{/* Header */}
|
||||
<div className="border-b bg-background px-6 py-4 flex items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<Button variant="ghost" size="icon" onClick={() => navigate(-1)}>
|
||||
<ArrowLeft className="h-5 w-5" />
|
||||
</Button>
|
||||
<div>
|
||||
<h1 className="text-lg font-semibold">
|
||||
{replyTo ? 'Rispondi a PEC' : 'Nuova PEC'}
|
||||
</h1>
|
||||
{replyTo && (
|
||||
<p className="text-xs text-muted-foreground">
|
||||
In risposta a: {replyTo.subject}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="border-b bg-background px-6 py-4 flex items-center gap-3">
|
||||
<Button variant="ghost" size="icon" onClick={() => navigate(-1)}>
|
||||
<ArrowLeft className="h-5 w-5" />
|
||||
</Button>
|
||||
<div>
|
||||
<h1 className="text-lg font-semibold">
|
||||
{replyTo ? 'Rispondi a PEC' : 'Nuova PEC'}
|
||||
</h1>
|
||||
{replyTo && (
|
||||
<p className="text-xs text-muted-foreground">
|
||||
In risposta a: {replyTo.subject}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Form */}
|
||||
<div className="flex-1 overflow-y-auto">
|
||||
<form onSubmit={handleSubmit(onSubmit)} className="max-w-3xl mx-auto px-6 py-8 space-y-6">
|
||||
{/* Avviso */}
|
||||
<form
|
||||
onSubmit={handleSubmit(onSubmit)}
|
||||
className="max-w-4xl mx-auto px-6 py-6 space-y-5"
|
||||
>
|
||||
{/* Avviso informativo */}
|
||||
<div className="rounded-lg border border-blue-200 bg-blue-50 p-3 flex items-start gap-2">
|
||||
<AlertCircle className="h-4 w-4 text-blue-600 mt-0.5 flex-shrink-0" />
|
||||
<p className="text-sm text-blue-700">
|
||||
@@ -130,7 +195,7 @@ export function ComposePage() {
|
||||
</div>
|
||||
|
||||
{/* Casella mittente */}
|
||||
<div className="space-y-2">
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor="mailbox_id">Casella mittente *</Label>
|
||||
{mailboxesLoading ? (
|
||||
<div className="h-10 rounded-md border bg-muted animate-pulse" />
|
||||
@@ -141,8 +206,10 @@ export function ComposePage() {
|
||||
) : (
|
||||
<select
|
||||
id="mailbox_id"
|
||||
className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm"
|
||||
{...register('mailbox_id', { required: 'Seleziona una casella mittente' })}
|
||||
className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2"
|
||||
{...register('mailbox_id', {
|
||||
required: 'Seleziona una casella mittente',
|
||||
})}
|
||||
>
|
||||
<option value="">Seleziona casella...</option>
|
||||
{activeCaselle.map((mb) => (
|
||||
@@ -158,7 +225,7 @@ export function ComposePage() {
|
||||
</div>
|
||||
|
||||
{/* Destinatari A: */}
|
||||
<div className="space-y-2">
|
||||
<div className="space-y-1.5">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label>Destinatari (A:) *</Label>
|
||||
<Button
|
||||
@@ -178,7 +245,8 @@ export function ComposePage() {
|
||||
type="email"
|
||||
placeholder="destinatario@pec.it"
|
||||
{...register(`to_addresses.${idx}.value`, {
|
||||
required: idx === 0 ? 'Almeno un destinatario è obbligatorio' : false,
|
||||
required:
|
||||
idx === 0 ? 'Almeno un destinatario è obbligatorio' : false,
|
||||
})}
|
||||
/>
|
||||
{toFields.length > 1 && (
|
||||
@@ -202,7 +270,7 @@ export function ComposePage() {
|
||||
</div>
|
||||
|
||||
{/* CC */}
|
||||
<div className="space-y-2">
|
||||
<div className="space-y-1.5">
|
||||
{!showCc ? (
|
||||
<button
|
||||
type="button"
|
||||
@@ -247,7 +315,7 @@ export function ComposePage() {
|
||||
</div>
|
||||
|
||||
{/* Oggetto */}
|
||||
<div className="space-y-2">
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor="subject">Oggetto *</Label>
|
||||
<Input
|
||||
id="subject"
|
||||
@@ -259,25 +327,92 @@ export function ComposePage() {
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Corpo */}
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="body_text">Testo del messaggio</Label>
|
||||
<textarea
|
||||
id="body_text"
|
||||
rows={12}
|
||||
placeholder="Testo della PEC..."
|
||||
className="flex w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 resize-y"
|
||||
{...register('body_text')}
|
||||
{/* Corpo – Rich Text Editor */}
|
||||
<div className="space-y-1.5">
|
||||
<Label>Testo del messaggio</Label>
|
||||
<RichTextEditor
|
||||
value={bodyHtml}
|
||||
onChange={setBodyHtml}
|
||||
placeholder="Scrivi il testo della PEC..."
|
||||
minHeight="280px"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Azioni */}
|
||||
<div className="flex items-center justify-between pt-4 border-t">
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
onClick={() => navigate(-1)}
|
||||
{/* ── Allegati ────────────────────────────────────────────────── */}
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label>Allegati</Label>
|
||||
<span className="text-xs text-muted-foreground">Max 20 MB per file</span>
|
||||
</div>
|
||||
|
||||
{/* Lista allegati caricati */}
|
||||
{attachments.length > 0 && (
|
||||
<div className="space-y-1.5">
|
||||
{attachments.map((file, idx) => (
|
||||
<div
|
||||
key={`${file.name}-${file.size}-${idx}`}
|
||||
className="flex items-center gap-2.5 px-3 py-2 bg-muted/50 border rounded-md"
|
||||
>
|
||||
<Paperclip className="h-3.5 w-3.5 text-muted-foreground flex-shrink-0" />
|
||||
<span
|
||||
className="text-sm flex-1 truncate font-medium"
|
||||
title={file.name}
|
||||
>
|
||||
{file.name}
|
||||
</span>
|
||||
<span className="text-xs text-muted-foreground whitespace-nowrap">
|
||||
{formatFileSize(file.size)}
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
className="ml-1 rounded p-0.5 text-muted-foreground hover:text-destructive hover:bg-destructive/10 transition-colors"
|
||||
onClick={() => removeAttachment(idx)}
|
||||
title="Rimuovi allegato"
|
||||
>
|
||||
<X className="h-3.5 w-3.5" />
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Zona drag-and-drop / click per aggiungere file */}
|
||||
<div
|
||||
className="border-2 border-dashed rounded-md p-5 flex flex-col items-center gap-2 cursor-pointer hover:border-primary/60 hover:bg-primary/5 transition-colors"
|
||||
onClick={() => fileInputRef.current?.click()}
|
||||
onDragOver={(e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
}}
|
||||
onDrop={(e) => {
|
||||
e.preventDefault()
|
||||
handleFileAdd(e.dataTransfer.files)
|
||||
}}
|
||||
>
|
||||
<Upload className="h-7 w-7 text-muted-foreground" />
|
||||
<div className="text-center">
|
||||
<p className="text-sm font-medium text-foreground">
|
||||
Clicca o trascina i file qui
|
||||
</p>
|
||||
<p className="text-xs text-muted-foreground mt-0.5">
|
||||
Qualsiasi tipo di file • Max 20 MB per file
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Input file nascosto */}
|
||||
<input
|
||||
ref={fileInputRef}
|
||||
type="file"
|
||||
multiple
|
||||
className="hidden"
|
||||
onChange={(e) => handleFileAdd(e.target.files)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* ── Azioni ──────────────────────────────────────────────────── */}
|
||||
<div className="flex items-center justify-between pt-4 border-t">
|
||||
<Button type="button" variant="outline" onClick={() => navigate(-1)}>
|
||||
Annulla
|
||||
</Button>
|
||||
<Button
|
||||
@@ -287,6 +422,11 @@ export function ComposePage() {
|
||||
>
|
||||
<Send className="h-4 w-4 mr-2" />
|
||||
Invia PEC
|
||||
{attachments.length > 0 && (
|
||||
<span className="ml-1.5 bg-primary-foreground/20 text-primary-foreground rounded-full px-1.5 text-xs font-semibold">
|
||||
+{attachments.length}
|
||||
</span>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
*
|
||||
* Funzionalità:
|
||||
* - Selezione singola e multipla tramite checkbox
|
||||
* - Barra azioni bulk (stella, rimuovi stella, archivia, rimuovi archivio)
|
||||
* - Barra azioni bulk (stella, rimuovi stella, archivia, rimuovi archivio, assegna tag)
|
||||
* - Pulsanti azione rapida su hover di ogni riga (stella, archivia)
|
||||
* - Tutte le azioni funzionano anche in senso inverso (unstar / unarchive)
|
||||
* - Badge tag colorati per ogni messaggio
|
||||
*/
|
||||
import { useEffect, useState, useCallback } from 'react'
|
||||
import { useNavigate, useParams } from 'react-router-dom'
|
||||
@@ -31,13 +31,17 @@ import {
|
||||
CheckSquare,
|
||||
Square,
|
||||
X,
|
||||
Tag,
|
||||
} from 'lucide-react'
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
import toast from 'react-hot-toast'
|
||||
import { Button } from '@/components/ui/Button'
|
||||
import { Input } from '@/components/ui/Input'
|
||||
import { PecStateBadge } from '@/components/PecBadge/PecBadge'
|
||||
import { TagBadgeList } from '@/components/TagManager/TagBadge'
|
||||
import { TagSelector } from '@/components/TagManager/TagSelector'
|
||||
import { messagesApi } from '@/api/messages.api'
|
||||
import { labelsApi } from '@/api/labels.api'
|
||||
import { mailboxesApi } from '@/api/mailboxes.api'
|
||||
import { virtualBoxesApi } from '@/api/virtual_boxes.api'
|
||||
import { formatRelative, truncate } from '@/lib/utils'
|
||||
@@ -75,6 +79,9 @@ export function InboxPage({ viewMode }: InboxPageProps) {
|
||||
// ── Stato selezione ─────────────────────────────────────────────────────────
|
||||
const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set())
|
||||
|
||||
// ── Stato dialog tag bulk ────────────────────────────────────────────────────
|
||||
const [showTagSelector, setShowTagSelector] = useState(false)
|
||||
|
||||
// Resetta lo stato UI ogni volta che si cambia casella, virtual box o cartella
|
||||
useEffect(() => {
|
||||
setSearchInput('')
|
||||
@@ -248,6 +255,31 @@ export function InboxPage({ viewMode }: InboxPageProps) {
|
||||
onError: (error) => toast.error(getErrorMessage(error)),
|
||||
})
|
||||
|
||||
// ── Bulk tag ─────────────────────────────────────────────────────────────────
|
||||
const bulkLabelMutation = useMutation({
|
||||
mutationFn: labelsApi.bulkLabels,
|
||||
onSuccess: (result, payload) => {
|
||||
invalidateMessages()
|
||||
setSelectedIds(new Set())
|
||||
setShowTagSelector(false)
|
||||
const n = result.updated
|
||||
if (payload.action === 'add') {
|
||||
toast.success(`Tag aggiunti a ${n} ${n === 1 ? 'messaggio' : 'messaggi'}`)
|
||||
} else {
|
||||
toast.success(`Tag rimossi da ${n} ${n === 1 ? 'messaggio' : 'messaggi'}`)
|
||||
}
|
||||
},
|
||||
onError: (error) => toast.error(getErrorMessage(error)),
|
||||
})
|
||||
|
||||
const handleBulkTag = (labelIds: string[], action: 'add' | 'remove') => {
|
||||
bulkLabelMutation.mutate({
|
||||
message_ids: Array.from(selectedIds),
|
||||
label_ids: labelIds,
|
||||
action,
|
||||
})
|
||||
}
|
||||
|
||||
const handleBulkStar = () =>
|
||||
bulkMutation.mutate({ ids: Array.from(selectedIds), is_starred: true })
|
||||
const handleBulkUnstar = () =>
|
||||
@@ -495,6 +527,17 @@ export function InboxPage({ viewMode }: InboxPageProps) {
|
||||
Ripristina dalla posta
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{/* Assegna tag bulk */}
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="h-8 text-xs border-blue-200 hover:bg-blue-100 dark:border-blue-700"
|
||||
onClick={() => setShowTagSelector(true)}
|
||||
>
|
||||
<Tag className="h-3.5 w-3.5 mr-1 text-primary" />
|
||||
Tag
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -599,6 +642,18 @@ export function InboxPage({ viewMode }: InboxPageProps) {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* ── Dialog assegnazione tag bulk ── */}
|
||||
{showTagSelector && (
|
||||
<TagSelector
|
||||
mode="bulk"
|
||||
open={showTagSelector}
|
||||
onClose={() => setShowTagSelector(false)}
|
||||
messageCount={selectedCount}
|
||||
onApply={handleBulkTag}
|
||||
isApplying={bulkLabelMutation.isPending}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -715,6 +770,13 @@ function MessageRow({
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Tag badges */}
|
||||
{message.labels && message.labels.length > 0 && (
|
||||
<div className="mt-1" onClick={(e) => e.stopPropagation()}>
|
||||
<TagBadgeList labels={message.labels} maxVisible={4} size="sm" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{message.body_text && (
|
||||
<p className="text-xs text-muted-foreground truncate mt-0.5">
|
||||
{truncate(message.body_text, 120)}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { useState } from 'react'
|
||||
import { useParams, useNavigate } from 'react-router-dom'
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
import {
|
||||
@@ -10,12 +11,16 @@ import {
|
||||
Paperclip,
|
||||
Mail,
|
||||
Send,
|
||||
Tag,
|
||||
} from 'lucide-react'
|
||||
import toast from 'react-hot-toast'
|
||||
import { Button } from '@/components/ui/Button'
|
||||
import { PecStateBadge, PecTypeBadge } from '@/components/PecBadge/PecBadge'
|
||||
import { ReceiptTree } from '@/components/ReceiptTree/ReceiptTree'
|
||||
import { TagBadge } from '@/components/TagManager/TagBadge'
|
||||
import { TagSelector } from '@/components/TagManager/TagSelector'
|
||||
import { messagesApi } from '@/api/messages.api'
|
||||
import { labelsApi } from '@/api/labels.api'
|
||||
import { formatDate, formatBytes } from '@/lib/utils'
|
||||
import { getErrorMessage } from '@/api/client'
|
||||
|
||||
@@ -24,6 +29,9 @@ export function MessageDetailPage() {
|
||||
const navigate = useNavigate()
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
// Dialog tag
|
||||
const [showTagSelector, setShowTagSelector] = useState(false)
|
||||
|
||||
// Carica messaggio
|
||||
const {
|
||||
data: message,
|
||||
@@ -72,6 +80,15 @@ export function MessageDetailPage() {
|
||||
onError: (error) => toast.error(getErrorMessage(error)),
|
||||
})
|
||||
|
||||
// Download allegato autenticato
|
||||
const handleDownloadAttachment = async (att: { id: string; filename: string }) => {
|
||||
try {
|
||||
await messagesApi.downloadAttachment(message?.id ?? id!, att.id, att.filename)
|
||||
} catch (error) {
|
||||
toast.error(getErrorMessage(error))
|
||||
}
|
||||
}
|
||||
|
||||
// Ripristina dall'archivio
|
||||
const unarchiveMutation = useMutation({
|
||||
mutationFn: () => messagesApi.unarchive(id!),
|
||||
@@ -83,6 +100,38 @@ export function MessageDetailPage() {
|
||||
onError: (error) => toast.error(getErrorMessage(error)),
|
||||
})
|
||||
|
||||
// Imposta tag del messaggio
|
||||
const setLabelsMutation = useMutation({
|
||||
mutationFn: (labelIds: string[]) =>
|
||||
labelsApi.setMessageLabels(id!, { label_ids: labelIds }),
|
||||
onSuccess: (updatedLabels) => {
|
||||
// Aggiorna la cache del messaggio con i nuovi label
|
||||
queryClient.setQueryData(['message', id], (old: typeof message) => {
|
||||
if (!old) return old
|
||||
return { ...old, labels: updatedLabels }
|
||||
})
|
||||
// Invalida la lista messaggi per aggiornare i badge nella inbox
|
||||
queryClient.invalidateQueries({ queryKey: ['messages'] })
|
||||
setShowTagSelector(false)
|
||||
toast.success('Tag aggiornati')
|
||||
},
|
||||
onError: (error) => toast.error(getErrorMessage(error)),
|
||||
})
|
||||
|
||||
// Rimuove singolo tag (click su × nel badge)
|
||||
const removeLabelMutation = useMutation({
|
||||
mutationFn: (labelId: string) =>
|
||||
labelsApi.removeMessageLabels(id!, { label_ids: [labelId] }),
|
||||
onSuccess: (updatedLabels) => {
|
||||
queryClient.setQueryData(['message', id], (old: typeof message) => {
|
||||
if (!old) return old
|
||||
return { ...old, labels: updatedLabels }
|
||||
})
|
||||
queryClient.invalidateQueries({ queryKey: ['messages'] })
|
||||
},
|
||||
onError: (error) => toast.error(getErrorMessage(error)),
|
||||
})
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="flex items-center justify-center h-64">
|
||||
@@ -103,6 +152,8 @@ export function MessageDetailPage() {
|
||||
)
|
||||
}
|
||||
|
||||
const currentLabelIds = (message.labels || []).map((l) => l.id)
|
||||
|
||||
return (
|
||||
<div className="flex flex-col h-full">
|
||||
{/* Toolbar */}
|
||||
@@ -117,6 +168,22 @@ export function MessageDetailPage() {
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
{/* Gestisci tag */}
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => setShowTagSelector(true)}
|
||||
title="Gestisci tag"
|
||||
>
|
||||
<Tag className="h-4 w-4 mr-1 text-primary" />
|
||||
Tag
|
||||
{message.labels && message.labels.length > 0 && (
|
||||
<span className="ml-1 text-xs bg-primary text-primary-foreground rounded-full px-1.5 py-0.5">
|
||||
{message.labels.length}
|
||||
</span>
|
||||
)}
|
||||
</Button>
|
||||
|
||||
{/* Stella / Preferito */}
|
||||
<Button
|
||||
variant="ghost"
|
||||
@@ -212,6 +279,28 @@ export function MessageDetailPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Tag badges */}
|
||||
{message.labels && message.labels.length > 0 && (
|
||||
<div className="flex items-center gap-2 flex-wrap">
|
||||
{message.labels.map((label) => (
|
||||
<TagBadge
|
||||
key={label.id}
|
||||
label={label}
|
||||
size="md"
|
||||
onRemove={() => removeLabelMutation.mutate(label.id)}
|
||||
/>
|
||||
))}
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowTagSelector(true)}
|
||||
className="inline-flex items-center gap-1 px-2.5 py-1 rounded-full text-sm text-muted-foreground border border-dashed border-muted-foreground/40 hover:border-primary hover:text-primary transition-colors"
|
||||
>
|
||||
<Tag className="h-3.5 w-3.5" />
|
||||
Modifica
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Dettagli busta */}
|
||||
<div className="rounded-lg border bg-muted/30 p-4 space-y-2">
|
||||
<div className="grid grid-cols-[auto,1fr] gap-x-4 gap-y-1.5 text-sm">
|
||||
@@ -291,11 +380,11 @@ export function MessageDetailPage() {
|
||||
</h3>
|
||||
<div className="grid gap-2 sm:grid-cols-2">
|
||||
{attachments.map((att) => (
|
||||
<a
|
||||
<button
|
||||
key={att.id}
|
||||
href={messagesApi.getAttachmentUrl(message.id, att.id)}
|
||||
download={att.filename}
|
||||
className="flex items-center gap-3 rounded-lg border bg-background p-3 hover:bg-muted/50 transition-colors group"
|
||||
type="button"
|
||||
onClick={() => handleDownloadAttachment(att)}
|
||||
className="flex items-center gap-3 rounded-lg border bg-background p-3 hover:bg-muted/50 transition-colors group text-left w-full"
|
||||
>
|
||||
<div className="h-10 w-10 rounded-lg bg-primary/10 flex items-center justify-center flex-shrink-0">
|
||||
<Paperclip className="h-5 w-5 text-primary" />
|
||||
@@ -307,7 +396,7 @@ export function MessageDetailPage() {
|
||||
</p>
|
||||
</div>
|
||||
<Download className="h-4 w-4 text-muted-foreground group-hover:text-foreground flex-shrink-0" />
|
||||
</a>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
@@ -342,6 +431,18 @@ export function MessageDetailPage() {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Dialog gestione tag */}
|
||||
{showTagSelector && (
|
||||
<TagSelector
|
||||
mode="single"
|
||||
open={showTagSelector}
|
||||
onClose={() => setShowTagSelector(false)}
|
||||
currentLabelIds={currentLabelIds}
|
||||
onApply={(labelIds) => setLabelsMutation.mutate(labelIds)}
|
||||
isApplying={setLabelsMutation.isPending}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -133,6 +133,47 @@ export interface ConnectionTestResult {
|
||||
capabilities: string[] | null
|
||||
}
|
||||
|
||||
// ─── Label (Tag) ──────────────────────────────────────────────────────────────
|
||||
|
||||
export interface LabelResponse {
|
||||
id: string
|
||||
tenant_id: string
|
||||
name: string
|
||||
color: string | null
|
||||
}
|
||||
|
||||
export interface LabelCreate {
|
||||
name: string
|
||||
color?: string | null
|
||||
}
|
||||
|
||||
export interface LabelUpdate {
|
||||
name?: string
|
||||
color?: string | null
|
||||
}
|
||||
|
||||
export interface MessageLabelSetRequest {
|
||||
label_ids: string[]
|
||||
}
|
||||
|
||||
export interface MessageLabelAddRequest {
|
||||
label_ids: string[]
|
||||
}
|
||||
|
||||
export interface MessageLabelRemoveRequest {
|
||||
label_ids: string[]
|
||||
}
|
||||
|
||||
export interface MessageBulkLabelRequest {
|
||||
message_ids: string[]
|
||||
label_ids: string[]
|
||||
action: 'add' | 'remove'
|
||||
}
|
||||
|
||||
export interface MessageBulkLabelResponse {
|
||||
updated: number
|
||||
}
|
||||
|
||||
// ─── Message ──────────────────────────────────────────────────────────────────
|
||||
|
||||
export type PecDirection = 'inbound' | 'outbound'
|
||||
@@ -185,6 +226,7 @@ export interface MessageResponse {
|
||||
raw_eml_path: string | null
|
||||
created_at: string
|
||||
updated_at: string
|
||||
labels: LabelResponse[]
|
||||
}
|
||||
|
||||
export interface MessageListResponse {
|
||||
|
||||
Reference in New Issue
Block a user