diff --git a/src/Umbraco.Web.UI.Client/src/mocks/handlers/rte-embed.handlers.ts b/src/Umbraco.Web.UI.Client/src/mocks/handlers/rte-embed.handlers.ts
index 16719a60b6..671bb2af10 100644
--- a/src/Umbraco.Web.UI.Client/src/mocks/handlers/rte-embed.handlers.ts
+++ b/src/Umbraco.Web.UI.Client/src/mocks/handlers/rte-embed.handlers.ts
@@ -1,22 +1,17 @@
const { rest } = window.MockServiceWorker;
-import type { OEmbedResult} from '@umbraco-cms/backoffice/modal';
-import { OEmbedStatus } from '@umbraco-cms/backoffice/modal';
+import type { OEmbedResponseModel } from '@umbraco-cms/backoffice/external/backend-api';
import { umbracoPath } from '@umbraco-cms/backoffice/utils';
export const handlers = [
- rest.get(umbracoPath('/rteembed'), (req, res, ctx) => {
- const widthParam = req.url.searchParams.get('width');
+ rest.get(umbracoPath('/oembed/query'), (req, res, ctx) => {
+ const widthParam = req.url.searchParams.get('maxWidth');
const width = widthParam ? parseInt(widthParam) : 360;
- const heightParam = req.url.searchParams.get('height');
+ const heightParam = req.url.searchParams.get('maxHeight');
const height = heightParam ? parseInt(heightParam) : 240;
- const response: OEmbedResult = {
- supportsDimensions: true,
+ const response: OEmbedResponseModel = {
markup: ``,
- oEmbedStatus: OEmbedStatus.Success,
- width,
- height,
};
return res(ctx.status(200), ctx.json(response));
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/content-type/workspace/views/design/content-type-design-editor.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/content-type/workspace/views/design/content-type-design-editor.element.ts
index bd97af52bb..f42f8a68f8 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/core/content-type/workspace/views/design/content-type-design-editor.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/content-type/workspace/views/design/content-type-design-editor.element.ts
@@ -31,7 +31,7 @@ export class UmbContentTypeDesignEditorElement extends UmbLitElement implements
identifier: 'content-type-tabs-sorter',
itemSelector: 'uui-tab',
containerSelector: 'uui-tab-group',
- disabledItemSelector: '#root-tab',
+ disabledItemSelector: ':not([sortable])',
resolvePlacement: (args) => args.relatedRect.left + args.relatedRect.width * 0.5 > args.pointerX,
onChange: ({ model }) => {
this._tabs = model;
@@ -47,30 +47,30 @@ export class UmbContentTypeDesignEditorElement extends UmbLitElement implements
// Doesn't exist in model
if (newIndex === -1) return;
- // First in list
- if (newIndex === 0 && model.length > 1) {
- this.#tabsStructureHelper.partialUpdateContainer(item.id, { sortOrder: model[1].sortOrder - 1 });
- return;
+ // As origin we set prev sort order to -1, so if no other then our item will become 0
+ let prevSortOrder = -1;
+
+ // If not first in list, then get the sortOrder of the item before. [NL]
+ if (newIndex > 0 && model.length > 0) {
+ prevSortOrder = model[newIndex - 1].sortOrder;
}
- // Not first in list
- if (newIndex > 0 && model.length > 1) {
- const prevItemSortOrder = model[newIndex - 1].sortOrder;
+ // increase the prevSortOrder and use it for the moved item,
+ this.#tabsStructureHelper.partialUpdateContainer(item.id, {
+ sortOrder: ++prevSortOrder,
+ });
- let weight = 1;
- this.#tabsStructureHelper.partialUpdateContainer(item.id, { sortOrder: prevItemSortOrder + weight });
-
- // Check for overlaps
- // TODO: Make sure this take inheritance into considerations.
- model.some((entry, index) => {
- if (index <= newIndex) return;
- if (entry.sortOrder === prevItemSortOrder + weight) {
- weight++;
- this.#tabsStructureHelper.partialUpdateContainer(entry.id, { sortOrder: prevItemSortOrder + weight });
- }
- // Break the loop
- return true;
+ // Adjust everyone right after, until there is a gap between the sortOrders: [NL]
+ let i = newIndex + 1;
+ let entry: UmbPropertyTypeContainerModel | undefined;
+ // As long as there is an item with the index & the sortOrder is less or equal to the prevSortOrder, we will update the sortOrder:
+ while ((entry = model[i]) !== undefined && entry.sortOrder <= prevSortOrder) {
+ // Increase the prevSortOrder and use it for the item:
+ this.#tabsStructureHelper.partialUpdateContainer(entry.id, {
+ sortOrder: ++prevSortOrder,
});
+
+ i++;
}
},
});
@@ -399,7 +399,7 @@ export class UmbContentTypeDesignEditorElement extends UmbLitElement implements
? this.localize.term('general_reorderDone')
: this.localize.term('general_reorder');
- return html`
+ return html`
${this._compositionRepositoryAlias
? html`
+ data-umb-tab-id=${ifDefined(tab.id)}
+ ?sortable=${ownedTab}>
${this.renderTabInner(tab, tabActive, ownedTab)}
`;
}
@@ -581,6 +582,7 @@ export class UmbContentTypeDesignEditorElement extends UmbLitElement implements
position: relative;
border-left: 1px hidden transparent;
border-right: 1px solid var(--uui-color-border);
+ background-color: var(--uui-color-surface);
}
.not-active uui-button {
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/embedded-media/embedded-media-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/embedded-media/embedded-media-modal.element.ts
index a0177a7f7a..43f43d1823 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/embedded-media/embedded-media-modal.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/embedded-media/embedded-media-modal.element.ts
@@ -1,235 +1,146 @@
-import { css, html, unsafeHTML, when, customElement, property, state } from '@umbraco-cms/backoffice/external/lit';
+import { UmbOEmbedRepository } from './repository/oembed.repository.js';
+import { css, html, unsafeHTML, when, customElement, state } from '@umbraco-cms/backoffice/external/lit';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
-import type {
- OEmbedResult,
- UmbEmbeddedMediaModalData,
- UmbEmbeddedMediaModalValue} from '@umbraco-cms/backoffice/modal';
-import {
- OEmbedStatus,
- UmbModalBaseElement,
-} from '@umbraco-cms/backoffice/modal';
-import { umbracoPath } from '@umbraco-cms/backoffice/utils';
-
-interface UmbEmbeddedMediaModalModel {
- url?: string;
- info?: string;
- a11yInfo?: string;
- originalWidth: number;
- originalHeight: number;
- width: number;
- height: number;
- constrain: boolean;
-}
+import type { UmbEmbeddedMediaModalData, UmbEmbeddedMediaModalValue } from '@umbraco-cms/backoffice/modal';
+import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
+import type { UUIButtonState, UUIInputEvent } from '@umbraco-cms/backoffice/external/uui';
@customElement('umb-embedded-media-modal')
export class UmbEmbeddedMediaModalElement extends UmbModalBaseElement<
UmbEmbeddedMediaModalData,
UmbEmbeddedMediaModalValue
> {
- #loading = false;
- #embedResult!: OEmbedResult;
-
- #handleConfirm() {
- this.value = {
- preview: this.#embedResult.markup,
- originalWidth: this._model.width,
- originalHeight: this._model.originalHeight,
- width: this.#embedResult.width,
- height: this.#embedResult.height,
- };
- this.modalContext?.submit();
- }
-
- #handleCancel() {
- this.modalContext?.reject();
- }
+ #oEmbedRepository = new UmbOEmbedRepository(this);
+ #validUrl?: string;
@state()
- private _model: UmbEmbeddedMediaModalModel = {
- url: '',
- width: 360,
- height: 240,
- constrain: true,
- info: '',
- a11yInfo: '',
- originalHeight: 240,
- originalWidth: 360,
- };
+ private _loading?: UUIButtonState;
+
+ @state()
+ private _width = 360;
+
+ @state()
+ private _height = 240;
+
+ @state()
+ private _url = '';
connectedCallback() {
super.connectedCallback();
+ if (this.data?.width) this._width = this.data.width;
+ if (this.data?.height) this._height = this.data.height;
+ if (this.data?.constrain) this.value = { ...this.value, constrain: this.data.constrain };
+
if (this.data?.url) {
- Object.assign(this._model, this.data);
+ this._url = this.data.url;
this.#getPreview();
}
}
async #getPreview() {
- this._model.info = '';
- this._model.a11yInfo = '';
+ this._loading = 'waiting';
- this.#loading = true;
- this.requestUpdate('_model');
+ const { data } = await this.#oEmbedRepository.requestOEmbed({
+ url: this._url,
+ maxWidth: this._width,
+ maxHeight: this._height,
+ });
- try {
- // TODO => use backend cli when available
- const result = await fetch(
- umbracoPath('/rteembed?') +
- new URLSearchParams({
- url: this._model.url,
- width: this._model.width?.toString(),
- height: this._model.height?.toString(),
- } as { [key: string]: string }),
- );
-
- this.#embedResult = await result.json();
-
- switch (this.#embedResult.oEmbedStatus) {
- case 0:
- this.#onPreviewFailed('Not supported');
- break;
- case 1:
- this.#onPreviewFailed('Could not embed media - please ensure the URL is valid');
- break;
- case 2:
- this._model.info = '';
- this._model.a11yInfo = 'Retrieved URL';
- break;
- }
- } catch (e) {
- this.#onPreviewFailed('Could not embed media - please ensure the URL is valid');
+ if (data) {
+ this.#validUrl = this._url;
+ this.value = { ...this.value, markup: data.markup, url: this.#validUrl };
+ this._loading = 'success';
+ } else {
+ this.#validUrl = undefined;
+ this._loading = 'failed';
}
-
- this.#loading = false;
- this.requestUpdate('_model');
}
- #onPreviewFailed(message: string) {
- this._model.info = message;
- this._model.a11yInfo = message;
+ #onUrlChange(e: UUIInputEvent) {
+ this._url = e.target.value as string;
}
- #onUrlChange(e: InputEvent) {
- this._model.url = (e.target as HTMLInputElement).value;
- this.requestUpdate('_model');
+ #onWidthChange(e: UUIInputEvent) {
+ this._width = parseInt(e.target.value as string, 10);
+ this.#getPreview();
}
- #onWidthChange(e: InputEvent) {
- this._model.width = parseInt((e.target as HTMLInputElement).value, 10);
- this.#changeSize('width');
- }
-
- #onHeightChange(e: InputEvent) {
- this._model.height = parseInt((e.target as HTMLInputElement).value, 10);
- this.#changeSize('height');
- }
-
- /**
- * Calculates the width or height axis dimension when the other is changed.
- * If constrain is false, axis change independently
- * @param axis {string}
- */
- #changeSize(axis: 'width' | 'height') {
- const resize = this._model.originalWidth !== this._model.width || this._model.originalHeight !== this._model.height;
-
- if (this._model.constrain) {
- if (axis === 'width') {
- this._model.height = Math.round((this._model.width / this._model.originalWidth) * this._model.height);
- } else {
- this._model.width = Math.round((this._model.height / this._model.originalHeight) * this._model.width);
- }
- }
-
- this._model.originalWidth = this._model.width;
- this._model.originalHeight = this._model.height;
-
- if (this._model.url !== '' && resize) {
- this.#getPreview();
- }
+ #onHeightChange(e: UUIInputEvent) {
+ this._height = parseInt(e.target.value as string, 10);
+ this.#getPreview();
}
#onConstrainChange() {
- this._model.constrain = !this._model.constrain;
- }
-
- /**
- * If the embed does not support dimensions, or was not requested successfully
- * the width, height and constrain controls are disabled
- * @returns {boolean}
- */
- #dimensionControlsDisabled() {
- return !this.#embedResult?.supportsDimensions || this.#embedResult?.oEmbedStatus !== OEmbedStatus.Success;
+ const constrain = !this.value?.constrain;
+ this.value = { ...this.value, constrain };
}
render() {
return html`
-
+
-
+
+ label=${this.localize.term('general_retrieve')}>
${when(
- this.#embedResult?.oEmbedStatus === OEmbedStatus.Success || this._model.a11yInfo,
+ this.#validUrl !== undefined,
() =>
- html`
+ html`
- ${when(this.#loading, () => html`
`)}
- ${when(this.#embedResult?.markup, () => html`${unsafeHTML(this.#embedResult.markup)}`)}
- ${when(this._model.info, () => html`
${this._model.info}
`)}
- ${when(
- this._model.a11yInfo,
- () => html`
${this._model.a11yInfo}
`,
- )}
+ ${when(this._loading === 'waiting', () => html`
`)}
+ ${when(this.value?.markup, () => html`${unsafeHTML(this.value.markup)}`)}
`,
)}
-
+
+ @change=${this.#onWidthChange}
+ ?disabled=${this.#validUrl ? false : true}>
-
+
+ @change=${this.#onHeightChange}
+ ?disabled=${this.#validUrl ? false : true}>
-
+
+ .checked=${this.value?.constrain ?? false}>
- Cancel
+ this.modalContext?.reject()}>
+ label=${this.localize.term('buttons_confirmActionConfirm')}
+ @click=${() => this.modalContext?.submit()}>
`;
}
@@ -237,27 +148,11 @@ export class UmbEmbeddedMediaModalElement extends UmbModalBaseElement<
static styles = [
UmbTextStyles,
css`
- h3 {
- margin-left: var(--uui-size-space-5);
- margin-right: var(--uui-size-space-5);
- }
-
uui-input {
width: 100%;
--uui-button-border-radius: 0;
}
- .sr-only {
- clip: rect(0, 0, 0, 0);
- border: 0;
- height: 1px;
- margin: -1px;
- overflow: hidden;
- padding: 0;
- position: absolute;
- width: 1px;
- }
-
umb-property-layout:first-child {
padding-top: 0;
}
@@ -265,10 +160,6 @@ export class UmbEmbeddedMediaModalElement extends UmbModalBaseElement<
umb-property-layout:last-child {
padding-bottom: 0;
}
-
- p {
- margin-bottom: 0;
- }
`,
];
}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/embedded-media/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/embedded-media/index.ts
new file mode 100644
index 0000000000..3d76f338dd
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/embedded-media/index.ts
@@ -0,0 +1 @@
+export * from './repository/index.js';
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/embedded-media/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/embedded-media/manifests.ts
new file mode 100644
index 0000000000..9cf9968724
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/embedded-media/manifests.ts
@@ -0,0 +1,13 @@
+import { manifests as repositories } from './repository/manifests.js';
+import type { ManifestModal } from '@umbraco-cms/backoffice/extension-registry';
+
+const modals: Array
= [
+ {
+ type: 'modal',
+ alias: 'Umb.Modal.EmbeddedMedia',
+ name: 'Embedded Media Modal',
+ element: () => import('./embedded-media-modal.element.js'),
+ },
+];
+
+export const manifests = [...modals, ...repositories];
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/embedded-media/repository/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/embedded-media/repository/index.ts
new file mode 100644
index 0000000000..1a6e303708
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/embedded-media/repository/index.ts
@@ -0,0 +1,2 @@
+export { UmbOEmbedRepository } from './oembed.repository.js';
+export { UMB_OEMBED_REPOSITORY_ALIAS } from './manifests.js';
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/embedded-media/repository/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/embedded-media/repository/manifests.ts
new file mode 100644
index 0000000000..580f3e1026
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/embedded-media/repository/manifests.ts
@@ -0,0 +1,13 @@
+import { UmbOEmbedRepository } from './oembed.repository.js';
+import type { ManifestRepository, ManifestTypes } from '@umbraco-cms/backoffice/extension-registry';
+
+export const UMB_OEMBED_REPOSITORY_ALIAS = 'Umb.Repository.OEmbed';
+
+const repository: ManifestRepository = {
+ type: 'repository',
+ alias: UMB_OEMBED_REPOSITORY_ALIAS,
+ name: 'OEmbed Repository',
+ api: UmbOEmbedRepository,
+};
+
+export const manifests: Array = [repository];
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/embedded-media/repository/oembed.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/embedded-media/repository/oembed.repository.ts
new file mode 100644
index 0000000000..344c067453
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/embedded-media/repository/oembed.repository.ts
@@ -0,0 +1,20 @@
+import { UmbOEmbedServerDataSource } from './oembed.server.data.js';
+import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
+import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
+import type { UmbApi } from '@umbraco-cms/backoffice/extension-api';
+
+export class UmbOEmbedRepository extends UmbControllerBase implements UmbApi {
+ #dataSource = new UmbOEmbedServerDataSource(this);
+
+ constructor(host: UmbControllerHost) {
+ super(host);
+ }
+
+ async requestOEmbed({ url, maxWidth, maxHeight }: { url?: string; maxWidth?: number; maxHeight?: number }) {
+ const { data, error } = await this.#dataSource.getOEmbedQuery({ url, maxWidth, maxHeight });
+ if (!error) {
+ return { data };
+ }
+ return { error };
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/embedded-media/repository/oembed.server.data.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/embedded-media/repository/oembed.server.data.ts
new file mode 100644
index 0000000000..88c45e3eb4
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/embedded-media/repository/oembed.server.data.ts
@@ -0,0 +1,31 @@
+import { OEmbedService } from '@umbraco-cms/backoffice/external/backend-api';
+import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
+import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
+
+/**
+ * A data source for the OEmbed that fetches data from a given URL.
+ * @export
+ * @class UmbOEmbedServerDataSource
+ * @implements {RepositoryDetailDataSource}
+ */
+export class UmbOEmbedServerDataSource {
+ #host: UmbControllerHost;
+
+ /**
+ * Creates an instance of UmbOEmbedServerDataSource.
+ * @param {UmbControllerHost} host
+ * @memberof UmbOEmbedServerDataSource
+ */
+ constructor(host: UmbControllerHost) {
+ this.#host = host;
+ }
+
+ /**
+ * Fetches markup for the given URL.
+ * @param {string} unique
+ * @memberof UmbOEmbedServerDataSource
+ */
+ async getOEmbedQuery({ url, maxWidth, maxHeight }: { url?: string; maxWidth?: number; maxHeight?: number }) {
+ return tryExecuteAndNotify(this.#host, OEmbedService.getOembedQuery({ url, maxWidth, maxHeight }));
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/index.ts
new file mode 100644
index 0000000000..5a1c0033a6
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/index.ts
@@ -0,0 +1 @@
+export * from './embedded-media/index.js';
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/token/embedded-media-modal.token.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/token/embedded-media-modal.token.ts
index 7eca2cf44c..0fb7df92ca 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/token/embedded-media-modal.token.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/token/embedded-media-modal.token.ts
@@ -1,31 +1,18 @@
import { UmbModalToken } from './modal-token.js';
-export enum OEmbedStatus {
- NotSupported,
- Error,
- Success,
-}
-
-export interface UmbEmbeddedMediaDimensions {
- width: number;
- height: number;
- constrain?: boolean;
-}
-
-export interface UmbEmbeddedMediaModalData extends UmbEmbeddedMediaDimensions {
+export interface UmbEmbeddedMediaModalData extends Partial {
url?: string;
}
-export interface OEmbedResult extends UmbEmbeddedMediaDimensions {
- oEmbedStatus: OEmbedStatus;
- supportsDimensions: boolean;
- markup?: string;
+export interface UmbEmbeddedMediaDimensionsModel {
+ constrain: boolean;
+ width: number;
+ height: number;
}
export interface UmbEmbeddedMediaModalValue extends UmbEmbeddedMediaModalData {
- preview?: string;
- originalWidth: number;
- originalHeight: number;
+ markup: string;
+ url: string;
}
export const UMB_EMBEDDED_MEDIA_MODAL = new UmbModalToken(
diff --git a/src/Umbraco.Web.UI.Client/src/packages/tiny-mce/plugins/tiny-mce-embeddedmedia.plugin.ts b/src/Umbraco.Web.UI.Client/src/packages/tiny-mce/plugins/tiny-mce-embeddedmedia.plugin.ts
index 7d389d2281..1cadeaa0fe 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/tiny-mce/plugins/tiny-mce-embeddedmedia.plugin.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/tiny-mce/plugins/tiny-mce-embeddedmedia.plugin.ts
@@ -6,10 +6,22 @@ export default class UmbTinyMceEmbeddedMediaPlugin extends UmbTinyMcePluginBase
constructor(args: TinyMcePluginArguments) {
super(args);
- this.editor.ui.registry.addButton('umbembeddialog', {
+ this.editor.ui.registry.addToggleButton('umbembeddialog', {
icon: 'embed',
tooltip: 'Embed',
onAction: () => this.#onAction(),
+ onSetup: (api) => {
+ const editor = this.editor;
+ const onNodeChange = () => {
+ const selectedElm = editor.selection.getNode();
+ api.setActive(
+ selectedElm.nodeName.toUpperCase() === 'DIV' && selectedElm.classList.contains('umb-embed-holder'),
+ );
+ };
+
+ editor.on('NodeChange', onNodeChange);
+ return () => editor.off('NodeChange', onNodeChange);
+ },
});
}
@@ -44,17 +56,18 @@ export default class UmbTinyMceEmbeddedMediaPlugin extends UmbTinyMcePluginBase
#insertInEditor(embed: UmbEmbeddedMediaModalValue, activeElement: HTMLElement) {
// Wrap HTML preview content here in a DIV with non-editable class of .mceNonEditable
// This turns it into a selectable/cutable block to move about
+
const wrapper = this.editor.dom.create(
'div',
{
class: 'mceNonEditable umb-embed-holder',
'data-embed-url': embed.url ?? '',
- 'data-embed-height': embed.height,
- 'data-embed-width': embed.width,
+ 'data-embed-height': embed.height!,
+ 'data-embed-width': embed.width!,
'data-embed-constrain': embed.constrain ?? false,
contenteditable: false,
},
- embed.preview,
+ embed.markup,
);
// Only replace if activeElement is an Embed element.