Merge remote-tracking branch 'origin/main' into feature/datatypepickerflow-property-icons
This commit is contained in:
@@ -35,6 +35,7 @@ export class UmbPropertyEditorUIBlockGridTypeConfigurationElement
|
||||
extends UmbLitElement
|
||||
implements UmbPropertyEditorUiElement
|
||||
{
|
||||
#moveData?: Array<UmbBlockTypeWithGroupKey>;
|
||||
#sorter = new UmbSorterController<MappedGroupWithBlockTypes, HTMLElement>(this, {
|
||||
getUniqueOfElement: (element) => element.getAttribute('data-umb-group-key'),
|
||||
getUniqueOfModel: (modelEntry) => modelEntry.key!,
|
||||
@@ -128,13 +129,40 @@ export class UmbPropertyEditorUIBlockGridTypeConfigurationElement
|
||||
this.#sorter.setModel(this._groupsWithBlockTypes);
|
||||
}
|
||||
|
||||
#onChange(e: CustomEvent, groupKey?: string) {
|
||||
#onDelete(e: CustomEvent, groupKey?: string) {
|
||||
const updatedValues = (e.target as UmbInputBlockTypeElement).value.map((value) => ({ ...value, groupKey }));
|
||||
const filteredValues = this.value.filter((value) => value.groupKey !== groupKey);
|
||||
this.value = [...filteredValues, ...updatedValues];
|
||||
this.dispatchEvent(new UmbPropertyValueChangeEvent());
|
||||
}
|
||||
|
||||
async #onChange(e: CustomEvent) {
|
||||
e.stopPropagation();
|
||||
const element = e.target as UmbInputBlockTypeElement;
|
||||
const value = element.value;
|
||||
|
||||
if (!e.detail?.moveComplete) {
|
||||
// Container change, store data of the new group...
|
||||
const newGroupKey = element.getAttribute('data-umb-group-key');
|
||||
const movedItem = e.detail?.item as UmbBlockTypeWithGroupKey;
|
||||
// Check if item moved back to original group...
|
||||
movedItem.groupKey === newGroupKey
|
||||
? (this.#moveData = undefined)
|
||||
: (this.#moveData = value.map((block) => ({ ...block, groupKey: newGroupKey })));
|
||||
} else if (e.detail?.moveComplete) {
|
||||
// Move complete, get the blocks that were in an untouched group
|
||||
const blocks = this.value
|
||||
.filter((block) => !value.find((value) => value.contentElementTypeKey === block.contentElementTypeKey))
|
||||
.filter(
|
||||
(block) => !this.#moveData?.find((value) => value.contentElementTypeKey === block.contentElementTypeKey),
|
||||
);
|
||||
|
||||
this.value = this.#moveData ? [...blocks, ...value, ...this.#moveData] : [...blocks, ...value];
|
||||
this.dispatchEvent(new UmbPropertyValueChangeEvent());
|
||||
this.#moveData = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
#onCreate(e: CustomEvent, groupKey?: string) {
|
||||
const selectedElementType = e.detail.contentElementTypeKey;
|
||||
if (selectedElementType) {
|
||||
@@ -170,8 +198,9 @@ export class UmbPropertyEditorUIBlockGridTypeConfigurationElement
|
||||
? html`<umb-input-block-type
|
||||
.value=${this._notGroupedBlockTypes}
|
||||
.workspacePath=${this._workspacePath}
|
||||
@change=${this.#onChange}
|
||||
@create=${(e: CustomEvent) => this.#onCreate(e, undefined)}
|
||||
@change=${(e: CustomEvent) => this.#onChange(e, undefined)}></umb-input-block-type>`
|
||||
@delete=${(e: CustomEvent) => this.#onDelete(e, undefined)}></umb-input-block-type>`
|
||||
: ''}
|
||||
${repeat(
|
||||
this._groupsWithBlockTypes,
|
||||
@@ -180,10 +209,12 @@ export class UmbPropertyEditorUIBlockGridTypeConfigurationElement
|
||||
html`<div class="group" data-umb-group-key=${ifDefined(group.key)}>
|
||||
${group.key ? this.#renderGroupInput(group.key, group.name) : nothing}
|
||||
<umb-input-block-type
|
||||
data-umb-group-key=${group.key}
|
||||
.value=${group.blocks}
|
||||
.workspacePath=${this._workspacePath}
|
||||
@change=${this.#onChange}
|
||||
@create=${(e: CustomEvent) => this.#onCreate(e, group.key)}
|
||||
@change=${(e: CustomEvent) => this.#onChange(e, group.key)}></umb-input-block-type>
|
||||
@delete=${(e: CustomEvent) => this.#onDelete(e, group.key)}></umb-input-block-type>
|
||||
</div>`,
|
||||
)}
|
||||
</div>`;
|
||||
|
||||
@@ -3,7 +3,10 @@ import '../../../block-type/components/input-block-type/index.js';
|
||||
import { UMB_BLOCK_LIST_TYPE } from '../../types.js';
|
||||
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import { html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import type { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor';
|
||||
import {
|
||||
UmbPropertyValueChangeEvent,
|
||||
type UmbPropertyEditorConfigCollection,
|
||||
} from '@umbraco-cms/backoffice/property-editor';
|
||||
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
|
||||
import { UMB_WORKSPACE_MODAL, UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/modal';
|
||||
|
||||
@@ -51,14 +54,19 @@ export class UmbPropertyEditorUIBlockListBlockConfigurationElement
|
||||
}
|
||||
}
|
||||
|
||||
#onChange(e: CustomEvent) {
|
||||
e.stopPropagation();
|
||||
this.value = (e.target as UmbInputBlockTypeElement).value;
|
||||
this.dispatchEvent(new UmbPropertyValueChangeEvent());
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`<umb-input-block-type
|
||||
.value=${this.value}
|
||||
.workspacePath=${this._workspacePath}
|
||||
@create=${this.#onCreate}
|
||||
@change=${(e: Event) => {
|
||||
this.value = (e.target as UmbInputBlockTypeElement).value;
|
||||
}}></umb-input-block-type>`;
|
||||
@delete=${this.#onChange}
|
||||
@change=${this.#onChange}></umb-input-block-type>`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +1,41 @@
|
||||
import type { UmbBlockTypeBaseModel } from '../../types.js';
|
||||
import type { UmbBlockTypeCardElement } from '../block-type-card/index.js';
|
||||
import type { UmbBlockTypeBaseModel, UmbBlockTypeWithGroupKey } from '../../types.js';
|
||||
import { UMB_MODAL_MANAGER_CONTEXT, umbConfirmModal } from '@umbraco-cms/backoffice/modal';
|
||||
import '../block-type-card/index.js';
|
||||
import { css, html, customElement, property, state, repeat } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
|
||||
import type { UmbPropertyDatasetContext } from '@umbraco-cms/backoffice/property';
|
||||
import { UMB_PROPERTY_DATASET_CONTEXT } from '@umbraco-cms/backoffice/property';
|
||||
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
|
||||
import { UmbDeleteEvent } from '@umbraco-cms/backoffice/event';
|
||||
import { UMB_DOCUMENT_TYPE_PICKER_MODAL } from '@umbraco-cms/backoffice/document-type';
|
||||
import { UmbSorterController } from '@umbraco-cms/backoffice/sorter';
|
||||
|
||||
@customElement('umb-input-block-type')
|
||||
export class UmbInputBlockTypeElement<
|
||||
BlockType extends UmbBlockTypeBaseModel = UmbBlockTypeBaseModel,
|
||||
BlockType extends UmbBlockTypeWithGroupKey = UmbBlockTypeWithGroupKey,
|
||||
> extends UmbLitElement {
|
||||
#sorter = new UmbSorterController<BlockType, UmbBlockTypeCardElement>(this, {
|
||||
getUniqueOfElement: (element) => element.contentElementTypeKey,
|
||||
getUniqueOfModel: (modelEntry) => modelEntry.contentElementTypeKey!,
|
||||
itemSelector: 'umb-block-type-card',
|
||||
identifier: 'umb-block-type-sorter',
|
||||
containerSelector: '#blocks',
|
||||
onChange: ({ model }) => {
|
||||
this._items = model;
|
||||
},
|
||||
onContainerChange: ({ model, item }) => {
|
||||
this._items = model;
|
||||
this.dispatchEvent(new CustomEvent('change', { detail: { item } }));
|
||||
},
|
||||
onEnd: () => {
|
||||
this.dispatchEvent(new CustomEvent('change', { detail: { moveComplete: true } }));
|
||||
},
|
||||
});
|
||||
|
||||
@property({ type: Array, attribute: false })
|
||||
public set value(items) {
|
||||
this._items = items ?? [];
|
||||
this.#sorter.setModel(this._items);
|
||||
}
|
||||
public get value() {
|
||||
return this._items;
|
||||
@@ -67,7 +88,7 @@ export class UmbInputBlockTypeElement<
|
||||
|
||||
deleteItem(contentElementTypeKey: string) {
|
||||
this.value = this.value.filter((x) => x.contentElementTypeKey !== contentElementTypeKey);
|
||||
this.dispatchEvent(new UmbChangeEvent());
|
||||
this.dispatchEvent(new UmbDeleteEvent());
|
||||
}
|
||||
|
||||
protected getFormElement() {
|
||||
@@ -85,7 +106,7 @@ export class UmbInputBlockTypeElement<
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`<div>
|
||||
return html`<div id="blocks">
|
||||
${repeat(this.value, (block) => block.contentElementTypeKey, this.#renderItem)} ${this.#renderButton()}
|
||||
</div>`;
|
||||
}
|
||||
@@ -93,6 +114,7 @@ export class UmbInputBlockTypeElement<
|
||||
#renderItem = (block: BlockType) => {
|
||||
return html`
|
||||
<umb-block-type-card
|
||||
.data-umb-content-element-key=${block.contentElementTypeKey}
|
||||
.name=${block.label}
|
||||
.iconColor=${block.iconColor}
|
||||
.backgroundColor=${block.backgroundColor}
|
||||
@@ -125,6 +147,10 @@ export class UmbInputBlockTypeElement<
|
||||
grid-template-rows: repeat(auto-fill, minmax(160px, 1fr));
|
||||
}
|
||||
|
||||
[drag-placeholder] {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
#add-button {
|
||||
text-align: center;
|
||||
min-height: 150px;
|
||||
|
||||
@@ -30,4 +30,5 @@ export * from './input-upload-field/index.js';
|
||||
export * from './multiple-color-picker-input/index.js';
|
||||
export * from './multiple-text-string-input/index.js';
|
||||
export * from './popover-layout/index.js';
|
||||
export * from './ref-item/index.js';
|
||||
export * from './table/index.js';
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export * from './ref-item.element.js';
|
||||
@@ -0,0 +1,75 @@
|
||||
import { html, customElement, css, property, when, nothing, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api';
|
||||
import { UUIRefElement, UUIRefEvent, UUIRefNodeElement } from '@umbraco-cms/backoffice/external/uui';
|
||||
|
||||
@customElement('umb-ref-item')
|
||||
export class UmbRefItemElement extends UmbElementMixin(UUIRefElement) {
|
||||
@property({ type: String })
|
||||
name = '';
|
||||
|
||||
@property({ type: String })
|
||||
detail = '';
|
||||
|
||||
@property({ type: String })
|
||||
icon = '';
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.selectable = true;
|
||||
|
||||
this.addEventListener(UUIRefEvent.OPEN, () => this.dispatchEvent(new Event('click')));
|
||||
}
|
||||
|
||||
public render() {
|
||||
return html`
|
||||
<button
|
||||
type="button"
|
||||
id="btn-item"
|
||||
tabindex="0"
|
||||
@click=${this.handleOpenClick}
|
||||
@keydown=${this.handleOpenKeydown}
|
||||
?disabled=${this.disabled}>
|
||||
${when(
|
||||
this.icon,
|
||||
() => html`<span id="icon"><uui-icon name=${this.icon ?? ''}></uui-icon></span>`,
|
||||
() => nothing,
|
||||
)}
|
||||
<div id="info">
|
||||
<div id="name">${this.name}</div>
|
||||
<small id="detail">${this.detail}</small>
|
||||
</div>
|
||||
</button>
|
||||
<div id="select-border"></div>
|
||||
<slot></slot>
|
||||
`;
|
||||
}
|
||||
|
||||
static styles = [
|
||||
...UUIRefElement.styles,
|
||||
...UUIRefNodeElement.styles,
|
||||
css`
|
||||
:host {
|
||||
padding: calc(var(--uui-size-4) + 1px);
|
||||
}
|
||||
|
||||
#btn-item {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
align-self: stretch;
|
||||
line-height: normal;
|
||||
|
||||
display: flex;
|
||||
position: relative;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'umb-ref-item': UmbRefItemElement;
|
||||
}
|
||||
}
|
||||
@@ -1,39 +1,80 @@
|
||||
import { css, html, customElement, repeat, nothing, when } from '@umbraco-cms/backoffice/external/lit';
|
||||
import {
|
||||
css,
|
||||
html,
|
||||
customElement,
|
||||
repeat,
|
||||
nothing,
|
||||
when,
|
||||
state,
|
||||
ifDefined,
|
||||
} from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import type { UmbItemPickerModalData, UmbItemPickerModel } from '@umbraco-cms/backoffice/modal';
|
||||
|
||||
@customElement('umb-item-picker-modal')
|
||||
export class UmbItemPickerModalElement extends UmbModalBaseElement<UmbItemPickerModalData, UmbItemPickerModel> {
|
||||
@state()
|
||||
private _filtered: Array<UmbItemPickerModel> = [];
|
||||
|
||||
#close() {
|
||||
this.modalContext?.reject();
|
||||
}
|
||||
|
||||
#filter(event: { target: HTMLInputElement }) {
|
||||
if (!this.data) return;
|
||||
|
||||
if (event.target.value) {
|
||||
const query = event.target.value.toLowerCase();
|
||||
this._filtered = this.data.items.filter(
|
||||
(item) => item.label.toLowerCase().includes(query) || item.value.toLowerCase().includes(query),
|
||||
);
|
||||
} else {
|
||||
this._filtered = this.data.items;
|
||||
}
|
||||
}
|
||||
|
||||
#submit(item: UmbItemPickerModel) {
|
||||
this.modalContext?.setValue(item);
|
||||
this.modalContext?.submit();
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
|
||||
if (!this.data) return;
|
||||
this._filtered = this.data.items;
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.data) return nothing;
|
||||
const items = this.data.items;
|
||||
const items = this._filtered;
|
||||
return html`
|
||||
<umb-body-layout headline=${this.data.headline}>
|
||||
<div>
|
||||
<div id="main">
|
||||
<uui-input type="search" placeholder=${this.localize.term('placeholders_filter')} @input=${this.#filter}>
|
||||
<div slot="prepend">
|
||||
<uui-icon name="search"></uui-icon>
|
||||
</div>
|
||||
</uui-input>
|
||||
${when(
|
||||
items.length,
|
||||
() => html`
|
||||
<uui-box>
|
||||
${repeat(
|
||||
items,
|
||||
(item) => item.value,
|
||||
(item) => html`
|
||||
<uui-button @click=${() => this.#submit(item)} look="placeholder" label="${item.label}">
|
||||
<h4>${item.label}</h4>
|
||||
<p>${item.description}</p>
|
||||
</uui-button>
|
||||
`,
|
||||
)}
|
||||
<uui-ref-list>
|
||||
${repeat(
|
||||
items,
|
||||
(item) => item.value,
|
||||
(item) => html`
|
||||
<umb-ref-item
|
||||
name=${item.label}
|
||||
detail=${ifDefined(item.description)}
|
||||
icon=${ifDefined(item.icon)}
|
||||
@click=${() => this.#submit(item)}>
|
||||
</umb-ref-item>
|
||||
`,
|
||||
)}
|
||||
</uui-ref-list>
|
||||
</uui-box>
|
||||
`,
|
||||
() => html`<p>There are no items to select.</p>`,
|
||||
@@ -49,6 +90,16 @@ export class UmbItemPickerModalElement extends UmbModalBaseElement<UmbItemPicker
|
||||
static styles = [
|
||||
UmbTextStyles,
|
||||
css`
|
||||
#main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--uui-size-space-5);
|
||||
}
|
||||
|
||||
uui-box > uui-input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
uui-box > uui-button {
|
||||
display: block;
|
||||
--uui-button-content-align: flex-start;
|
||||
|
||||
@@ -16,10 +16,8 @@ export abstract class UmbModalBaseElement<
|
||||
@property({ type: Object, attribute: false })
|
||||
public manifest?: ModalManifestType;
|
||||
|
||||
#modalContext?: UmbModalContext<ModalDataType, ModalValueType> | undefined;
|
||||
@property({ attribute: false })
|
||||
public get modalContext(): UmbModalContext<ModalDataType, ModalValueType> | undefined {
|
||||
return this.#modalContext;
|
||||
}
|
||||
public set modalContext(context: UmbModalContext<ModalDataType, ModalValueType> | undefined) {
|
||||
this.#modalContext = context;
|
||||
if (context) {
|
||||
@@ -35,7 +33,9 @@ export abstract class UmbModalBaseElement<
|
||||
);
|
||||
}
|
||||
}
|
||||
#modalContext?: UmbModalContext<ModalDataType, ModalValueType> | undefined;
|
||||
public get modalContext(): UmbModalContext<ModalDataType, ModalValueType> | undefined {
|
||||
return this.#modalContext;
|
||||
}
|
||||
|
||||
@property({ attribute: false })
|
||||
public set data(value: ModalDataType | undefined) {
|
||||
|
||||
@@ -6,8 +6,9 @@ export type UmbItemPickerModalData = {
|
||||
};
|
||||
|
||||
export type UmbItemPickerModel = {
|
||||
label: string;
|
||||
description?: string;
|
||||
icon?: string;
|
||||
label: string;
|
||||
value: string;
|
||||
};
|
||||
|
||||
|
||||
@@ -64,19 +64,22 @@ export class UmbDynamicRootOriginPickerModalModalElement extends UmbModalBaseEle
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<umb-body-layout headline="${this.localize.term('dynamicRoot_pickDynamicRootOriginTitle')}">
|
||||
<umb-body-layout headline=${this.localize.term('dynamicRoot_pickDynamicRootOriginTitle')}>
|
||||
<div id="main">
|
||||
<uui-box>
|
||||
${repeat(
|
||||
this._origins,
|
||||
(item) => item.alias,
|
||||
(item) => html`
|
||||
<uui-button @click=${() => this.#choose(item)} look="placeholder" label="${ifDefined(item.meta.label)}">
|
||||
<h3>${item.meta.label}</h3>
|
||||
<p>${item.meta.description}</p>
|
||||
</uui-button>
|
||||
`,
|
||||
)}
|
||||
<uui-ref-list>
|
||||
${repeat(
|
||||
this._origins,
|
||||
(item) => item.alias,
|
||||
(item) => html`
|
||||
<umb-ref-item
|
||||
name=${ifDefined(item.meta.label)}
|
||||
detail=${ifDefined(item.meta.description)}
|
||||
icon=${ifDefined(item.meta.icon)}
|
||||
@click=${() => this.#choose(item)}></umb-ref-item>
|
||||
`,
|
||||
)}
|
||||
</uui-ref-list>
|
||||
</uui-box>
|
||||
</div>
|
||||
<div slot="actions">
|
||||
|
||||
@@ -52,19 +52,22 @@ export class UmbDynamicRootQueryStepPickerModalModalElement extends UmbModalBase
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<umb-body-layout headline="${this.localize.term('dynamicRoot_pickDynamicRootQueryStepTitle')}">
|
||||
<umb-body-layout headline=${this.localize.term('dynamicRoot_pickDynamicRootQueryStepTitle')}>
|
||||
<div id="main">
|
||||
<uui-box>
|
||||
${repeat(
|
||||
this._querySteps,
|
||||
(item) => item.alias,
|
||||
(item) => html`
|
||||
<uui-button @click=${() => this.#choose(item)} look="placeholder" label="${ifDefined(item.meta.label)}">
|
||||
<h3>${item.meta.label}</h3>
|
||||
<p>${item.meta.description}</p>
|
||||
</uui-button>
|
||||
`,
|
||||
)}
|
||||
<uui-ref-list>
|
||||
${repeat(
|
||||
this._querySteps,
|
||||
(item) => item.alias,
|
||||
(item) => html`
|
||||
<umb-ref-item
|
||||
name=${ifDefined(item.meta.label)}
|
||||
detail=${ifDefined(item.meta.description)}
|
||||
icon=${ifDefined(item.meta.icon)}
|
||||
@click=${() => this.#choose(item)}></umb-ref-item>
|
||||
`,
|
||||
)}
|
||||
</uui-ref-list>
|
||||
</uui-box>
|
||||
</div>
|
||||
<div slot="actions">
|
||||
|
||||
@@ -111,9 +111,7 @@ export class UmbDashboardPublishedStatusElement extends UmbLitElement {
|
||||
}
|
||||
|
||||
render() {
|
||||
// TODO: Are we supposed to have the debug element here?
|
||||
return html`
|
||||
<umb-debug visible dialog></umb-debug>
|
||||
<uui-box headline="Published Cache Status">
|
||||
<p>${this._publishedStatusText}</p>
|
||||
<uui-button
|
||||
|
||||
Reference in New Issue
Block a user