From f3658bf356c790ca34b33cfaf2e66367c880d65f Mon Sep 17 00:00:00 2001 From: Lee Kelleher Date: Thu, 3 Apr 2025 10:44:57 +0100 Subject: [PATCH] Tiptap RTE: Style Menu extension kind (#18918) * Adds 'styleMenu' Tiptap toolbar extension kind * Adds icons for `

` and `

` tags * Adds commands to HTML Global Attributes extension for setting the `class` and `id` attributes. * Renamed "default-tiptap-toolbar-element.api.ts" file The "element" part was confusing. * Toolbar Menu: uses correct `item` value * Cascading Menu: adds localization for the label * Adds `label` attribute to UUI components for accessibility. * Toolbar Menu: uses correct `appearance` value * Removed unrequired `api` from Style Select * Destructs the `item.data` object --- .../tiptap/extensions/tiptap-div.extension.ts | 4 +- ...tiptap-html-global-attributes.extension.ts | 44 +++++++++++++ .../extensions/tiptap-span.extension.ts | 2 +- .../core/icon-registry/icon-dictionary.json | 8 +++ .../src/packages/core/icon-registry/icons.ts | 6 ++ .../icon-registry/icons/icon-heading-4.ts | 1 + .../icon-registry/icons/icon-paragraph.ts | 1 + .../cascading-menu-popover.element.ts | 8 ++- .../input-tiptap/tiptap-toolbar.element.ts | 2 +- ...t.api.ts => default-tiptap-toolbar-api.ts} | 0 .../toolbar/style-menu.tiptap-toolbar-api.ts | 34 ++++++++++ ...tap-toolbar-color-picker-button.element.ts | 2 +- .../toolbar/tiptap-toolbar-menu.element.ts | 9 +-- .../packages/tiptap/extensions/manifests.ts | 46 ++++++++----- .../extensions/style-select/manifests.ts | 65 ++++++++++++------- .../style-select.tiptap-toolbar-api.ts | 22 +------ .../extensions/tiptap-toolbar.extension.ts | 30 ++++++--- 17 files changed, 205 insertions(+), 79 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-heading-4.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-paragraph.ts rename src/Umbraco.Web.UI.Client/src/packages/tiptap/components/toolbar/{default-tiptap-toolbar-element.api.ts => default-tiptap-toolbar-api.ts} (100%) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/tiptap/components/toolbar/style-menu.tiptap-toolbar-api.ts diff --git a/src/Umbraco.Web.UI.Client/src/external/tiptap/extensions/tiptap-div.extension.ts b/src/Umbraco.Web.UI.Client/src/external/tiptap/extensions/tiptap-div.extension.ts index 86563b88c6..e7855d4288 100644 --- a/src/Umbraco.Web.UI.Client/src/external/tiptap/extensions/tiptap-div.extension.ts +++ b/src/Umbraco.Web.UI.Client/src/external/tiptap/extensions/tiptap-div.extension.ts @@ -23,10 +23,10 @@ export const Div = Node.create({ }, parseHTML() { - return [{ tag: 'div' }]; + return [{ tag: this.name }]; }, renderHTML({ HTMLAttributes }) { - return ['div', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]; + return [this.name, mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]; }, }); diff --git a/src/Umbraco.Web.UI.Client/src/external/tiptap/extensions/tiptap-html-global-attributes.extension.ts b/src/Umbraco.Web.UI.Client/src/external/tiptap/extensions/tiptap-html-global-attributes.extension.ts index b86b6ecc31..011a8209c6 100644 --- a/src/Umbraco.Web.UI.Client/src/external/tiptap/extensions/tiptap-html-global-attributes.extension.ts +++ b/src/Umbraco.Web.UI.Client/src/external/tiptap/extensions/tiptap-html-global-attributes.extension.ts @@ -52,4 +52,48 @@ export const HtmlGlobalAttributes = Extension.create + ({ commands }) => { + if (!className) return false; + const types = type ? [type] : this.options.types; + return types + .map((type) => commands.updateAttributes(type, { class: className })) + .every((response) => response); + }, + unsetClassName: + (type) => + ({ commands }) => { + const types = type ? [type] : this.options.types; + return types.map((type) => commands.resetAttributes(type, 'class')).every((response) => response); + }, + setId: + (id, type) => + ({ commands }) => { + if (!id) return false; + const types = type ? [type] : this.options.types; + return types.map((type) => commands.updateAttributes(type, { id })).every((response) => response); + }, + unsetId: + (type) => + ({ commands }) => { + const types = type ? [type] : this.options.types; + return types.map((type) => commands.resetAttributes(type, 'id')).every((response) => response); + }, + }; + }, }); + +declare module '@tiptap/core' { + interface Commands { + htmlGlobalAttributes: { + setClassName: (className?: string, type?: string) => ReturnType; + unsetClassName: (type?: string) => ReturnType; + setId: (id?: string, type?: string) => ReturnType; + unsetId: (type?: string) => ReturnType; + }; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/external/tiptap/extensions/tiptap-span.extension.ts b/src/Umbraco.Web.UI.Client/src/external/tiptap/extensions/tiptap-span.extension.ts index a4a375f100..6d49c46461 100644 --- a/src/Umbraco.Web.UI.Client/src/external/tiptap/extensions/tiptap-span.extension.ts +++ b/src/Umbraco.Web.UI.Client/src/external/tiptap/extensions/tiptap-span.extension.ts @@ -28,7 +28,7 @@ export const Span = Mark.create({ return { setSpanStyle: (styles) => - ({ commands, editor, chain }) => { + ({ commands, editor }) => { if (!styles) return false; const existing = editor.getAttributes(this.name)?.style as string; 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 d4badf6fb5..5675562abc 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 @@ -986,6 +986,10 @@ "name": "icon-heading-3", "file": "heading-3.svg" }, + { + "name": "icon-heading-4", + "file": "heading-4.svg" + }, { "name": "icon-headphones", "file": "headphones.svg" @@ -1507,6 +1511,10 @@ "name": "icon-partly-cloudy", "file": "cloud-sun.svg" }, + { + "name": "icon-paragraph", + "file": "pilcrow.svg" + }, { "name": "icon-paste-in", "file": "clipboard-paste.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 03eb3c6d1b..6efeae5314 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 @@ -775,6 +775,9 @@ path: () => import("./icons/icon-heading-2.js"), name: "icon-heading-3", path: () => import("./icons/icon-heading-3.js"), },{ +name: "icon-heading-4", +path: () => import("./icons/icon-heading-4.js"), +},{ name: "icon-headphones", path: () => import("./icons/icon-headphones.js"), },{ @@ -1217,6 +1220,9 @@ path: () => import("./icons/icon-paper-plane.js"), name: "icon-partly-cloudy", path: () => import("./icons/icon-partly-cloudy.js"), },{ +name: "icon-paragraph", +path: () => import("./icons/icon-paragraph.js"), +},{ name: "icon-paste-in", legacy: true, hidden: true, diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-heading-4.ts b/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-heading-4.ts new file mode 100644 index 0000000000..765f9c988a --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-heading-4.ts @@ -0,0 +1 @@ +export default ``; \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-paragraph.ts b/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-paragraph.ts new file mode 100644 index 0000000000..e22a3a37e7 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icons/icon-paragraph.ts @@ -0,0 +1 @@ +export default ``; \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/packages/tiptap/components/cascading-menu-popover/cascading-menu-popover.element.ts b/src/Umbraco.Web.UI.Client/src/packages/tiptap/components/cascading-menu-popover/cascading-menu-popover.element.ts index 513abc2ffc..047b6c0589 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/tiptap/components/cascading-menu-popover/cascading-menu-popover.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/tiptap/components/cascading-menu-popover/cascading-menu-popover.element.ts @@ -1,4 +1,5 @@ import { css, customElement, html, ifDefined, property, repeat, when } from '@umbraco-cms/backoffice/external/lit'; +import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api'; import { UUIPopoverContainerElement } from '@umbraco-cms/backoffice/external/uui'; export type UmbCascadingMenuItem = { @@ -12,7 +13,7 @@ export type UmbCascadingMenuItem = { }; @customElement('umb-cascading-menu-popover') -export class UmbCascadingMenuPopoverElement extends UUIPopoverContainerElement { +export class UmbCascadingMenuPopoverElement extends UmbElementMixin(UUIPopoverContainerElement) { @property({ type: Array }) items?: Array; @@ -70,6 +71,8 @@ export class UmbCascadingMenuPopoverElement extends UUIPopoverContainerElement { element.setAttribute('popovertarget', popoverId); } + const label = this.localize.string(item.label); + return html`

this.#onMouseEnter(item, popoverId)} @@ -80,11 +83,12 @@ export class UmbCascadingMenuPopoverElement extends UUIPopoverContainerElement { () => html` this.#onClick(item, popoverId)}> ${when(item.icon, (icon) => html``)} diff --git a/src/Umbraco.Web.UI.Client/src/packages/tiptap/components/input-tiptap/tiptap-toolbar.element.ts b/src/Umbraco.Web.UI.Client/src/packages/tiptap/components/input-tiptap/tiptap-toolbar.element.ts index 33fc3116cf..44ffd238b2 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/tiptap/components/input-tiptap/tiptap-toolbar.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/tiptap/components/input-tiptap/tiptap-toolbar.element.ts @@ -61,7 +61,7 @@ export class UmbTiptapToolbarElement extends UmbLitElement { }, undefined, undefined, - () => import('../toolbar/default-tiptap-toolbar-element.api.js'), + () => import('../toolbar/default-tiptap-toolbar-api.js'), ); this.#extensionsController.apiProperties = { configuration: this.configuration }; diff --git a/src/Umbraco.Web.UI.Client/src/packages/tiptap/components/toolbar/default-tiptap-toolbar-element.api.ts b/src/Umbraco.Web.UI.Client/src/packages/tiptap/components/toolbar/default-tiptap-toolbar-api.ts similarity index 100% rename from src/Umbraco.Web.UI.Client/src/packages/tiptap/components/toolbar/default-tiptap-toolbar-element.api.ts rename to src/Umbraco.Web.UI.Client/src/packages/tiptap/components/toolbar/default-tiptap-toolbar-api.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/tiptap/components/toolbar/style-menu.tiptap-toolbar-api.ts b/src/Umbraco.Web.UI.Client/src/packages/tiptap/components/toolbar/style-menu.tiptap-toolbar-api.ts new file mode 100644 index 0000000000..797c382aec --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/tiptap/components/toolbar/style-menu.tiptap-toolbar-api.ts @@ -0,0 +1,34 @@ +import { UmbTiptapToolbarElementApiBase } from '../../extensions/base.js'; +import type { MetaTiptapToolbarStyleMenuItem } from '../../extensions/types.js'; +import type { ChainedCommands, Editor } from '@umbraco-cms/backoffice/external/tiptap'; + +export default class UmbTiptapToolbarStyleMenuApi extends UmbTiptapToolbarElementApiBase { + #commands: Record ChainedCommands }> = { + h1: { type: 'heading', command: (chain) => chain.toggleHeading({ level: 1 }) }, + h2: { type: 'heading', command: (chain) => chain.toggleHeading({ level: 2 }) }, + h3: { type: 'heading', command: (chain) => chain.toggleHeading({ level: 3 }) }, + h4: { type: 'heading', command: (chain) => chain.toggleHeading({ level: 4 }) }, + h5: { type: 'heading', command: (chain) => chain.toggleHeading({ level: 5 }) }, + h6: { type: 'heading', command: (chain) => chain.toggleHeading({ level: 6 }) }, + p: { type: 'paragraph', command: (chain) => chain.setParagraph() }, + blockquote: { type: 'blockquote', command: (chain) => chain.toggleBlockquote() }, + code: { type: 'code', command: (chain) => chain.toggleCode() }, + codeBlock: { type: 'codeBlock', command: (chain) => chain.toggleCodeBlock() }, + div: { type: 'div', command: (chain) => chain.toggleNode('div', 'paragraph') }, + em: { type: 'italic', command: (chain) => chain.setItalic() }, + ol: { type: 'orderedList', command: (chain) => chain.toggleOrderedList() }, + strong: { type: 'bold', command: (chain) => chain.setBold() }, + s: { type: 'strike', command: (chain) => chain.setStrike() }, + span: { type: 'span', command: (chain) => chain.toggleMark('span') }, + u: { type: 'underline', command: (chain) => chain.setUnderline() }, + ul: { type: 'bulletList', command: (chain) => chain.toggleBulletList() }, + }; + + override execute(editor?: Editor, item?: MetaTiptapToolbarStyleMenuItem) { + if (!editor || !item?.data) return; + const { tag, id, class: className } = item.data; + const focus = editor.chain().focus(); + const ext = tag ? this.#commands[tag] : null; + (ext?.command?.(focus) ?? focus).setId(id, ext?.type).setClassName(className, ext?.type).run(); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/tiptap/components/toolbar/tiptap-toolbar-color-picker-button.element.ts b/src/Umbraco.Web.UI.Client/src/packages/tiptap/components/toolbar/tiptap-toolbar-color-picker-button.element.ts index ff19362aec..07b173accc 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/tiptap/components/toolbar/tiptap-toolbar-color-picker-button.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/tiptap/components/toolbar/tiptap-toolbar-color-picker-button.element.ts @@ -38,7 +38,7 @@ export class UmbTiptapToolbarColorPickerButtonElement extends UmbTiptapToolbarBu - + diff --git a/src/Umbraco.Web.UI.Client/src/packages/tiptap/components/toolbar/tiptap-toolbar-menu.element.ts b/src/Umbraco.Web.UI.Client/src/packages/tiptap/components/toolbar/tiptap-toolbar-menu.element.ts index 9576445ecf..7f7726eb10 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/tiptap/components/toolbar/tiptap-toolbar-menu.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/tiptap/components/toolbar/tiptap-toolbar-menu.element.ts @@ -49,8 +49,9 @@ export class UmbTiptapToolbarMenuElement extends UmbLitElement { } async #setMenu() { - if (!this.#manifest?.meta.items) return; - this.#menu = await this.#getMenuItems(this.#manifest.meta.items); + const items = this.#manifest?.items ?? this.#manifest?.meta.items; + if (!items) return; + this.#menu = await this.#getMenuItems(items); } async #getMenuItems(items: Array): Promise> { @@ -92,10 +93,10 @@ export class UmbTiptapToolbarMenuElement extends UmbLitElement { } return { - icon: item.icon, + icon: item.appearance?.icon ?? item.icon, items, label: item.label, - style: item.style, + style: item.appearance?.style ?? item.style, separatorAfter: item.separatorAfter, element, execute: () => this.api?.execute(this.editor, item), diff --git a/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/manifests.ts index cb3b5c79ea..06305ea6bd 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/manifests.ts @@ -33,6 +33,16 @@ const kinds: Array = [ element: () => import('../components/toolbar/tiptap-toolbar-menu.element.js'), }, }, + { + type: 'kind', + alias: 'Umb.Kind.TiptapToolbar.StyleMenu', + matchKind: 'styleMenu', + matchType: 'tiptapToolbarExtension', + manifest: { + api: () => import('../components/toolbar/style-menu.tiptap-toolbar-api.js'), + element: () => import('../components/toolbar/tiptap-toolbar-menu.element.js'), + }, + }, ]; const coreExtensions: Array = [ @@ -581,17 +591,17 @@ const toolbarExtensions: Array = [ alias: 'Umb.Tiptap.Toolbar.FontFamily', name: 'Font Family Tiptap Extension', api: () => import('./toolbar/font-family.tiptap-toolbar-api.js'), + items: [ + { label: 'Sans serif', appearance: { style: 'font-family: sans-serif;' }, data: 'sans-serif' }, + { label: 'Serif', appearance: { style: 'font-family: serif;' }, data: 'serif' }, + { label: 'Monospace', appearance: { style: 'font-family: monospace;' }, data: 'monospace' }, + { label: 'Cursive', appearance: { style: 'font-family: cursive;' }, data: 'cursive' }, + { label: 'Fantasy', appearance: { style: 'font-family: fantasy;' }, data: 'fantasy' }, + ], meta: { alias: 'umbFontFamily', icon: 'icon-ruler-alt', label: 'Font family', - items: [ - { label: 'Sans serif', style: 'font-family: sans-serif;', data: 'sans-serif' }, - { label: 'Serif', style: 'font-family: serif;', data: 'serif' }, - { label: 'Monospace', style: 'font-family: monospace;', data: 'monospace' }, - { label: 'Cursive', style: 'font-family: cursive;', data: 'cursive' }, - { label: 'Fantasy', style: 'font-family: fantasy;', data: 'fantasy' }, - ], }, }, { @@ -600,21 +610,21 @@ const toolbarExtensions: Array = [ alias: 'Umb.Tiptap.Toolbar.FontSize', name: 'Font Size Tiptap Extension', api: () => import('./toolbar/font-size.tiptap-toolbar-api.js'), + items: [ + { label: '8pt', data: '8pt;' }, + { label: '10pt', data: '10pt;' }, + { label: '12pt', data: '12pt;' }, + { label: '14pt', data: '14pt;' }, + { label: '16pt', data: '16pt;' }, + { label: '18pt', data: '18pt;' }, + { label: '24pt', data: '24pt;' }, + { label: '26pt', data: '26pt;' }, + { label: '48pt', data: '48pt;' }, + ], meta: { alias: 'umbFontSize', icon: 'icon-ruler', label: 'Font size', - items: [ - { label: '8pt', data: '8pt;' }, - { label: '10pt', data: '10pt;' }, - { label: '12pt', data: '12pt;' }, - { label: '14pt', data: '14pt;' }, - { label: '16pt', data: '16pt;' }, - { label: '18pt', data: '18pt;' }, - { label: '24pt', data: '24pt;' }, - { label: '26pt', data: '26pt;' }, - { label: '48pt', data: '48pt;' }, - ], }, }, { diff --git a/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/style-select/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/style-select/manifests.ts index 915c7c939e..60c0894e84 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/style-select/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/style-select/manifests.ts @@ -1,35 +1,54 @@ export const manifests: Array = [ { type: 'tiptapToolbarExtension', - kind: 'menu', + kind: 'styleMenu', alias: 'Umb.Tiptap.Toolbar.StyleSelect', name: 'Style Select Tiptap Extension', - api: () => import('./style-select.tiptap-toolbar-api.js'), + items: [ + { + label: 'Headers', + items: [ + { + label: 'Page header', + appearance: { icon: 'icon-heading-2', style: 'font-size: x-large;font-weight: bold;' }, + data: { tag: 'h2' }, + }, + { + label: 'Section header', + appearance: { icon: 'icon-heading-3', style: 'font-size: large;font-weight: bold;' }, + data: { tag: 'h3' }, + }, + { + label: 'Paragraph header', + appearance: { icon: 'icon-heading-4', style: 'font-weight: bold;' }, + data: { tag: 'h4' }, + }, + ], + }, + { + label: 'Blocks', + items: [{ label: 'Paragraph', appearance: { icon: 'icon-paragraph' }, data: { tag: 'p' } }], + }, + { + label: 'Containers', + items: [ + { + label: 'Block quote', + appearance: { icon: 'icon-blockquote', style: 'font-style: italic;' }, + data: { tag: 'blockquote' }, + }, + { + label: 'Code block', + appearance: { icon: 'icon-code', style: 'font-family: monospace;' }, + data: { tag: 'codeBlock' }, + }, + ], + }, + ], meta: { alias: 'umbStyleSelect', icon: 'icon-palette', label: 'Style Select', - items: [ - { - label: 'Headers', - items: [ - { label: 'Page header', data: 'h2', style: 'font-size: x-large;font-weight: bold;' }, - { label: 'Section header', data: 'h3', style: 'font-size: large;font-weight: bold;' }, - { label: 'Paragraph header', data: 'h4', style: 'font-weight: bold;' }, - ], - }, - { - label: 'Blocks', - items: [{ label: 'Paragraph', data: 'p' }], - }, - { - label: 'Containers', - items: [ - { label: 'Quote', data: 'blockquote', style: 'font-style: italic;' }, - { label: 'Code', data: 'codeBlock', style: 'font-family: monospace;' }, - ], - }, - ], }, }, ]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/style-select/style-select.tiptap-toolbar-api.ts b/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/style-select/style-select.tiptap-toolbar-api.ts index 3c65eed2f8..d67746a412 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/style-select/style-select.tiptap-toolbar-api.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/style-select/style-select.tiptap-toolbar-api.ts @@ -1,20 +1,4 @@ -import { UmbTiptapToolbarElementApiBase } from '../base.js'; -import type { MetaTiptapToolbarMenuItem } from '../types.js'; -import type { Editor } from '@umbraco-cms/backoffice/external/tiptap'; +import UmbTiptapToolbarStyleMenuApi from '../../components/toolbar/style-menu.tiptap-toolbar-api.js'; -export default class UmbTiptapToolbarStyleSelectExtensionApi extends UmbTiptapToolbarElementApiBase { - #commands: Record void> = { - h2: (editor) => editor?.chain().focus().toggleHeading({ level: 2 }).run(), - h3: (editor) => editor?.chain().focus().toggleHeading({ level: 3 }).run(), - h4: (editor) => editor?.chain().focus().toggleHeading({ level: 4 }).run(), - p: (editor) => editor?.chain().focus().setParagraph().run(), - blockquote: (editor) => editor?.chain().focus().toggleBlockquote().run(), - codeBlock: (editor) => editor?.chain().focus().toggleCodeBlock().run(), - }; - - override execute(editor?: Editor, item?: MetaTiptapToolbarMenuItem) { - if (!item?.data) return; - const key = item.data.toString(); - this.#commands[key](editor); - } -} +/** @deprecated No longer used internally. This class will be removed in Umbraco 17. [LK] */ +export default class UmbTiptapToolbarStyleSelectExtensionApi extends UmbTiptapToolbarStyleMenuApi {} diff --git a/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/tiptap-toolbar.extension.ts b/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/tiptap-toolbar.extension.ts index 35432bca51..9370648134 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/tiptap-toolbar.extension.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/tiptap-toolbar.extension.ts @@ -30,27 +30,40 @@ export interface ManifestTiptapToolbarExtensionColorPickerButtonKind< kind: 'colorPickerButton'; } -export interface MetaTiptapToolbarMenuItem { - data?: unknown; +export interface MetaTiptapToolbarMenuItem { + appearance?: { icon?: string; style?: string }; + data?: ItemDataType; element?: ElementLoaderProperty; elementName?: string; + /** @deprecated No longer used, please use `appearance: { icon }`. This will be removed in Umbraco 17. [LK] */ icon?: string; - items?: Array; + items?: Array>; label: string; separatorAfter?: boolean; + /** @deprecated No longer used, please use `appearance: { style }`. This will be removed in Umbraco 17. [LK] */ style?: string; } export interface MetaTiptapToolbarMenuExtension extends MetaTiptapToolbarExtension { look?: 'icon' | 'text'; - items: Array; + /** @deprecated No longer used, please use `items` at the root manifest. This will be removed in Umbraco 17. [LK] */ + items?: Array; } -export interface ManifestTiptapToolbarExtensionMenuKind< - MetaType extends MetaTiptapToolbarMenuExtension = MetaTiptapToolbarMenuExtension, -> extends ManifestTiptapToolbarExtension { +export interface ManifestTiptapToolbarExtensionMenuKind + extends ManifestTiptapToolbarExtension { type: 'tiptapToolbarExtension'; kind: 'menu'; + items?: Array; +} + +export type MetaTiptapToolbarStyleMenuItem = MetaTiptapToolbarMenuItem<{ tag?: string; class?: string; id?: string }>; + +export interface ManifestTiptapToolbarExtensionStyleMenuKind + extends ManifestTiptapToolbarExtension { + type: 'tiptapToolbarExtension'; + kind: 'styleMenu'; + items: Array; } declare global { @@ -59,6 +72,7 @@ declare global { | ManifestTiptapToolbarExtension | ManifestTiptapToolbarExtensionButtonKind | ManifestTiptapToolbarExtensionColorPickerButtonKind - | ManifestTiptapToolbarExtensionMenuKind; + | ManifestTiptapToolbarExtensionMenuKind + | ManifestTiptapToolbarExtensionStyleMenuKind; } }