Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
320739d79d | ||
|
|
495b5c3d50 | ||
|
|
b592188067 | ||
|
|
b5cf7a10f8 | ||
|
|
f4b5cbb739 | ||
|
|
4f2df1d391 |
+1
-1
@@ -5,7 +5,7 @@ import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api';
|
||||
@customElement('example-dashboard-with-tree')
|
||||
export class ExampleDashboardWithTree extends UmbElementMixin(LitElement) {
|
||||
override render() {
|
||||
return html`<uui-box><umb-tree alias=${EXAMPLE_TREE_ALIAS}></umb-tree></uui-box>`;
|
||||
return html`<uui-box><umb-tree alias=${EXAMPLE_TREE_ALIAS} .props=${{ hideTreeRoot: true }}></umb-tree></uui-box>`;
|
||||
}
|
||||
|
||||
static override styles = [
|
||||
|
||||
@@ -9,7 +9,8 @@ import type { UmbTreeExpansionModel } from '../expansion-manager/types.js';
|
||||
import type { UmbTreeItemModel, UmbTreeRootModel, UmbTreeStartNode } from '../types.js';
|
||||
import type { UmbTreeRepository } from '../data/index.js';
|
||||
import type { UmbTreeRootItemsRequestArgs } from '../data/types.js';
|
||||
import { UmbBooleanState, UmbObjectState } from '@umbraco-cms/backoffice/observable-api';
|
||||
import { UmbTreeViewManager } from '../view/tree-view.manager.js';
|
||||
import { UmbBooleanState, UmbObjectState, UmbArrayState } from '@umbraco-cms/backoffice/observable-api';
|
||||
import { UmbContextBase } from '@umbraco-cms/backoffice/class-api';
|
||||
import { UmbDeprecation, UmbSelectionManager, debounce } from '@umbraco-cms/backoffice/utils';
|
||||
import { UmbExtensionApiInitializer } from '@umbraco-cms/backoffice/extension-api';
|
||||
@@ -38,6 +39,10 @@ export class UmbDefaultTreeContext<
|
||||
#expandTreeRoot = new UmbBooleanState(undefined);
|
||||
public readonly expandTreeRoot = this.#expandTreeRoot.asObservable();
|
||||
|
||||
#treeViewManager = new UmbTreeViewManager(this);
|
||||
public readonly views = this.#treeViewManager.views;
|
||||
public readonly currentView = this.#treeViewManager.currentView;
|
||||
|
||||
#treeItemChildrenManager = new UmbTreeItemChildrenManager<TreeItemType, TreeRootType, RequestArgsType>(this);
|
||||
public readonly rootItems = this.#treeItemChildrenManager.children;
|
||||
public readonly hasChildren = this.#treeItemChildrenManager.hasChildren;
|
||||
@@ -56,6 +61,9 @@ export class UmbDefaultTreeContext<
|
||||
|
||||
readonly activeManager = new UmbTreeItemActiveManager(this);
|
||||
|
||||
#items = new UmbArrayState<TreeItemType | TreeRootType>([], (x) => x.unique);
|
||||
public readonly items = this.#items.asObservable();
|
||||
|
||||
#manifest?: ManifestTree;
|
||||
#repository?: UmbTreeRepository<TreeItemType, TreeRootType>;
|
||||
|
||||
@@ -176,6 +184,7 @@ export class UmbDefaultTreeContext<
|
||||
|
||||
if (data) {
|
||||
this.#treeRoot.setValue(data);
|
||||
this.#items.setValue([data]);
|
||||
this.#treeItemChildrenManager.setTreeItem(data);
|
||||
this.#treeItemExpansionManager.setTreeItem(data);
|
||||
this.pagination.setTotalItems(1);
|
||||
@@ -188,6 +197,14 @@ export class UmbDefaultTreeContext<
|
||||
}
|
||||
}
|
||||
|
||||
setCurrentView(viewUnique: string) {
|
||||
this.#treeViewManager.setCurrentView(viewUnique);
|
||||
}
|
||||
|
||||
getCurrentView() {
|
||||
return this.#treeViewManager.getCurrentView();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the hideTreeRoot config
|
||||
* @param {boolean} hideTreeRoot - Whether to hide the tree root
|
||||
@@ -198,6 +215,12 @@ export class UmbDefaultTreeContext<
|
||||
// we need to reset the tree if this config changes
|
||||
this.#clearTree();
|
||||
this.loadTree();
|
||||
|
||||
if (hideTreeRoot) {
|
||||
this.observe(this.#treeItemChildrenManager.children, (children) => {
|
||||
this.#items.setValue(children);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,10 +6,13 @@ import type {
|
||||
UmbTreeStartNode,
|
||||
} from '../types.js';
|
||||
import type { UmbTreeExpansionModel } from '../expansion-manager/types.js';
|
||||
import type { UmbTreeViewItemModel } from '../view/types.js';
|
||||
import type { ManifestTreeView } from '../view/extension/tree-view.extension.js';
|
||||
import type { UmbDefaultTreeContext } from './default-tree.context.js';
|
||||
import { css, customElement, html, nothing, property, repeat, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { customElement, html, nothing, property, repeat, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
|
||||
import type { PropertyValueMap } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { getItemFallbackIcon } from '@umbraco-cms/backoffice/entity-item';
|
||||
|
||||
@customElement('umb-default-tree')
|
||||
export class UmbDefaultTreeElement extends UmbLitElement {
|
||||
@@ -60,41 +63,14 @@ export class UmbDefaultTreeElement extends UmbLitElement {
|
||||
expansion: UmbTreeExpansionModel = [];
|
||||
|
||||
@state()
|
||||
private _rootItems: UmbTreeItemModel[] = [];
|
||||
private _views?: Array<UmbTreeViewItemModel>;
|
||||
|
||||
@state()
|
||||
private _treeRoot?: UmbTreeRootModel;
|
||||
|
||||
@state()
|
||||
private _currentPage = 1;
|
||||
|
||||
@state()
|
||||
private _hasPreviousItems = false;
|
||||
|
||||
@state()
|
||||
private _hasNextItems = false;
|
||||
|
||||
@state()
|
||||
private _isLoadingPrevChildren = false;
|
||||
|
||||
@state()
|
||||
private _isLoadingNextChildren = false;
|
||||
private _currentView?: UmbTreeViewItemModel;
|
||||
|
||||
#observeData() {
|
||||
this.observe(this._api?.treeRoot, (treeRoot) => (this._treeRoot = treeRoot));
|
||||
this.observe(this._api?.rootItems, (rootItems) => (this._rootItems = rootItems ?? []));
|
||||
this.observe(this._api?.pagination.currentPage, (value) => (this._currentPage = value ?? 1));
|
||||
this.observe(this._api?.isLoadingPrevChildren, (value) => (this._isLoadingPrevChildren = value ?? false));
|
||||
this.observe(this._api?.isLoadingNextChildren, (value) => (this._isLoadingNextChildren = value ?? false));
|
||||
|
||||
this.observe(
|
||||
this._api?.targetPagination?.totalPrevItems,
|
||||
(value) => (this._hasPreviousItems = value ? value > 0 : false),
|
||||
);
|
||||
this.observe(
|
||||
this._api?.targetPagination?.totalNextItems,
|
||||
(value) => (this._hasNextItems = value ? value > 0 : false),
|
||||
);
|
||||
this.observe(this._api?.views, (views) => (this._views = views));
|
||||
this.observe(this._api?.currentView, (currentView) => (this._currentView = currentView));
|
||||
}
|
||||
|
||||
protected override async updated(
|
||||
@@ -148,74 +124,46 @@ export class UmbDefaultTreeElement extends UmbLitElement {
|
||||
return this._api?.expansion.getExpansion();
|
||||
}
|
||||
|
||||
#onLoadPrev(event: any) {
|
||||
event.stopPropagation();
|
||||
this._api?.loadPrevItems?.();
|
||||
}
|
||||
|
||||
#onLoadNext(event: any) {
|
||||
event.stopPropagation();
|
||||
const next = (this._currentPage = this._currentPage + 1);
|
||||
this._api?.pagination.setCurrentPageNumber(next);
|
||||
#onViewClick(view: UmbTreeViewItemModel) {
|
||||
this._api?.setCurrentView(view.unique);
|
||||
}
|
||||
|
||||
override render() {
|
||||
return html` ${this.#renderTreeRoot()} ${this.#renderRootItems()}`;
|
||||
}
|
||||
|
||||
#renderTreeRoot() {
|
||||
if (this.hideTreeRoot || this._treeRoot === undefined) return nothing;
|
||||
return html`
|
||||
<umb-tree-item
|
||||
.entityType=${this._treeRoot.entityType}
|
||||
.props=${{
|
||||
hideActions: this.hideTreeItemActions,
|
||||
item: this._treeRoot,
|
||||
isMenu: this.isMenu,
|
||||
}}></umb-tree-item>
|
||||
<div>${this.#renderViewsBundle()}</div>
|
||||
|
||||
<umb-extension-slot
|
||||
type="treeView"
|
||||
.filter=${(manifest: ManifestTreeView) => manifest.alias === this._currentView?.unique}></umb-extension-slot>
|
||||
`;
|
||||
}
|
||||
|
||||
#renderRootItems() {
|
||||
// only show the root items directly if the tree root is hidden
|
||||
if (this.hideTreeRoot === true) {
|
||||
return html`
|
||||
${this.#renderLoadPrevButton()}
|
||||
${repeat(
|
||||
this._rootItems,
|
||||
(item, index) => item.name + '___' + index,
|
||||
(item) => html`
|
||||
<umb-tree-item
|
||||
.entityType=${item.entityType}
|
||||
.props=${{ hideActions: this.hideTreeItemActions, item, isMenu: this.isMenu }}></umb-tree-item>
|
||||
`,
|
||||
)}
|
||||
${this.#renderLoadNextButton()}
|
||||
`;
|
||||
} else {
|
||||
return nothing;
|
||||
}
|
||||
#renderViewsBundle() {
|
||||
if (!this._views || this._views.length === 0 || !this._currentView) return nothing;
|
||||
|
||||
return html`<uui-button compact popovertarget="tree-view-popover" label="status">
|
||||
<umb-icon name=${this._currentView.icon ?? getItemFallbackIcon()}></umb-icon>
|
||||
</uui-button>
|
||||
<uui-popover-container id="tree-view-popover" placement="bottom-end">
|
||||
<umb-popover-layout>
|
||||
<div class="filter-dropdown">
|
||||
${repeat(
|
||||
this._views,
|
||||
(view) => view.unique,
|
||||
(view) => this.#renderViewItem(view),
|
||||
)}
|
||||
</div>
|
||||
</umb-popover-layout>
|
||||
</uui-popover-container>`;
|
||||
}
|
||||
|
||||
#renderLoadPrevButton() {
|
||||
if (!this._hasPreviousItems) return nothing;
|
||||
return html`<umb-tree-load-prev-button
|
||||
@click=${this.#onLoadPrev}
|
||||
.loading=${this._isLoadingPrevChildren}></umb-tree-load-prev-button>`;
|
||||
#renderViewItem(view: UmbTreeViewItemModel) {
|
||||
return html`
|
||||
<uui-menu-item @click-label=${() => this.#onViewClick(view)} ?active=${view.unique === this._currentView?.unique}>
|
||||
<umb-icon slot="icon" name=${view.icon ?? getItemFallbackIcon()}></umb-icon>
|
||||
</uui-menu-item>
|
||||
`;
|
||||
}
|
||||
|
||||
#renderLoadNextButton() {
|
||||
if (!this._hasNextItems) return nothing;
|
||||
return html`<umb-tree-load-more-button
|
||||
@click=${this.#onLoadNext}
|
||||
.loading=${this._isLoadingNextChildren}></umb-tree-load-more-button> `;
|
||||
}
|
||||
|
||||
static override styles = css`
|
||||
#load-more {
|
||||
width: 100%;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
export default UmbDefaultTreeElement;
|
||||
|
||||
@@ -4,6 +4,7 @@ import { manifests as entityActionManifests } from './entity-actions/manifests.j
|
||||
import { manifests as folderManifests } from './folder/manifests.js';
|
||||
import { manifests as treeMenuItemManifests } from './tree-menu-item/manifests.js';
|
||||
import { manifests as treePickerManifests } from './tree-picker-modal/manifests.js';
|
||||
import { manifests as viewManifests } from './view/manifests.js';
|
||||
import type { UmbExtensionManifestKind } from '@umbraco-cms/backoffice/extension-registry';
|
||||
|
||||
export const manifests: Array<UmbExtensionManifest | UmbExtensionManifestKind> = [
|
||||
@@ -13,4 +14,5 @@ export const manifests: Array<UmbExtensionManifest | UmbExtensionManifestKind> =
|
||||
...folderManifests,
|
||||
...treeMenuItemManifests,
|
||||
...treePickerManifests,
|
||||
...viewManifests,
|
||||
];
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
import type { ManifestElement, ManifestWithDynamicConditions } from '@umbraco-cms/backoffice/extension-api';
|
||||
|
||||
export interface ManifestTreeView extends ManifestElement, ManifestWithDynamicConditions<UmbExtensionConditionConfig> {
|
||||
type: 'treeView';
|
||||
meta: MetaTreeView;
|
||||
}
|
||||
|
||||
export interface MetaTreeView {
|
||||
label: string;
|
||||
icon: string;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface UmbExtensionManifestMap {
|
||||
UmbTreeView: ManifestTreeView;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export type * from './tree-view.extension.js';
|
||||
@@ -0,0 +1,22 @@
|
||||
export const manifests: Array<UmbExtensionManifest> = [
|
||||
{
|
||||
type: 'treeView',
|
||||
alias: 'Umb.TreeView.Menu',
|
||||
name: 'Menu Tree View',
|
||||
element: () => import('./tree-menu-view/tree-menu-view.element.js'),
|
||||
meta: {
|
||||
label: 'Menu',
|
||||
icon: 'icon-blockquote',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'treeView',
|
||||
alias: 'Umb.TreeView.Card',
|
||||
name: 'Card Tree View',
|
||||
element: () => import('./tree-card-view/tree-card-view.element.js'),
|
||||
meta: {
|
||||
label: 'Card',
|
||||
icon: 'icon-grid-2',
|
||||
},
|
||||
},
|
||||
];
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
import { UMB_TREE_CONTEXT } from '../../constants.js';
|
||||
import type { UmbTreeItemModel, UmbTreeRootModel } from '../../types.js';
|
||||
import { css, customElement, html, ifDefined, nothing, repeat, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
|
||||
|
||||
@customElement('umb-tree-card-view')
|
||||
export class UmbTreeCardViewElement extends UmbLitElement {
|
||||
@state()
|
||||
private _items: Array<UmbTreeItemModel | UmbTreeRootModel> | undefined;
|
||||
|
||||
#treeContext?: typeof UMB_TREE_CONTEXT.TYPE;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.consumeContext(UMB_TREE_CONTEXT, (context) => {
|
||||
this.#treeContext = context;
|
||||
this.#observeData();
|
||||
});
|
||||
}
|
||||
|
||||
#observeData() {
|
||||
this.observe(this.#treeContext?.items, (items) => (this._items = items));
|
||||
}
|
||||
|
||||
#expand() {
|
||||
console.log('expand');
|
||||
}
|
||||
|
||||
override render() {
|
||||
return html`${this.#renderItems()}`;
|
||||
}
|
||||
|
||||
#renderItems() {
|
||||
if (!this._items) return nothing;
|
||||
console.log(this._items);
|
||||
|
||||
return html`
|
||||
<div id="tree-card-grid">
|
||||
${repeat(
|
||||
this._items,
|
||||
(item, index) => item.name + '___' + index,
|
||||
(item) =>
|
||||
html` <uui-card
|
||||
><umb-icon name=${ifDefined(item.icon)}></umb-icon>
|
||||
<h3>${item.name}</h3>
|
||||
${item.hasChildren ? html`<uui-button @click=${this.#expand}>Expand</uui-button>` : nothing}
|
||||
</uui-card>`,
|
||||
)}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
static override styles = css`
|
||||
#tree-card-grid {
|
||||
display: grid;
|
||||
gap: var(--uui-size-space-5);
|
||||
grid-template-columns: repeat(auto-fill, minmax(var(--umb-card-medium-min-width), 1fr));
|
||||
grid-auto-rows: var(--umb-card-medium-min-width);
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
export { UmbTreeCardViewElement as element };
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'umb-tree-card-view': UmbTreeCardViewElement;
|
||||
}
|
||||
}
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
import { UMB_TREE_CONTEXT } from '../../tree.context.token.js';
|
||||
import type { UmbTreeItemModel, UmbTreeRootModel } from '../../types.js';
|
||||
import { customElement, html, repeat, state, nothing, css } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
|
||||
|
||||
@customElement('umb-tree-menu-view')
|
||||
export class UmbTreeMenuViewElement extends UmbLitElement {
|
||||
@state()
|
||||
private _items: Array<UmbTreeItemModel | UmbTreeRootModel> | undefined;
|
||||
|
||||
@state()
|
||||
private _currentPage = 1;
|
||||
|
||||
@state()
|
||||
private _hasPreviousItems = false;
|
||||
|
||||
@state()
|
||||
private _hasNextItems = false;
|
||||
|
||||
@state()
|
||||
private _isLoadingPrevChildren = false;
|
||||
|
||||
@state()
|
||||
private _isLoadingNextChildren = false;
|
||||
|
||||
#treeContext?: typeof UMB_TREE_CONTEXT.TYPE;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.consumeContext(UMB_TREE_CONTEXT, (context) => {
|
||||
this.#treeContext = context;
|
||||
this.#observeData();
|
||||
});
|
||||
}
|
||||
|
||||
#observeData() {
|
||||
this.observe(this.#treeContext?.items, (items) => (this._items = items));
|
||||
this.observe(this.#treeContext?.pagination.currentPage, (value) => (this._currentPage = value ?? 1));
|
||||
this.observe(this.#treeContext?.isLoadingPrevChildren, (value) => (this._isLoadingPrevChildren = value ?? false));
|
||||
this.observe(this.#treeContext?.isLoadingNextChildren, (value) => (this._isLoadingNextChildren = value ?? false));
|
||||
|
||||
this.observe(
|
||||
this.#treeContext?.targetPagination?.totalPrevItems,
|
||||
(value) => (this._hasPreviousItems = value ? value > 0 : false),
|
||||
);
|
||||
this.observe(
|
||||
this.#treeContext?.targetPagination?.totalNextItems,
|
||||
(value) => (this._hasNextItems = value ? value > 0 : false),
|
||||
);
|
||||
}
|
||||
|
||||
#onLoadPrev(event: any) {
|
||||
event.stopPropagation();
|
||||
this.#treeContext?.loadPrevItems?.();
|
||||
}
|
||||
|
||||
#onLoadNext(event: any) {
|
||||
event.stopPropagation();
|
||||
const next = (this._currentPage = this._currentPage + 1);
|
||||
this.#treeContext?.pagination.setCurrentPageNumber(next);
|
||||
}
|
||||
|
||||
override render() {
|
||||
return html`${this.#renderItems()}`;
|
||||
}
|
||||
|
||||
#renderItems() {
|
||||
if (!this._items) return nothing;
|
||||
|
||||
return html`
|
||||
${this.#renderLoadPrevButton()}
|
||||
${repeat(
|
||||
this._items,
|
||||
(item, index) => item.name + '___' + index,
|
||||
(item) => html`
|
||||
<umb-tree-item
|
||||
.entityType=${item.entityType}
|
||||
.props=${{ hideActions: false, item, isMenu: false }}></umb-tree-item>
|
||||
`,
|
||||
)}
|
||||
${this.#renderLoadNextButton()}
|
||||
`;
|
||||
}
|
||||
|
||||
// .props=${{ hideActions: this.hideTreeItemActions, item, isMenu: this.isMenu }}
|
||||
|
||||
#renderLoadPrevButton() {
|
||||
if (!this._hasPreviousItems) return nothing;
|
||||
return html`<umb-tree-load-prev-button
|
||||
@click=${this.#onLoadPrev}
|
||||
.loading=${this._isLoadingPrevChildren}></umb-tree-load-prev-button>`;
|
||||
}
|
||||
|
||||
#renderLoadNextButton() {
|
||||
if (!this._hasNextItems) return nothing;
|
||||
return html`<umb-tree-load-more-button
|
||||
@click=${this.#onLoadNext}
|
||||
.loading=${this._isLoadingNextChildren}></umb-tree-load-more-button> `;
|
||||
}
|
||||
|
||||
static override styles = css`
|
||||
#load-more {
|
||||
width: 100%;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
export { UmbTreeMenuViewElement as element };
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'umb-tree-menu-view': UmbTreeMenuViewElement;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import type { UmbTreeViewItemModel } from './types.js';
|
||||
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
|
||||
import { UmbExtensionsManifestInitializer } from '@umbraco-cms/backoffice/extension-api';
|
||||
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import { UmbArrayState, UmbObjectState } from '@umbraco-cms/backoffice/observable-api';
|
||||
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
|
||||
|
||||
export class UmbTreeViewManager extends UmbControllerBase {
|
||||
#views = new UmbArrayState<UmbTreeViewItemModel>([], (x) => x.unique);
|
||||
public readonly views = this.#views.asObservable();
|
||||
|
||||
#currentView = new UmbObjectState<UmbTreeViewItemModel | undefined>(undefined);
|
||||
public readonly currentView = this.#currentView.asObservable();
|
||||
|
||||
constructor(host: UmbControllerHost) {
|
||||
super(host);
|
||||
this.#observeViews();
|
||||
}
|
||||
|
||||
public setCurrentView(unique: string) {
|
||||
const view = this.#views.getValue().find((view) => view.unique === unique);
|
||||
this.#currentView.setValue(view);
|
||||
}
|
||||
|
||||
public getCurrentView() {
|
||||
return this.#currentView.getValue();
|
||||
}
|
||||
|
||||
#observeViews() {
|
||||
return new UmbExtensionsManifestInitializer(this, umbExtensionsRegistry, 'treeView', null, (views) => {
|
||||
const manifests = views.map((view) => view.manifest);
|
||||
|
||||
const items = manifests.map((view) => ({
|
||||
unique: view.alias,
|
||||
entityType: 'tree-view',
|
||||
name: view.meta.label,
|
||||
icon: view.meta.icon,
|
||||
}));
|
||||
|
||||
this.#views.setValue(items);
|
||||
|
||||
// TODO: change this
|
||||
this.setCurrentView(items[0]?.unique ?? '');
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import type { UmbItemModel } from '@umbraco-cms/backoffice/entity-item';
|
||||
|
||||
export interface UmbTreeViewItemModel extends UmbItemModel {
|
||||
unique: string;
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
import type { ManifestElement } from '@umbraco-cms/backoffice/extension-api';
|
||||
|
||||
export interface ManifestEntityDataPickerDisplayMode extends ManifestElement<any> {
|
||||
type: 'entityDataPickerDisplayMode';
|
||||
meta?: MetaEntityDataPickerDisplayMode;
|
||||
}
|
||||
|
||||
export interface MetaEntityDataPickerDisplayMode {
|
||||
label: string;
|
||||
description?: string;
|
||||
icon?: string;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface UmbExtensionManifestMap {
|
||||
UmbEntityDataPickerDisplayMode: ManifestEntityDataPickerDisplayMode;
|
||||
}
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export type * from './entity-data-picker-display-mode.extension.js';
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
import { manifests as propertyEditorUiManifests } from './property-editor/manifests.js';
|
||||
|
||||
export const manifests: Array<UmbExtensionManifest> = [...propertyEditorUiManifests];
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
import type { ManifestEntityDataPickerDisplayMode } from '../extension/types.js';
|
||||
import type { UmbEntityDataPickerDisplayModePropertyEditorValue } from './types.js';
|
||||
import { customElement, html, nothing, property, repeat, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
|
||||
import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation';
|
||||
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/property-editor';
|
||||
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
|
||||
import type { UUIComboboxElement } from '@umbraco-cms/backoffice/external/uui';
|
||||
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
|
||||
|
||||
@customElement('umb-entity-data-picker-display-mode-property-editor-ui')
|
||||
export class UmbEntityDataPickerDisplayModePropertyEditorUIElement
|
||||
extends UmbFormControlMixin<UmbEntityDataPickerDisplayModePropertyEditorValue | undefined, typeof UmbLitElement>(
|
||||
UmbLitElement,
|
||||
undefined,
|
||||
)
|
||||
implements UmbPropertyEditorUiElement
|
||||
{
|
||||
/**
|
||||
* Sets the input to readonly mode, meaning value cannot be changed but still able to read and select its content.
|
||||
* @type {boolean}
|
||||
* @attr
|
||||
* @default false
|
||||
*/
|
||||
@property({ type: Boolean, reflect: true })
|
||||
readonly = false;
|
||||
|
||||
@state()
|
||||
private _displayModes: Array<ManifestEntityDataPickerDisplayMode> = [];
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.#observeDisplayModes();
|
||||
}
|
||||
|
||||
#observeDisplayModes() {
|
||||
this.observe(
|
||||
umbExtensionsRegistry.byType('entityDataPickerDisplayMode'),
|
||||
(extensions) => {
|
||||
this._displayModes = extensions;
|
||||
},
|
||||
'observeDisplayModes',
|
||||
);
|
||||
}
|
||||
|
||||
override focus() {
|
||||
return this.shadowRoot?.querySelector<UUIComboboxElement>('uui-combobox')?.focus();
|
||||
}
|
||||
|
||||
#onChange(event: CustomEvent & { target: UUIComboboxElement }) {
|
||||
const selected = event.target.value;
|
||||
|
||||
// Ensure the value is of the correct type before setting it.
|
||||
if (typeof selected === 'string') {
|
||||
this.value = { ids: [selected] };
|
||||
this.dispatchEvent(new UmbChangeEvent());
|
||||
} else {
|
||||
throw new Error('Selected is not of type string. Cannot set property value.');
|
||||
}
|
||||
}
|
||||
|
||||
override render() {
|
||||
return html` <uui-combobox value=${this.value?.ids[0] || ''} @change=${this.#onChange}>
|
||||
<uui-combobox-list
|
||||
>${repeat(
|
||||
this._displayModes ?? [],
|
||||
(property) => property.alias,
|
||||
(property) => this.#renderOption(property),
|
||||
)}</uui-combobox-list
|
||||
>
|
||||
</uui-combobox>`;
|
||||
}
|
||||
|
||||
#renderOption(item: ManifestEntityDataPickerDisplayMode) {
|
||||
const label = item.meta?.label || item.name;
|
||||
const description = item.meta?.description;
|
||||
|
||||
return html`
|
||||
<uui-combobox-list-option
|
||||
.displayValue=${label}
|
||||
style="display: flex; gap: 9px; align-items: center; padding: var(--uui-size-3)"
|
||||
.value=${item.alias}>
|
||||
<uui-icon name="icon-wrench"></uui-icon>
|
||||
<div style="display: flex; flex-direction: column">
|
||||
<b>${label}</b>
|
||||
${description ? html`<small>${description}</small>` : nothing}
|
||||
</div>
|
||||
</uui-combobox-list-option>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
export { UmbEntityDataPickerDisplayModePropertyEditorUIElement as element };
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'umb-entity-data-picker-display-mode-property-editor-ui': UmbEntityDataPickerDisplayModePropertyEditorUIElement;
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
export const manifests: Array<UmbExtensionManifest> = [
|
||||
{
|
||||
type: 'propertyEditorUi',
|
||||
alias: 'Umb.PropertyEditorUi.EntityDataPicker.DisplayMode',
|
||||
name: 'Entity Data Picker Display Mode Property Editor UI',
|
||||
element: () => import('./entity-data-picker-display-mode-property-editor-ui.element.js'),
|
||||
meta: {
|
||||
label: 'Entity Data Picker Display Mode',
|
||||
icon: 'icon-page-add',
|
||||
group: 'pickers',
|
||||
supportsReadOnly: true,
|
||||
},
|
||||
},
|
||||
];
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
export type UmbEntityDataPickerDisplayModePropertyEditorValue = {
|
||||
ids: Array<string>;
|
||||
};
|
||||
+2
@@ -3,6 +3,7 @@ import { manifests as pickerItemManifests } from './picker-item/manifests.js';
|
||||
import { manifests as pickerSearchManifests } from './picker-search/manifests.js';
|
||||
import { manifests as pickerTreeManifests } from './picker-tree/manifests.js';
|
||||
import { manifests as propertyEditorManifests } from './property-editor/manifests.js';
|
||||
import { manifests as displayModeManifests } from './display-mode/manifests.js';
|
||||
|
||||
export const manifests: Array<UmbExtensionManifest> = [
|
||||
...pickerCollectionMenuManifests,
|
||||
@@ -10,4 +11,5 @@ export const manifests: Array<UmbExtensionManifest> = [
|
||||
...pickerSearchManifests,
|
||||
...pickerTreeManifests,
|
||||
...propertyEditorManifests,
|
||||
...displayModeManifests,
|
||||
];
|
||||
|
||||
+40
@@ -17,7 +17,47 @@ export const manifests: Array<UmbExtensionManifest> = [
|
||||
enabled: true,
|
||||
forDataSourceTypes: [UMB_PICKER_DATA_SOURCE_TYPE],
|
||||
},
|
||||
settings: {
|
||||
properties: [
|
||||
{
|
||||
alias: 'displayMode',
|
||||
label: 'Display Mode',
|
||||
propertyEditorUiAlias: 'Umb.PropertyEditorUi.EntityDataPicker.DisplayMode',
|
||||
weight: 100,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
...schemaManifests,
|
||||
{
|
||||
type: 'entityDataPickerDisplayMode',
|
||||
alias: 'Umb.EntityDataPickerDisplayMode.MenuItem',
|
||||
name: 'Menu Item Entity Data Picker Display Mode',
|
||||
weight: 900,
|
||||
meta: {
|
||||
label: 'Menu Item',
|
||||
description: 'Description of Menu Item display mode.',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'entityDataPickerDisplayMode',
|
||||
alias: 'Umb.EntityDataPickerDisplayMode.RefItem',
|
||||
name: 'Ref Item Entity Data Picker Display Mode',
|
||||
weight: 800,
|
||||
meta: {
|
||||
label: 'Reference Item',
|
||||
description: 'Description of Reference Item display mode.',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'entityDataPickerDisplayMode',
|
||||
alias: 'Umb.EntityDataPickerDisplayMode.Card',
|
||||
name: 'Card Entity Data Picker Display Mode',
|
||||
weight: 700,
|
||||
meta: {
|
||||
label: 'Card',
|
||||
description: 'Description of Card display mode.',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user