Tiptap extensions field
observes the Block configuration, updates UI accordingly, to enable/disable the Block extension.
This commit is contained in:
committed by
Jacob Overgaard
parent
bd5b898fce
commit
22f8aac99f
@@ -2648,6 +2648,7 @@ export default {
|
||||
extGroup_interactive: 'Interactive elements',
|
||||
extGroup_media: 'Embeds and media',
|
||||
extGroup_structure: 'Content structure',
|
||||
extGroup_unknown: 'Uncategorized',
|
||||
toobar_availableItems: 'Available toolbar items',
|
||||
toobar_availableItemsEmpty: 'There are no toolbar extensions to show',
|
||||
toolbar_designer: 'Toolbar designer',
|
||||
|
||||
@@ -1,4 +1,14 @@
|
||||
import { customElement, css, html, property, state, repeat, when, nothing } from '@umbraco-cms/backoffice/external/lit';
|
||||
import {
|
||||
customElement,
|
||||
css,
|
||||
html,
|
||||
ifDefined,
|
||||
nothing,
|
||||
property,
|
||||
state,
|
||||
repeat,
|
||||
when,
|
||||
} from '@umbraco-cms/backoffice/external/lit';
|
||||
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
|
||||
import { UmbPropertyValueChangeEvent } from '@umbraco-cms/backoffice/property-editor';
|
||||
@@ -7,12 +17,14 @@ import type {
|
||||
UmbPropertyEditorConfigCollection,
|
||||
UmbPropertyEditorUiElement,
|
||||
} from '@umbraco-cms/backoffice/property-editor';
|
||||
import { UMB_PROPERTY_DATASET_CONTEXT } from '@umbraco-cms/backoffice/property';
|
||||
|
||||
type UmbTiptapExtension = {
|
||||
alias: string;
|
||||
label: string;
|
||||
icon?: string;
|
||||
group?: string;
|
||||
description?: string;
|
||||
};
|
||||
|
||||
type UmbTiptapExtensionGroupItem = UmbTiptapExtension & {
|
||||
@@ -24,6 +36,9 @@ type UmbTiptapExtensionGroup = {
|
||||
extensions: Array<UmbTiptapExtensionGroupItem>;
|
||||
};
|
||||
|
||||
const TIPTAP_CORE_EXTENSION_ALIAS = 'Umb.Tiptap.RichTextEssentials';
|
||||
const TIPTAP_BLOCK_EXTENSION_ALIAS = 'Umb.Tiptap.Block';
|
||||
|
||||
const elementName = 'umb-property-editor-ui-tiptap-extensions-configuration';
|
||||
|
||||
@customElement(elementName)
|
||||
@@ -31,8 +46,10 @@ export class UmbPropertyEditorUiTiptapExtensionsConfigurationElement
|
||||
extends UmbLitElement
|
||||
implements UmbPropertyEditorUiElement
|
||||
{
|
||||
#disabledExtensions = new Set<string>([TIPTAP_CORE_EXTENSION_ALIAS]);
|
||||
|
||||
@property({ attribute: false })
|
||||
value?: Array<string> = [];
|
||||
value?: Array<string> = [TIPTAP_CORE_EXTENSION_ALIAS];
|
||||
|
||||
@property({ attribute: false })
|
||||
config?: UmbPropertyEditorConfigCollection;
|
||||
@@ -43,6 +60,41 @@ export class UmbPropertyEditorUiTiptapExtensionsConfigurationElement
|
||||
@state()
|
||||
private _groups: Array<UmbTiptapExtensionGroup> = [];
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.consumeContext(UMB_PROPERTY_DATASET_CONTEXT, async (dataset) => {
|
||||
this.observe(
|
||||
await dataset.propertyValueByAlias<Array<unknown>>('blocks'),
|
||||
(blocks) => {
|
||||
const tmpValue = this.value ? [...this.value] : [];
|
||||
|
||||
// When blocks are configured, the block extension can be enabled;
|
||||
// otherwise, the block extension must be disabled.
|
||||
if (blocks?.length) {
|
||||
// Check if the block extension is already enabled, if not, add it.
|
||||
if (!tmpValue.includes(TIPTAP_BLOCK_EXTENSION_ALIAS)) {
|
||||
tmpValue.push(TIPTAP_BLOCK_EXTENSION_ALIAS);
|
||||
}
|
||||
this.#disabledExtensions.delete(TIPTAP_BLOCK_EXTENSION_ALIAS);
|
||||
} else {
|
||||
// Check if the block extension is enabled, if so, remove it.
|
||||
const idx = tmpValue.indexOf(TIPTAP_BLOCK_EXTENSION_ALIAS) ?? -1;
|
||||
if (idx >= 0) {
|
||||
tmpValue.splice(idx, 1);
|
||||
}
|
||||
this.#disabledExtensions.add(TIPTAP_BLOCK_EXTENSION_ALIAS);
|
||||
}
|
||||
|
||||
if (!this.value || !this.#isArrayEqualTo(tmpValue, this.value)) {
|
||||
this.#setValue(tmpValue);
|
||||
this.#syncViewModel();
|
||||
}
|
||||
},
|
||||
'_observeBlocks',
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
protected override async firstUpdated(_changedProperties: PropertyValueMap<unknown>) {
|
||||
super.firstUpdated(_changedProperties);
|
||||
|
||||
@@ -51,43 +103,60 @@ export class UmbPropertyEditorUiTiptapExtensionsConfigurationElement
|
||||
.sort((a, b) => a.alias.localeCompare(b.alias))
|
||||
.map((ext) => ({ alias: ext.alias, label: ext.meta.label, icon: ext.meta.icon, group: ext.meta.group }));
|
||||
|
||||
// Hardcoded core extension
|
||||
this._extensions.unshift({
|
||||
alias: TIPTAP_CORE_EXTENSION_ALIAS,
|
||||
label: 'Rich Text Essentials',
|
||||
icon: 'icon-browser-window',
|
||||
group: '#tiptap_extGroup_formatting',
|
||||
description: 'This is a core extension, it must be enabled',
|
||||
});
|
||||
|
||||
if (!this.value) {
|
||||
// The default value is all extensions enabled
|
||||
this.value = this._extensions.map((ext) => ext.alias);
|
||||
this.dispatchEvent(new UmbPropertyValueChangeEvent());
|
||||
this.#setValue(this._extensions.map((ext) => ext.alias));
|
||||
}
|
||||
|
||||
const items: Array<UmbTiptapExtensionGroupItem> = this._extensions.map((extension) => ({
|
||||
...extension,
|
||||
selected: this.value!.includes(extension.alias),
|
||||
}));
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-expect-error
|
||||
const grouped = Object.groupBy(items, (item: UmbTiptapExtensionGroupItem) => item.group || 'Uncategorized');
|
||||
|
||||
this._groups = Object.keys(grouped)
|
||||
.sort((a, b) => a.localeCompare(b))
|
||||
.map((key) => ({ group: key, extensions: grouped[key] }));
|
||||
this.#syncViewModel();
|
||||
});
|
||||
}
|
||||
|
||||
#isArrayEqualTo(a: Array<string>, b: Array<string>) {
|
||||
return a.length === b.length && a.every((item) => b.includes(item)) && b.every((item) => a.includes(item));
|
||||
}
|
||||
|
||||
#onClick(item: UmbTiptapExtensionGroupItem) {
|
||||
item.selected = !item.selected;
|
||||
|
||||
if (!this.value) {
|
||||
this.value = [];
|
||||
}
|
||||
const tmpValue = item.selected
|
||||
? [...(this.value ?? []), item.alias]
|
||||
: (this.value ?? []).filter((alias) => alias !== item.alias);
|
||||
|
||||
if (item.selected) {
|
||||
this.value = [...this.value, item.alias];
|
||||
} else {
|
||||
this.value = this.value.filter((alias) => alias !== item.alias);
|
||||
}
|
||||
this.#setValue(tmpValue);
|
||||
}
|
||||
|
||||
#setValue(value: Array<string>) {
|
||||
this.value = value;
|
||||
this.dispatchEvent(new UmbPropertyValueChangeEvent());
|
||||
}
|
||||
|
||||
#syncViewModel() {
|
||||
const items: Array<UmbTiptapExtensionGroupItem> = this._extensions.map((extension) => ({
|
||||
...extension,
|
||||
selected: this.value!.includes(extension.alias) || extension.alias === TIPTAP_CORE_EXTENSION_ALIAS,
|
||||
}));
|
||||
|
||||
const uncategorizedLabel = this.localize.term('tiptap_extGroup_unknown');
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-expect-error
|
||||
const grouped = Object.groupBy(items, (item: UmbTiptapExtensionGroupItem) => item.group || uncategorizedLabel);
|
||||
|
||||
this._groups = Object.keys(grouped)
|
||||
.sort((a, b) => a.localeCompare(b))
|
||||
.map((key) => ({ group: key, extensions: grouped[key] }));
|
||||
}
|
||||
|
||||
override render() {
|
||||
if (!this._groups.length) return nothing;
|
||||
return html`
|
||||
@@ -97,27 +166,15 @@ export class UmbPropertyEditorUiTiptapExtensionsConfigurationElement
|
||||
<div class="group">
|
||||
<uui-label>${this.localize.string(group.group)}</uui-label>
|
||||
<ul>
|
||||
${when(
|
||||
group.group === '#tiptap_extGroup_formatting',
|
||||
() => html`
|
||||
<li title="This is a core extension, it must be enabled">
|
||||
<uui-checkbox checked disabled label="Rich Text Essentials">
|
||||
<div class="inner">
|
||||
<umb-icon name="icon-browser-window"></umb-icon>
|
||||
<span>Rich Text Essentials</span>
|
||||
</div>
|
||||
</uui-checkbox>
|
||||
</li>
|
||||
`,
|
||||
)}
|
||||
${repeat(
|
||||
group.extensions,
|
||||
(item) => html`
|
||||
<li>
|
||||
<li title=${ifDefined(item.description)}>
|
||||
<uui-checkbox
|
||||
label=${this.localize.string(item.label)}
|
||||
value=${item.alias}
|
||||
?checked=${item.selected}
|
||||
?disabled=${this.#disabledExtensions.has(item.alias)}
|
||||
@change=${() => this.#onClick(item)}>
|
||||
<div class="inner">
|
||||
${when(item.icon, () => html`<umb-icon .name=${item.icon}></umb-icon>`)}
|
||||
|
||||
Reference in New Issue
Block a user