diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icon-dictionary.json b/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icon-dictionary.json
index 4fae5c0ec7..f8dd3ed1b4 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icon-dictionary.json
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icon-dictionary.json
@@ -233,6 +233,10 @@
"name": "icon-block",
"file": "ban.svg"
},
+ {
+ "name": "icon-blockquote",
+ "file": "text-quote.svg"
+ },
{
"_name": "icon-blueprint",
"____file": "blueprint.svg"
@@ -245,6 +249,10 @@
"name": "icon-boat-shipping",
"file": "ship.svg"
},
+ {
+ "name": "icon-bold",
+ "file": "bold.svg"
+ },
{
"_name": "icon-bomb",
"____file": "bomb.svg"
@@ -797,6 +805,10 @@
"_name": "icon-eject",
"____file": "eject.svg"
},
+ {
+ "name": "icon-embed",
+ "file": "monitor-play.svg"
+ },
{
"name": "icon-employee",
"file": "user.svg",
@@ -1071,6 +1083,18 @@
"_name": "icon-hd",
"____file": "hd.svg"
},
+ {
+ "name": "icon-heading-1",
+ "file": "heading-1.svg"
+ },
+ {
+ "name": "icon-heading-2",
+ "file": "heading-2.svg"
+ },
+ {
+ "name": "icon-heading-3",
+ "file": "heading-3.svg"
+ },
{
"name": "icon-headphones",
"file": "headphones.svg"
@@ -1104,6 +1128,10 @@
"name": "icon-home",
"file": "house.svg"
},
+ {
+ "name": "icon-horizontal-rule",
+ "file": "separator-horizontal.svg"
+ },
{
"name": "icon-hourglass",
"file": "hourglass.svg"
@@ -1153,6 +1181,10 @@
"file": "smartphone.svg",
"legacy": true
},
+ {
+ "name": "icon-italic",
+ "file": "italic.svg"
+ },
{
"name": "icon-item-arrangement",
"file": "table-properties.svg",
@@ -2128,6 +2160,10 @@
"file": "square-activity.svg",
"legacy": true
},
+ {
+ "name": "icon-strikethrough",
+ "file": "strikethrough.svg"
+ },
{
"name": "icon-sunny",
"file": "sun.svg"
@@ -2178,6 +2214,22 @@
"name": "icon-terminal",
"file": "square-terminal.svg"
},
+ {
+ "name": "icon-text-align-center",
+ "file": "align-center.svg"
+ },
+ {
+ "name": "icon-text-align-justify",
+ "file": "align-justify.svg"
+ },
+ {
+ "name": "icon-text-align-left",
+ "file": "align-left.svg"
+ },
+ {
+ "name": "icon-text-align-right",
+ "file": "align-right.svg"
+ },
{
"name": "icon-theater",
"file": "drama.svg"
@@ -2308,6 +2360,10 @@
"name": "icon-undo",
"file": "undo-2.svg"
},
+ {
+ "name": "icon-underline",
+ "file": "underline.svg"
+ },
{
"name": "icon-unlocked",
"file": "lock-open.svg"
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons.ts b/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons.ts
index ff42d07bc6..acc2b0e7c6 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons.ts
@@ -159,6 +159,10 @@ name: "icon-block",
path: () => import("./icons/icon-block.js"),
},{
+name: "icon-blockquote",
+
+path: () => import("./icons/icon-blockquote.js"),
+},{
name: "icon-bluetooth",
path: () => import("./icons/icon-bluetooth.js"),
@@ -167,6 +171,10 @@ name: "icon-boat-shipping",
path: () => import("./icons/icon-boat-shipping.js"),
},{
+name: "icon-bold",
+
+path: () => import("./icons/icon-bold.js"),
+},{
name: "icon-bones",
path: () => import("./icons/icon-bones.js"),
@@ -627,6 +635,10 @@ name: "icon-edit",
path: () => import("./icons/icon-edit.js"),
},{
+name: "icon-embed",
+
+path: () => import("./icons/icon-embed.js"),
+},{
name: "icon-employee",
legacy: true,
path: () => import("./icons/icon-employee.js"),
@@ -855,6 +867,18 @@ name: "icon-hard-drive",
legacy: true,
path: () => import("./icons/icon-hard-drive.js"),
},{
+name: "icon-heading-1",
+
+path: () => import("./icons/icon-heading-1.js"),
+},{
+name: "icon-heading-2",
+
+path: () => import("./icons/icon-heading-2.js"),
+},{
+name: "icon-heading-3",
+
+path: () => import("./icons/icon-heading-3.js"),
+},{
name: "icon-headphones",
path: () => import("./icons/icon-headphones.js"),
@@ -887,6 +911,10 @@ name: "icon-home",
path: () => import("./icons/icon-home.js"),
},{
+name: "icon-horizontal-rule",
+
+path: () => import("./icons/icon-horizontal-rule.js"),
+},{
name: "icon-hourglass",
path: () => import("./icons/icon-hourglass.js"),
@@ -927,6 +955,10 @@ name: "icon-iphone",
legacy: true,
path: () => import("./icons/icon-iphone.js"),
},{
+name: "icon-italic",
+
+path: () => import("./icons/icon-italic.js"),
+},{
name: "icon-item-arrangement",
legacy: true,
path: () => import("./icons/icon-item-arrangement.js"),
@@ -1803,6 +1835,10 @@ name: "icon-stream",
legacy: true,
path: () => import("./icons/icon-stream.js"),
},{
+name: "icon-strikethrough",
+
+path: () => import("./icons/icon-strikethrough.js"),
+},{
name: "icon-sunny",
path: () => import("./icons/icon-sunny.js"),
@@ -1851,6 +1887,22 @@ name: "icon-terminal",
path: () => import("./icons/icon-terminal.js"),
},{
+name: "icon-text-align-center",
+
+path: () => import("./icons/icon-text-align-center.js"),
+},{
+name: "icon-text-align-justify",
+
+path: () => import("./icons/icon-text-align-justify.js"),
+},{
+name: "icon-text-align-left",
+
+path: () => import("./icons/icon-text-align-left.js"),
+},{
+name: "icon-text-align-right",
+
+path: () => import("./icons/icon-text-align-right.js"),
+},{
name: "icon-theater",
path: () => import("./icons/icon-theater.js"),
@@ -1967,6 +2019,10 @@ name: "icon-undo",
path: () => import("./icons/icon-undo.js"),
},{
+name: "icon-underline",
+
+path: () => import("./icons/icon-underline.js"),
+},{
name: "icon-unlocked",
path: () => import("./icons/icon-unlocked.js"),
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-blockquote.ts b/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-blockquote.ts
new file mode 100644
index 0000000000..7d4802defc
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-blockquote.ts
@@ -0,0 +1,17 @@
+export default `
+
+`;
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-bold.ts b/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-bold.ts
new file mode 100644
index 0000000000..6b4b1d986b
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-bold.ts
@@ -0,0 +1,14 @@
+export default `
+
+`;
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-embed.ts b/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-embed.ts
new file mode 100644
index 0000000000..22fdef036f
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-embed.ts
@@ -0,0 +1,17 @@
+export default `
+
+`;
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-heading-1.ts b/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-heading-1.ts
new file mode 100644
index 0000000000..20fe0c5dd1
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-heading-1.ts
@@ -0,0 +1,17 @@
+export default `
+
+`;
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-heading-2.ts b/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-heading-2.ts
new file mode 100644
index 0000000000..f062a49ca9
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-heading-2.ts
@@ -0,0 +1,17 @@
+export default `
+
+`;
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-heading-3.ts b/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-heading-3.ts
new file mode 100644
index 0000000000..cb237bb4a2
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-heading-3.ts
@@ -0,0 +1,18 @@
+export default `
+
+`;
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-horizontal-rule.ts b/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-horizontal-rule.ts
new file mode 100644
index 0000000000..424f13bb2f
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-horizontal-rule.ts
@@ -0,0 +1,16 @@
+export default `
+
+`;
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-italic.ts b/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-italic.ts
new file mode 100644
index 0000000000..d70979bfe6
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-italic.ts
@@ -0,0 +1,16 @@
+export default `
+
+`;
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-strikethrough.ts b/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-strikethrough.ts
new file mode 100644
index 0000000000..9af35d7e81
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-strikethrough.ts
@@ -0,0 +1,16 @@
+export default `
+
+`;
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-text-align-center.ts b/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-text-align-center.ts
new file mode 100644
index 0000000000..5d985fd584
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-text-align-center.ts
@@ -0,0 +1,16 @@
+export default `
+
+`;
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-text-align-justify.ts b/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-text-align-justify.ts
new file mode 100644
index 0000000000..7279356fc8
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-text-align-justify.ts
@@ -0,0 +1,16 @@
+export default `
+
+`;
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-text-align-left.ts b/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-text-align-left.ts
new file mode 100644
index 0000000000..43f4ebf794
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-text-align-left.ts
@@ -0,0 +1,16 @@
+export default `
+
+`;
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-text-align-right.ts b/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-text-align-right.ts
new file mode 100644
index 0000000000..a03f55eec2
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-text-align-right.ts
@@ -0,0 +1,16 @@
+export default `
+
+`;
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-underline.ts b/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-underline.ts
new file mode 100644
index 0000000000..84f133257c
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-underline.ts
@@ -0,0 +1,15 @@
+export default `
+
+`;
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/components/input-tiptap/icons.ts b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/components/input-tiptap/icons.ts
deleted file mode 100644
index 2676404411..0000000000
--- a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/components/input-tiptap/icons.ts
+++ /dev/null
@@ -1,268 +0,0 @@
-import { html } from '@umbraco-cms/backoffice/external/lit';
-
-const iconSize = '16px';
-export const bold = html``;
-
-export const italic = html``;
-
-export const underline = html``;
-
-export const strikethrough = html``;
-export const heading1 = html``;
-export const heading2 = html``;
-export const heading3 = html``;
-export const blockquote = html``;
-export const code = html``;
-export const bulletList = html``;
-export const orderedList = html``;
-export const horizontalRule = html``;
-export const alignLeft = html``;
-export const alignCenter = html``;
-export const alignRight = html``;
-export const alignJustify = html``;
-
-export const link = html``;
diff --git a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/components/input-tiptap/input-tiptap.element.ts b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/components/input-tiptap/input-tiptap.element.ts
index 2041b8bcec..0be12259f8 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/components/input-tiptap/input-tiptap.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/components/input-tiptap/input-tiptap.element.ts
@@ -3,28 +3,14 @@ import { css, customElement, html, property, state, when } from '@umbraco-cms/ba
import { loadManifestApi } from '@umbraco-cms/backoffice/extension-api';
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
import {
- Blockquote,
- Bold,
- BulletList,
- Code,
- CodeBlock,
Document,
Dropcursor,
Editor,
Gapcursor,
HardBreak,
- Heading,
History,
- HorizontalRule,
- Italic,
- Link,
- ListItem,
- OrderedList,
Paragraph,
- Strike,
Text,
- TextAlign,
- Underline,
} from '@umbraco-cms/backoffice/external/tiptap';
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
@@ -34,7 +20,9 @@ import type { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/
import './tiptap-fixed-menu.element.js';
import './tiptap-hover-menu.element.js';
-@customElement('umb-input-tiptap')
+const elementName = 'umb-input-tiptap';
+
+@customElement(elementName)
export class UmbInputTiptapElement extends UmbFormControlMixin(UmbLitElement) {
#requiredExtensions = [Document, Dropcursor, Gapcursor, HardBreak, History, Paragraph, Text];
@@ -88,26 +76,7 @@ export class UmbInputTiptapElement extends UmbFormControlMixin {
this.value = editor.getHTML();
@@ -142,6 +111,14 @@ export class UmbInputTiptapElement extends UmbFormControlMixin code) {
- background-color: var(--uui-color-surface-alt);
- padding: var(--uui-size-space-1) var(--uui-size-space-2);
- border-radius: calc(var(--uui-border-radius) * 2);
- }
+ code:not(pre > code) {
+ background-color: var(--uui-color-surface-alt);
+ padding: var(--uui-size-space-1) var(--uui-size-space-2);
+ border-radius: calc(var(--uui-border-radius) * 2);
+ }
- #editor code {
- font-family: 'Roboto Mono', monospace;
- background: none;
- color: inherit;
- font-size: 0.8rem;
- padding: 0;
- }
- .tiptap {
- height: 100%;
- width: 100%;
- outline: none;
- white-space: pre-wrap;
- min-width: 0;
- }
- #editor p,
- #editor h1,
- #editor h2,
- #editor h3 {
- margin-top: 0;
- margin-bottom: 0.5em;
+ code {
+ font-family: 'Roboto Mono', monospace;
+ background: none;
+ color: inherit;
+ font-size: 0.8rem;
+ padding: 0;
+ }
+
+ h1,
+ h2,
+ h3,
+ p {
+ margin-top: 0;
+ margin-bottom: 0.5em;
+ }
}
`,
];
}
-export default UmbInputTiptapElement;
-
declare global {
interface HTMLElementTagNameMap {
- 'umb-input-tiptap': UmbInputTiptapElement;
+ [elementName]: UmbInputTiptapElement;
}
}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/components/input-tiptap/tiptap-fixed-menu.element.ts b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/components/input-tiptap/tiptap-fixed-menu.element.ts
index 122c1d4c8b..5b879b5c4a 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/components/input-tiptap/tiptap-fixed-menu.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/components/input-tiptap/tiptap-fixed-menu.element.ts
@@ -1,144 +1,15 @@
-import type { UmbTiptapToolbarButton } from '../../extensions/types.js';
import type { ManifestTiptapExtension } from '../../extensions/tiptap-extension.js';
-import * as icons from './icons.js';
-import { css, customElement, html, property, state, when } from '@umbraco-cms/backoffice/external/lit';
+import { css, customElement, html, property } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import type { Editor } from '@umbraco-cms/backoffice/external/tiptap';
-@customElement('umb-tiptap-fixed-menu')
+const elementName = 'umb-tiptap-fixed-menu';
+
+@customElement(elementName)
export class UmbTiptapFixedMenuElement extends UmbLitElement {
@property({ type: Boolean, reflect: true })
readonly = false;
- @state()
- actions: Array = [
- // TODO: I don't think we need a paragraph button. It's the default state.
- // {
- // name: 'paragraph',
- // icon: html``,
- // command: (editor) => editor?.chain().focus().setParagraph().run(),
- // },
- {
- name: 'bold',
- icon: icons.bold,
- isActive: (editor) => editor?.isActive('bold'),
- command: (editor) => editor?.chain().focus().toggleBold().run(),
- },
- {
- name: 'italic',
- icon: icons.italic,
- isActive: (editor) => editor?.isActive('italic'),
- command: (editor) => editor?.chain().focus().toggleItalic().run(),
- },
- {
- name: 'underline',
- icon: icons.underline,
- isActive: (editor) => editor?.isActive('underline'),
- command: (editor) => editor?.chain().focus().toggleUnderline().run(),
- },
- {
- name: 'strikethrough',
- icon: icons.strikethrough,
- isActive: (editor) => editor?.isActive('strike'),
- command: (editor) => editor?.chain().focus().toggleStrike().run(),
- },
- {
- name: 'h1',
- icon: icons.heading1,
- isActive: (editor) => editor?.isActive('heading', { level: 1 }),
- command: (editor) => editor?.chain().focus().toggleHeading({ level: 1 }).run(),
- },
- {
- name: 'h2',
- icon: icons.heading2,
- isActive: (editor) => editor?.isActive('heading', { level: 2 }),
- command: (editor) => editor?.chain().focus().toggleHeading({ level: 2 }).run(),
- },
- {
- name: 'h3',
- icon: icons.heading3,
- isActive: (editor) => editor?.isActive('heading', { level: 3 }),
- command: (editor) => editor?.chain().focus().toggleHeading({ level: 3 }).run(),
- },
- {
- name: 'blockquote',
- icon: icons.blockquote,
- isActive: (editor) => editor?.isActive('blockquote'),
- command: (editor) => editor?.chain().focus().toggleBlockquote().run(),
- },
- {
- name: 'code',
- icon: icons.code,
- isActive: (editor) => editor?.isActive('codeBlock'),
- command: (editor) => editor?.chain().focus().toggleCodeBlock().run(),
- },
- {
- name: 'bullet-list',
- icon: icons.bulletList,
- isActive: (editor) => editor?.isActive('bulletList'),
- command: (editor) => editor?.chain().focus().toggleBulletList().run(),
- },
- {
- name: 'ordered-list',
- icon: icons.orderedList,
- isActive: (editor) => editor?.isActive('orderedList'),
- command: (editor) => editor?.chain().focus().toggleOrderedList().run(),
- },
- {
- name: 'horizontal-rule',
- icon: icons.horizontalRule,
- isActive: (editor) => editor?.isActive('horizontalRule'),
- command: (editor) => editor?.chain().focus().setHorizontalRule().run(),
- },
- {
- name: 'align-left',
- icon: icons.alignLeft,
- isActive: (editor) => editor?.isActive({ textAlign: 'left' }),
- command: (editor) => editor?.chain().focus().setTextAlign('left').run(),
- },
- {
- name: 'align-center',
- icon: icons.alignCenter,
- isActive: (editor) => editor?.isActive({ textAlign: 'center' }),
- command: (editor) => editor?.chain().focus().setTextAlign('center').run(),
- },
- {
- name: 'align-right',
- icon: icons.alignRight,
- isActive: (editor) => editor?.isActive({ textAlign: 'right' }),
- command: (editor) => editor?.chain().focus().setTextAlign('right').run(),
- },
- {
- name: 'align-justify',
- icon: icons.alignJustify,
- isActive: (editor) => editor?.isActive({ textAlign: 'justify' }),
- command: (editor) => editor?.chain().focus().setTextAlign('justify').run(),
- },
- {
- name: 'link',
- icon: icons.link,
- isActive: (editor) => editor?.isActive('link'),
- command: () => {
- const text = prompt('Enter the text');
- const url = prompt('Enter the URL');
-
- if (url && text && this.editor) {
- const { from } = this.editor.state.selection;
- this.editor
- .chain()
- .focus()
- .insertContent(text)
- .setTextSelection({ from: from, to: from + text.length })
- .setLink({ href: url, target: '_blank' })
- .run();
- }
- },
- },
- ];
-
@property({ attribute: false })
set editor(value) {
const oldValue = this.#editor;
@@ -146,35 +17,14 @@ export class UmbTiptapFixedMenuElement extends UmbLitElement {
return;
}
this.#editor = value;
- this.#editor?.on('selectionUpdate', this.#onUpdate);
- this.#editor?.on('update', this.#onUpdate);
- // todo add listener for commands
}
get editor() {
return this.#editor;
}
#editor?: Editor;
- #onUpdate = () => {
- this.requestUpdate();
- };
-
override render() {
return html`
- ${this.actions.map(
- (action) => html`
-
- `,
- )}
!!ext.kind || !!ext.element}
@@ -187,10 +37,13 @@ export class UmbTiptapFixedMenuElement extends UmbLitElement {
:host {
border-radius: var(--uui-border-radius);
border: 1px solid var(--uui-color-border);
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0;
background-color: var(--uui-color-surface);
color: var(--color-text);
display: grid;
grid-template-columns: repeat(auto-fill, minmax(24px, 1fr));
+ gap: 4px;
position: sticky;
top: -25px;
left: 0px;
@@ -202,42 +55,11 @@ export class UmbTiptapFixedMenuElement extends UmbLitElement {
pointer-events: none;
background-color: var(--uui-color-surface-alt);
}
-
- button {
- color: var(--uui-color-interactive);
- width: 24px;
- height: 24px;
- padding: 4px;
- border: none;
- background: none;
- cursor: pointer;
- margin: 0;
- border-radius: 4px;
- box-sizing: border-box;
- }
-
- button:hover {
- color: var(--uui-color-interactive-emphasis);
- background-color: var(--uui-color-surface-alt);
- }
-
- button.active {
- background-color: var(--uui-color-selected);
- color: var(--uui-color-selected-contrast);
- }
- button.active:hover {
- background-color: var(--uui-color-selected-emphasis);
- }
-
- button img {
- width: 100%;
- height: 100%;
- }
`;
}
declare global {
interface HTMLElementTagNameMap {
- 'umb-tiptap-fixed-menu': UmbTiptapFixedMenuElement;
+ [elementName]: UmbTiptapFixedMenuElement;
}
}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/components/input-tiptap/tiptap-hover-menu.element.ts b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/components/input-tiptap/tiptap-hover-menu.element.ts
index 28c9feb62e..30f1458cb7 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/components/input-tiptap/tiptap-hover-menu.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/components/input-tiptap/tiptap-hover-menu.element.ts
@@ -24,7 +24,6 @@ export class UmbTiptapHoverMenuElement extends LitElement {
}
#onUpdate = () => {
- console.log('LINK ACTIVE');
if (this.editor?.isActive('link')) {
// show the popover
this.showPopover();
@@ -34,7 +33,6 @@ export class UmbTiptapHoverMenuElement extends LitElement {
};
override render() {
- console.log('RENDER HOVER MENU');
return html``;
}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/components/toolbar/tiptap-toolbar-button.element.ts b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/components/toolbar/tiptap-toolbar-button.element.ts
new file mode 100644
index 0000000000..fc3c7219bd
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/components/toolbar/tiptap-toolbar-button.element.ts
@@ -0,0 +1,66 @@
+import type { ManifestTiptapExtensionButtonKind } from '../../extensions/tiptap-extension.js';
+import type { UmbTiptapToolbarElementApi } from '../../extensions/types.js';
+import type { Editor } from '@umbraco-cms/backoffice/external/tiptap';
+import { customElement, html, ifDefined, state, when } from '@umbraco-cms/backoffice/external/lit';
+import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
+
+const elementName = 'umb-tiptap-toolbar-button';
+
+@customElement(elementName)
+export class UmbTiptapToolbarButtonElement extends UmbLitElement {
+ public api?: UmbTiptapToolbarElementApi;
+ public editor?: Editor;
+ public manifest?: ManifestTiptapExtensionButtonKind;
+
+ @state()
+ private _isActive = false;
+
+ override connectedCallback() {
+ super.connectedCallback();
+
+ if (this.editor) {
+ this.editor.on('selectionUpdate', this.#onEditorUpdate);
+ this.editor.on('update', this.#onEditorUpdate);
+ }
+ }
+
+ override disconnectedCallback() {
+ super.disconnectedCallback();
+
+ if (this.editor) {
+ this.editor.off('selectionUpdate', this.#onEditorUpdate);
+ this.editor.off('update', this.#onEditorUpdate);
+ }
+ }
+
+ #onEditorUpdate = () => {
+ if (this.api && this.editor && this.manifest) {
+ this._isActive = this.api.isActive(this.editor);
+ }
+ };
+
+ override render() {
+ return html`
+ this.api?.execute(this.editor)}>
+ ${when(
+ this.manifest?.meta.icon,
+ () => html``,
+ () => html`${this.manifest?.meta.label}`,
+ )}
+
+ `;
+ }
+}
+
+export { UmbTiptapToolbarButtonElement as element };
+
+declare global {
+ interface HTMLElementTagNameMap {
+ [elementName]: UmbTiptapToolbarButtonElement;
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/blockquote.extension.ts b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/blockquote.extension.ts
new file mode 100644
index 0000000000..d1ecfdfe19
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/blockquote.extension.ts
@@ -0,0 +1,11 @@
+import { UmbTiptapToolbarElementApiBase } from '../types.js';
+import { Blockquote } from '@umbraco-cms/backoffice/external/tiptap';
+import type { Editor } from '@umbraco-cms/backoffice/external/tiptap';
+
+export default class UmbTiptapBlockquoteExtensionApi extends UmbTiptapToolbarElementApiBase {
+ getTiptapExtensions = () => [Blockquote];
+
+ override execute(editor?: Editor) {
+ editor?.chain().focus().toggleBlockquote().run();
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/bold.extension.ts b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/bold.extension.ts
new file mode 100644
index 0000000000..e65d167551
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/bold.extension.ts
@@ -0,0 +1,11 @@
+import { UmbTiptapToolbarElementApiBase } from '../types.js';
+import { Bold } from '@umbraco-cms/backoffice/external/tiptap';
+import type { Editor } from '@umbraco-cms/backoffice/external/tiptap';
+
+export default class UmbTiptapBoldExtensionApi extends UmbTiptapToolbarElementApiBase {
+ getTiptapExtensions = () => [Bold];
+
+ override execute(editor?: Editor) {
+ editor?.chain().focus().toggleBold().run();
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/bullet-list.extension.ts b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/bullet-list.extension.ts
new file mode 100644
index 0000000000..8dd956279c
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/bullet-list.extension.ts
@@ -0,0 +1,11 @@
+import { UmbTiptapToolbarElementApiBase } from '../types.js';
+import { BulletList, ListItem } from '@umbraco-cms/backoffice/external/tiptap';
+import type { Editor } from '@umbraco-cms/backoffice/external/tiptap';
+
+export default class UmbTiptapBulletListExtensionApi extends UmbTiptapToolbarElementApiBase {
+ getTiptapExtensions = () => [BulletList, ListItem];
+
+ override execute(editor?: Editor) {
+ editor?.chain().focus().toggleBulletList().run();
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/code-block.extension.ts b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/code-block.extension.ts
new file mode 100644
index 0000000000..7cfa5861b2
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/code-block.extension.ts
@@ -0,0 +1,12 @@
+import { UmbTiptapToolbarElementApiBase } from '../types.js';
+import { Code, CodeBlock } from '@umbraco-cms/backoffice/external/tiptap';
+import type { Editor } from '@umbraco-cms/backoffice/external/tiptap';
+
+export default class UmbTiptapCodeBlockExtensionApi extends UmbTiptapToolbarElementApiBase {
+ getTiptapExtensions = () => [Code, CodeBlock];
+
+ override execute(editor?: Editor) {
+ // editor.chain().focus().toggleCode().run();
+ editor?.chain().focus().toggleCodeBlock().run();
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/heading1.extension.ts b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/heading1.extension.ts
new file mode 100644
index 0000000000..7543e321fb
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/heading1.extension.ts
@@ -0,0 +1,15 @@
+import { UmbTiptapToolbarElementApiBase } from '../types.js';
+import { Heading } from '@umbraco-cms/backoffice/external/tiptap';
+import type { Editor } from '@umbraco-cms/backoffice/external/tiptap';
+
+export default class UmbTiptapHeading1ExtensionApi extends UmbTiptapToolbarElementApiBase {
+ getTiptapExtensions = () => [Heading];
+
+ override isActive(editor?: Editor) {
+ return editor?.isActive('heading', { level: 1 }) === true;
+ }
+
+ override execute(editor?: Editor) {
+ editor?.chain().focus().toggleHeading({ level: 1 }).run();
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/heading2.extension.ts b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/heading2.extension.ts
new file mode 100644
index 0000000000..3edcf7b57a
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/heading2.extension.ts
@@ -0,0 +1,15 @@
+import { UmbTiptapToolbarElementApiBase } from '../types.js';
+import { Heading } from '@umbraco-cms/backoffice/external/tiptap';
+import type { Editor } from '@umbraco-cms/backoffice/external/tiptap';
+
+export default class UmbTiptapHeading2ExtensionApi extends UmbTiptapToolbarElementApiBase {
+ getTiptapExtensions = () => [Heading];
+
+ override isActive(editor?: Editor) {
+ return editor?.isActive('heading', { level: 2 }) === true;
+ }
+
+ override execute(editor?: Editor) {
+ editor?.chain().focus().toggleHeading({ level: 2 }).run();
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/heading3.extension.ts b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/heading3.extension.ts
new file mode 100644
index 0000000000..9def84dc2c
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/heading3.extension.ts
@@ -0,0 +1,15 @@
+import { UmbTiptapToolbarElementApiBase } from '../types.js';
+import { Heading } from '@umbraco-cms/backoffice/external/tiptap';
+import type { Editor } from '@umbraco-cms/backoffice/external/tiptap';
+
+export default class UmbTiptapHeading3ExtensionApi extends UmbTiptapToolbarElementApiBase {
+ getTiptapExtensions = () => [Heading];
+
+ override isActive(editor?: Editor) {
+ return editor?.isActive('heading', { level: 3 }) === true;
+ }
+
+ override execute(editor?: Editor) {
+ editor?.chain().focus().toggleHeading({ level: 3 }).run();
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/horizontal-rule.extension.ts b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/horizontal-rule.extension.ts
new file mode 100644
index 0000000000..0219f45673
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/horizontal-rule.extension.ts
@@ -0,0 +1,11 @@
+import { UmbTiptapToolbarElementApiBase } from '../types.js';
+import { HorizontalRule } from '@umbraco-cms/backoffice/external/tiptap';
+import type { Editor } from '@umbraco-cms/backoffice/external/tiptap';
+
+export default class UmbTiptapHorizontalRuleExtensionApi extends UmbTiptapToolbarElementApiBase {
+ getTiptapExtensions = () => [HorizontalRule];
+
+ override execute(editor?: Editor) {
+ editor?.chain().focus().setHorizontalRule().run();
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/image.extension.ts b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/image.extension.ts
new file mode 100644
index 0000000000..bf8b9956e9
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/image.extension.ts
@@ -0,0 +1,8 @@
+import { UmbTiptapToolbarElementApiBase } from '../types.js';
+import { UmbImage } from '@umbraco-cms/backoffice/external/tiptap';
+
+export default class UmbTiptapImageExtensionApi extends UmbTiptapToolbarElementApiBase {
+ getTiptapExtensions() {
+ return [UmbImage.configure({ inline: true })];
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/italic.extension.ts b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/italic.extension.ts
new file mode 100644
index 0000000000..ff122f81e4
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/italic.extension.ts
@@ -0,0 +1,11 @@
+import { UmbTiptapToolbarElementApiBase } from '../types.js';
+import { Italic } from '@umbraco-cms/backoffice/external/tiptap';
+import type { Editor } from '@umbraco-cms/backoffice/external/tiptap';
+
+export default class UmbTiptapItalicExtensionApi extends UmbTiptapToolbarElementApiBase {
+ getTiptapExtensions = () => [Italic];
+
+ override execute(editor?: Editor) {
+ editor?.chain().focus().toggleItalic().run();
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/manifests.ts
new file mode 100644
index 0000000000..9ef58cd081
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/manifests.ts
@@ -0,0 +1,221 @@
+import type { ManifestTiptapExtension, ManifestTiptapExtensionButtonKind } from '../tiptap-extension.js';
+
+export const manifests: Array = [
+ {
+ type: 'tiptapExtension',
+ kind: 'button',
+ alias: 'Umb.Tiptap.Blockquote',
+ name: 'Blockquote Tiptap Extension',
+ api: () => import('./blockquote.extension.js'),
+ weight: 995,
+ meta: {
+ alias: 'blockquote',
+ icon: 'icon-blockquote',
+ label: 'Blockquote',
+ },
+ },
+ {
+ type: 'tiptapExtension',
+ kind: 'button',
+ alias: 'Umb.Tiptap.Bold',
+ name: 'Bold Tiptap Extension',
+ api: () => import('./bold.extension.js'),
+ weight: 999,
+ meta: {
+ alias: 'bold',
+ icon: 'icon-bold',
+ label: 'Bold',
+ },
+ },
+ {
+ type: 'tiptapExtension',
+ kind: 'button',
+ alias: 'Umb.Tiptap.BulletList',
+ name: 'Bullet List Tiptap Extension',
+ api: () => import('./bullet-list.extension.js'),
+ weight: 993,
+ meta: {
+ alias: 'bulletList',
+ icon: 'icon-bulleted-list',
+ label: 'Bullet List',
+ },
+ },
+ {
+ type: 'tiptapExtension',
+ kind: 'button',
+ alias: 'Umb.Tiptap.CodeBlock',
+ name: 'Code Block Tiptap Extension',
+ api: () => import('./code-block.extension.js'),
+ weight: 994,
+ meta: {
+ alias: 'codeBlock',
+ icon: 'icon-code',
+ label: 'Code Block',
+ },
+ },
+ {
+ type: 'tiptapExtension',
+ kind: 'button',
+ alias: 'Umb.Tiptap.Heading1',
+ name: 'Heading 1 Tiptap Extension',
+ api: () => import('./heading1.extension.js'),
+ weight: 949,
+ meta: {
+ alias: 'heading1',
+ icon: 'icon-heading-1',
+ label: 'Heading 1',
+ },
+ },
+ {
+ type: 'tiptapExtension',
+ kind: 'button',
+ alias: 'Umb.Tiptap.Heading2',
+ name: 'Heading 2 Tiptap Extension',
+ api: () => import('./heading2.extension.js'),
+ weight: 948,
+ meta: {
+ alias: 'heading2',
+ icon: 'icon-heading-2',
+ label: 'Heading 2',
+ },
+ },
+ {
+ type: 'tiptapExtension',
+ kind: 'button',
+ alias: 'Umb.Tiptap.Heading3',
+ name: 'Heading 3 Tiptap Extension',
+ api: () => import('./heading3.extension.js'),
+ weight: 947,
+ meta: {
+ alias: 'heading3',
+ icon: 'icon-heading-3',
+ label: 'Heading 3',
+ },
+ },
+ {
+ type: 'tiptapExtension',
+ kind: 'button',
+ alias: 'Umb.Tiptap.HorizontalRule',
+ name: 'Horizontal Rule Tiptap Extension',
+ api: () => import('./horizontal-rule.extension.js'),
+ weight: 991,
+ meta: {
+ alias: 'horizontalRule',
+ icon: 'icon-horizontal-rule',
+ label: 'Horizontal Rule',
+ },
+ },
+ {
+ type: 'tiptapExtension',
+ alias: 'Umb.Tiptap.Image',
+ name: 'Image Tiptap Extension',
+ api: () => import('./image.extension.js'),
+ meta: {
+ alias: 'image',
+ },
+ },
+ {
+ type: 'tiptapExtension',
+ kind: 'button',
+ alias: 'Umb.Tiptap.Italic',
+ name: 'Italic Tiptap Extension',
+ api: () => import('./italic.extension.js'),
+ weight: 998,
+ meta: {
+ alias: 'italic',
+ icon: 'icon-italic',
+ label: 'Italic',
+ },
+ },
+ {
+ type: 'tiptapExtension',
+ kind: 'button',
+ alias: 'Umb.Tiptap.OrderedList',
+ name: 'Ordered List Tiptap Extension',
+ api: () => import('./ordered-list.extension.js'),
+ weight: 992,
+ meta: {
+ alias: 'orderedList',
+ icon: 'icon-ordered-list',
+ label: 'Ordered List',
+ },
+ },
+ {
+ type: 'tiptapExtension',
+ kind: 'button',
+ alias: 'Umb.Tiptap.Strike',
+ name: 'Strike Tiptap Extension',
+ api: () => import('./strike.extension.js'),
+ weight: 996,
+ meta: {
+ alias: 'strike',
+ icon: 'icon-strikethrough',
+ label: 'Strike',
+ },
+ },
+ {
+ type: 'tiptapExtension',
+ kind: 'button',
+ alias: 'Umb.Tiptap.TextAlignCenter',
+ name: 'Text Align Center Tiptap Extension',
+ api: () => import('./text-align-center.extension.js'),
+ weight: 918,
+ meta: {
+ alias: 'text-align-center',
+ icon: 'icon-text-align-center',
+ label: 'Text Align Center',
+ },
+ },
+ {
+ type: 'tiptapExtension',
+ kind: 'button',
+ alias: 'Umb.Tiptap.TextAlignJustify',
+ name: 'Text Align Justify Tiptap Extension',
+ api: () => import('./text-align-justify.extension.js'),
+ weight: 916,
+ meta: {
+ alias: 'text-align-justify',
+ icon: 'icon-text-align-justify',
+ label: 'Text Align Justify',
+ },
+ },
+ {
+ type: 'tiptapExtension',
+ kind: 'button',
+ alias: 'Umb.Tiptap.TextAlignLeft',
+ name: 'Text Align Left Tiptap Extension',
+ api: () => import('./text-align-left.extension.js'),
+ weight: 919,
+ meta: {
+ alias: 'text-align-left',
+ icon: 'icon-text-align-left',
+ label: 'Text Align Left',
+ },
+ },
+ {
+ type: 'tiptapExtension',
+ kind: 'button',
+ alias: 'Umb.Tiptap.TextAlignRight',
+ name: 'Text Align Right Tiptap Extension',
+ api: () => import('./text-align-right.extension.js'),
+ weight: 917,
+ meta: {
+ alias: 'text-align-right',
+ icon: 'icon-text-align-right',
+ label: 'Text Align Right',
+ },
+ },
+ {
+ type: 'tiptapExtension',
+ kind: 'button',
+ alias: 'Umb.Tiptap.Underline',
+ name: 'Underline Tiptap Extension',
+ api: () => import('./underline.extension.js'),
+ weight: 997,
+ meta: {
+ alias: 'underline',
+ icon: 'icon-underline',
+ label: 'Underline',
+ },
+ },
+];
diff --git a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/ordered-list.extension.ts b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/ordered-list.extension.ts
new file mode 100644
index 0000000000..471d794e1c
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/ordered-list.extension.ts
@@ -0,0 +1,11 @@
+import { UmbTiptapToolbarElementApiBase } from '../types.js';
+import { OrderedList, ListItem } from '@umbraco-cms/backoffice/external/tiptap';
+import type { Editor } from '@umbraco-cms/backoffice/external/tiptap';
+
+export default class UmbTiptapOrderedListExtensionApi extends UmbTiptapToolbarElementApiBase {
+ getTiptapExtensions = () => [OrderedList, ListItem];
+
+ override execute(editor?: Editor) {
+ editor?.chain().focus().toggleOrderedList().run();
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/strike.extension.ts b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/strike.extension.ts
new file mode 100644
index 0000000000..b073c12dd9
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/strike.extension.ts
@@ -0,0 +1,11 @@
+import { UmbTiptapToolbarElementApiBase } from '../types.js';
+import { Strike } from '@umbraco-cms/backoffice/external/tiptap';
+import type { Editor } from '@umbraco-cms/backoffice/external/tiptap';
+
+export default class UmbTiptapStrikeExtensionApi extends UmbTiptapToolbarElementApiBase {
+ getTiptapExtensions = () => [Strike];
+
+ override execute(editor?: Editor) {
+ editor?.chain().focus().toggleStrike().run();
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/text-align-center.extension.ts b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/text-align-center.extension.ts
new file mode 100644
index 0000000000..fa9c90855c
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/text-align-center.extension.ts
@@ -0,0 +1,19 @@
+import { UmbTiptapToolbarElementApiBase } from '../types.js';
+import { TextAlign } from '@umbraco-cms/backoffice/external/tiptap';
+import type { Editor } from '@umbraco-cms/backoffice/external/tiptap';
+
+export default class UmbTiptapTextAlignCenterExtensionApi extends UmbTiptapToolbarElementApiBase {
+ getTiptapExtensions = () => [
+ TextAlign.configure({
+ types: ['heading', 'paragraph', 'blockquote', 'orderedList', 'bulletList', 'codeBlock'],
+ }),
+ ];
+
+ override isActive(editor?: Editor) {
+ return editor?.isActive({ textAlign: 'center' }) === true;
+ }
+
+ override execute(editor?: Editor) {
+ editor?.chain().focus().setTextAlign('center').run();
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/text-align-justify.extension.ts b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/text-align-justify.extension.ts
new file mode 100644
index 0000000000..03e197654f
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/text-align-justify.extension.ts
@@ -0,0 +1,19 @@
+import { UmbTiptapToolbarElementApiBase } from '../types.js';
+import { TextAlign } from '@umbraco-cms/backoffice/external/tiptap';
+import type { Editor } from '@umbraco-cms/backoffice/external/tiptap';
+
+export default class UmbTiptapTextAlignJustifyExtensionApi extends UmbTiptapToolbarElementApiBase {
+ getTiptapExtensions = () => [
+ TextAlign.configure({
+ types: ['heading', 'paragraph', 'blockquote', 'orderedList', 'bulletList', 'codeBlock'],
+ }),
+ ];
+
+ override isActive(editor?: Editor) {
+ return editor?.isActive({ textAlign: 'justify' }) === true;
+ }
+
+ override execute(editor?: Editor) {
+ editor?.chain().focus().setTextAlign('justify').run();
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/text-align-left.extension.ts b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/text-align-left.extension.ts
new file mode 100644
index 0000000000..2f35da46d2
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/text-align-left.extension.ts
@@ -0,0 +1,19 @@
+import { UmbTiptapToolbarElementApiBase } from '../types.js';
+import { TextAlign } from '@umbraco-cms/backoffice/external/tiptap';
+import type { Editor } from '@umbraco-cms/backoffice/external/tiptap';
+
+export default class UmbTiptapTextAlignLeftExtensionApi extends UmbTiptapToolbarElementApiBase {
+ getTiptapExtensions = () => [
+ TextAlign.configure({
+ types: ['heading', 'paragraph', 'blockquote', 'orderedList', 'bulletList', 'codeBlock'],
+ }),
+ ];
+
+ override isActive(editor?: Editor) {
+ return editor?.isActive({ textAlign: 'left' }) === true;
+ }
+
+ override execute(editor?: Editor) {
+ editor?.chain().focus().setTextAlign('left').run();
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/text-align-right.extension.ts b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/text-align-right.extension.ts
new file mode 100644
index 0000000000..62de9a54f9
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/text-align-right.extension.ts
@@ -0,0 +1,19 @@
+import { UmbTiptapToolbarElementApiBase } from '../types.js';
+import { TextAlign } from '@umbraco-cms/backoffice/external/tiptap';
+import type { Editor } from '@umbraco-cms/backoffice/external/tiptap';
+
+export default class UmbTiptapTextAlignRightExtensionApi extends UmbTiptapToolbarElementApiBase {
+ getTiptapExtensions = () => [
+ TextAlign.configure({
+ types: ['heading', 'paragraph', 'blockquote', 'orderedList', 'bulletList', 'codeBlock'],
+ }),
+ ];
+
+ override isActive(editor?: Editor) {
+ return editor?.isActive({ textAlign: 'right' }) === true;
+ }
+
+ override execute(editor?: Editor) {
+ editor?.chain().focus().setTextAlign('right').run();
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/underline.extension.ts b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/underline.extension.ts
new file mode 100644
index 0000000000..4e1bac6d6a
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/core/underline.extension.ts
@@ -0,0 +1,11 @@
+import { UmbTiptapToolbarElementApiBase } from '../types.js';
+import { Underline } from '@umbraco-cms/backoffice/external/tiptap';
+import type { Editor } from '@umbraco-cms/backoffice/external/tiptap';
+
+export default class UmbTiptapUnderlineExtensionApi extends UmbTiptapToolbarElementApiBase {
+ getTiptapExtensions = () => [Underline];
+
+ override execute(editor?: Editor) {
+ editor?.chain().focus().toggleUnderline().run();
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/manifests.ts
index 8afb03e629..4b9394020d 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/manifests.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/manifests.ts
@@ -1,4 +1,5 @@
-import type { ManifestTiptapExtension } from './tiptap-extension.js';
+import type { ManifestTiptapExtension, ManifestTiptapExtensionButtonKind } from './tiptap-extension.js';
+import { manifests as core } from './core/manifests.js';
import type { ManifestTypes, UmbExtensionManifestKind } from '@umbraco-cms/backoffice/extension-registry';
const kinds: Array = [
@@ -8,33 +9,63 @@ const kinds: Array = [
matchKind: 'button',
matchType: 'tiptapExtension',
manifest: {
- element: () => import('./tiptap-toolbar-button.element.js'),
+ element: () => import('../components/toolbar/tiptap-toolbar-button.element.js'),
},
},
];
-const extensions: Array = [
+const umbExtensions: Array = [
{
type: 'tiptapExtension',
- alias: 'Umb.Tiptap.Image',
- name: 'Image Tiptap Extension',
+ kind: 'button',
+ alias: 'Umb.Tiptap.CodeEditor',
+ name: 'Code Editor Tiptap Extension',
+ api: () => import('./umb/code-editor.extension.js'),
weight: 1000,
- api: () => import('./tiptap-image.extension.js'),
- meta: {},
+ meta: {
+ alias: 'umb-code-editor',
+ icon: 'icon-code',
+ label: '#general_viewSourceCode',
+ },
+ },
+ {
+ type: 'tiptapExtension',
+ kind: 'button',
+ alias: 'Umb.Tiptap.Embed',
+ name: 'Embed Tiptap Extension',
+ api: () => import('./umb/embed.extension.js'),
+ meta: {
+ alias: 'umb-embed',
+ icon: 'icon-embed',
+ label: 'Embed',
+ },
},
{
type: 'tiptapExtension',
kind: 'button',
alias: 'Umb.Tiptap.MediaPicker',
name: 'Media Picker Tiptap Extension',
- weight: 900,
- api: () => import('./tiptap-mediapicker.extension.js'),
+ api: () => import('./umb/mediapicker.extension.js'),
meta: {
alias: 'umb-media',
icon: 'icon-picture',
label: 'Media picker',
},
},
+ {
+ type: 'tiptapExtension',
+ kind: 'button',
+ alias: 'Umb.Tiptap.UrlPicker',
+ name: 'URL Picker Tiptap Extension',
+ api: () => import('./umb/urlpicker.extension.js'),
+ meta: {
+ alias: 'umb-link',
+ icon: 'icon-link',
+ label: 'URL picker',
+ },
+ },
];
+const extensions: Array = [...core, ...umbExtensions];
+
export const manifests: Array = [...kinds, ...extensions];
diff --git a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/tiptap-extension.ts b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/tiptap-extension.ts
index 40c9fd6186..5ecb61da5d 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/tiptap-extension.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/tiptap-extension.ts
@@ -8,8 +8,9 @@ export interface ManifestTiptapExtension this.api?.execute(this.editor)}>
- ${when(
- this.manifest?.meta.icon,
- () => html``,
- () => html`${this.manifest?.meta.label}`,
- )}
-
- `;
- }
-}
-
-export { UmbTiptapToolbarButtonElement as element };
-
-declare global {
- interface HTMLElementTagNameMap {
- [elementName]: UmbTiptapToolbarButtonElement;
- }
-}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/types.ts b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/types.ts
index 5a2d19ccd4..949d73f056 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/types.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/types.ts
@@ -1,23 +1,36 @@
+import type { ManifestTiptapExtension } from './tiptap-extension.js';
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import type { Editor, Extension, Mark, Node } from '@umbraco-cms/backoffice/external/tiptap';
-import type { TemplateResult } from '@umbraco-cms/backoffice/external/lit';
import type { UmbApi } from '@umbraco-cms/backoffice/extension-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
-export abstract class UmbTiptapExtensionApi extends UmbControllerBase implements UmbApi {
+export interface UmbTiptapExtensionApi extends UmbApi {
+ getTiptapExtensions(): Array;
+}
+
+export abstract class UmbTiptapExtensionApiBase extends UmbControllerBase implements UmbApi {
+ public manifest?: ManifestTiptapExtension;
+
constructor(host: UmbControllerHost) {
super(host);
}
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- execute(editor?: Editor) {}
-
abstract getTiptapExtensions(): Array;
}
-export interface UmbTiptapToolbarButton {
- name: string;
- icon: string | TemplateResult;
- isActive: (editor?: Editor) => boolean | undefined;
- command: (editor?: Editor) => boolean | undefined | void | Promise | Promise | Promise;
+export interface UmbTiptapToolbarElementApi extends UmbTiptapExtensionApi {
+ execute(editor?: Editor): void;
+ isActive(editor?: Editor): boolean;
+}
+
+export abstract class UmbTiptapToolbarElementApiBase
+ extends UmbTiptapExtensionApiBase
+ implements UmbTiptapToolbarElementApi
+{
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ public execute(editor?: Editor) {}
+
+ public isActive(editor?: Editor) {
+ return editor && this.manifest?.meta.alias ? editor?.isActive(this.manifest.meta.alias) : false;
+ }
}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/umb/code-editor.extension.ts b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/umb/code-editor.extension.ts
new file mode 100644
index 0000000000..be55c65dbe
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/umb/code-editor.extension.ts
@@ -0,0 +1,28 @@
+import { UmbTiptapToolbarElementApiBase } from '../types.js';
+import type { Editor } from '@umbraco-cms/backoffice/external/tiptap';
+import { UMB_CODE_EDITOR_MODAL, UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal';
+
+export default class UmbTiptapCodeEditorExtensionApi extends UmbTiptapToolbarElementApiBase {
+ getTiptapExtensions = () => [];
+
+ override async execute(editor?: Editor) {
+ console.log('umb-code-editor.execute', editor);
+ if (!editor) return;
+
+ const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT);
+ const modal = modalManager.open(this, UMB_CODE_EDITOR_MODAL, {
+ data: {
+ headline: 'Edit source code',
+ content: editor?.getHTML() ?? '',
+ language: 'html',
+ },
+ });
+
+ if (!modal) return;
+
+ const data = await modal.onSubmit().catch(() => undefined);
+ if (!data) return;
+
+ editor?.commands.setContent(data.content, true);
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/umb/embed.extension.ts b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/umb/embed.extension.ts
new file mode 100644
index 0000000000..f09ecfd084
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/umb/embed.extension.ts
@@ -0,0 +1,11 @@
+import { UmbTiptapToolbarElementApiBase } from '../types.js';
+import type { Editor } from '@umbraco-cms/backoffice/external/tiptap';
+
+export default class UmbTiptapEmbedExtensionApi extends UmbTiptapToolbarElementApiBase {
+ getTiptapExtensions = () => [];
+
+ override async execute(editor?: Editor) {
+ console.log('umb-embed.execute', editor);
+ // Research: https://github.com/ueberdosis/tiptap/tree/main/packages/extension-youtube
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/tiptap-mediapicker.extension.ts b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/umb/mediapicker.extension.ts
similarity index 84%
rename from src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/tiptap-mediapicker.extension.ts
rename to src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/umb/mediapicker.extension.ts
index 7d96091761..6947d772b8 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/tiptap-mediapicker.extension.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/umb/mediapicker.extension.ts
@@ -1,14 +1,14 @@
-import { UmbTiptapExtensionApi } from './types.js';
+import { UmbTiptapToolbarElementApiBase } from '../types.js';
import { mergeAttributes, Node } from '@umbraco-cms/backoffice/external/tiptap';
import { UMB_MEDIA_PICKER_MODAL } from '@umbraco-cms/backoffice/media';
import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal';
import type { Editor } from '@umbraco-cms/backoffice/external/tiptap';
-export default class UmbTiptapMediaPickerPlugin extends UmbTiptapExtensionApi {
+export default class UmbTiptapMediaPickerExtensionApi extends UmbTiptapToolbarElementApiBase {
getTiptapExtensions() {
return [
Node.create({
- name: 'umbMediaPicker',
+ name: 'umb-media',
priority: 1000,
group: 'block',
marks: '',
@@ -33,7 +33,9 @@ export default class UmbTiptapMediaPickerPlugin extends UmbTiptapExtensionApi {
];
}
- //isActive: (editor?: Editor) => editor?.isActive('umbMediaPicker') || editor?.isActive('image'),
+ override isActive(editor?: Editor) {
+ return editor?.isActive('umb-media') === true || editor?.isActive('image') === true;
+ }
override async execute(editor?: Editor) {
console.log('umb-media.execute', editor);
diff --git a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/umb/urlpicker.extension.ts b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/umb/urlpicker.extension.ts
new file mode 100644
index 0000000000..7bedab735b
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/extensions/umb/urlpicker.extension.ts
@@ -0,0 +1,27 @@
+import { UmbTiptapToolbarElementApiBase } from '../types.js';
+import { Link } from '@umbraco-cms/backoffice/external/tiptap';
+import type { Editor } from '@umbraco-cms/backoffice/external/tiptap';
+
+export default class UmbTiptapUrlPickerExtensionApi extends UmbTiptapToolbarElementApiBase {
+ getTiptapExtensions() {
+ return [Link.extend({ openOnClick: false })];
+ }
+
+ override async execute(editor?: Editor) {
+ console.log('umb-link.execute', editor);
+
+ const text = prompt('Enter the text');
+ const url = prompt('Enter the URL');
+
+ if (url && text && editor) {
+ const { from } = editor.state.selection;
+ editor
+ .chain()
+ .focus()
+ .insertContent(text)
+ .setTextSelection({ from: from, to: from + text.length })
+ .setLink({ href: url, target: '_blank' })
+ .run();
+ }
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/property-editors/tiptap/property-editor-ui-tiptap.element.ts b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/property-editors/tiptap/property-editor-ui-tiptap.element.ts
index 60dedc1240..d1dee314ae 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/property-editors/tiptap/property-editor-ui-tiptap.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/rte/tiptap/property-editors/tiptap/property-editor-ui-tiptap.element.ts
@@ -1,18 +1,13 @@
-import type UmbInputTiptapElement from '../../components/input-tiptap/input-tiptap.element.js';
+import type { UmbInputTiptapElement } from '../../components/input-tiptap/input-tiptap.element.js';
import { customElement, html, property, state } from '@umbraco-cms/backoffice/external/lit';
+import { UmbBlockRteEntriesContext, UmbBlockRteManagerContext } from '@umbraco-cms/backoffice/block-rte';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
-import {
- UmbPropertyValueChangeEvent,
- type UmbPropertyEditorConfigCollection,
-} from '@umbraco-cms/backoffice/property-editor';
+import { UmbPropertyValueChangeEvent } from '@umbraco-cms/backoffice/property-editor';
+import type { UmbBlockRteLayoutModel } from '@umbraco-cms/backoffice/block-rte';
+import type { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor';
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
import '../../components/input-tiptap/input-tiptap.element.js';
-import {
- UmbBlockRteEntriesContext,
- UmbBlockRteManagerContext,
- type UmbBlockRteLayoutModel,
-} from '@umbraco-cms/backoffice/block-rte';
import type { UmbBlockValueType } from '@umbraco-cms/backoffice/block';
// Look at Tiny for correct types
@@ -23,11 +18,13 @@ export interface UmbRichTextEditorValueType {
const UMB_BLOCK_RTE_BLOCK_LAYOUT_ALIAS = 'Umbraco.RichText';
+const elementName = 'umb-property-editor-ui-tiptap';
+
/**
* @element umb-property-editor-ui-tiptap
*/
-@customElement('umb-property-editor-ui-tiptap')
-export class UmbPropertyEditorUITiptapElement extends UmbLitElement implements UmbPropertyEditorUiElement {
+@customElement(elementName)
+export class UmbPropertyEditorUiTiptapElement extends UmbLitElement implements UmbPropertyEditorUiElement {
//
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
this._config = config;
@@ -110,7 +107,7 @@ export class UmbPropertyEditorUITiptapElement extends UmbLitElement implements U
}
#onChange(event: CustomEvent & { target: UmbInputTiptapElement }) {
- const value = event.target.value as string;
+ const value = event.target.value;
this._latestMarkup = value;
// TODO: Validate blocks
@@ -148,10 +145,10 @@ export class UmbPropertyEditorUITiptapElement extends UmbLitElement implements U
}
}
-export default UmbPropertyEditorUITiptapElement;
+export { UmbPropertyEditorUiTiptapElement as element };
declare global {
interface HTMLElementTagNameMap {
- 'umb-property-editor-ui-tiptap': UmbPropertyEditorUITiptapElement;
+ [elementName]: UmbPropertyEditorUiTiptapElement;
}
}