Merge branch 'main' into v14/feature/example-using-icons

This commit is contained in:
Niels Lyngsø
2024-08-15 13:03:27 +02:00
committed by GitHub

View File

@@ -1,9 +1,13 @@
import { UmbMemberCollectionRepository } from '../../collection/index.js';
import { UmbMemberSearchProvider } from '../../search/member.search-provider.js';
import type { UmbMemberDetailModel } from '../../types.js';
import type { UmbMemberItemModel } from '../../repository/index.js';
import type { UmbMemberPickerModalValue, UmbMemberPickerModalData } from './member-picker-modal.token.js';
import { html, customElement, state, repeat } from '@umbraco-cms/backoffice/external/lit';
import { UmbSelectionManager } from '@umbraco-cms/backoffice/utils';
import { css, customElement, html, nothing, repeat, state, when } from '@umbraco-cms/backoffice/external/lit';
import { debounce, UmbSelectionManager } from '@umbraco-cms/backoffice/utils';
import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import type { UUIInputEvent } from '@umbraco-cms/backoffice/external/uui';
@customElement('umb-member-picker-modal')
export class UmbMemberPickerModalElement extends UmbModalBaseElement<
@@ -13,8 +17,18 @@ export class UmbMemberPickerModalElement extends UmbModalBaseElement<
@state()
private _members: Array<UmbMemberDetailModel> = [];
@state()
private _searchQuery: string = '';
@state()
private _searchResult: Array<UmbMemberItemModel> = [];
@state()
private _searching = false;
#collectionRepository = new UmbMemberCollectionRepository(this);
#selectionManager = new UmbSelectionManager(this);
#searchProvider = new UmbMemberSearchProvider(this);
override connectedCallback(): void {
super.connectedCallback();
@@ -23,6 +37,18 @@ export class UmbMemberPickerModalElement extends UmbModalBaseElement<
this.#selectionManager.setSelection(this.value?.selection ?? []);
}
constructor() {
super();
this.observe(
this.#selectionManager.selection,
(selection) => {
this.updateValue({ selection });
this.requestUpdate();
},
'umbSelectionObserver',
);
}
override async firstUpdated() {
const { data } = await this.#collectionRepository.requestCollection({});
this._members = data?.items ?? [];
@@ -36,43 +62,143 @@ export class UmbMemberPickerModalElement extends UmbModalBaseElement<
}
}
#submit() {
this.value = { selection: this.#selectionManager.getSelection() };
this.modalContext?.submit();
#onSearchInput(event: UUIInputEvent) {
const value = event.target.value as string;
this._searchQuery = value;
if (!this._searchQuery) {
this._searchResult = [];
this._searching = false;
return;
}
this._searching = true;
this.#debouncedSearch();
}
#close() {
this.modalContext?.reject();
#debouncedSearch = debounce(this.#search, 300);
async #search() {
if (!this._searchQuery) return;
const { data } = await this.#searchProvider.search({ query: this._searchQuery });
this._searchResult = data?.items ?? [];
this._searching = false;
}
#onSearchClear() {
this._searchQuery = '';
this._searchResult = [];
}
override render() {
return html`<umb-body-layout headline=${this.localize.term('defaultdialogs_selectMembers')}>
<uui-box>
${repeat(
this.#filteredMembers,
(item) => item.unique,
(item) => html`
<uui-menu-item
label=${item.variants[0].name ?? ''}
selectable
@selected=${() => this.#selectionManager.select(item.unique)}
@deselected=${() => this.#selectionManager.deselect(item.unique)}
?selected=${this.#selectionManager.isSelected(item.unique)}>
<uui-icon slot="icon" name="icon-globe"></uui-icon>
</uui-menu-item>
return html`
<umb-body-layout headline=${this.localize.term('defaultdialogs_selectMembers')}>
<uui-box>${this.#renderSearch()} ${this.#renderItems()}</uui-box>
<div slot="actions">
<uui-button
label=${this.localize.term('general_cancel')}
@click=${() => this.modalContext?.reject()}></uui-button>
<uui-button
color="positive"
look="primary"
label=${this.localize.term('general_submit')}
@click=${() => this.modalContext?.submit()}></uui-button>
</div>
</umb-body-layout>
`;
}
#renderItems() {
if (this._searchQuery) return nothing;
return html`
${repeat(
this.#filteredMembers,
(item) => item.unique,
(item) => this.#renderMemberItem(item),
)}
`;
}
#renderSearch() {
return html`
<uui-input
id="search-input"
placeholder=${this.localize.term('placeholders_search')}
.value=${this._searchQuery}
@input=${this.#onSearchInput}>
<div slot="prepend">
${this._searching
? html`<uui-loader-circle id="search-indicator"></uui-loader-circle>`
: html`<uui-icon name="search"></uui-icon>`}
</div>
${when(
this._searchQuery,
() => html`
<div slot="append">
<uui-button type="button" @click=${this.#onSearchClear} compact>
<uui-icon name="icon-delete"></uui-icon>
</uui-button>
</div>
`,
)}
</uui-box>
<div slot="actions">
<uui-button label=${this.localize.term('general_cancel')} @click=${this.#close}></uui-button>
<uui-button
label=${this.localize.term('general_submit')}
look="primary"
color="positive"
@click=${this.#submit}></uui-button>
</div>
</umb-body-layout> `;
</uui-input>
<div id="search-divider"></div>
${this.#renderSearchResult()}
`;
}
#renderSearchResult() {
if (this._searchQuery && this._searching === false && this._searchResult.length === 0) {
return this.#renderEmptySearchResult();
}
return html`
${repeat(
this._searchResult,
(item) => item.unique,
(item) => this.#renderMemberItem(item),
)}
`;
}
#renderEmptySearchResult() {
return html`<small>No result for <strong>"${this._searchQuery}"</strong>.</small>`;
}
#renderMemberItem(item: UmbMemberItemModel | UmbMemberDetailModel) {
return html`
<uui-menu-item
label=${item.variants[0].name ?? ''}
selectable
@selected=${() => this.#selectionManager.select(item.unique)}
@deselected=${() => this.#selectionManager.deselect(item.unique)}
?selected=${this.#selectionManager.isSelected(item.unique)}>
<uui-icon slot="icon" name="icon-user"></uui-icon>
</uui-menu-item>
`;
}
static override styles = [
UmbTextStyles,
css`
#search-input {
width: 100%;
}
#search-divider {
width: 100%;
height: 1px;
background-color: var(--uui-color-divider);
margin-top: var(--uui-size-space-5);
margin-bottom: var(--uui-size-space-3);
}
#search-indicator {
margin-left: 7px;
margin-top: 4px;
}
`,
];
}
export default UmbMemberPickerModalElement;