Introduces getStyles() for Tiptap extensions (#18075)
This commit is contained in:
@@ -1,12 +1,14 @@
|
||||
import type { UmbTiptapExtensionApi } from '../../extensions/types.js';
|
||||
import type { UmbTiptapToolbarValue } from '../types.js';
|
||||
import { css, customElement, html, property, state, when } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { css, customElement, html, property, state, unsafeCSS, when } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { loadManifestApi } from '@umbraco-cms/backoffice/extension-api';
|
||||
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import { Editor } from '@umbraco-cms/backoffice/external/tiptap';
|
||||
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
|
||||
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
|
||||
import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation';
|
||||
import type { CSSResultGroup } from '@umbraco-cms/backoffice/external/lit';
|
||||
import type { Extensions } from '@umbraco-cms/backoffice/external/tiptap';
|
||||
import type { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor';
|
||||
|
||||
import './tiptap-hover-menu.element.js';
|
||||
@@ -45,6 +47,9 @@ export class UmbInputTiptapElement extends UmbFormControlMixin<string, typeof Um
|
||||
@state()
|
||||
private readonly _extensions: Array<UmbTiptapExtensionApi> = [];
|
||||
|
||||
@state()
|
||||
private _styles: Array<CSSResultGroup> = [];
|
||||
|
||||
@state()
|
||||
_toolbar: UmbTiptapToolbarValue = [[[]]];
|
||||
|
||||
@@ -100,14 +105,24 @@ export class UmbInputTiptapElement extends UmbFormControlMixin<string, typeof Um
|
||||
|
||||
this._toolbar = this.configuration?.getValueByAlias<UmbTiptapToolbarValue>('toolbar') ?? [[[]]];
|
||||
|
||||
const extensions = this._extensions
|
||||
.map((ext) => ext.getTiptapExtensions({ configuration: this.configuration }))
|
||||
.flat();
|
||||
const tiptapExtensions: Extensions = [];
|
||||
|
||||
this._extensions.forEach((ext) => {
|
||||
const tiptapExt = ext.getTiptapExtensions({ configuration: this.configuration });
|
||||
if (tiptapExt?.length) {
|
||||
tiptapExtensions.push(...tiptapExt);
|
||||
}
|
||||
|
||||
const styles = ext.getStyles();
|
||||
if (styles) {
|
||||
this._styles.push(styles);
|
||||
}
|
||||
});
|
||||
|
||||
this._editor = new Editor({
|
||||
element: element,
|
||||
editable: !this.readonly,
|
||||
extensions: extensions,
|
||||
extensions: tiptapExtensions,
|
||||
content: this.#value,
|
||||
onBeforeCreate: ({ editor }) => {
|
||||
this._extensions.forEach((ext) => ext.setEditor(editor));
|
||||
@@ -125,6 +140,7 @@ export class UmbInputTiptapElement extends UmbFormControlMixin<string, typeof Um
|
||||
!this._editor && !this._extensions?.length,
|
||||
() => html`<div id="loader"><uui-loader></uui-loader></div>`,
|
||||
() => html`
|
||||
${this.#renderStyles()}
|
||||
<umb-tiptap-toolbar
|
||||
.toolbar=${this._toolbar}
|
||||
.editor=${this._editor}
|
||||
@@ -136,6 +152,15 @@ export class UmbInputTiptapElement extends UmbFormControlMixin<string, typeof Um
|
||||
`;
|
||||
}
|
||||
|
||||
#renderStyles() {
|
||||
if (!this._styles?.length) return;
|
||||
return html`
|
||||
<style>
|
||||
${this._styles.map((style) => unsafeCSS(style))}
|
||||
</style>
|
||||
`;
|
||||
}
|
||||
|
||||
static override readonly styles = [
|
||||
css`
|
||||
:host {
|
||||
@@ -158,23 +183,6 @@ export class UmbInputTiptapElement extends UmbFormControlMixin<string, typeof Um
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.tiptap {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
outline: none;
|
||||
white-space: pre-wrap;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.tiptap .is-editor-empty:first-child::before {
|
||||
color: var(--uui-color-text);
|
||||
opacity: 0.55;
|
||||
content: attr(data-placeholder);
|
||||
float: left;
|
||||
height: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#editor {
|
||||
/* Required as overflow is set to auto, so that the scrollbars don't appear. */
|
||||
display: flex;
|
||||
@@ -189,6 +197,24 @@ export class UmbInputTiptapElement extends UmbFormControlMixin<string, typeof Um
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
.tiptap {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
outline: none;
|
||||
white-space: pre-wrap;
|
||||
min-width: 0;
|
||||
|
||||
.is-editor-empty:first-child::before {
|
||||
color: var(--uui-color-text);
|
||||
opacity: 0.55;
|
||||
content: attr(data-placeholder);
|
||||
float: left;
|
||||
height: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* The following styles are required for the "StarterKit" extension. */
|
||||
pre {
|
||||
background-color: var(--uui-color-surface-alt);
|
||||
padding: var(--uui-size-space-2) var(--uui-size-space-4);
|
||||
@@ -220,118 +246,12 @@ export class UmbInputTiptapElement extends UmbFormControlMixin<string, typeof Um
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
figure {
|
||||
> p,
|
||||
img {
|
||||
pointer-events: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
&.ProseMirror-selectednode {
|
||||
outline: 3px solid var(--uui-color-focus);
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
&.ProseMirror-selectednode {
|
||||
outline: 3px solid var(--uui-color-focus);
|
||||
}
|
||||
}
|
||||
|
||||
li {
|
||||
> p {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.umb-embed-holder {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.umb-embed-holder > * {
|
||||
user-select: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.umb-embed-holder.ProseMirror-selectednode {
|
||||
outline: 2px solid var(--uui-palette-spanish-pink-light);
|
||||
}
|
||||
|
||||
.umb-embed-holder::before {
|
||||
z-index: 1000;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
content: ' ';
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
@@ -6,6 +6,7 @@ import type {
|
||||
UmbTiptapToolbarElementApi,
|
||||
} from './types.js';
|
||||
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
|
||||
import type { CSSResultGroup } from '@umbraco-cms/backoffice/external/lit';
|
||||
import type { Editor, Extension, Mark, Node } from '@umbraco-cms/backoffice/external/tiptap';
|
||||
import type { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor';
|
||||
|
||||
@@ -27,6 +28,13 @@ export abstract class UmbTiptapExtensionApiBase extends UmbControllerBase implem
|
||||
this._editor = editor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getStyles(): CSSResultGroup | null | undefined {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,35 @@
|
||||
import { UmbTiptapExtensionApiBase } from '../base.js';
|
||||
import { css } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { umbEmbeddedMedia } from '@umbraco-cms/backoffice/external/tiptap';
|
||||
|
||||
export default class UmbTiptapEmbeddedMediaExtensionApi extends UmbTiptapExtensionApiBase {
|
||||
getTiptapExtensions = () => [umbEmbeddedMedia.configure({ inline: true })];
|
||||
|
||||
override getStyles = () => css`
|
||||
.umb-embed-holder {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.umb-embed-holder > * {
|
||||
user-select: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.umb-embed-holder.ProseMirror-selectednode {
|
||||
outline: 2px solid var(--uui-palette-spanish-pink-light);
|
||||
}
|
||||
|
||||
.umb-embed-holder::before {
|
||||
z-index: 1000;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
content: ' ';
|
||||
}
|
||||
|
||||
.umb-embed-holder.ProseMirror-selectednode::before {
|
||||
background: rgba(0, 0, 0, 0.025);
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,28 @@
|
||||
import { UmbTiptapExtensionApiBase } from '../base.js';
|
||||
import { css } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbImage } from '@umbraco-cms/backoffice/external/tiptap';
|
||||
|
||||
export default class UmbTiptapImageExtensionApi extends UmbTiptapExtensionApiBase {
|
||||
getTiptapExtensions() {
|
||||
return [UmbImage.configure({ inline: true })];
|
||||
}
|
||||
getTiptapExtensions = () => [UmbImage.configure({ inline: true })];
|
||||
|
||||
override getStyles = () => css`
|
||||
figure {
|
||||
> p,
|
||||
img {
|
||||
pointer-events: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
&.ProseMirror-selectednode {
|
||||
outline: 3px solid var(--uui-color-focus);
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
&.ProseMirror-selectednode {
|
||||
outline: 3px solid var(--uui-color-focus);
|
||||
}
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,69 @@
|
||||
import { UmbTiptapExtensionApiBase } from '../base.js';
|
||||
import { css } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { Table, TableHeader, TableRow, TableCell } from '@umbraco-cms/backoffice/external/tiptap';
|
||||
|
||||
export default class UmbTiptapTableExtensionApi extends UmbTiptapExtensionApiBase {
|
||||
getTiptapExtensions = () => [Table.configure({ resizable: true }), TableHeader, TableRow, TableCell];
|
||||
|
||||
override getStyles = () => css`
|
||||
.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;
|
||||
}
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { ManifestTiptapExtension } from './tiptap.extension.js';
|
||||
import type { ManifestTiptapToolbarExtension } from './tiptap-toolbar.extension.js';
|
||||
import type { CSSResultGroup } from '@umbraco-cms/backoffice/external/lit';
|
||||
import type { Editor, Extension, Mark, Node } from '@umbraco-cms/backoffice/external/tiptap';
|
||||
import type { UmbApi } from '@umbraco-cms/backoffice/extension-api';
|
||||
import type { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor';
|
||||
@@ -18,6 +19,11 @@ export interface UmbTiptapExtensionApi extends UmbApi {
|
||||
*/
|
||||
setEditor(editor: Editor): void;
|
||||
|
||||
/**
|
||||
* Gets the styles for the extension
|
||||
*/
|
||||
getStyles(): CSSResultGroup | null | undefined;
|
||||
|
||||
/**
|
||||
* Gets the Tiptap extensions for the editor.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user