diff --git a/package-lock.json b/package-lock.json
index 39c8007..23167ad 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "directus-extension-flexible-editor",
- "version": "1.4.2",
+ "version": "1.5.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "directus-extension-flexible-editor",
- "version": "1.4.2",
+ "version": "1.5.0",
"license": "GPL-3.0",
"dependencies": {
"@tiptap/core": "^2.2.4",
@@ -45,6 +45,7 @@
"@types/lodash": "^4.14.195",
"@types/node": "^20.11.17",
"@types/uuid": "^9.0.2",
+ "@types/validator": "^13.12.0",
"lodash": "^4.17.21",
"typescript": "^5.3.3",
"uuid": "^9.0.0",
@@ -1613,6 +1614,12 @@
"integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==",
"dev": true
},
+ "node_modules/@types/validator": {
+ "version": "13.12.0",
+ "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.12.0.tgz",
+ "integrity": "sha512-nH45Lk7oPIJ1RVOF6JgFI6Dy0QpHEzq4QecZhvguxYPDwT8c93prCMqAtiIttm39voZ+DDR+qkNnMpJmMBRqag==",
+ "dev": true
+ },
"node_modules/@unhead/dom": {
"version": "1.9.10",
"resolved": "https://registry.npmjs.org/@unhead/dom/-/dom-1.9.10.tgz",
diff --git a/package.json b/package.json
index b1cd209..c521587 100644
--- a/package.json
+++ b/package.json
@@ -72,6 +72,7 @@
"@types/lodash": "^4.14.195",
"@types/node": "^20.11.17",
"@types/uuid": "^9.0.2",
+ "@types/validator": "^13.12.0",
"lodash": "^4.17.21",
"typescript": "^5.3.3",
"uuid": "^9.0.0",
diff --git a/src/display/extensions.ts b/src/display/extensions.ts
index 4d8f5fb..796d173 100644
--- a/src/display/extensions.ts
+++ b/src/display/extensions.ts
@@ -1,4 +1,4 @@
import extensions from "../../shared/extensions";
-import RelationBlock from "../interface/nodes/relation-block";
+import RelationBlock from "../interface/tools/relation-block/node-extension";
export default [...extensions, RelationBlock];
diff --git a/src/interface/components/RelationBlockMenu.vue b/src/interface/components/RelationBlockMenu.vue
deleted file mode 100644
index 3e585a1..0000000
--- a/src/interface/components/RelationBlockMenu.vue
+++ /dev/null
@@ -1,81 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/interface/components/ToolButtonFullscreen.vue b/src/interface/components/ToolButtonFullscreen.vue
deleted file mode 100644
index 8a3db88..0000000
--- a/src/interface/components/ToolButtonFullscreen.vue
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
-
diff --git a/src/interface/components/Toolbar.vue b/src/interface/components/Toolbar.vue
index 1f5ac65..c416695 100644
--- a/src/interface/components/Toolbar.vue
+++ b/src/interface/components/Toolbar.vue
@@ -1,11 +1,5 @@
-
-
-
-
-
-
@@ -167,6 +137,9 @@
--toolbar-item-m: 1px;
--toolbar-dropdown-p: 2px;
+
+ display: flex;
+ flex-wrap: wrap;
}
.toolbar-dropdown-button :deep(.button) {
diff --git a/src/interface/directus-core/v10.4.3 b/src/interface/directus-core/v10.4.3
deleted file mode 100644
index e69de29..0000000
diff --git a/src/interface/interface.vue b/src/interface/interface.vue
index 6fed830..ef11d64 100644
--- a/src/interface/interface.vue
+++ b/src/interface/interface.vue
@@ -17,7 +17,7 @@
>
([]);
diff --git a/src/interface/lib/define-tool.ts b/src/interface/lib/define-tool.ts
new file mode 100644
index 0000000..81ba6c4
--- /dev/null
+++ b/src/interface/lib/define-tool.ts
@@ -0,0 +1,3 @@
+import type { Tool } from "../types";
+
+export const defineTool = (tool: Tool) => tool;
diff --git a/src/interface/tools/utils/index.ts b/src/interface/lib/extend-mark-range-if-unselected.ts
similarity index 100%
rename from src/interface/tools/utils/index.ts
rename to src/interface/lib/extend-mark-range-if-unselected.ts
diff --git a/src/interface/lib/index.ts b/src/interface/lib/index.ts
new file mode 100644
index 0000000..63dfde9
--- /dev/null
+++ b/src/interface/lib/index.ts
@@ -0,0 +1,2 @@
+export * from "./define-tool";
+export * from "./extend-mark-range-if-unselected";
diff --git a/src/interface/tools/blockquote.ts b/src/interface/tools/blockquote.ts
index 3f4bab5..50048e6 100644
--- a/src/interface/tools/blockquote.ts
+++ b/src/interface/tools/blockquote.ts
@@ -1,11 +1,11 @@
// https://tiptap.dev/api/nodes/blockquote
import Blockquote from "@tiptap/extension-blockquote";
+import { defineTool } from "../lib";
import customMessages from "../i18n/custom-messages";
import type { Editor } from "@tiptap/core";
-import type { Tool } from "../types";
-export default {
+export default defineTool({
key: "blockquote",
name: customMessages.tools.blockquote,
icon: "format_quote",
@@ -15,4 +15,4 @@ export default {
disabled: (editor: Editor) =>
!editor.can().chain().focus().toggleBlockquote().run(),
active: (editor: Editor) => editor.isActive("blockquote"),
-} as Tool;
+});
diff --git a/src/interface/tools/bold.ts b/src/interface/tools/bold.ts
index 9abf20b..caf61bc 100644
--- a/src/interface/tools/bold.ts
+++ b/src/interface/tools/bold.ts
@@ -2,11 +2,10 @@
import Bold from "@tiptap/extension-bold";
import customMessages from "../i18n/custom-messages";
-import { extendMarkRangeIfUnselected } from "./utils";
+import { defineTool, extendMarkRangeIfUnselected } from "../lib";
import type { Editor } from "@tiptap/core";
-import type { Tool } from "../types";
-export default {
+export default defineTool({
key: "bold",
name: customMessages.tools.bold,
icon: "format_bold",
@@ -17,4 +16,4 @@ export default {
disabled: (editor: Editor) =>
!editor.can().chain().focus().toggleBold().run(),
active: (editor: Editor) => editor.isActive("bold"),
-} as Tool;
+});
diff --git a/src/interface/tools/bullet-list.ts b/src/interface/tools/bullet-list.ts
index 059722a..245bade 100644
--- a/src/interface/tools/bullet-list.ts
+++ b/src/interface/tools/bullet-list.ts
@@ -2,11 +2,11 @@
import BulletList from "@tiptap/extension-bullet-list";
import ListItem from "@tiptap/extension-list-item";
+import { defineTool } from "../lib";
import customMessages from "../i18n/custom-messages";
import type { Editor } from "@tiptap/core";
-import type { Tool } from "../types";
-export default {
+export default defineTool({
key: "bulletList",
name: customMessages.tools.bullet_list,
icon: "format_list_bulleted",
@@ -16,4 +16,4 @@ export default {
disabled: (editor: Editor) =>
!editor.can().chain().focus().toggleBulletList().run(),
active: (editor: Editor) => editor.isActive("bulletList"),
-} as Tool;
+});
diff --git a/src/interface/tools/code-block.ts b/src/interface/tools/code-block.ts
index 1e0db01..38516fb 100644
--- a/src/interface/tools/code-block.ts
+++ b/src/interface/tools/code-block.ts
@@ -1,11 +1,11 @@
// https://tiptap.dev/api/nodes/code-block
import CodeBlock from "@tiptap/extension-code-block";
+import { defineTool } from "../lib";
import customMessages from "../i18n/custom-messages";
import type { Editor } from "@tiptap/core";
-import type { Tool } from "../types";
-export default {
+export default defineTool({
key: "codeBlock",
name: customMessages.tools.code_block,
extension: [CodeBlock],
@@ -15,4 +15,4 @@ export default {
disabled: (editor: Editor) =>
!editor.can().chain().focus().toggleCodeBlock().run(),
active: (editor: Editor) => editor.isActive("codeBlock"),
-} as Tool;
+});
diff --git a/src/interface/tools/code.ts b/src/interface/tools/code.ts
index 088029f..33d2db4 100644
--- a/src/interface/tools/code.ts
+++ b/src/interface/tools/code.ts
@@ -1,12 +1,11 @@
// https://tiptap.dev/api/marks/code
import Code from "@tiptap/extension-code";
+import { defineTool, extendMarkRangeIfUnselected } from "../lib";
import customMessages from "../i18n/custom-messages";
-import { extendMarkRangeIfUnselected } from "./utils";
import type { Editor } from "@tiptap/core";
-import type { Tool } from "../types";
-export default {
+export default defineTool({
key: "code",
name: customMessages.tools.code,
icon: "code",
@@ -17,4 +16,4 @@ export default {
disabled: (editor: Editor) =>
!editor.can().chain().focus().toggleCode().run(),
active: (editor: Editor) => editor.isActive("code"),
-} as Tool;
+});
diff --git a/src/interface/tools/fullscreen.ts b/src/interface/tools/fullscreen.ts
deleted file mode 100644
index 35579f0..0000000
--- a/src/interface/tools/fullscreen.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import customMessages from "../i18n/custom-messages";
-import ToolButtonFullscreen from "../components/ToolButtonFullscreen.vue";
-import type { Tool } from "../types";
-
-export default {
- key: "fullscreen",
- name: customMessages.tools.fullscreen,
- extension: [],
- toolbarButton: ToolButtonFullscreen,
- disabledInSingleLineMode: true,
-} as Tool;
diff --git a/src/interface/tools/fullscreen/ToolButton.vue b/src/interface/tools/fullscreen/ToolButton.vue
new file mode 100644
index 0000000..d577148
--- /dev/null
+++ b/src/interface/tools/fullscreen/ToolButton.vue
@@ -0,0 +1,20 @@
+
+
+
+
+
diff --git a/src/interface/tools/fullscreen/index.ts b/src/interface/tools/fullscreen/index.ts
new file mode 100644
index 0000000..125c8f3
--- /dev/null
+++ b/src/interface/tools/fullscreen/index.ts
@@ -0,0 +1,11 @@
+import { defineTool } from "../../lib";
+import customMessages from "../../i18n/custom-messages";
+import ToolButton from "./ToolButton.vue";
+
+export default defineTool({
+ key: "fullscreen",
+ name: customMessages.tools.fullscreen,
+ extension: [],
+ toolbarButton: ToolButton,
+ disabledInSingleLineMode: true,
+});
diff --git a/src/interface/tools/hard-break.ts b/src/interface/tools/hard-break.ts
index 171a0e2..82e358f 100644
--- a/src/interface/tools/hard-break.ts
+++ b/src/interface/tools/hard-break.ts
@@ -1,11 +1,11 @@
// https://tiptap.dev/api/nodes/hard-break
import HardBreak from "@tiptap/extension-hard-break";
+import { defineTool } from "../lib";
import customMessages from "../i18n/custom-messages";
import type { Editor } from "@tiptap/core";
-import type { Tool } from "../types";
-export default {
+export default defineTool({
key: "hardBreak",
name: customMessages.tools.hard_break,
icon: "keyboard_return",
@@ -16,4 +16,4 @@ export default {
!editor.can().chain().focus().setHardBreak().run(),
disabledInSingleLineMode: true,
active: () => false,
-} as Tool;
+});
diff --git a/src/interface/tools/heading.ts b/src/interface/tools/heading.ts
index 7fe5a1f..72dfa72 100644
--- a/src/interface/tools/heading.ts
+++ b/src/interface/tools/heading.ts
@@ -1,12 +1,13 @@
// https://tiptap.dev/api/nodes/heading
import Heading from "@tiptap/extension-heading";
+import { defineTool } from "../lib";
import customMessages from "../i18n/custom-messages";
import type { Level, HeadingOptions } from "@tiptap/extension-heading";
import type { Editor, AnyExtension } from "@tiptap/core";
-import type { Tool, ToolSelection } from "../types";
+import type { ToolSelection } from "../types";
-export default (level: Level): Tool => {
+export default (level: Level) => {
const headingKeys = ["h1", "h2", "h3", "h4", "h5", "h6"];
const headingExtension = (selection: ToolSelection): AnyExtension => {
const levels = headingKeys
@@ -18,7 +19,7 @@ export default (level: Level): Tool => {
};
const msgKey = `h${level}` as keyof typeof customMessages.tools;
- return {
+ return defineTool({
key: `h${level}`,
name: customMessages.tools[msgKey],
display: `H${level}`,
@@ -30,5 +31,5 @@ export default (level: Level): Tool => {
disabled: (editor: Editor) =>
!editor.can().chain().focus().toggleHeading({ level }).run(),
active: (editor: Editor) => editor.isActive("heading", { level }),
- };
+ });
};
diff --git a/src/interface/tools/history.ts b/src/interface/tools/history.ts
index 4777430..9021042 100644
--- a/src/interface/tools/history.ts
+++ b/src/interface/tools/history.ts
@@ -1,11 +1,11 @@
// https://tiptap.dev/api/extensions/history
import History from "@tiptap/extension-history";
+import { defineTool } from "../lib";
import customMessages from "../i18n/custom-messages";
import type { Editor } from "@tiptap/core";
-import type { Tool } from "../types";
-const undo: Tool = {
+const undo = defineTool({
key: "undo",
name: customMessages.tools.undo,
icon: "undo",
@@ -14,9 +14,9 @@ const undo: Tool = {
action: (editor: Editor) => editor.chain().focus().undo().run(),
disabled: (editor: Editor) => !editor.can().chain().focus().undo().run(),
active: () => false,
-};
+});
-const redo: Tool = {
+const redo = defineTool({
key: "redo",
name: customMessages.tools.redo,
icon: "redo",
@@ -25,6 +25,6 @@ const redo: Tool = {
action: (editor: Editor) => editor.chain().focus().redo().run(),
disabled: (editor: Editor) => !editor.can().chain().focus().redo().run(),
active: () => false,
-};
+});
export default { undo, redo };
diff --git a/src/interface/tools/horizontal-rule.ts b/src/interface/tools/horizontal-rule.ts
index 1c4a8ed..c07945b 100644
--- a/src/interface/tools/horizontal-rule.ts
+++ b/src/interface/tools/horizontal-rule.ts
@@ -1,11 +1,11 @@
// https://tiptap.dev/api/nodes/horizontal-rule
import HorizontalRule from "@tiptap/extension-horizontal-rule";
+import { defineTool } from "../lib";
import customMessages from "../i18n/custom-messages";
import type { Editor } from "@tiptap/core";
-import type { Tool } from "../types";
-export default {
+export default defineTool({
key: "horizontalRule",
name: customMessages.tools.hr,
icon: "horizontal_rule",
@@ -17,4 +17,4 @@ export default {
!editor.can().chain().focus().setHorizontalRule().run(),
disabledInSingleLineMode: true,
active: () => false,
-} as Tool;
+});
diff --git a/src/interface/tools/index.ts b/src/interface/tools/index.ts
index 0babccb..2bc245c 100644
--- a/src/interface/tools/index.ts
+++ b/src/interface/tools/index.ts
@@ -50,8 +50,15 @@ const tools: Tool[] = [
fullscreen,
];
-export const selectedTools = (selection: ToolSelection) =>
- tools.filter(({ key }) => selection.indexOf(key) >= 0);
+export const selectedTools = (
+ selection: ToolSelection,
+ includeRelationBlock = false
+) =>
+ tools.filter(
+ ({ key }) =>
+ selection.indexOf(key) >= 0 ||
+ (includeRelationBlock && key == "relation-block")
+ );
export const toolsExtensions = (selection: ToolSelection): AnyExtension[] => {
const toolsExtensions: AnyExtension[] = [];
diff --git a/src/interface/tools/italic.ts b/src/interface/tools/italic.ts
index 2e98386..b754e64 100644
--- a/src/interface/tools/italic.ts
+++ b/src/interface/tools/italic.ts
@@ -2,11 +2,10 @@
import Italic from "@tiptap/extension-italic";
import customMessages from "../i18n/custom-messages";
-import { extendMarkRangeIfUnselected } from "./utils";
+import { defineTool, extendMarkRangeIfUnselected } from "../lib";
import type { Editor } from "@tiptap/core";
-import type { Tool } from "../types";
-export default {
+export default defineTool({
key: "italic",
name: customMessages.tools.italic,
icon: "format_italic",
@@ -16,4 +15,4 @@ export default {
extendMarkRangeIfUnselected(editor, "italic").toggleItalic().run(),
disabled: (editor) => !editor.can().chain().focus().toggleItalic().run(),
active: (editor: Editor) => editor.isActive("italic"),
-} as Tool;
+});
diff --git a/src/interface/tools/link/AddButton.vue b/src/interface/tools/link/AddButton.vue
new file mode 100644
index 0000000..3ddfde3
--- /dev/null
+++ b/src/interface/tools/link/AddButton.vue
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/interface/components/DialogLink.vue b/src/interface/tools/link/DialogLink.vue
similarity index 97%
rename from src/interface/components/DialogLink.vue
rename to src/interface/tools/link/DialogLink.vue
index e794bb6..5e34b94 100644
--- a/src/interface/components/DialogLink.vue
+++ b/src/interface/tools/link/DialogLink.vue
@@ -65,9 +65,9 @@
import isEmail from 'validator/lib/isEmail';
import isURL from 'validator/lib/isURL';
import isSlug from 'validator/lib/isSlug';
- import { ref, computed, watch, watchEffect } from 'vue'
+ import { ref, computed, watchEffect } from 'vue'
import { useI18n } from "vue-i18n";
- import { useI18nFallback } from '../composables/use-i18n-fallback'
+ import { useI18nFallback } from '../../composables/use-i18n-fallback'
// Props
@@ -171,7 +171,7 @@
if (type === 'external_link') {
const protocolExists = linkTypes
- .filter(({ value }) => value === type)[0].prefix
+ .filter(({ value }) => value === type)[0]!.prefix
.some(prefix => href.startsWith(prefix));
if (!protocolExists) {
diff --git a/src/interface/tools/link.ts b/src/interface/tools/link/index.ts
similarity index 58%
rename from src/interface/tools/link.ts
rename to src/interface/tools/link/index.ts
index 334dc6b..a181861 100644
--- a/src/interface/tools/link.ts
+++ b/src/interface/tools/link/index.ts
@@ -1,44 +1,24 @@
// https://tiptap.dev/api/marks/link
import Link from "@tiptap/extension-link";
-import customMessages from "../i18n/custom-messages";
-import DialogLink from "../components/DialogLink.vue";
-import type { Ref } from "vue";
+import { defineTool } from "../../lib";
+import customMessages from "../../i18n/custom-messages";
+import AddButton from "./AddButton.vue";
import type { Editor } from "@tiptap/core";
-import type { Tool, LinkAttributes, Dialog } from "../types";
-const add: Tool = {
+const add = defineTool({
// https://tiptap.dev/api/marks/link
key: "link",
name: customMessages.tools.link,
icon: "link",
extension: [linkExtenstionConfig],
- action: (editor: Editor, { dialog }: { dialog: Ref