diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/collection/views/grid/media-grid-collection-view.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/collection/views/grid/media-grid-collection-view.element.ts index 23e31aa5a0..db2b147848 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/collection/views/grid/media-grid-collection-view.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/collection/views/grid/media-grid-collection-view.element.ts @@ -153,6 +153,13 @@ export class UmbMediaGridCollectionViewElement extends UmbLitElement { grid-auto-rows: 200px; gap: var(--uui-size-space-5); } + + img { + background-image: url('data:image/svg+xml;charset=utf-8,'); + background-size: 10px 10px; + background-repeat: repeat; + } + umb-icon { font-size: var(--uui-size-8); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.context.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.context.ts index 4082e820eb..fc06cf3dc2 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.context.ts @@ -1,11 +1,11 @@ -import { UMB_MEDIA_PICKER_MODAL, type UmbMediaCardItemModel } from '../../modals/index.js'; +import { + UMB_MEDIA_PICKER_MODAL, + type UmbMediaPickerModalData, + type UmbMediaPickerModalValue, + type UmbMediaCardItemModel, +} from '../../modals/index.js'; import { UMB_MEDIA_ITEM_REPOSITORY_ALIAS } from '../../repository/index.js'; import type { UmbMediaItemModel } from '../../repository/item/types.js'; -import type { UmbMediaTreeItemModel } from '../../tree/index.js'; -import type { - UmbMediaTreePickerModalData, - UmbMediaTreePickerModalValue, -} from '../../tree/media-tree-picker-modal.token.js'; import { UmbPickerInputContext } from '@umbraco-cms/backoffice/picker-input'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api'; @@ -14,9 +14,9 @@ import { ImageCropModeModel } from '@umbraco-cms/backoffice/external/backend-api export class UmbMediaPickerContext extends UmbPickerInputContext< UmbMediaItemModel, - UmbMediaTreeItemModel, - UmbMediaTreePickerModalData, - UmbMediaTreePickerModalValue + UmbMediaItemModel, + UmbMediaPickerModalData, + UmbMediaPickerModalValue > { #imagingRepository: UmbImagingRepository; @@ -40,14 +40,7 @@ export class UmbMediaPickerContext extends UmbPickerInputContext< this.#cardItems.setValue( selectedItems.map((item) => { const url = data?.find((x) => x.unique === item.unique)?.url; - return { - icon: item.mediaType.icon, - name: item.name, - unique: item.unique, - isTrashed: item.isTrashed, - entityType: item.entityType, - url, - }; + return { ...item, url }; }), ); }); diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.element.ts index 70e3e0c948..b86839a893 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.element.ts @@ -8,7 +8,6 @@ import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { UmbModalRouteRegistrationController, UMB_WORKSPACE_MODAL } from '@umbraco-cms/backoffice/modal'; import { UmbSorterController } from '@umbraco-cms/backoffice/sorter'; import { UUIFormControlMixin } from '@umbraco-cms/backoffice/external/uui'; -import type { UmbUploadableFileModel } from '@umbraco-cms/backoffice/media'; @customElement('umb-input-media') export class UmbInputMediaElement extends UUIFormControlMixin(UmbLitElement, '') { @@ -22,9 +21,10 @@ export class UmbInputMediaElement extends UUIFormControlMixin(UmbLitElement, '') identifier: 'Umb.SorterIdentifier.InputMedia', itemSelector: 'uui-card-media', containerSelector: '.container', + /** TODO: This component probably needs some grid-like logic for resolve placement... [LI] */ + resolvePlacement: () => false, onChange: ({ model }) => { this.selection = model; - this.dispatchEvent(new UmbChangeEvent()); }, }); @@ -89,6 +89,12 @@ export class UmbInputMediaElement extends UUIFormControlMixin(UmbLitElement, '') @property({ type: Boolean }) showOpenButton?: boolean; + @property({ type: String }) + startNode = ''; + + @property({ type: Boolean }) + multiple = false; + @property() public set value(idsString: string) { // Its with full purpose we don't call super.value, as thats being handled by the observation of the context selection. @@ -99,10 +105,10 @@ export class UmbInputMediaElement extends UUIFormControlMixin(UmbLitElement, '') } @state() - private _editMediaPath = ''; + protected editMediaPath = ''; @state() - private _items?: Array; + protected items?: Array; #pickerContext = new UmbMediaPickerContext(this); @@ -115,12 +121,12 @@ export class UmbInputMediaElement extends UUIFormControlMixin(UmbLitElement, '') return { data: { entityType: 'media', preset: {} } }; }) .observeRouteBuilder((routeBuilder) => { - this._editMediaPath = routeBuilder({}); + this.editMediaPath = routeBuilder({}); }); this.observe(this.#pickerContext.selection, (selection) => (this.value = selection.join(','))); this.observe(this.#pickerContext.cardItems, (cardItems) => { - this._items = cardItems; + this.items = cardItems; }); this.addValidator( @@ -149,43 +155,31 @@ export class UmbInputMediaElement extends UUIFormControlMixin(UmbLitElement, '') #openPicker() { this.#pickerContext.openPicker({ - hideTreeRoot: true, + multiple: this.multiple, + startNode: this.startNode, pickableFilter: this.#pickableFilter, }); } - async #onUploadCompleted(e: CustomEvent) { - const completed = e.detail?.completed as Array; - const uploaded = completed.map((file) => file.unique); - - this.selection = [...this.selection, ...uploaded]; - this.dispatchEvent(new UmbChangeEvent()); + protected onRemove(item: UmbMediaCardItemModel) { + this.#pickerContext.requestRemoveItem(item.unique); } render() { - return html`${this.#renderDropzone()} -
${this.#renderItems()} ${this.#renderAddButton()}
`; - } - - #renderDropzone() { - if (this._items && this._items.length >= this.max) return; - return html``; + return html`
${this.#renderItems()} ${this.#renderAddButton()}
`; } #renderItems() { - if (!this._items?.length) return; + if (!this.items?.length) return; return html`${repeat( - this._items, + this.items, (item) => item.unique, - (item) => this.#renderItem(item), + (item) => this.renderItem(item), )}`; } #renderAddButton() { - if (this._items && this.max && this._items.length >= this.max) return; + if ((this.items && this.max && this.items.length >= this.max) || (this.items?.length && !this.multiple)) return; return html` + ${item.url ? html`${item.name}` - : html``} - ${this.#renderIsTrashed(item)} + : html``} + ${this.renderIsTrashed(item)} - ${this.#renderOpenButton(item)} - - - this.#pickerContext.requestRemoveItem(item.unique)} - label="Remove media ${item.name}"> + @click=${() => this.onRemove(item)}> @@ -221,7 +214,7 @@ export class UmbInputMediaElement extends UUIFormControlMixin(UmbLitElement, '') `; } - #renderIsTrashed(item: UmbMediaCardItemModel) { + protected renderIsTrashed(item: UmbMediaCardItemModel) { if (!item.isTrashed) return; return html` @@ -230,18 +223,6 @@ export class UmbInputMediaElement extends UUIFormControlMixin(UmbLitElement, '') `; } - #renderOpenButton(item: UmbMediaCardItemModel) { - if (!this.showOpenButton) return; - return html` - - - - `; - } - static styles = [ css` :host { @@ -250,8 +231,8 @@ export class UmbInputMediaElement extends UUIFormControlMixin(UmbLitElement, '') .container { display: grid; gap: var(--uui-size-space-3); - grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); - grid-template-rows: repeat(auto-fill, minmax(160px, 1fr)); + grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); + grid-auto-rows: 150px; } #btn-add { diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts index de83d120a3..1865bc7f66 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts @@ -1,24 +1,39 @@ -import { type UmbMediaItemModel, UmbMediaItemRepository, UmbMediaUrlRepository } from '../../repository/index.js'; +import { UmbMediaItemRepository, UmbMediaUrlRepository } from '../../repository/index.js'; import { UmbMediaTreeRepository } from '../../tree/media-tree.repository.js'; import { UMB_MEDIA_ROOT_ENTITY_TYPE } from '../../entity.js'; +import type { UmbDropzoneElement } from '../../dropzone/dropzone.element.js'; +import type { UmbMediaItemModel } from '../../repository/index.js'; import type { UmbMediaCardItemModel, UmbMediaPathModel } from './types.js'; import type { UmbMediaPickerFolderPathElement } from './components/media-picker-folder-path.element.js'; import type { UmbMediaPickerModalData, UmbMediaPickerModalValue } from './media-picker-modal.token.js'; -import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal'; -import { UmbImagingRepository } from '@umbraco-cms/backoffice/imaging'; -import { css, html, customElement, state, repeat, ifDefined } from '@umbraco-cms/backoffice/external/lit'; -import type { UUIInputEvent } from '@umbraco-cms/backoffice/external/uui'; +import { css, html, customElement, state, repeat, ifDefined, query } from '@umbraco-cms/backoffice/external/lit'; +import { debounce } from '@umbraco-cms/backoffice/utils'; import { ImageCropModeModel } from '@umbraco-cms/backoffice/external/backend-api'; +import { UmbImagingRepository } from '@umbraco-cms/backoffice/imaging'; +import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal'; +import { UMB_CONTENT_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/content'; +import type { UUIInputEvent } from '@umbraco-cms/backoffice/external/uui'; const root: UmbMediaPathModel = { name: 'Media', unique: null, entityType: UMB_MEDIA_ROOT_ENTITY_TYPE }; @customElement('umb-media-picker-modal') -export class UmbMediaPickerModalElement extends UmbModalBaseElement { +export class UmbMediaPickerModalElement extends UmbModalBaseElement< + UmbMediaPickerModalData, + UmbMediaPickerModalValue +> { #mediaTreeRepository = new UmbMediaTreeRepository(this); // used to get file structure #mediaUrlRepository = new UmbMediaUrlRepository(this); // used to get urls #mediaItemRepository = new UmbMediaItemRepository(this); // used to search #imagingRepository = new UmbImagingRepository(this); // used to get image renditions + #dataType?: { unique: string }; + + @state() + private _filter: (item: UmbMediaCardItemModel) => boolean = () => true; + + @state() + private _selectableFilter: (item: UmbMediaCardItemModel) => boolean = () => true; + #mediaItemsCurrentFolder: Array = []; @state() @@ -33,9 +48,25 @@ export class UmbMediaPickerModalElement extends UmbModalBaseElement { + this.observe(context.dataType, (dataType) => { + this.#dataType = dataType; + }); + }); + } + async connectedCallback(): Promise { super.connectedCallback(); + if (this.data?.filter) this._filter = this.data?.filter; + if (this.data?.pickableFilter) this._selectableFilter = this.data?.pickableFilter; + if (this.data?.startNode) { const { data } = await this.#mediaItemRepository.requestItems([this.data.startNode]); @@ -53,6 +84,7 @@ export class UmbMediaPickerModalElement extends UmbModalBaseElement { - const url = data?.find((media) => media.unique === item.unique)?.url; - return { - name: item.name, - unique: item.unique, - url, - icon: item.mediaType.icon, - entityType: item.entityType, - isTrashed: item.isTrashed, - }; - }); + return items + .map((item): UmbMediaCardItemModel => { + const url = data?.find((media) => media.unique === item.unique)?.url; + return { ...item, url }; + }) + .filter((item) => this._filter(item)); } #onOpen(item: UmbMediaCardItemModel) { @@ -129,9 +156,13 @@ export class UmbMediaPickerModalElement extends UmbModalBaseElement found.isTrashed === false)); } + #debouncedSearch = debounce(() => { + this.#filterMediaItems(); + }, 500); + #onSearch(e: UUIInputEvent) { this._searchQuery = (e.target.value as string).toLocaleLowerCase(); - this.#filterMediaItems(); + this.#debouncedSearch(); } #onPathChange(e: CustomEvent) { @@ -176,37 +207,43 @@ export class UmbMediaPickerModalElement extends UmbModalBaseElement - - `; + `; } - // Where should this be placed, without it looking terrible? - // (this._searchOnlyThisFolder = !this._searchOnlyThisFolder)} label=${this.localize.term('general_excludeFromSubFolders')}> - #renderCard(item: UmbMediaCardItemModel) { + const disabled = !this._selectableFilter(item); return html` this.#onOpen(item)} @selected=${() => this.#onSelected(item)} @deselected=${() => this.#onDeselected(item)} ?selected=${this.value?.selection?.find((value) => value === item.unique)} - selectable> + ?selectable=${!disabled}> ${item.url ? html`${ifDefined(item.name)}` - : html``} + : html``} `; } @@ -241,8 +278,8 @@ export class UmbMediaPickerModalElement extends UmbModalBaseElement { startNode?: string | null; multiple?: boolean; + pickableFilter?: (item: ItemType) => boolean; + filter?: (item: ItemType) => boolean; } export type UmbMediaPickerModalValue = { selection: string[]; }; -export const UMB_MEDIA_PICKER_MODAL = new UmbModalToken( +export const UMB_MEDIA_PICKER_MODAL = new UmbModalToken, UmbMediaPickerModalValue>( 'Umb.Modal.MediaPicker', { modal: { diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/types.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/types.ts index 04c244d93c..9209e33c72 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/types.ts @@ -1,12 +1,7 @@ -import type { UmbMediaEntityType } from '../../entity.js'; +import type { UmbMediaItemModel } from '../../repository/index.js'; import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity'; -export interface UmbMediaCardItemModel { - name: string; - unique: string; - entityType: UmbMediaEntityType; - isTrashed: boolean; - icon: string; +export interface UmbMediaCardItemModel extends UmbMediaItemModel { url?: string; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-entity-picker/property-editor-ui-media-entity-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-entity-picker/property-editor-ui-media-entity-picker.element.ts index 2653a68a76..6e6bbafd45 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-entity-picker/property-editor-ui-media-entity-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-entity-picker/property-editor-ui-media-entity-picker.element.ts @@ -33,7 +33,7 @@ export class UmbPropertyEditorUIMediaEntityPickerElement extends UmbLitElement i return undefined; } - #onChange(event: { target: UmbInputMediaElement }) { + #onChange(event: CustomEvent & { target: UmbInputMediaElement }) { this.value = event.target.selection?.join(',') ?? null; this.dispatchEvent(new UmbPropertyValueChangeEvent()); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/components/index.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/components/index.ts new file mode 100644 index 0000000000..9044e60dbf --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/components/index.ts @@ -0,0 +1 @@ +export * from './input-rich-media/index.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/components/input-rich-media/index.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/components/input-rich-media/index.ts new file mode 100644 index 0000000000..0c7c12b80e --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/components/input-rich-media/index.ts @@ -0,0 +1 @@ +export * from './input-rich-media.element.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/components/input-rich-media/input-rich-media.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/components/input-rich-media/input-rich-media.element.ts new file mode 100644 index 0000000000..b933120f23 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/components/input-rich-media/input-rich-media.element.ts @@ -0,0 +1,69 @@ +import type { UmbCropModel } from '../../index.js'; +import type { UmbMediaCardItemModel } from '../../../../modals/index.js'; +import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; +import { customElement, html, ifDefined, property } from '@umbraco-cms/backoffice/external/lit'; +import { UmbInputMediaElement } from '@umbraco-cms/backoffice/media'; +import type { UmbUploadableFileModel } from '@umbraco-cms/backoffice/media'; + +const elementName = 'umb-input-rich-media'; +@customElement(elementName) +export class UmbInputRichMediaElement extends UmbInputMediaElement { + @property({ type: Boolean }) + focalPointEnabled = false; + + @property({ type: Array }) + crops?: Array; + + async #onUploadCompleted(e: CustomEvent) { + const completed = e.detail?.completed as Array; + const uploaded = completed.map((file) => file.unique); + + this.selection = [...this.selection, ...uploaded]; + this.dispatchEvent(new UmbChangeEvent()); + } + + render() { + return html`${this.#renderDropzone()} ${super.render()}`; + } + + #renderDropzone() { + if (this.items && this.items.length >= this.max) return; + return html``; + } + + protected renderItem(item: UmbMediaCardItemModel) { + return html` + { + alert('open media crops modal'); + }}> + ${item.url + ? html`${item.name}` + : html``} + ${this.renderIsTrashed(item)} + + + + + this.onRemove(item)}> + + + + + `; + } +} + +export { UmbInputRichMediaElement as element }; + +declare global { + interface HTMLElementTagNameMap { + [elementName]: UmbInputRichMediaElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/index.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/index.ts index 54a8835b52..e8c480b60c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/index.ts @@ -5,5 +5,12 @@ export type UmbMediaPickerPropertyValue = { mediaKey: string; mediaTypeAlias: string; focalPoint: { left: number; top: number } | null; - crops: Array<{ alias: string; width: number; height: number }>; + crops: Array; }; + +export interface UmbCropModel { + label: string; + alias: string; + width: number; + height: number; +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/property-editor-ui-media-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/property-editor-ui-media-picker.element.ts index f6e7749aab..6a98cca0e5 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/property-editor-ui-media-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/property-editor-ui-media-picker.element.ts @@ -1,18 +1,19 @@ -import type { UmbInputMediaElement } from '../../components/input-media/input-media.element.js'; -import '../../components/input-media/input-media.element.js'; -import type { UmbMediaPickerPropertyValue } from './index.js'; -import { html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit'; -import { - UmbPropertyValueChangeEvent, - type UmbPropertyEditorConfigCollection, -} from '@umbraco-cms/backoffice/property-editor'; -import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry'; -import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; +import type { UmbInputRichMediaElement } from './components/input-rich-media/input-rich-media.element.js'; +import type { UmbCropModel, UmbMediaPickerPropertyValue } from './index.js'; +import { customElement, html, property, state } from '@umbraco-cms/backoffice/external/lit'; import { UmbId } from '@umbraco-cms/backoffice/id'; +import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; +import { UmbPropertyValueChangeEvent } from '@umbraco-cms/backoffice/property-editor'; +import type { NumberRangeValueType } from '@umbraco-cms/backoffice/models'; +import type { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor'; +import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry'; + +import './components/input-rich-media/input-rich-media.element.js'; /** * @element umb-property-editor-ui-media-picker */ + @customElement('umb-property-editor-ui-media-picker') export class UmbPropertyEditorUIMediaPickerElement extends UmbLitElement implements UmbPropertyEditorUiElement { @property({ attribute: false }) @@ -21,36 +22,57 @@ export class UmbPropertyEditorUIMediaPickerElement extends UmbLitElement impleme this._items = this.value ? this.value.map((x) => x.mediaKey) : []; } //TODO: Add support for document specific crops. The server side already supports this. - public get value() { return this.#value; } + @state() + private _startNode: string = ''; + + @state() + private _focalPointEnabled: boolean = false; + + @state() + private _crops: Array = []; + + @state() + private _allowedMediaTypes: Array = []; + public set config(config: UmbPropertyEditorConfigCollection | undefined) { - const validationLimit = config?.getByAlias('validationLimit'); - if (!validationLimit) return; + if (!config) return; - const minMax: Record = validationLimit.value as any; + this._multiple = Boolean(config.getValueByAlias('multiple')); + this._startNode = config.getValueByAlias('startNodeId') ?? ''; + this._focalPointEnabled = Boolean(config.getValueByAlias('enableFocalPoint')); + this._crops = config?.getValueByAlias>('crops') ?? []; - this._limitMin = minMax.min ?? 0; - this._limitMax = minMax.max ?? Infinity; + const filter = config.getValueByAlias('filter'); + this._allowedMediaTypes = filter?.split(',') ?? []; + + const minMax = config.getValueByAlias('validationLimit'); + this._limitMin = minMax?.min ?? 0; + this._limitMax = minMax?.max ?? Infinity; } public get config() { return undefined; } + @state() + private _multiple: boolean = false; + @state() _items: Array = []; @state() private _limitMin: number = 0; + @state() private _limitMax: number = Infinity; #value: Array = []; - #onChange(event: CustomEvent) { - const selection = (event.target as UmbInputMediaElement).selection; + #onChange(event: CustomEvent & { target: UmbInputRichMediaElement }) { + const selection = event.target.selection; const result = selection.map((mediaKey) => { return { @@ -69,12 +91,17 @@ export class UmbPropertyEditorUIMediaPickerElement extends UmbLitElement impleme render() { return html` - - + `; } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/tree/media-tree.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/tree/media-tree.repository.ts index 8b3478a9ed..d9dbf394ea 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/tree/media-tree.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/tree/media-tree.repository.ts @@ -1,13 +1,23 @@ import { UMB_MEDIA_ROOT_ENTITY_TYPE } from '../entity.js'; import { UmbMediaTreeServerDataSource } from './media-tree.server.data-source.js'; -import type { UmbMediaTreeItemModel, UmbMediaTreeRootModel } from './types.js'; +import type { + UmbMediaTreeChildrenOfRequestArgs, + UmbMediaTreeItemModel, + UmbMediaTreeRootItemsRequestArgs, + UmbMediaTreeRootModel, +} from './types.js'; import { UMB_MEDIA_TREE_STORE_CONTEXT } from './media-tree.store.js'; import { UmbTreeRepositoryBase } from '@umbraco-cms/backoffice/tree'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import type { UmbApi } from '@umbraco-cms/backoffice/extension-api'; export class UmbMediaTreeRepository - extends UmbTreeRepositoryBase + extends UmbTreeRepositoryBase< + UmbMediaTreeItemModel, + UmbMediaTreeRootModel, + UmbMediaTreeRootItemsRequestArgs, + UmbMediaTreeChildrenOfRequestArgs + > implements UmbApi { constructor(host: UmbControllerHost) { diff --git a/src/Umbraco.Web.UI.Client/src/packages/packages/package-builder/workspace/workspace-package-builder.element.ts b/src/Umbraco.Web.UI.Client/src/packages/packages/package-builder/workspace/workspace-package-builder.element.ts index b388e2e0ae..e4809f0ad0 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/packages/package-builder/workspace/workspace-package-builder.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/packages/package-builder/workspace/workspace-package-builder.element.ts @@ -229,7 +229,10 @@ export class UmbWorkspacePackageBuilderElement extends UmbLitElement { return html`
- +