diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-builder/workspace/workspace-package-builder.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-builder/workspace/workspace-package-builder.element.ts
index 9dce5a6dca..ccb98189a6 100644
--- a/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-builder/workspace/workspace-package-builder.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-builder/workspace/workspace-package-builder.element.ts
@@ -259,7 +259,7 @@ export class UmbWorkspacePackageBuilderElement extends UmbLitElement {
#renderDataTypeSection() {
return html`
-
+
`;
}
diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.context.ts
new file mode 100644
index 0000000000..2f91e61fea
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.context.ts
@@ -0,0 +1,10 @@
+import { UmbPickerContext } from '@umbraco-cms/backoffice/picker';
+import { UmbDataTypeRepository } from '../../repository/data-type.repository';
+import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
+import { UMB_DATA_TYPE_PICKER_MODAL } from '@umbraco-cms/backoffice/modal';
+
+export class UmbDataTypePickerContext extends UmbPickerContext {
+ constructor(host: UmbControllerHostElement) {
+ super(host, 'Umb.Repository.DataType', UMB_DATA_TYPE_PICKER_MODAL);
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.element.ts
new file mode 100644
index 0000000000..126c0d97f5
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.element.ts
@@ -0,0 +1,128 @@
+import { css, html } from 'lit';
+import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
+import { customElement, property, state } from 'lit/decorators.js';
+import { FormControlMixin } from '@umbraco-ui/uui-base/lib/mixins';
+import { UmbDataTypePickerContext } from './data-type-input.context';
+import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
+import type { DataTypeItemResponseModel } from '@umbraco-cms/backoffice/backend-api';
+import { UMB_DATA_TYPE_PICKER_MODAL } from '@umbraco-cms/backoffice/modal';
+
+@customElement('umb-data-type-input')
+export class UmbDataTypeInputElement extends FormControlMixin(UmbLitElement) {
+ static styles = [
+ UUITextStyles,
+ css`
+ #add-button {
+ width: 100%;
+ }
+ `,
+ ];
+ /**
+ * This is a minimum amount of selected items in this input.
+ * @type {number}
+ * @attr
+ * @default undefined
+ */
+ @property({ type: Number })
+ min?: number;
+
+ /**
+ * Min validation message.
+ * @type {boolean}
+ * @attr
+ * @default
+ */
+ @property({ type: String, attribute: 'min-message' })
+ minMessage = 'This field need more items';
+
+ /**
+ * This is a maximum amount of selected items in this input.
+ * @type {number}
+ * @attr
+ * @default undefined
+ */
+ @property({ type: Number })
+ max?: number;
+
+ /**
+ * Max validation message.
+ * @type {boolean}
+ * @attr
+ * @default
+ */
+ @property({ type: String, attribute: 'min-message' })
+ maxMessage = 'This field exceeds the allowed amount of items';
+
+ private _selectedIds: Array = [];
+ public get selectedIds(): Array {
+ return this._selectedIds;
+ }
+ public set selectedIds(ids: Array) {
+ this._selectedIds = ids;
+ super.value = ids.join(',');
+ }
+
+ @property()
+ public set value(idsString: string) {
+ if (idsString !== this._value) {
+ this.selectedIds = idsString.split(/[ ,]+/);
+ }
+ }
+
+ @state()
+ private _items?: Array;
+
+ #pickerContext = new UmbDataTypePickerContext(this);
+
+ constructor() {
+ super();
+
+ this.addValidator(
+ 'rangeUnderflow',
+ () => this.minMessage,
+ () => !!this.min && this._selectedIds.length < this.min
+ );
+
+ this.addValidator(
+ 'rangeOverflow',
+ () => this.maxMessage,
+ () => !!this.max && this._selectedIds.length > this.max
+ );
+
+ this.observe(this.#pickerContext.selection, (selection) => (this.selectedIds = selection));
+ //this.observe(this.#pickerContext.items, (items) => (this._items = items));
+ }
+
+ protected getFormElement() {
+ return undefined;
+ }
+
+ render() {
+ return html`
+ ${this._items?.map((item) => this._renderItem(item))}
+ this.#pickerContext.openPicker()} label="open"
+ >Add
+ `;
+ }
+
+ private _renderItem(item: DataTypeItemResponseModel) {
+ return html`
+
+
+ this.#pickerContext.removeItem(item.id)} label="Remove Data Type ${item.name}"
+ >Remove
+
+
+ `;
+ }
+}
+
+export default UmbDataTypeInputElement;
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'umb-data-type-input': UmbDataTypeInputElement;
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/index.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/index.ts
new file mode 100644
index 0000000000..c076c5f9a3
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/index.ts
@@ -0,0 +1 @@
+import './data-type-input/data-type-input.element';
diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/index.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/index.ts
new file mode 100644
index 0000000000..758f322450
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/index.ts
@@ -0,0 +1 @@
+import './components';
diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/manifests.ts
index fac58d2628..28e0f18938 100644
--- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/manifests.ts
+++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/manifests.ts
@@ -3,6 +3,7 @@ import { manifests as repositoryManifests } from './repository/manifests';
import { manifests as menuItemManifests } from './menu-item/manifests';
import { manifests as treeManifests } from './tree/manifests';
import { manifests as workspaceManifests } from './workspace/manifests';
+import { manifests as modalManifests } from './modal/manifests';
export const manifests = [
...entityActions,
@@ -10,4 +11,5 @@ export const manifests = [
...menuItemManifests,
...treeManifests,
...workspaceManifests,
+ ...modalManifests,
];
diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/modal/data-type-picker/data-type-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/modal/data-type-picker/data-type-picker-modal.element.ts
new file mode 100644
index 0000000000..dd4d6d3a25
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/modal/data-type-picker/data-type-picker-modal.element.ts
@@ -0,0 +1,77 @@
+import { css, html } from 'lit';
+import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
+import { customElement, property, state } from 'lit/decorators.js';
+import type { UmbTreeElement } from '../../../../shared/components/tree/tree.element';
+import {
+ UmbDocumentTypePickerModalData,
+ UmbDocumentTypePickerModalResult,
+ UmbModalHandler,
+} from '@umbraco-cms/backoffice/modal';
+import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
+
+// TODO: make use of UmbPickerLayoutBase
+@customElement('umb-data-type-picker-modal')
+export class UmbDataTypePickerModalElement extends UmbLitElement {
+ static styles = [UUITextStyles, css``];
+
+ @property({ attribute: false })
+ modalHandler?: UmbModalHandler;
+
+ @property({ type: Object, attribute: false })
+ data?: UmbDocumentTypePickerModalData;
+
+ @state()
+ _selection: Array = [];
+
+ @state()
+ _multiple = true;
+
+ connectedCallback() {
+ super.connectedCallback();
+ this._selection = this.data?.selection ?? [];
+ this._multiple = this.data?.multiple ?? true;
+ }
+
+ private _handleSelectionChange(e: CustomEvent) {
+ e.stopPropagation();
+ const element = e.target as UmbTreeElement;
+ //TODO: Should multiple property be implemented here or be passed down into umb-tree?
+ this._selection = this._multiple ? element.selection : [element.selection[element.selection.length - 1]];
+ }
+
+ private _submit() {
+ this.modalHandler?.submit({ selection: this._selection });
+ }
+
+ private _close() {
+ this.modalHandler?.reject();
+ }
+
+ render() {
+ return html`
+
+
+
+
+
+
+
+
+
+
+
+ `;
+ }
+}
+
+export default UmbDataTypePickerModalElement;
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'umb-data-type-picker-modal': UmbDataTypePickerModalElement;
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/modal/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/modal/manifests.ts
new file mode 100644
index 0000000000..838aba346b
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/modal/manifests.ts
@@ -0,0 +1,12 @@
+import type { ManifestModal } from '@umbraco-cms/backoffice/extensions-registry';
+
+const modals: Array = [
+ {
+ type: 'modal',
+ alias: 'Umb.Modal.DataTypePicker',
+ name: 'Data Type Picker Modal',
+ loader: () => import('./data-type-picker/data-type-picker-modal.element'),
+ },
+];
+
+export const manifests = [...modals];
diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/index.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/index.ts
index a578c12d5c..c86644f739 100644
--- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/index.ts
+++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/index.ts
@@ -11,6 +11,8 @@ import { manifests as logviewerManifests } from './logviewer/manifests';
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extensions-api';
import { ManifestTypes } from '@umbraco-cms/backoffice/extensions-registry';
+import './data-types/components';
+
export const manifests = [
...settingsSectionManifests,
...settingsMenuManifests,