Merge remote-tracking branch 'origin/v15/feature/tiptap' into v15/feature/rte/tiptap/ext/embed

This commit is contained in:
Jacob Overgaard
2024-09-26 14:15:56 +02:00
14 changed files with 318 additions and 22 deletions

View File

@@ -32,6 +32,10 @@
"@tiptap/extension-ordered-list": "^2.7.0",
"@tiptap/extension-paragraph": "^2.7.0",
"@tiptap/extension-strike": "^2.7.0",
"@tiptap/extension-table": "^2.7.3",
"@tiptap/extension-table-cell": "^2.7.3",
"@tiptap/extension-table-header": "^2.7.3",
"@tiptap/extension-table-row": "^2.7.3",
"@tiptap/extension-text": "^2.7.0",
"@tiptap/extension-text-align": "^2.6.6",
"@tiptap/extension-underline": "^2.6.6",
@@ -6731,6 +6735,55 @@
"@tiptap/core": "^2.7.0-pre.0"
}
},
"node_modules/@tiptap/extension-table": {
"version": "2.7.3",
"resolved": "https://registry.npmjs.org/@tiptap/extension-table/-/extension-table-2.7.3.tgz",
"integrity": "sha512-zv1SGgVywTY3vs+9EIMdYS7jZMovlfsraZ3Qdz1YkqN3dNZBUukXrfpZaJqzVwUvRehCVvjA+HG7zH12RU/XYQ==",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/ueberdosis"
},
"peerDependencies": {
"@tiptap/core": "^2.7.0",
"@tiptap/pm": "^2.7.0"
}
},
"node_modules/@tiptap/extension-table-cell": {
"version": "2.7.3",
"resolved": "https://registry.npmjs.org/@tiptap/extension-table-cell/-/extension-table-cell-2.7.3.tgz",
"integrity": "sha512-C6f2dAcatk/XROZ2Q1owv4DBrTyfVzfsK1Jh7rk3mkpEa8oh/lPKR8thYjmaLC/BlPYjtVuIbMIqp9lz6U/Ufw==",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/ueberdosis"
},
"peerDependencies": {
"@tiptap/core": "^2.7.0"
}
},
"node_modules/@tiptap/extension-table-header": {
"version": "2.7.3",
"resolved": "https://registry.npmjs.org/@tiptap/extension-table-header/-/extension-table-header-2.7.3.tgz",
"integrity": "sha512-eL1FVn+GBf0dRYmsE88QeJa3azwVKhyYDAFTmoGIwilHsjbNzb4ptUGi+ko2XpxLHvY+XfGLe3+UEZbQ3FDOIA==",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/ueberdosis"
},
"peerDependencies": {
"@tiptap/core": "^2.7.0"
}
},
"node_modules/@tiptap/extension-table-row": {
"version": "2.7.3",
"resolved": "https://registry.npmjs.org/@tiptap/extension-table-row/-/extension-table-row-2.7.3.tgz",
"integrity": "sha512-gB6gXYVCGWn6IDb/oV3ds1LI0yLLIwymcvcu1MWnT9p8qClZPaId/J6/+mQbSGCEc8G1SzYYUhnu2dsaVIsFsw==",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/ueberdosis"
},
"peerDependencies": {
"@tiptap/core": "^2.7.0"
}
},
"node_modules/@tiptap/extension-text": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-2.7.0.tgz",

View File

@@ -212,6 +212,10 @@
"@tiptap/extension-ordered-list": "^2.7.0",
"@tiptap/extension-paragraph": "^2.7.0",
"@tiptap/extension-strike": "^2.7.0",
"@tiptap/extension-table": "^2.7.3",
"@tiptap/extension-table-cell": "^2.7.3",
"@tiptap/extension-table-header": "^2.7.3",
"@tiptap/extension-table-row": "^2.7.3",
"@tiptap/extension-text": "^2.7.0",
"@tiptap/extension-text-align": "^2.6.6",
"@tiptap/extension-underline": "^2.6.6",

View File

@@ -0,0 +1,40 @@
import { Node } from '@tiptap/core';
export interface FigcaptionOptions {
/**
* HTML attributes to add to the image element.
* @default {}
* @example { class: 'foo' }
*/
HTMLAttributes: Record<string, any>;
}
export const Figcaption = Node.create<FigcaptionOptions>({
name: 'figcaption',
addOptions() {
return {
HTMLAttributes: {},
};
},
group: 'block',
content: 'inline*',
selectable: false,
draggable: false,
parseHTML() {
return [
{
tag: 'figcaption',
},
];
},
renderHTML({ HTMLAttributes }) {
return [this.name, HTMLAttributes, 0];
},
});

View File

@@ -0,0 +1,52 @@
import { mergeAttributes, Node } from '@tiptap/core';
export interface FigureOptions {
/**
* HTML attributes to add to the image element.
* @default {}
* @example { class: 'foo' }
*/
HTMLAttributes: Record<string, any>;
}
export const Figure = Node.create<FigureOptions>({
name: 'figure',
group: 'block',
content: 'block+',
draggable: true,
selectable: true,
isolating: true,
atom: true,
addAttributes() {
return {
figcaption: {
default: '',
},
};
},
addOptions() {
return {
HTMLAttributes: {},
};
},
parseHTML() {
return [
{
tag: 'figure',
getAttrs: (dom) => {
const figcaption = dom.querySelector('figcaption');
return {
figcaption: figcaption?.textContent || '',
};
},
},
];
},
renderHTML({ HTMLAttributes }) {
return [this.name, mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0];
},
});

View File

@@ -1,7 +1,19 @@
import Image from '@tiptap/extension-image';
export interface UmbImageAttributes {
src: string;
alt?: string;
title?: string;
width?: string;
height?: string;
loading?: string;
srcset?: string;
sizes?: string;
'data-tmpimg'?: string;
'data-udi'?: string;
}
export const UmbImage = Image.extend({
name: 'umbImage',
addAttributes() {
return {
...this.parent?.(),
@@ -22,7 +34,6 @@ export const UmbImage = Image.extend({
},
'data-tmpimg': { default: null },
'data-udi': { default: null },
'data-caption': { default: null },
};
},
});
@@ -38,19 +49,7 @@ declare module '@tiptap/core' {
* .commands
* .setImage({ src: 'https://tiptap.dev/logo.png', alt: 'tiptap', title: 'tiptap logo' })
*/
setImage: (options: {
src: string;
alt?: string;
title?: string;
width?: string;
height?: string;
loading?: string;
srcset?: string;
sizes?: string;
'data-tmpimg'?: string;
'data-udi'?: string;
'data-caption'?: string;
}) => ReturnType;
setImage: (options: UmbImageAttributes) => ReturnType;
};
}
}

View File

@@ -1,4 +1,4 @@
// REQUIRED EXTENSIONS START
// REQUIRED EXTENSIONS
export * from '@tiptap/core';
export { Document } from '@tiptap/extension-document';
export { Dropcursor } from '@tiptap/extension-dropcursor';
@@ -7,7 +7,8 @@ export { HardBreak } from '@tiptap/extension-hard-break';
export { History } from '@tiptap/extension-history';
export { Paragraph } from '@tiptap/extension-paragraph';
export { Text } from '@tiptap/extension-text';
// REQUIRED EXTENSIONS END
// OPTIONAL EXTENSIONS
export { Blockquote } from '@tiptap/extension-blockquote';
export { Bold } from '@tiptap/extension-bold';
export { BulletList } from '@tiptap/extension-bullet-list';
@@ -15,14 +16,21 @@ export { Code } from '@tiptap/extension-code';
export { CodeBlock } from '@tiptap/extension-code-block';
export { Heading } from '@tiptap/extension-heading';
export { HorizontalRule } from '@tiptap/extension-horizontal-rule';
export { Image } from '@tiptap/extension-image';
export { Italic } from '@tiptap/extension-italic';
export { Link } from '@tiptap/extension-link';
export { ListItem } from '@tiptap/extension-list-item';
export { OrderedList } from '@tiptap/extension-ordered-list';
export { Strike } from '@tiptap/extension-strike';
export { Table } from '@tiptap/extension-table';
export { TableCell } from '@tiptap/extension-table-cell';
export { TableHeader } from '@tiptap/extension-table-header';
export { TableRow } from '@tiptap/extension-table-row';
export { TextAlign } from '@tiptap/extension-text-align';
export { Underline } from '@tiptap/extension-underline';
export { Image } from '@tiptap/extension-image';
// CUSTOM EXTENSIONS
export * from './extensions/tiptap-umb-embedded-media.extension.js';
export * from './extensions/tiptap-figcaption.extension.js';
export * from './extensions/tiptap-figure.extension.js';
export * from './extensions/tiptap-umb-image.extension.js';

View File

@@ -1982,6 +1982,10 @@
"name": "icon-tab-key",
"file": "arrow-right-to-line.svg"
},
{
"name": "icon-table",
"file": "table.svg"
},
{
"name": "icon-tag",
"file": "tag.svg"

View File

@@ -1867,6 +1867,10 @@ name: "icon-tab-key",
path: () => import("./icons/icon-tab-key.js"),
},{
name: "icon-table",
path: () => import("./icons/icon-table.js"),
},{
name: "icon-tag",
path: () => import("./icons/icon-tag.js"),

View File

@@ -0,0 +1,17 @@
export default `<!-- @license lucide-static v0.446.0 - ISC -->
<svg
class="lucide lucide-table"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.75"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M12 3v18" />
<rect width="18" height="18" x="3" y="3" rx="2" />
<path d="M3 9h18" />
<path d="M3 15h18" />
</svg>
`;

View File

@@ -27,7 +27,7 @@ export class UmbMediaCaptionAltTextModalElement extends UmbModalBaseElement<
const { data } = await this.#mediaDetailRepository.requestByUnique(this.#mediaUnique);
if (!data) return;
this.value = { altText: data.variants[0].name, caption: undefined, url: data.urls[0]?.url ?? '' };
this.value = { ...this.value, altText: this.value.altText ?? data.variants[0].name, url: data.urls[0]?.url ?? '' };
}
override render() {
@@ -46,11 +46,14 @@ export class UmbMediaCaptionAltTextModalElement extends UmbModalBaseElement<
<uui-input
id="caption"
label="caption"
.value=${this.value?.caption ?? ''}
@input=${(e: UUIInputEvent) =>
(this.value = { ...this.value, caption: e.target.value as string })}></uui-input>
<img src=${this.value?.url ?? ''} alt=${this.value?.altText ?? ''} />
${this.value?.caption ?? ''}
<figure id="mainobject">
<img src=${this.value?.url ?? ''} alt=${this.value?.altText ?? ''} />
<figcaption>${this.value?.caption ?? ''}</figcaption>
</figure>
</div>
<div slot="actions">
<uui-button label=${this.localize.term('general_close')} @click=${this._rejectModal}></uui-button>
@@ -64,7 +67,7 @@ export class UmbMediaCaptionAltTextModalElement extends UmbModalBaseElement<
`;
}
static override styles = [
static override readonly styles = [
css`
uui-input {
margin-bottom: var(--uui-size-layout-1);
@@ -74,6 +77,17 @@ export class UmbMediaCaptionAltTextModalElement extends UmbModalBaseElement<
display: flex;
flex-direction: column;
}
#mainobject {
display: flex;
flex-direction: column;
max-width: 100%;
img {
max-width: 100%;
height: auto;
}
}
`,
];
}

View File

@@ -205,6 +205,65 @@ export class UmbInputTiptapElement extends UmbFormControlMixin<string, typeof Um
.umb-embed-holder.ProseMirror-selectednode::before {
background: rgba(0, 0, 0, 0.025);
/* Table-specific styling */
.tableWrapper {
margin: 1.5rem 0;
overflow-x: auto;
table {
border-collapse: collapse;
margin: 0;
overflow: hidden;
table-layout: fixed;
width: 100%;
td,
th {
border: 1px solid var(--uui-color-border);
box-sizing: border-box;
min-width: 1em;
padding: 6px 8px;
position: relative;
vertical-align: top;
> * {
margin-bottom: 0;
}
}
th {
background-color: var(--uui-color-background);
font-weight: bold;
text-align: left;
}
.selectedCell:after {
background: var(--uui-color-surface-emphasis);
content: '';
left: 0;
right: 0;
top: 0;
bottom: 0;
pointer-events: none;
position: absolute;
z-index: 2;
}
.column-resize-handle {
background-color: var(--uui-color-default);
bottom: -2px;
pointer-events: none;
position: absolute;
right: -2px;
top: 0;
width: 3px;
}
}
}
.resize-cursor {
cursor: ew-resize;
cursor: col-resize;
}
}
`,

View File

@@ -0,0 +1,6 @@
import { UmbTiptapExtensionApiBase } from '../types.js';
import { Figure, Figcaption } from '@umbraco-cms/backoffice/external/tiptap';
export default class UmbTiptapFigureExtensionApi extends UmbTiptapExtensionApiBase {
getTiptapExtensions = () => [Figcaption, Figure];
}

View File

@@ -53,6 +53,18 @@ export const manifests: Array<ManifestTiptapExtension | ManifestTiptapExtensionB
label: 'Code Block',
},
},
{
type: 'tiptapExtension',
alias: 'Umb.Tiptap.Figure',
name: 'Figure Tiptap Extension',
api: () => import('./figure.extension.js'),
weight: 955,
meta: {
alias: 'figure',
icon: 'icon-frame',
label: 'Figure',
},
},
{
type: 'tiptapExtension',
kind: 'button',
@@ -153,6 +165,19 @@ export const manifests: Array<ManifestTiptapExtension | ManifestTiptapExtensionB
label: 'Strike',
},
},
{
type: 'tiptapExtension',
kind: 'button',
alias: 'Umb.Tiptap.Table',
name: 'Table Tiptap Extension',
api: () => import('./table.extension.js'),
weight: 909,
meta: {
alias: 'table',
icon: 'icon-table',
label: 'Table',
},
},
{
type: 'tiptapExtension',
kind: 'button',

View File

@@ -0,0 +1,11 @@
import { UmbTiptapToolbarElementApiBase } from '../types.js';
import { Table, TableHeader, TableRow, TableCell } from '@umbraco-cms/backoffice/external/tiptap';
import type { Editor } from '@umbraco-cms/backoffice/external/tiptap';
export default class UmbTiptapTableExtensionApi extends UmbTiptapToolbarElementApiBase {
getTiptapExtensions = () => [Table.configure({ resizable: true }), TableHeader, TableRow, TableCell];
override execute(editor?: Editor) {
editor?.commands.insertTable({ rows: 3, cols: 3, withHeaderRow: true });
}
}