Merge remote-tracking branch 'origin' into v14/chore/check-paths-in-dist-cms

This commit is contained in:
Jacob Overgaard
2024-06-26 11:37:30 +02:00
115 changed files with 1295 additions and 959 deletions

View File

@@ -9,21 +9,24 @@ export class UmbInstallerUserElement extends UmbLitElement {
@state()
private _userFormData?: { name: string; password: string; email: string; subscribeToNewsletter: boolean };
private _installerContext?: UmbInstallerContext;
@state()
private _minimumPasswordLength = 10;
#installerContext?: UmbInstallerContext;
constructor() {
super();
this.consumeContext(UMB_INSTALLER_CONTEXT, (installerContext) => {
this._installerContext = installerContext;
this.#installerContext = installerContext;
this._observeInstallerData();
});
}
private _observeInstallerData() {
if (!this._installerContext) return;
if (!this.#installerContext) return;
this.observe(this._installerContext.data, ({ user }) => {
this.observe(this.#installerContext.data, ({ user }) => {
this._userFormData = {
name: user.name,
password: user.password,
@@ -31,6 +34,10 @@ export class UmbInstallerUserElement extends UmbLitElement {
subscribeToNewsletter: user.subscribeToNewsletter ?? false,
};
});
this.observe(this.#installerContext.settings, (settings) => {
this._minimumPasswordLength = settings?.user.minCharLength ?? this._minimumPasswordLength;
});
}
private _handleSubmit = (e: SubmitEvent) => {
@@ -48,8 +55,8 @@ export class UmbInstallerUserElement extends UmbLitElement {
const email = formData.get('email') as string;
const subscribeToNewsletter = formData.has('subscribeToNewsletter');
this._installerContext?.appendData({ user: { name, password, email, subscribeToNewsletter } });
this._installerContext?.nextStep();
this.#installerContext?.appendData({ user: { name, password, email, subscribeToNewsletter } });
this.#installerContext?.nextStep();
};
override render() {
@@ -87,6 +94,7 @@ export class UmbInstallerUserElement extends UmbLitElement {
id="password"
name="password"
label="password"
minlength=${this._minimumPasswordLength}
.value=${this._userFormData?.password}
required
required-message="Password is required"></uui-input-password>

File diff suppressed because it is too large Load Diff

View File

@@ -8566,6 +8566,29 @@ providerName
});
}
/**
* @returns unknown OK
* @throws ApiError
*/
public static getUserByIdCalculateStartNodes(data: UserData['payloads']['GetUserByIdCalculateStartNodes']): CancelablePromise<UserData['responses']['GetUserByIdCalculateStartNodes']> {
const {
id
} = data;
return __request(OpenAPI, {
method: 'GET',
url: '/umbraco/management/api/v1/user/{id}/calculate-start-nodes',
path: {
id
},
errors: {
401: `The resource is protected and requires an authentication token`,
403: `The authenticated user do not have access to this resource`,
404: `Not Found`,
},
});
}
/**
* @returns string OK
* @throws ApiError

View File

@@ -76,7 +76,7 @@ class UmbUserMockDB extends UmbEntityMockDbBase<UmbMockUserModel> {
hasAccessToSensitiveData: true,
avatarUrls: [],
hasAccessToAllLanguages: true,
languageIsoCode: firstUser.languageIsoCode,
languageIsoCode: firstUser.languageIsoCode || null,
languages: [],
documentStartNodeIds: firstUser.documentStartNodeIds,
mediaStartNodeIds: firstUser.mediaStartNodeIds,

View File

@@ -1,11 +1,10 @@
import type { UmbBlockGridTypeAreaType } from '../../../types.js';
import type { UmbPropertyDatasetContext } from '@umbraco-cms/backoffice/property';
import { UMB_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/property';
import {
type UmbInvariantDatasetWorkspaceContext,
type UmbRoutableWorkspaceContext,
type UmbWorkspaceContext,
UmbWorkspaceRouteManager,
import type {
UmbInvariantDatasetWorkspaceContext,
UmbRoutableWorkspaceContext,
UmbWorkspaceContext,
} from '@umbraco-cms/backoffice/workspace';
import {
UmbSubmittableWorkspaceContextBase,
@@ -69,7 +68,6 @@ export class UmbBlockGridAreaTypeWorkspaceContext
if (value) {
const blockTypeData = value.find((x: UmbBlockGridTypeAreaType) => x.key === unique);
if (blockTypeData) {
console.log(blockTypeData);
this.#data.setValue(blockTypeData);
return;
}

View File

@@ -30,8 +30,8 @@ export class UmbBlockGridEntryContext
implements UmbBlockGridScalableContext
{
//
readonly columnSpan = this._layout.asObservablePart((x) => x?.columnSpan);
readonly rowSpan = this._layout.asObservablePart((x) => x?.rowSpan);
readonly columnSpan = this._layout.asObservablePart((x) => x ? x.columnSpan ?? null : undefined);
readonly rowSpan = this._layout.asObservablePart((x) => x ? x.rowSpan ?? null : undefined);
readonly layoutAreas = this._layout.asObservablePart((x) => x?.areas);
readonly columnSpanOptions = this._blockType.asObservablePart((x) => x?.columnSpanOptions ?? []);
readonly areaTypeGridColumns = this._blockType.asObservablePart((x) => x?.areaGridColumns);
@@ -208,7 +208,7 @@ export class UmbBlockGridEntryContext
this.observe(
observeMultiple([this.columnSpan, this.relevantColumnSpanOptions, this._entries.layoutColumns]),
([columnSpan, relevantColumnSpanOptions, layoutColumns]) => {
if (!layoutColumns) return;
if (!layoutColumns || columnSpan === undefined) return;
const newColumnSpan = this.#calcColumnSpan(
columnSpan ?? layoutColumns,
relevantColumnSpanOptions,
@@ -230,16 +230,15 @@ export class UmbBlockGridEntryContext
this.observe(
observeMultiple([this.minMaxRowSpan, this.rowSpan]),
([minMax, rowSpan]) => {
if (minMax) {
const newRowSpan = Math.max(minMax[0], Math.min(rowSpan ?? 1, minMax[1]));
if (newRowSpan !== rowSpan) {
const layoutValue = this._layout.getValue();
if (!layoutValue) return;
this._layout.setValue({
...layoutValue,
rowSpan: newRowSpan,
});
}
if (!minMax || rowSpan === undefined) return;
const newRowSpan = Math.max(minMax[0], Math.min(rowSpan ?? 1, minMax[1]));
if (newRowSpan !== rowSpan) {
const layoutValue = this._layout.getValue();
if (!layoutValue) return;
this._layout.setValue({
...layoutValue,
rowSpan: newRowSpan,
});
}
},
'observeRowSpanValidation',
@@ -259,10 +258,8 @@ export class UmbBlockGridEntryContext
return newColumnSpan;
}
} else {
// Reset to the layoutColumns.
if (layoutColumns !== columnSpan) {
return layoutColumns;
}
// Fallback to the layoutColumns.
return layoutColumns;
}
return columnSpan;
}

View File

@@ -17,14 +17,13 @@ import {
} from '@umbraco-cms/backoffice/property-editor';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UMB_BLOCK_GRID_TYPE, type UmbBlockGridTypeGroupType } from '@umbraco-cms/backoffice/block-grid';
import { UMB_BLOCK_GRID_TYPE, UMB_BLOCK_GRID_TYPE_WORKSPACE_MODAL, type UmbBlockGridTypeGroupType } from '@umbraco-cms/backoffice/block-grid';
import type { UUIInputEvent } from '@umbraco-cms/backoffice/external/uui';
import {
UMB_PROPERTY_CONTEXT,
UMB_PROPERTY_DATASET_CONTEXT,
type UmbPropertyDatasetContext,
} from '@umbraco-cms/backoffice/property';
import { UMB_WORKSPACE_MODAL } from '@umbraco-cms/backoffice/modal';
import { UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/router';
import { UmbSorterController } from '@umbraco-cms/backoffice/sorter';
@@ -61,8 +60,8 @@ export class UmbPropertyEditorUIBlockGridTypeConfigurationElement
#datasetContext?: UmbPropertyDatasetContext;
#blockTypeWorkspaceModalRegistration?: UmbModalRouteRegistrationController<
typeof UMB_WORKSPACE_MODAL.DATA,
typeof UMB_WORKSPACE_MODAL.VALUE
typeof UMB_BLOCK_GRID_TYPE_WORKSPACE_MODAL.DATA,
typeof UMB_BLOCK_GRID_TYPE_WORKSPACE_MODAL.VALUE
>;
#value: Array<UmbBlockTypeWithGroupKey> = [];
@@ -105,11 +104,8 @@ export class UmbPropertyEditorUIBlockGridTypeConfigurationElement
this.#observeBlockGroups();
});
this.#blockTypeWorkspaceModalRegistration = new UmbModalRouteRegistrationController(this, UMB_WORKSPACE_MODAL)
this.#blockTypeWorkspaceModalRegistration = new UmbModalRouteRegistrationController(this, UMB_BLOCK_GRID_TYPE_WORKSPACE_MODAL)
.addAdditionalPath(UMB_BLOCK_GRID_TYPE)
.onSetup(() => {
return { data: { entityType: UMB_BLOCK_GRID_TYPE, preset: {} }, modal: { size: 'large' } };
})
.observeRouteBuilder((routeBuilder) => {
const newpath = routeBuilder({});
this._workspacePath = newpath;

View File

@@ -0,0 +1,17 @@
import { UMB_BLOCK_GRID_TYPE, type UmbBlockGridTypeModel } from '../types.js';
import type { UmbWorkspaceModalData, UmbWorkspaceModalValue } from '@umbraco-cms/backoffice/modal';
import { UmbModalToken } from '@umbraco-cms/backoffice/modal';
export type UmbBlockGridTypeWorkspaceData = UmbWorkspaceModalData<UmbBlockGridTypeModel>;
export const UMB_BLOCK_GRID_TYPE_WORKSPACE_MODAL = new UmbModalToken<UmbBlockGridTypeWorkspaceData, UmbWorkspaceModalValue>(
'Umb.Modal.Workspace',
{
modal: {
type: 'sidebar',
size: 'large',
},
data: { entityType: UMB_BLOCK_GRID_TYPE, preset: {allowAtRoot: true} },
},
// Recast the type, so the entityType data prop is not required:
) as UmbModalToken<Omit<UmbWorkspaceModalData, 'entityType' | 'preset'>, UmbWorkspaceModalValue>;

View File

@@ -18,6 +18,6 @@ export const UMB_BLOCK_GRID_WORKSPACE_MODAL = new UmbModalToken<UmbBlockGridWork
size: 'medium',
},
data: { entityType: 'block', preset: {}, originData: { index: -1, parentUnique: null } },
// Recast the type, so the entityType data prop is not required:
},
// Recast the type, so the entityType data prop is not required:
) as UmbModalToken<Omit<UmbWorkspaceModalData, 'entityType'>, UmbWorkspaceModalValue>;

View File

@@ -1,2 +1,3 @@
export const UMB_BLOCK_GRID_TYPE_WORKSPACE_ALIAS = 'Umb.Workspace.BlockGridType';
export * from './block-grid-workspace.modal-token.js';
export * from './block-grid-type-workspace.modal-token.js';

View File

@@ -16,6 +16,6 @@ export const UMB_BLOCK_LIST_WORKSPACE_MODAL = new UmbModalToken<UmbBlockListWork
size: 'medium',
},
data: { entityType: 'block', preset: {}, originData: { index: -1 } },
// Recast the type, so the entityType data prop is not required:
},
// Recast the type, so the entityType data prop is not required:
) as UmbModalToken<Omit<UmbWorkspaceModalData, 'entityType'>, UmbWorkspaceModalValue>;

View File

@@ -12,6 +12,6 @@ export const UMB_BLOCK_RTE_WORKSPACE_MODAL = new UmbModalToken<UmbBlockRteWorksp
size: 'medium',
},
data: { entityType: 'block', preset: {}, originData: {} },
// Recast the type, so the entityType data prop is not required:
},
// Recast the type, so the entityType data prop is not required:
) as UmbModalToken<Omit<UmbWorkspaceModalData, 'entityType'>, UmbWorkspaceModalValue>;

View File

@@ -1,5 +1,3 @@
import type { UmbBlockTypeCardElement } from '../block-type-card/index.js';
import type { UmbBlockTypeBaseModel, UmbBlockTypeWithGroupKey } from '../../types.js';
import { umbConfirmModal } from '@umbraco-cms/backoffice/modal';
import { UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/router';
import { css, html, customElement, property, state, repeat } from '@umbraco-cms/backoffice/external/lit';
@@ -12,6 +10,8 @@ import {
UMB_DOCUMENT_TYPE_PICKER_MODAL,
} from '@umbraco-cms/backoffice/document-type';
import { UmbSorterController } from '@umbraco-cms/backoffice/sorter';
import type { UmbBlockTypeBaseModel, UmbBlockTypeWithGroupKey } from '../../types.js';
import type { UmbBlockTypeCardElement } from '../block-type-card/index.js';
import '../block-type-card/index.js';
@@ -123,10 +123,6 @@ export class UmbInputBlockTypeElement<
this.dispatchEvent(new UmbDeleteEvent());
}
protected getFormElement() {
return undefined;
}
async #onRequestDelete(item: BlockType) {
const store = await this.getContext(UMB_DOCUMENT_TYPE_ITEM_STORE_CONTEXT);
const contentType = store.getItems([item.contentElementTypeKey]);

View File

@@ -10,7 +10,6 @@ import {
UmbSubmittableWorkspaceContextBase,
UmbInvariantWorkspacePropertyDatasetContext,
UmbWorkspaceIsNewRedirectController,
UmbWorkspaceRouteManager,
} from '@umbraco-cms/backoffice/workspace';
import { UmbArrayState, UmbObjectState, appendToFrozenArray } from '@umbraco-cms/backoffice/observable-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
@@ -99,12 +98,22 @@ export class UmbBlockTypeWorkspaceContext<BlockTypeData extends UmbBlockTypeWith
async create(contentElementTypeId: string, groupKey?: string | null) {
this.resetState();
//Only set groupKey property if it exists
const data: BlockTypeData = {
contentElementTypeKey: contentElementTypeId,
...(groupKey && { groupKey: groupKey }),
let data: BlockTypeData = {
contentElementTypeKey: contentElementTypeId
} as BlockTypeData;
// If we have a modal context, we blend in the modal preset data: [NL]
if (this.modalContext) {
data = { ...data, ...this.modalContext.data.preset };
}
// Only set groupKey property if it has been parsed to this method
if (groupKey) {
data.groupKey = groupKey;
}
this.setIsNew(true);
this.#data.setValue(data);
return { data };

View File

@@ -1,8 +1,8 @@
import { UMB_BLOCK_WORKSPACE_CONTEXT } from '../workspace/block-workspace.context-token.js';
import { UmbConditionBase } from '@umbraco-cms/backoffice/extension-registry';
import type { BlockWorkspaceHasSettingsConditionConfig } from '@umbraco-cms/backoffice/extension-registry';
import type { UmbConditionControllerArguments, UmbExtensionCondition } from '@umbraco-cms/backoffice/extension-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UMB_BLOCK_WORKSPACE_CONTEXT } from '../workspace/block-workspace.context-token.js';
export class UmbBlockWorkspaceHasSettingsCondition
extends UmbConditionBase<BlockWorkspaceHasSettingsConditionConfig>
@@ -18,7 +18,7 @@ export class UmbBlockWorkspaceHasSettingsCondition
this.observe(
context.settings.contentTypeId,
(settingsContentTypeId) => {
this.permitted = !!settingsContentTypeId;
this.permitted = settingsContentTypeId !== undefined;
},
'observeSettingsElementTypeId',
);

View File

@@ -62,7 +62,6 @@ export abstract class UmbBlockEntriesContext<
return this._layoutEntries.setValue(layouts);
}
setOneLayout(layoutData: BlockLayoutType) {
console.log('setOneLayout', layoutData);
return this._layoutEntries.appendOne(layoutData);
}

View File

@@ -307,6 +307,9 @@ export abstract class UmbBlockEntryContext<
},
'observeContent',
);
/*
This two way binding does not work well, might need to further investigate what the exact problem is.
this.observe(
this.content,
(content) => {
@@ -316,6 +319,7 @@ export abstract class UmbBlockEntryContext<
},
'observeInternalContent',
);
*/
// observe settings:
const settingsUdi = this._layout.value?.settingsUdi;
@@ -334,7 +338,6 @@ export abstract class UmbBlockEntryContext<
this.settings,
(settings) => {
if (settings) {
console.log('settings to be set', this.#contentUdi, settings);
this._manager?.setOneSettings(settings);
}
},
@@ -352,8 +355,6 @@ export abstract class UmbBlockEntryContext<
this.observe(
this._manager.contentTypeOf(contentTypeKey),
(contentType) => {
//this.#contentElementTypeAlias.setValue(contentType?.alias);
//this.#contentElementTypeName.setValue(contentType?.name);
this.#contentElementType.setValue(contentType);
this._gotContentType(contentType);
},

View File

@@ -1,6 +1,6 @@
import type { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry';
import { manifests as conditionManifests } from './conditions/manifests.js';
import { manifests as modalManifests } from './modals/manifests.js';
import { manifests as workspaceManifests } from './workspace/manifests.js';
import type { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry';
export const manifests: Array<ManifestTypes> = [...modalManifests, ...workspaceManifests, ...conditionManifests];

View File

@@ -1,11 +1,11 @@
import type { UmbBlockDataType } from '../types.js';
import { UmbBlockElementPropertyDatasetContext } from './block-element-property-dataset.context.js';
import type { UmbContentTypeModel } from '@umbraco-cms/backoffice/content-type';
import { UmbContentTypeStructureManager } from '@umbraco-cms/backoffice/content-type';
import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import { UmbDocumentTypeDetailRepository } from '@umbraco-cms/backoffice/document-type';
import type { UmbBlockDataType } from '../types.js';
import { UmbBlockElementPropertyDatasetContext } from './block-element-property-dataset.context.js';
export class UmbBlockElementManager extends UmbControllerBase {
//

View File

@@ -1,5 +1,5 @@
import type { UmbBlockElementPropertyDatasetContext } from './block-element-property-dataset.context.js';
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
import type { UmbBlockElementPropertyDatasetContext } from './block-element-property-dataset.context.js';
export const UMB_BLOCK_ELEMENT_PROPERTY_DATASET_CONTEXT = new UmbContextToken<UmbBlockElementPropertyDatasetContext>(
'UmbPropertyDatasetContext',

View File

@@ -1,11 +1,11 @@
import type { UmbBlockElementManager } from './block-element-manager.js';
import { UMB_BLOCK_ELEMENT_PROPERTY_DATASET_CONTEXT } from './block-element-property-dataset.context-token.js';
import type { UmbPropertyDatasetContext } from '@umbraco-cms/backoffice/property';
import { UMB_PROPERTY_DATASET_CONTEXT } from '@umbraco-cms/backoffice/property';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import { UmbVariantId } from '@umbraco-cms/backoffice/variant';
import type { Observable } from '@umbraco-cms/backoffice/external/rxjs';
import { UMB_BLOCK_ELEMENT_PROPERTY_DATASET_CONTEXT } from './block-element-property-dataset.context-token.js';
import type { UmbBlockElementManager } from './block-element-manager.js';
export class UmbBlockElementPropertyDatasetContext extends UmbControllerBase implements UmbPropertyDatasetContext {
#elementManager: UmbBlockElementManager;

View File

@@ -1,6 +1,6 @@
import type { UmbBlockWorkspaceContext } from './block-workspace.context.js';
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
import type { UmbWorkspaceContext } from '@umbraco-cms/backoffice/workspace';
import type { UmbBlockWorkspaceContext } from './block-workspace.context.js';
export const UMB_BLOCK_WORKSPACE_CONTEXT = new UmbContextToken<UmbWorkspaceContext, UmbBlockWorkspaceContext>(
'UmbWorkspaceContext',

View File

@@ -1,6 +1,3 @@
import type { UmbBlockDataType, UmbBlockLayoutBaseModel } from '../types.js';
import { UmbBlockElementManager } from './block-element-manager.js';
import { UmbBlockWorkspaceEditorElement } from './block-workspace-editor.element.js';
import {
UmbSubmittableWorkspaceContextBase,
type UmbRoutableWorkspaceContext,
@@ -9,13 +6,16 @@ import {
import { UmbObjectState, UmbStringState } from '@umbraco-cms/backoffice/observable-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import type { ManifestWorkspace } from '@umbraco-cms/backoffice/extension-registry';
import { UMB_MODAL_CONTEXT } from '@umbraco-cms/backoffice/modal';
import { decodeFilePath } from '@umbraco-cms/backoffice/utils';
import type { UmbBlockDataType, UmbBlockLayoutBaseModel } from '../types.js';
import { UmbBlockWorkspaceEditorElement } from './block-workspace-editor.element.js';
import { UmbBlockElementManager } from './block-element-manager.js';
import {
UMB_BLOCK_ENTRIES_CONTEXT,
UMB_BLOCK_MANAGER_CONTEXT,
type UmbBlockWorkspaceData,
} from '@umbraco-cms/backoffice/block';
import { UMB_MODAL_CONTEXT } from '@umbraco-cms/backoffice/modal';
import { decodeFilePath } from '@umbraco-cms/backoffice/utils';
export type UmbBlockWorkspaceElementManagerNames = 'content' | 'settings';
export class UmbBlockWorkspaceContext<LayoutDataType extends UmbBlockLayoutBaseModel = UmbBlockLayoutBaseModel>

View File

@@ -13,6 +13,6 @@ export const UMB_BLOCK_WORKSPACE_MODAL = new UmbModalToken<UmbBlockWorkspaceData
size: 'large',
},
data: { entityType: 'block', preset: {}, originData: {} },
// Recast the type, so the entityType data prop is not required:
},
// Recast the type, so the entityType data prop is not required:
) as UmbModalToken<Omit<UmbWorkspaceModalData, 'entityType'>, UmbWorkspaceModalValue>;

View File

@@ -1,6 +1,6 @@
import { UMB_BLOCK_WORKSPACE_ALIAS } from './index.js';
import { UmbSubmitWorkspaceAction } from '@umbraco-cms/backoffice/workspace';
import type { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry';
import { UMB_BLOCK_WORKSPACE_ALIAS } from './index.js';
export const manifests: Array<ManifestTypes> = [
{
@@ -73,8 +73,6 @@ export const manifests: Array<ManifestTypes> = [
alias: 'Umb.Condition.WorkspaceAlias',
match: UMB_BLOCK_WORKSPACE_ALIAS,
},
],
TODO_conditions: [
{
alias: 'Umb.Condition.BlockWorkspaceHasSettings',
},

View File

@@ -1,10 +1,10 @@
import { UMB_BLOCK_WORKSPACE_CONTEXT } from '../../block-workspace.context-token.js';
import type { UmbBlockWorkspaceElementManagerNames } from '../../block-workspace.context.js';
import { css, html, customElement, property, state, repeat } from '@umbraco-cms/backoffice/external/lit';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import type { UmbContentTypeModel, UmbPropertyTypeModel } from '@umbraco-cms/backoffice/content-type';
import { UmbContentTypePropertyStructureHelper } from '@umbraco-cms/backoffice/content-type';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import type { UmbBlockWorkspaceElementManagerNames } from '../../block-workspace.context.js';
import { UMB_BLOCK_WORKSPACE_CONTEXT } from '../../block-workspace.context-token.js';
@customElement('umb-block-workspace-view-edit-properties')
export class UmbBlockWorkspaceViewEditPropertiesElement extends UmbLitElement {

View File

@@ -1,9 +1,9 @@
import { UMB_BLOCK_WORKSPACE_CONTEXT } from '../../block-workspace.context-token.js';
import { css, html, customElement, property, state, repeat } from '@umbraco-cms/backoffice/external/lit';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import type { UmbContentTypeModel, UmbPropertyTypeContainerModel } from '@umbraco-cms/backoffice/content-type';
import { UmbContentTypeContainerStructureHelper } from '@umbraco-cms/backoffice/content-type';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UMB_BLOCK_WORKSPACE_CONTEXT } from '../../block-workspace.context-token.js';
import './block-workspace-view-edit-properties.element.js';
// eslint-disable-next-line import/order

View File

@@ -1,6 +1,3 @@
import { UMB_BLOCK_WORKSPACE_CONTEXT } from '../../block-workspace.context-token.js';
import type { UmbBlockWorkspaceElementManagerNames } from '../../block-workspace.context.js';
import type { UmbBlockWorkspaceViewEditTabElement } from './block-workspace-view-edit-tab.element.js';
import { css, html, customElement, state, repeat, property } from '@umbraco-cms/backoffice/external/lit';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import type { UmbContentTypeModel, UmbPropertyTypeContainerModel } from '@umbraco-cms/backoffice/content-type';
@@ -9,6 +6,9 @@ import type { UmbRoute, UmbRouterSlotChangeEvent, UmbRouterSlotInitEvent } from
import { encodeFolderName } from '@umbraco-cms/backoffice/router';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import type { ManifestWorkspaceView, UmbWorkspaceViewElement } from '@umbraco-cms/backoffice/extension-registry';
import type { UmbBlockWorkspaceElementManagerNames } from '../../block-workspace.context.js';
import { UMB_BLOCK_WORKSPACE_CONTEXT } from '../../block-workspace.context-token.js';
import type { UmbBlockWorkspaceViewEditTabElement } from './block-workspace-view-edit-tab.element.js';
@customElement('umb-block-workspace-view-edit')
export class UmbBlockWorkspaceViewEditElement extends UmbLitElement implements UmbWorkspaceViewElement {

View File

@@ -10,7 +10,7 @@ import { UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/rou
import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation';
@customElement('umb-input-collection-configuration')
export class UmbInputCollectionConfigurationElement extends UmbFormControlMixin(UmbLitElement) {
export class UmbInputCollectionConfigurationElement extends UmbFormControlMixin<string, typeof UmbLitElement>(UmbLitElement) {
protected override getFormElement() {
return undefined;
}
@@ -25,7 +25,7 @@ export class UmbInputCollectionConfigurationElement extends UmbFormControlMixin(
@property({ attribute: 'default-value' })
defaultValue?: string;
#setValue(value: string) {
#setValue(value: string | undefined) {
this.value = value;
this.dispatchEvent(new UmbChangeEvent());
}
@@ -65,7 +65,7 @@ export class UmbInputCollectionConfigurationElement extends UmbFormControlMixin(
}
#clearDataType() {
this.#setValue('');
this.#setValue(undefined);
}
#createDataType() {
@@ -99,7 +99,7 @@ export class UmbInputCollectionConfigurationElement extends UmbFormControlMixin(
if (!this.value || !this._dataTypePickerModalPath) return nothing;
return html`
<uui-ref-list>
<umb-ref-data-type standalone data-type-id=${this.value as string} @open=${this.#editDataType}>
<umb-ref-data-type standalone data-type-id=${this.value} @open=${this.#editDataType}>
<uui-action-bar slot="actions">
<uui-button
label=${this.localize.term('general_choose')}

View File

@@ -11,7 +11,7 @@ import type { UUIColorSwatchesEvent } from '@umbraco-cms/backoffice/external/uui
*/
@customElement('umb-input-color')
export class UmbInputColorElement extends UUIFormControlMixin(UmbLitElement, '') {
protected getFormElement() {
protected override getFormElement() {
return undefined;
}

View File

@@ -15,7 +15,7 @@ import type { UUIInputEvent } from '@umbraco-cms/backoffice/external/uui';
*/
@customElement('umb-input-date')
export class UmbInputDateElement extends UUIFormControlMixin(UmbLitElement, '') {
protected getFormElement() {
protected override getFormElement() {
return undefined;
}

View File

@@ -19,7 +19,7 @@ export class UmbInputDropdownListElement extends UUIFormControlMixin(UmbLitEleme
@query('uui-select')
private selectEle!: HTMLInputElement;
protected getFormElement() {
protected override getFormElement() {
return this.selectEle;
}

View File

@@ -3,13 +3,15 @@ import { splitStringToArray } from '@umbraco-cms/backoffice/utils';
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbSorterController } from '@umbraco-cms/backoffice/sorter';
import { UUIFormControlMixin } from '@umbraco-cms/backoffice/external/uui';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import type { UmbPickerInputContext } from '@umbraco-cms/backoffice/picker-input';
import type { UmbUniqueItemModel } from '@umbraco-cms/backoffice/models';
import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation';
@customElement('umb-input-entity')
export class UmbInputEntityElement extends UUIFormControlMixin(UmbLitElement, '') {
export class UmbInputEntityElement extends UmbFormControlMixin<string | undefined, typeof UmbLitElement>(
UmbLitElement,
) {
#sorter = new UmbSorterController<string>(this, {
getUniqueOfElement: (element) => {
return element.id;
@@ -26,7 +28,7 @@ export class UmbInputEntityElement extends UUIFormControlMixin(UmbLitElement, ''
},
});
protected getFormElement() {
protected override getFormElement() {
return undefined;
}
@@ -68,20 +70,20 @@ export class UmbInputEntityElement extends UUIFormControlMixin(UmbLitElement, ''
this.#pickerContext?.setSelection(uniques);
this.#sorter.setModel(uniques);
}
public get selection(): Array<string> | undefined {
return this.#pickerContext?.getSelection();
public get selection(): Array<string> {
return this.#pickerContext?.getSelection() ?? [];
}
@property()
public override set value(uniques: string) {
this.selection = splitStringToArray(uniques);
@property({ type: String })
public override set value(selectionString: string | undefined) {
this.selection = splitStringToArray(selectionString);
}
public override get value(): string {
return this.selection?.join(',') ?? '';
public override get value(): string | undefined {
return this.selection.length > 0 ? this.selection.join(',') : undefined;
}
@property({ attribute: false })
public set pickerContext(ctor: new (host: UmbControllerHost) => UmbPickerInputContext<any>) {
public set pickerContext(ctor: new (host: UmbControllerHost) => UmbPickerInputContext<any, any, any, any>) {
if (this.#pickerContext) return;
this.#pickerContext = new ctor(this);
this.#observePickerContext();
@@ -90,7 +92,7 @@ export class UmbInputEntityElement extends UUIFormControlMixin(UmbLitElement, ''
@state()
private _items?: Array<UmbUniqueItemModel>;
#pickerContext?: UmbPickerInputContext<any>;
#pickerContext?: UmbPickerInputContext;
constructor() {
super();

View File

@@ -6,7 +6,7 @@ import type { UUIColorPickerChangeEvent } from '@umbraco-cms/backoffice/external
@customElement('umb-input-eye-dropper')
export class UmbInputEyeDropperElement extends UUIFormControlMixin(UmbLitElement, '') {
protected getFormElement() {
protected override getFormElement() {
return undefined;
}

View File

@@ -21,7 +21,7 @@ export class UmbInputRadioButtonListElement extends UUIFormControlMixin(UmbLitEl
@property({ type: Array })
public list: Array<UmbRadioButtonItem> = [];
protected getFormElement() {
protected override getFormElement() {
return undefined;
}

View File

@@ -24,7 +24,7 @@ export class UmbInputSliderElement extends UUIFormControlMixin(UmbLitElement, ''
@property({ type: Boolean, attribute: 'enable-range' })
enableRange = false;
protected getFormElement() {
protected override getFormElement() {
return undefined;
}

View File

@@ -29,7 +29,7 @@ export class UmbInputToggleElement extends UUIFormControlMixin(UmbLitElement, ''
@state()
_currentLabel?: string;
protected getFormElement() {
protected override getFormElement() {
return undefined;
}

View File

@@ -171,7 +171,7 @@ export class UmbMultipleColorPickerInputElement extends UUIFormControlMixin(UmbL
this.dispatchEvent(new UmbChangeEvent());
}
protected getFormElement() {
protected override getFormElement() {
return undefined;
}

View File

@@ -123,7 +123,7 @@ export class UmbMultipleColorPickerItemInputElement extends UUIFormControlMixin(
this._input?.focus();
}
protected getFormElement() {
protected override getFormElement() {
return undefined;
}

View File

@@ -71,7 +71,7 @@ export class UmbInputMultipleTextStringItemElement extends UUIFormControlMixin(U
this._input?.focus();
}
protected getFormElement() {
protected override getFormElement() {
return undefined;
}

View File

@@ -484,11 +484,13 @@ export class UmbContentTypeDesignEditorPropertyElement extends UmbLitElement {
position: absolute;
top: var(--uui-size-space-2);
right: var(--uui-size-space-2);
display: none;
opacity: 0;
}
#editor:hover uui-action-bar,
#editor:focus uui-action-bar {
display: block;
#editor:focus uui-action-bar,
#editor:focus-within uui-action-bar {
opacity: 1;
}
a {

View File

@@ -36,7 +36,7 @@ export class UmbInputCultureSelectElement extends UUIFormControlMixin(UmbLitElem
#cultureRepository = new UmbCultureRepository(this);
protected getFormElement() {
protected override getFormElement() {
return undefined;
}

View File

@@ -55,7 +55,7 @@ export class UmbUiCultureInputElement extends UUIFormControlMixin(UmbLitElement,
}));
}
protected getFormElement() {
protected override getFormElement() {
return this._selectElement;
}

View File

@@ -26,7 +26,7 @@ export type UmbModalContextClassArgs<
// TODO: consider splitting this into two separate handlers
export class UmbModalContext<
ModalPreset extends { [key: string]: any } = { [key: string]: any },
ModalData extends { [key: string]: any } = { [key: string]: any },
ModalValue = any,
> extends UmbControllerBase {
//
@@ -35,19 +35,19 @@ export class UmbModalContext<
#submitRejecter?: (reason?: UmbModalRejectReason) => void;
public readonly key: string;
public readonly data: ModalPreset;
public readonly data: ModalData;
public readonly type: UmbModalType = 'dialog';
public readonly size: UUIModalSidebarSize = 'small';
public readonly backdropBackground?: string;
public readonly router: IRouterSlot | null = null;
public readonly alias: string | UmbModalToken<ModalPreset, ModalValue>;
public readonly alias: string | UmbModalToken<ModalData, ModalValue>;
#value;
public readonly value;
constructor(
host: UmbControllerHost,
modalAlias: string | UmbModalToken<ModalPreset, ModalValue>,
modalAlias: string | UmbModalToken<ModalData, ModalValue>,
args: UmbModalContextClassArgs<UmbModalToken>,
) {
super(host);
@@ -69,9 +69,9 @@ export class UmbModalContext<
this.data = Object.freeze(
// If we have both data and defaultData perform a deep merge
args.data && defaultData
? (umbDeepMerge(args.data as UmbDeepPartialObject<ModalPreset>, defaultData) as ModalPreset)
? (umbDeepMerge(args.data as UmbDeepPartialObject<ModalData>, defaultData) as ModalData)
: // otherwise pick one of them:
(args.data as ModalPreset) ?? defaultData,
(args.data as ModalData) ?? defaultData,
);
const initValue =

View File

@@ -8,7 +8,7 @@ import type { UmbModalToken, UmbPickerModalData, UmbPickerModalValue } from '@um
type PickerItemBaseType = { name: string; unique: string };
export class UmbPickerInputContext<
PickedItemType extends PickerItemBaseType,
PickedItemType extends PickerItemBaseType = PickerItemBaseType,
PickerItemType extends PickerItemBaseType = PickedItemType,
PickerModalConfigType extends UmbPickerModalData<PickerItemType> = UmbPickerModalData<PickerItemType>,
PickerModalValueType extends UmbPickerModalValue = UmbPickerModalValue,

View File

@@ -2,8 +2,11 @@ import type { UmbDataSourceResponse } from '../data-source-response.interface.js
import type { UmbReadDetailDataSource } from './read/index.js';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
export interface UmbDetailDataSourceConstructor<DetailType = any> {
new (host: UmbControllerHost): UmbDetailDataSource<DetailType>;
export interface UmbDetailDataSourceConstructor<
DetailType = any,
UmbDetailDataSourceType extends UmbDetailDataSource<DetailType> = UmbDetailDataSource<DetailType>,
> {
new (host: UmbControllerHost): UmbDetailDataSourceType;
}
export interface UmbDetailDataSource<DetailType> extends UmbReadDetailDataSource<DetailType> {

View File

@@ -8,14 +8,17 @@ import type { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
import type { UmbDetailStore } from '@umbraco-cms/backoffice/store';
import type { UmbApi } from '@umbraco-cms/backoffice/extension-api';
export abstract class UmbDetailRepositoryBase<DetailModelType extends { unique: string; entityType: string }>
export abstract class UmbDetailRepositoryBase<
DetailModelType extends { unique: string; entityType: string },
UmbDetailDataSourceType extends UmbDetailDataSource<DetailModelType> = UmbDetailDataSource<DetailModelType>,
>
extends UmbRepositoryBase
implements UmbDetailRepository<DetailModelType>, UmbApi
{
#init: Promise<unknown>;
#detailStore?: UmbDetailStore<DetailModelType>;
#detailSource: UmbDetailDataSource<DetailModelType>;
protected detailDataSource: UmbDetailDataSourceType;
#notificationContext?: UmbNotificationContext;
constructor(
@@ -25,7 +28,7 @@ export abstract class UmbDetailRepositoryBase<DetailModelType extends { unique:
) {
super(host);
this.#detailSource = new detailSource(host);
this.detailDataSource = new detailSource(host) as UmbDetailDataSourceType;
this.#init = Promise.all([
this.consumeContext(detailStoreContextAlias, (instance) => {
@@ -45,7 +48,7 @@ export abstract class UmbDetailRepositoryBase<DetailModelType extends { unique:
* @memberof UmbDetailRepositoryBase
*/
async createScaffold(preset?: Partial<DetailModelType>) {
return this.#detailSource.createScaffold(preset);
return this.detailDataSource.createScaffold(preset);
}
/**
@@ -58,7 +61,7 @@ export abstract class UmbDetailRepositoryBase<DetailModelType extends { unique:
if (!unique) throw new Error('Unique is missing');
await this.#init;
const { data, error } = await this.#detailSource.read(unique);
const { data, error } = await this.detailDataSource.read(unique);
if (data) {
this.#detailStore!.append(data);
@@ -78,7 +81,7 @@ export abstract class UmbDetailRepositoryBase<DetailModelType extends { unique:
if (!model) throw new Error('Data is missing');
await this.#init;
const { data: createdData, error } = await this.#detailSource.create(model, parentUnique);
const { data: createdData, error } = await this.detailDataSource.create(model, parentUnique);
if (createdData) {
this.#detailStore?.append(createdData);
@@ -102,7 +105,7 @@ export abstract class UmbDetailRepositoryBase<DetailModelType extends { unique:
if (!model.unique) throw new Error('Unique is missing');
await this.#init;
const { data: updatedData, error } = await this.#detailSource.update(model);
const { data: updatedData, error } = await this.detailDataSource.update(model);
if (updatedData) {
this.#detailStore!.updateItem(model.unique, updatedData);
@@ -125,7 +128,7 @@ export abstract class UmbDetailRepositoryBase<DetailModelType extends { unique:
if (!unique) throw new Error('Unique is missing');
await this.#init;
const { error } = await this.#detailSource.delete(unique);
const { error } = await this.detailDataSource.delete(unique);
if (!error) {
this.#detailStore!.removeItem(unique);
@@ -152,7 +155,7 @@ export abstract class UmbDetailRepositoryBase<DetailModelType extends { unique:
override destroy(): void {
this.#detailStore = undefined;
(this.#detailSource as any) = undefined;
(this.detailDataSource as any) = undefined;
super.destroy();
}
}

View File

@@ -1,12 +1,14 @@
import type { UmbSectionItemModel } from '../../repository/index.js';
import { UmbSectionPickerContext } from './input-section.context.js';
import { css, html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit';
import { UUIFormControlMixin } from '@umbraco-cms/backoffice/external/uui';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { splitStringToArray } from '@umbraco-cms/backoffice/utils';
import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation';
@customElement('umb-input-section')
export class UmbInputSectionElement extends UUIFormControlMixin(UmbLitElement, '') {
export class UmbInputSectionElement extends UmbFormControlMixin<string | undefined, typeof UmbLitElement>(
UmbLitElement,
) {
/**
* This is a minimum amount of selected items in this input.
* @type {number}
@@ -60,15 +62,12 @@ export class UmbInputSectionElement extends UUIFormControlMixin(UmbLitElement, '
return this.#pickerContext.getSelection();
}
@property()
public override set value(selectionString: string) {
// Its with full purpose we don't call super.value, as thats being handled by the observation of the context selection.
if (typeof selectionString !== 'string') return;
if (selectionString === this.value) return;
@property({ type: String })
public override set value(selectionString: string | undefined) {
this.selection = splitStringToArray(selectionString);
}
public override get value(): string {
return this.selection.join(',');
public override get value(): string | undefined {
return this.selection.length > 0 ? this.selection.join(',') : undefined;
}
@state()
@@ -95,7 +94,7 @@ export class UmbInputSectionElement extends UUIFormControlMixin(UmbLitElement, '
this.observe(this.#pickerContext.selectedItems, (selectedItems) => (this._items = selectedItems));
}
protected getFormElement() {
protected override getFormElement() {
return undefined;
}

View File

@@ -56,10 +56,10 @@ export class UmbWorkspaceEditorElement extends UmbLitElement {
}
private _createRoutes() {
this._routes = [];
let newRoutes: UmbRoute[] = [];
if (this._workspaceViews.length > 0) {
this._routes = this._workspaceViews.map((manifest) => {
newRoutes = this._workspaceViews.map((manifest) => {
return {
path: `view/${manifest.meta.pathname}`,
component: () => createExtensionElement(manifest),
@@ -72,14 +72,17 @@ export class UmbWorkspaceEditorElement extends UmbLitElement {
});
// If we have a post fix then we need to add a direct from the empty url of the split-view-index:
const firstView = this._workspaceViews[0];
if (firstView) {
this._routes.push({
// TODO: This is problematic, cause if a workspaceView appears later, then this takes over. And it is also a problem if it does not use redirect, but just a view defined with and empty path.
const firstRoute = newRoutes[0];
if (firstRoute) {
newRoutes.push({
path: ``,
redirectTo: `view/${firstView.meta.pathname}`,
redirectTo: firstRoute.path,
});
}
}
this._routes = newRoutes;
}
override render() {

View File

@@ -16,7 +16,7 @@ import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
*/
@customElement('umb-data-type-flow-input')
export class UmbInputDataTypeElement extends UUIFormControlMixin(UmbLitElement, '') {
protected getFormElement() {
protected override getFormElement() {
return undefined;
}

View File

@@ -1,15 +1,16 @@
import { UMB_DATA_TYPE_ITEM_REPOSITORY_ALIAS } from '../../repository/index.js';
import type { UmbDataTypeItemModel } from '../../repository/item/types.js';
import type { UmbDataTypePickerModalData } from '../../modals/index.js';
import { UMB_DATA_TYPE_PICKER_MODAL } from '../../modals/index.js';
import type { UmbDataTypeTreeItemModel } from '../../tree/types.js';
import { UmbPickerInputContext } from '@umbraco-cms/backoffice/picker-input';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UMB_DATA_TYPE_ITEM_REPOSITORY_ALIAS } from '../../repository/index.js';
import type { UmbDataTypeItemModel } from '../../repository/item/types.js';
import type { UmbDataTypePickerModalData, UmbDataTypePickerModalValue } from '../../modals/index.js';
import { UMB_DATA_TYPE_PICKER_MODAL } from '../../modals/index.js';
import type { UmbDataTypeTreeItemModel } from '../../tree/types.js';
export class UmbDataTypePickerContext extends UmbPickerInputContext<
UmbDataTypeItemModel,
UmbDataTypeTreeItemModel,
UmbDataTypePickerModalData
UmbDataTypePickerModalData,
UmbDataTypePickerModalValue
> {
constructor(host: UmbControllerHost) {
super(host, UMB_DATA_TYPE_ITEM_REPOSITORY_ALIAS, UMB_DATA_TYPE_PICKER_MODAL);

View File

@@ -113,7 +113,7 @@ export class UmbDataTypeInputElement extends UUIFormControlMixin(UmbLitElement,
this.observe(this.#pickerContext.selectedItems, (selectedItems) => (this._items = selectedItems), '_observerItems');
}
protected getFormElement() {
protected override getFormElement() {
return undefined;
}

View File

@@ -1,8 +1,8 @@
import { UmbDataTypeDetailRepository } from '../../repository/detail/data-type-detail.repository.js';
import { UUIIconRequestEvent, UUIRefNodeElement } from '@umbraco-cms/backoffice/external/uui';
import { html, customElement, property, state, css } from '@umbraco-cms/backoffice/external/lit';
import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api';
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
import { UmbDataTypeDetailRepository } from '../../repository/detail/data-type-detail.repository.js';
/**
* @element umb-ref-data-type

View File

@@ -71,7 +71,6 @@ export class UmbDataTypePickerFlowModalElement extends UmbModalBaseElement<
private _createDataType(propertyEditorUiAlias: string) {
// TODO: Could be nice with a more pretty way to prepend to the URL:
// Open create modal:
console.log('_createDataType', propertyEditorUiAlias);
this._createDataTypeModal.open(
{ uiAlias: propertyEditorUiAlias },
`create/parent/${UMB_DATA_TYPE_ENTITY_TYPE}/null`,

View File

@@ -1,6 +1,6 @@
import type { UmbDataTypeDetailModel } from '../types.js';
import type { UmbWorkspaceModalData, UmbWorkspaceModalValue } from '@umbraco-cms/backoffice/modal';
import { UmbModalToken } from '@umbraco-cms/backoffice/modal';
import type { UmbDataTypeDetailModel } from '../types.js';
export const UMB_DATATYPE_WORKSPACE_MODAL = new UmbModalToken<
UmbWorkspaceModalData<UmbDataTypeDetailModel>,

View File

@@ -1,13 +1,19 @@
import { UmbPickerInputContext } from '@umbraco-cms/backoffice/picker-input';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UMB_DICTIONARY_ITEM_REPOSITORY_ALIAS } from '../../repository/index.js';
import { UMB_DICTIONARY_PICKER_MODAL } from '../../modals/dictionary-picker-modal.token.js';
import type { UmbDictionaryItemModel } from '../../repository/index.js';
import type { UmbDictionaryTreeItemModel } from '../../tree/types.js';
import { UmbPickerInputContext } from '@umbraco-cms/backoffice/picker-input';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import type {
UmbDictionaryPickerModalData,
UmbDictionaryPickerModalValue,
} from '../../modals/dictionary-picker-modal.token.js';
export class UmbDictionaryPickerContext extends UmbPickerInputContext<
UmbDictionaryItemModel,
UmbDictionaryTreeItemModel
UmbDictionaryTreeItemModel,
UmbDictionaryPickerModalData,
UmbDictionaryPickerModalValue
> {
constructor(host: UmbControllerHost) {
super(host, UMB_DICTIONARY_ITEM_REPOSITORY_ALIAS, UMB_DICTIONARY_PICKER_MODAL);

View File

@@ -1,4 +1,4 @@
export * from './repository/index.js';
export * from './tree/index.js';
export * from './modals/dictionary-picker-modal.token.js';
export * from './entity.js';
export { UMB_DICTIONARY_PICKER_MODAL } from './modals/dictionary-picker-modal.token.js';

View File

@@ -104,7 +104,7 @@ export class UmbInputDocumentTypeElement extends UmbFormControlMixin<string | un
return this.#pickerContext.getSelection();
}
@property()
@property({ type: String })
public override set value(uniques: string | undefined) {
this.selection = splitStringToArray(uniques);
}

View File

@@ -44,7 +44,7 @@ export class UmbPropertyEditorUIDocumentTypePickerElement extends UmbLitElement
<umb-input-document-type
.min=${this.min}
.max=${this.max}
.value=${this.value ?? ''}
.value=${this.value}
?elementTypesOnly=${this.onlyElementTypes}
?showOpenButton=${this.showOpenButton}
@change=${this.#onChange}>

View File

@@ -1,7 +1,7 @@
import { UMB_DOCUMENT_TYPE_ENTITY_TYPE } from '../entity.js';
import { UMB_WORKSPACE_MODAL, UmbModalToken } from '@umbraco-cms/backoffice/modal';
import type { UmbDeepPartialObject } from '@umbraco-cms/backoffice/utils';
import type { UmbWorkspaceModalData, UmbWorkspaceModalValue } from '@umbraco-cms/backoffice/modal';
import { UMB_DOCUMENT_TYPE_ENTITY_TYPE } from '../entity.js';
export interface UmbDocumentTypeWorkspaceData extends UmbWorkspaceModalData {}

View File

@@ -6,12 +6,14 @@ import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbSorterController } from '@umbraco-cms/backoffice/sorter';
import { UMB_WORKSPACE_MODAL } from '@umbraco-cms/backoffice/modal';
import { UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/router';
import { UUIFormControlMixin } from '@umbraco-cms/backoffice/external/uui';
import type { UmbDocumentItemModel } from '@umbraco-cms/backoffice/document';
import type { UmbTreeStartNode } from '@umbraco-cms/backoffice/tree';
import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation';
@customElement('umb-input-document')
export class UmbInputDocumentElement extends UUIFormControlMixin(UmbLitElement, '') {
export class UmbInputDocumentElement extends UmbFormControlMixin<string | undefined, typeof UmbLitElement>(
UmbLitElement,
) {
#sorter = new UmbSorterController<string>(this, {
getUniqueOfElement: (element) => {
return element.id;
@@ -91,12 +93,12 @@ export class UmbInputDocumentElement extends UUIFormControlMixin(UmbLitElement,
@property({ type: Boolean })
showOpenButton?: boolean;
@property()
public override set value(idsString: string) {
this.selection = splitStringToArray(idsString);
@property({ type: String })
public override set value(selectionString: string | undefined) {
this.selection = splitStringToArray(selectionString);
}
public override get value() {
return this.selection.join(',');
public override get value(): string | undefined {
return this.selection.length > 0 ? this.selection.join(',') : undefined;
}
@state()
@@ -135,7 +137,7 @@ export class UmbInputDocumentElement extends UUIFormControlMixin(UmbLitElement,
this.observe(this.#pickerContext.selectedItems, (selectedItems) => (this._items = selectedItems), '_observerItems');
}
protected getFormElement() {
protected override getFormElement() {
return undefined;
}

View File

@@ -203,7 +203,7 @@ export class UmbPublicAccessModalElement extends UmbModalBaseElement<
<umb-localize key="publicAccess_paLoginPageHelp"> Choose the page that contains the login form </umb-localize>
</small>
<umb-input-document
.value=${this._loginDocumentId ? this._loginDocumentId : ''}
.value=${this._loginDocumentId}
max="1"
@change=${this.#onChangeLoginPage}></umb-input-document>
</div>
@@ -216,7 +216,7 @@ export class UmbPublicAccessModalElement extends UmbModalBaseElement<
</umb-localize>
</small>
<umb-input-document
.value=${this._errorDocumentId ? this._errorDocumentId : ''}
.value=${this._errorDocumentId}
max="1"
@change=${this.#onChangeErrorPage}></umb-input-document>
</div>`;

View File

@@ -41,7 +41,7 @@ export class UmbPropertyEditorUIDocumentPickerElement extends UmbLitElement impl
private _showOpenButton?: boolean;
#onChange(event: CustomEvent & { target: UmbInputDocumentElement }) {
this.value = event.target.selection.join(',');
this.value = event.target.value;
this.dispatchEvent(new UmbPropertyValueChangeEvent());
}
@@ -55,7 +55,7 @@ export class UmbPropertyEditorUIDocumentPickerElement extends UmbLitElement impl
.min=${this._min}
.max=${this._max}
.startNode=${startNode}
.value=${this.value ?? ''}
.value=${this.value}
?showOpenButton=${this._showOpenButton}
@change=${this.#onChange}>
</umb-input-document>

View File

@@ -37,7 +37,7 @@ export class UmbInputDocumentGranularUserPermissionElement extends UUIFormContro
this.consumeContext(UMB_MODAL_MANAGER_CONTEXT, (instance) => (this.#modalManagerContext = instance));
}
protected getFormElement() {
protected override getFormElement() {
return undefined;
}

View File

@@ -1,8 +1,8 @@
import { UmbPickerInputContext } from '@umbraco-cms/backoffice/picker-input';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import type { UmbLanguageItemModel } from '../../repository/index.js';
import { UMB_LANGUAGE_ITEM_REPOSITORY_ALIAS } from '../../repository/index.js';
import { UMB_LANGUAGE_PICKER_MODAL } from '../../modals/language-picker/index.js';
import { UmbPickerInputContext } from '@umbraco-cms/backoffice/picker-input';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
export class UmbLanguagePickerContext extends UmbPickerInputContext<UmbLanguageItemModel> {
constructor(host: UmbControllerHost) {

View File

@@ -115,7 +115,7 @@ export class UmbInputLanguageElement extends UUIFormControlMixin(UmbLitElement,
this.observe(this.#pickerContext.selectedItems, (selectedItems) => (this._items = selectedItems), '_observerItems');
}
protected getFormElement() {
protected override getFormElement() {
return undefined;
}

View File

@@ -1,5 +1,5 @@
import type { UmbLanguageItemModel } from '@umbraco-cms/backoffice/language';
import { UmbModalToken } from '@umbraco-cms/backoffice/modal';
import type { UmbLanguageItemModel } from '@umbraco-cms/backoffice/language';
export interface UmbLanguagePickerModalData {
multiple?: boolean;

View File

@@ -1,6 +1,6 @@
import type { UmbLanguageDetailModel } from '../../types.js';
import type { UmbWorkspaceModalData, UmbWorkspaceModalValue } from '@umbraco-cms/backoffice/modal';
import { UmbModalToken } from '@umbraco-cms/backoffice/modal';
import type { UmbLanguageDetailModel } from '../../types.js';
export const UMB_LANGUAGE_WORKSPACE_MODAL = new UmbModalToken<
UmbWorkspaceModalData<UmbLanguageDetailModel>,

View File

@@ -23,7 +23,7 @@ import type { UUIModalSidebarSize } from '@umbraco-cms/backoffice/external/uui';
@customElement('umb-input-markdown')
export class UmbInputMarkdownElement extends UUIFormControlMixin(UmbLitElement, '') {
protected getFormElement() {
protected override getFormElement() {
return this._codeEditor;
}

View File

@@ -7,10 +7,12 @@ import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UMB_WORKSPACE_MODAL } from '@umbraco-cms/backoffice/modal';
import { UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/router';
import { UmbSorterController } from '@umbraco-cms/backoffice/sorter';
import { UUIFormControlMixin } from '@umbraco-cms/backoffice/external/uui';
import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation';
@customElement('umb-input-media-type')
export class UmbInputMediaTypeElement extends UUIFormControlMixin(UmbLitElement, '') {
export class UmbInputMediaTypeElement extends UmbFormControlMixin<string | undefined, typeof UmbLitElement>(
UmbLitElement,
) {
#sorter = new UmbSorterController<string>(this, {
getUniqueOfElement: (element) => {
return element.id;
@@ -82,12 +84,12 @@ export class UmbInputMediaTypeElement extends UUIFormControlMixin(UmbLitElement,
return this.#pickerContext.getSelection();
}
@property()
public override set value(uniques: string) {
this.selection = splitStringToArray(uniques);
@property({ type: String })
public override set value(selectionString: string | undefined) {
this.selection = splitStringToArray(selectionString);
}
public override get value(): string {
return this.selection.join(',');
public override get value(): string | undefined {
return this.selection.length > 0 ? this.selection.join(',') : undefined;
}
@state()
@@ -126,7 +128,7 @@ export class UmbInputMediaTypeElement extends UUIFormControlMixin(UmbLitElement,
this.observe(this.#pickerContext.selectedItems, (selectedItems) => (this._items = selectedItems), '_observerItems');
}
protected getFormElement() {
protected override getFormElement() {
return undefined;
}

View File

@@ -15,24 +15,24 @@ export class UmbPropertyEditorUIMediaTypePickerElement extends UmbLitElement imp
if (!config) return;
const minMax = config?.getValueByAlias<UmbNumberRangeValueType>('validationLimit');
this.min = minMax?.min ?? 0;
this.max = minMax?.max ?? Infinity;
this._min = minMax?.min ?? 0;
this._max = minMax?.max ?? Infinity;
}
@state()
min = 0;
_min = 0;
@state()
max = Infinity;
_max = Infinity;
#onChange(event: CustomEvent & { target: UmbInputMediaTypeElement }) {
this.value = event.target.selection.join(',');
this.value = event.target.value;
this.dispatchEvent(new UmbPropertyValueChangeEvent());
}
override render() {
return html`
<umb-input-media-type .min=${this.min} .max=${this.max} .value=${this.value ?? ''} @change=${this.#onChange}>
<umb-input-media-type .min=${this._min} .max=${this._max} .value=${this.value} @change=${this.#onChange}>
</umb-input-media-type>
`;
}

View File

@@ -20,7 +20,7 @@ export class UmbMediaTypeWorkspaceViewStructureElement extends UmbLitElement imp
private _allowedContentTypeIDs?: Array<string>;
@state()
private _collection?: string | null;
private _collection?: string;
constructor() {
super();
@@ -82,10 +82,8 @@ export class UmbMediaTypeWorkspaceViewStructureElement extends UmbLitElement imp
<!-- TODO: maybe we want to somehow display the hierarchy, but not necessary in the same way as old backoffice? -->
<umb-input-media-type
.selection=${this._allowedContentTypeIDs ?? []}
@change="${(e: CustomEvent) => {
const sortedContentTypesList: Array<UmbContentTypeSortModel> = (
e.target as UmbInputMediaTypeElement
).selection.map((id, index) => ({
@change="${(e: CustomEvent & { target: UmbInputMediaTypeElement }) => {
const sortedContentTypesList: Array<UmbContentTypeSortModel> = e.target.selection.map((id, index) => ({
contentType: { unique: id },
sortOrder: index,
}));
@@ -101,7 +99,7 @@ export class UmbMediaTypeWorkspaceViewStructureElement extends UmbLitElement imp
<div slot="editor">
<umb-input-collection-configuration
default-value="3a0156c4-3b8c-4803-bdc1-6871faa83fff"
.value=${this._collection ?? ''}
.value=${this._collection}
@change=${(e: CustomEvent) => {
const unique = (e.target as UmbInputCollectionConfigurationElement).value as string;
this.#workspaceContext?.setCollection({ unique });

View File

@@ -79,7 +79,7 @@ export class UmbInputImageCropperFieldElement extends UmbLitElement {
}
}
#onCropClick(crop: any) {
protected onCropClick(crop: any) {
const index = this.crops.findIndex((c) => c.alias === crop.alias);
if (index === -1) return;
@@ -117,19 +117,19 @@ export class UmbInputImageCropperFieldElement extends UmbLitElement {
this.dispatchEvent(new UmbChangeEvent());
}
#onResetFocalPoint = () => {
protected onResetFocalPoint = () => {
this.focalPoint = { left: 0.5, top: 0.5 };
this.#updateValue();
};
override render() {
return html`
<div id="main">${this.#renderMain()}</div>
<div id="side">${this.#renderSide()}</div>
<div id="main">${this.renderMain()}</div>
<div id="side">${this.renderSide()}</div>
`;
}
#renderMain() {
protected renderMain() {
if (this.currentCrop) {
return html`
<umb-image-cropper
@@ -149,20 +149,22 @@ export class UmbInputImageCropperFieldElement extends UmbLitElement {
?hideFocalPoint=${this.hideFocalPoint}
@change=${this.#onFocalPointChange}>
</umb-image-cropper-focus-setter>
<div id="actions">
<slot name="actions"></slot>
${when(
!this.hideFocalPoint,
() =>
html`<uui-button
label=${this.localize.term('content_resetFocalPoint')}
@click=${this.#onResetFocalPoint}></uui-button>`,
)}
</div>
<div id="actions">${this.renderActions()}</div>
`;
}
#renderSide() {
protected renderActions() {
return html`<slot name="actions"></slot>
${when(
!this.hideFocalPoint,
() =>
html`<uui-button
label=${this.localize.term('content_resetFocalPoint')}
@click=${this.onResetFocalPoint}></uui-button>`,
)} `;
}
protected renderSide() {
if (!this.value || !this.crops) return;
return repeat(
@@ -170,7 +172,7 @@ export class UmbInputImageCropperFieldElement extends UmbLitElement {
(crop) => crop.alias + JSON.stringify(crop.coordinates),
(crop) =>
html` <umb-image-cropper-preview
@click=${() => this.#onCropClick(crop)}
@click=${() => this.onCropClick(crop)}
.crop=${crop}
.focalPoint=${this.focalPoint}
.src=${this.source}></umb-image-cropper-preview>`,
@@ -184,6 +186,7 @@ export class UmbInputImageCropperFieldElement extends UmbLitElement {
gap: var(--uui-size-space-3);
height: 400px;
}
#main {
max-width: 500px;
min-width: 300px;
@@ -193,13 +196,16 @@ export class UmbInputImageCropperFieldElement extends UmbLitElement {
gap: var(--uui-size-space-1);
flex-direction: column;
}
#actions {
display: flex;
justify-content: space-between;
}
umb-image-cropper-focus-setter {
height: calc(100% - 33px - var(--uui-size-space-1)); /* Temp solution to make room for actions */
}
#side {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));

View File

@@ -13,6 +13,9 @@ export class UmbImageCropperPreviewElement extends LitElement {
@property({ type: String, attribute: false })
src: string = '';
@property({ type: String })
label?: string;
@property({ attribute: false })
get focalPoint() {
return this.#focalPoint;
@@ -140,14 +143,14 @@ export class UmbImageCropperPreviewElement extends LitElement {
override render() {
if (!this.crop) {
return nothing;
return html`<span id="label">${this.label}</span>`;
}
return html`
<div id="container">
<img id="image" src=${this.src} alt="" />
</div>
<span id="alias">${this.crop.alias}</span>
<span id="alias">${this.label ?? this.crop.alias}</span>
<span id="dimensions">${this.crop.width} x ${this.crop.height}</span>
${this.crop.coordinates
? html`<span id="user-defined"><umb-localize key="imagecropper_customCrop">User defined</umb-localize></span>`
@@ -178,6 +181,9 @@ export class UmbImageCropperPreviewElement extends LitElement {
max-height: 200px;
user-select: none;
}
#label {
font-weight: bold;
}
#alias {
font-weight: bold;
margin-top: var(--uui-size-space-3);

View File

@@ -9,12 +9,12 @@ import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/router';
import { UmbSorterController } from '@umbraco-cms/backoffice/sorter';
import { UMB_WORKSPACE_MODAL } from '@umbraco-cms/backoffice/modal';
import { UUIFormControlMixin } from '@umbraco-cms/backoffice/external/uui';
import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation';
const elementName = 'umb-input-media';
@customElement(elementName)
export class UmbInputMediaElement extends UUIFormControlMixin(UmbLitElement, '') {
export class UmbInputMediaElement extends UmbFormControlMixin<string | undefined, typeof UmbLitElement>(UmbLitElement) {
#sorter = new UmbSorterController<string>(this, {
getUniqueOfElement: (element) => {
return element.getAttribute('detail');
@@ -107,12 +107,12 @@ export class UmbInputMediaElement extends UUIFormControlMixin(UmbLitElement, '')
@property({ type: String })
startNode = '';
@property()
public override set value(idsString: string) {
this.selection = splitStringToArray(idsString);
@property({ type: String })
public override set value(selectionString: string | undefined) {
this.selection = splitStringToArray(selectionString);
}
public override get value() {
return this.selection.join(',');
public override get value(): string | undefined {
return this.selection.length > 0 ? this.selection.join(',') : undefined;
}
@state()
@@ -141,7 +141,7 @@ export class UmbInputMediaElement extends UUIFormControlMixin(UmbLitElement, '')
this.observe(this.#pickerContext.selectedItems, async (selectedItems) => {
const missingCards = selectedItems.filter((item) => !this._cards.find((card) => card.unique === item.unique));
if (!missingCards.length) return;
if (selectedItems?.length && !missingCards.length) return;
if (!selectedItems?.length) {
this._cards = [];
@@ -173,7 +173,7 @@ export class UmbInputMediaElement extends UUIFormControlMixin(UmbLitElement, '')
);
}
protected getFormElement() {
protected override getFormElement() {
return undefined;
}

View File

@@ -233,7 +233,7 @@ export class UmbInputRichMediaElement extends UUIFormControlMixin(UmbLitElement,
);
}
protected getFormElement() {
protected override getFormElement() {
return undefined;
}

View File

@@ -0,0 +1,108 @@
import { UmbInputImageCropperFieldElement } from '../../../components/input-image-cropper/image-cropper-field.element.js';
import { css, customElement, html, repeat, when } from '@umbraco-cms/backoffice/external/lit';
@customElement('umb-image-cropper-editor-field')
export class UmbImageCropperEditorFieldElement extends UmbInputImageCropperFieldElement {
#resetCurrentCrop() {
this.currentCrop = undefined;
}
override renderActions() {
return html`
<slot name="actions"></slot>
${when(
!this.hideFocalPoint,
() => html`
<uui-button
compact
id="reset-focal-point"
label=${this.localize.term('content_resetFocalPoint')}
@click=${this.onResetFocalPoint}>
<uui-icon name="icon-axis-rotation"></uui-icon>
${this.localize.term('content_resetFocalPoint')}
</uui-button>
`,
)}
`;
}
override renderSide() {
if (!this.value || !this.crops) return;
return html` <umb-image-cropper-preview
@click=${this.#resetCurrentCrop}
?active=${!this.currentCrop}
.label=${this.localize.term('general_media')}></umb-image-cropper-preview>
${repeat(
this.crops,
(crop) => crop.alias + JSON.stringify(crop.coordinates),
(crop) => html`
<umb-image-cropper-preview
?active=${this.currentCrop?.alias === crop.alias}
@click=${() => this.onCropClick(crop)}
.crop=${crop}
.focalPoint=${this.focalPoint}
.src=${this.source}></umb-image-cropper-preview>
`,
)}`;
}
static override styles = css`
:host {
display: flex;
width: 100%;
box-sizing: border-box;
gap: var(--uui-size-space-3);
height: 400px;
}
#main {
width: 100%;
height: 100%;
display: flex;
gap: var(--uui-size-space-1);
flex-direction: column;
}
#actions {
display: flex;
justify-content: space-between;
}
#reset-focal-point uui-icon {
padding-right: var(--uui-size-3);
}
slot[name='actions'] {
display: block;
flex: 1;
}
#reset-current-crop[active],
[active] {
background-color: var(--uui-color-current);
}
umb-image-cropper-focus-setter {
height: calc(100% - 33px - var(--uui-size-space-1)); /* Temp solution to make room for actions */
}
#side {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
flex: none;
gap: var(--uui-size-space-3);
flex-grow: 1;
overflow-y: auto;
height: fit-content;
max-height: 100%;
}
`;
}
declare global {
interface HTMLElementTagNameMap {
'umb-image-cropper-editor-field': UmbImageCropperEditorFieldElement;
}
}

View File

@@ -0,0 +1 @@
export * from './image-cropper-editor-field.element.js';

View File

@@ -11,6 +11,7 @@ import { css, customElement, html, state } from '@umbraco-cms/backoffice/externa
import { UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/router';
import { UMB_MODAL_MANAGER_CONTEXT, UMB_WORKSPACE_MODAL, UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
import type { UmbModalManagerContext } from '@umbraco-cms/backoffice/modal';
import './components/image-cropper-editor-field.element.js';
/** TODO Make some of the components from property editor image cropper reuseable for this modal... */
@@ -131,20 +132,22 @@ export class UmbImageCropperEditorModalElement extends UmbModalBaseElement<
#renderBody() {
return html`
<div id="layout">
<umb-image-cropper-field
<umb-image-cropper-editor-field
.value=${this._imageCropperValue}
?hideFocalPoint=${this._hideFocalPoint}
@change=${this.#onChange}></umb-image-cropper-field>
<div id="options">
<uui-menu-item @click=${this.#openMediaPicker} label=${this.localize.term('mediaPicker_changeMedia')}>
<umb-icon slot="icon" name="icon-search"></umb-icon>
</uui-menu-item>
<uui-menu-item
href=${this._editMediaPath + 'edit/' + this._unique}
label=${this.localize.term('mediaPicker_openMedia')}>
<umb-icon slot="icon" name="icon-out"></umb-icon>
</uui-menu-item>
</div>
@change=${this.#onChange}>
<div id="actions" slot="actions">
<uui-button compact @click=${this.#openMediaPicker} label=${this.localize.term('mediaPicker_changeMedia')}>
<uui-icon name="icon-search"></uui-icon>${this.localize.term('mediaPicker_changeMedia')}
</uui-button>
<uui-button
compact
href=${this._editMediaPath + 'edit/' + this._unique}
label=${this.localize.term('mediaPicker_openMedia')}>
<uui-icon name="icon-out"></uui-icon>${this.localize.term('mediaPicker_openMedia')}
</uui-button>
</div>
</umb-image-cropper-editor-field>
</div>
`;
}
@@ -157,6 +160,17 @@ export class UmbImageCropperEditorModalElement extends UmbModalBaseElement<
flex-direction: column;
justify-content: space-between;
}
umb-image-cropper-editor-field {
flex-grow: 1;
}
#actions {
display: inline-flex;
gap: var(--uui-size-space-3);
}
uui-icon {
padding-right: var(--uui-size-3);
}
#options {
display: flex;

View File

@@ -1,2 +1,3 @@
export * from './components/index.js';
export * from './image-cropper-editor-modal.element.js';
export * from './image-cropper-editor-modal.token.js';

View File

@@ -1,5 +1,4 @@
import { html, customElement, property } from '@umbraco-cms/backoffice/external/lit';
import { splitStringToArray } from '@umbraco-cms/backoffice/utils';
import { html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbPropertyValueChangeEvent } from '@umbraco-cms/backoffice/property-editor';
import type { UmbNumberRangeValueType } from '@umbraco-cms/backoffice/models';
@@ -9,41 +8,34 @@ import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extensi
@customElement('umb-property-editor-ui-media-entity-picker')
export class UmbPropertyEditorUIMediaEntityPickerElement extends UmbLitElement implements UmbPropertyEditorUiElement {
#min: number = 0;
#max: number = Infinity;
@property({ attribute: false })
public set value(value: string | null | undefined) {
this.#selection = value ? (Array.isArray(value) ? value : splitStringToArray(value)) : [];
}
public get value() {
return this.#selection.length > 0 ? this.#selection.join(',') : null;
}
#selection: Array<string> = [];
@property({ type: String })
public value: string | undefined;
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
if (!config) return;
const minMax = config?.getValueByAlias<UmbNumberRangeValueType>('validationLimit');
this.#min = minMax?.min ?? 0;
this.#max = minMax?.max ?? Infinity;
}
public get config() {
return undefined;
this._min = minMax?.min ?? 0;
this._max = minMax?.max ?? Infinity;
}
@state()
_min: number = 0;
@state()
_max: number = Infinity;
#onChange(event: CustomEvent & { target: UmbInputMediaElement }) {
this.value = event.target.selection?.join(',') ?? null;
this.value = event.target.value;
this.dispatchEvent(new UmbPropertyValueChangeEvent());
}
override render() {
return html`
<umb-input-media
.min=${this.#min}
.max=${this.#max}
.selection=${this.#selection}
.min=${this._min}
.max=${this._max}
.value=${this.value}
@change=${this.#onChange}></umb-input-media>
`;
}

View File

@@ -7,10 +7,12 @@ import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbSorterController } from '@umbraco-cms/backoffice/sorter';
import { UMB_WORKSPACE_MODAL } from '@umbraco-cms/backoffice/modal';
import { UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/router';
import { UUIFormControlMixin } from '@umbraco-cms/backoffice/external/uui';
import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation';
@customElement('umb-input-member-group')
export class UmbInputMemberGroupElement extends UUIFormControlMixin(UmbLitElement, '') {
export class UmbInputMemberGroupElement extends UmbFormControlMixin<string | undefined, typeof UmbLitElement>(
UmbLitElement,
) {
#sorter = new UmbSorterController<string>(this, {
getUniqueOfElement: (element) => {
return element.id;
@@ -87,12 +89,12 @@ export class UmbInputMemberGroupElement extends UUIFormControlMixin(UmbLitElemen
@property({ type: Array })
allowedContentTypeIds?: string[] | undefined;
@property()
public override set value(idsString: string) {
this.selection = splitStringToArray(idsString);
@property({ type: String })
public override set value(selectionString: string | undefined) {
this.selection = splitStringToArray(selectionString);
}
public override get value(): string {
return this.selection.join(',');
public override get value(): string | undefined {
return this.selection.length > 0 ? this.selection.join(',') : undefined;
}
@property({ type: Object, attribute: false })
@@ -134,7 +136,7 @@ export class UmbInputMemberGroupElement extends UUIFormControlMixin(UmbLitElemen
this.observe(this.#pickerContext.selectedItems, (selectedItems) => (this._items = selectedItems), '_observeItems');
}
protected getFormElement() {
protected override getFormElement() {
return undefined;
}

View File

@@ -18,15 +18,15 @@ export class UmbPropertyEditorUIMemberGroupPickerElement extends UmbLitElement i
if (!config) return;
const minMax = config?.getValueByAlias<UmbNumberRangeValueType>('validationLimit');
this.min = minMax?.min ?? 0;
this.max = minMax?.max ?? Infinity;
this._min = minMax?.min ?? 0;
this._max = minMax?.max ?? Infinity;
}
@state()
min = 0;
_min = 0;
@state()
max = Infinity;
_max = Infinity;
#onChange(event: CustomEvent & { target: UmbInputMemberGroupElement }) {
this.value = event.target.value;
@@ -36,9 +36,9 @@ export class UmbPropertyEditorUIMemberGroupPickerElement extends UmbLitElement i
override render() {
return html`
<umb-input-member-group
.min=${this.min}
.max=${this.max}
.value=${this.value ?? ''}
.min=${this._min}
.max=${this._max}
.value=${this.value}
?showOpenButton=${true}
@change=${this.#onChange}></umb-input-member-group>
`;

View File

@@ -1,12 +1,14 @@
import { UmbMemberTypePickerContext } from './input-member-type.context.js';
import { css, html, customElement, property, state, repeat, when } from '@umbraco-cms/backoffice/external/lit';
import { splitStringToArray } from '@umbraco-cms/backoffice/utils';
import { UUIFormControlMixin } from '@umbraco-cms/backoffice/external/uui';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import type { UmbUniqueItemModel } from '@umbraco-cms/backoffice/models';
import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation';
@customElement('umb-input-member-type')
export class UmbInputMemberTypeElement extends UUIFormControlMixin(UmbLitElement, '') {
export class UmbInputMemberTypeElement extends UmbFormControlMixin<string | undefined, typeof UmbLitElement>(
UmbLitElement,
) {
/**
* This is a minimum amount of selected items in this input.
* @type {number}
@@ -60,13 +62,12 @@ export class UmbInputMemberTypeElement extends UUIFormControlMixin(UmbLitElement
return this.#pickerContext.getSelection();
}
@property()
public override 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. [NL]
this.selection = splitStringToArray(idsString);
@property({ type: String })
public override set value(selectionString: string | undefined) {
this.selection = splitStringToArray(selectionString);
}
public override get value(): string {
return this.selection.join(',');
public override get value(): string | undefined {
return this.selection.length > 0 ? this.selection.join(',') : undefined;
}
@state()
@@ -93,7 +94,7 @@ export class UmbInputMemberTypeElement extends UUIFormControlMixin(UmbLitElement
this.observe(this.#pickerContext.selectedItems, (selectedItems) => (this._items = selectedItems));
}
protected getFormElement() {
protected override getFormElement() {
return undefined;
}

View File

@@ -7,10 +7,12 @@ import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UMB_WORKSPACE_MODAL } from '@umbraco-cms/backoffice/modal';
import { UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/router';
import { UmbSorterController } from '@umbraco-cms/backoffice/sorter';
import { UUIFormControlMixin } from '@umbraco-cms/backoffice/external/uui';
import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation';
@customElement('umb-input-member')
export class UmbInputMemberElement extends UUIFormControlMixin(UmbLitElement, '') {
export class UmbInputMemberElement extends UmbFormControlMixin<string | undefined, typeof UmbLitElement>(
UmbLitElement,
) {
#sorter = new UmbSorterController<string>(this, {
getUniqueOfElement: (element) => {
return element.id;
@@ -87,12 +89,12 @@ export class UmbInputMemberElement extends UUIFormControlMixin(UmbLitElement, ''
@property({ type: Array })
allowedContentTypeIds?: string[] | undefined;
@property()
public override set value(idsString: string) {
this.selection = splitStringToArray(idsString);
@property({ type: String })
public override set value(selectionString: string | undefined) {
this.selection = splitStringToArray(selectionString);
}
public override get value(): string {
return this.selection.join(',');
public override get value(): string | undefined {
return this.selection.length > 0 ? this.selection.join(',') : undefined;
}
@property({ type: Object, attribute: false })
@@ -134,7 +136,7 @@ export class UmbInputMemberElement extends UUIFormControlMixin(UmbLitElement, ''
this.observe(this.#pickerContext.selectedItems, (selectedItems) => (this._items = selectedItems), '_observeItems');
}
protected getFormElement() {
protected override getFormElement() {
return undefined;
}

View File

@@ -21,10 +21,8 @@ export class UmbPropertyEditorUIMemberPickerElement extends UmbLitElement implem
this.dispatchEvent(new UmbPropertyValueChangeEvent());
}
override render() {
return html`
<umb-input-member min="0" max="1" .value=${this.value ?? ''} @change=${this.#onChange}></umb-input-member>
`;
override render() {
return html` <umb-input-member min="0" max="1" .value=${this.value} @change=${this.#onChange}></umb-input-member> `;
}
}

View File

@@ -37,7 +37,7 @@ export class UmbMultiUrlPickerElement extends UUIFormControlMixin(UmbLitElement,
},
});
protected getFormElement() {
protected override getFormElement() {
return undefined;
}

View File

@@ -34,7 +34,7 @@ export class UmbInputObjectTypeElement extends UUIFormControlMixin(UmbLitElement
});
}
protected getFormElement() {
protected override getFormElement() {
return undefined;
}

View File

@@ -198,7 +198,10 @@ export class UmbWorkspacePackageBuilderElement extends UmbLitElement {
return html`
<umb-property-layout label="Content" description="Select the starting root content">
<div slot="editor">
<umb-input-document max="1" .value=${this._package.contentNodeId ?? ''} @change=${this.#onContentChange}>
<umb-input-document
max="1"
.value=${this._package.contentNodeId ?? undefined}
@change=${this.#onContentChange}>
</umb-input-document>
<uui-checkbox
label="Include child nodes"

View File

@@ -26,7 +26,7 @@ export class UmbInputCheckboxListElement extends UUIFormControlMixin(UmbLitEleme
this.selection = value.split(',');
}
protected getFormElement() {
protected override getFormElement() {
return undefined;
}

View File

@@ -196,7 +196,7 @@ export class UmbInputCollectionContentTypePropertyElement extends UUIFormControl
#modalManager?: typeof UMB_MODAL_MANAGER_CONTEXT.TYPE;
protected getFormElement() {
protected override getFormElement() {
return undefined;
}

View File

@@ -1,6 +1,5 @@
import type { UmbContentPickerSource } from '../../types.js';
import { css, html, customElement, property } from '@umbraco-cms/backoffice/external/lit';
import { UUIFormControlMixin } from '@umbraco-cms/backoffice/external/uui';
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import type { UmbInputDocumentElement } from '@umbraco-cms/backoffice/document';
@@ -8,16 +7,20 @@ import type { UmbInputMediaElement } from '@umbraco-cms/backoffice/media';
import type { UmbInputMemberElement } from '@umbraco-cms/backoffice/member';
import type { UmbReferenceByUniqueAndType } from '@umbraco-cms/backoffice/models';
import type { UmbTreeStartNode } from '@umbraco-cms/backoffice/tree';
import { splitStringToArray } from '@umbraco-cms/backoffice/utils';
import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation';
const elementName = 'umb-input-content';
@customElement(elementName)
export class UmbInputContentElement extends UUIFormControlMixin(UmbLitElement, '') {
protected getFormElement() {
export class UmbInputContentElement extends UmbFormControlMixin<string | undefined, typeof UmbLitElement>(
UmbLitElement,
) {
protected override getFormElement() {
return undefined;
}
private _type: UmbContentPickerSource['type'] = 'content';
@property()
@property({ type: Object, attribute: false })
public set type(newType: UmbContentPickerSource['type']) {
const oldType = this._type;
if (newType?.toLowerCase() !== this._type) {
@@ -52,15 +55,23 @@ export class UmbInputContentElement extends UUIFormControlMixin(UmbLitElement, '
#entityTypeLookup = { content: 'document', media: 'media', member: 'member' };
// TODO: to be consistent with other pickers, this should be named `selection` [NL]
@property({ type: Array })
public set items(items: Array<UmbReferenceByUniqueAndType>) {
this.#selection = items?.map((item) => item.unique) ?? [];
this.value = items?.map((item) => item.unique).join(',');
}
public get items(): Array<UmbReferenceByUniqueAndType> {
return this.#selection.map((id) => ({ type: this.#entityTypeLookup[this._type], unique: id }));
}
@property({ type: String })
public override set value(selectionString: string | undefined) {
this.#selection = splitStringToArray(selectionString);
}
public override get value(): string | undefined {
return this.#selection.length > 0 ? this.#selection.join(',') : undefined;
}
#selection: Array<string> = [];
#onChange(event: CustomEvent) {

View File

@@ -10,7 +10,7 @@ import '../../../dynamic-root/input-content-picker-document-root/input-content-p
@customElement('umb-input-content-picker-source')
export class UmbInputContentPickerSourceElement extends UUIFormControlMixin(UmbLitElement, '') {
protected getFormElement() {
protected override getFormElement() {
return undefined;
}

View File

@@ -4,7 +4,6 @@ import {
UMB_CONTENT_PICKER_DOCUMENT_ROOT_QUERY_STEP_PICKER_MODAL,
} from '../modals/index.js';
import { html, css, customElement, property, ifDefined, state, repeat } from '@umbraco-cms/backoffice/external/lit';
import { UUIFormControlMixin } from '@umbraco-cms/backoffice/external/uui';
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
import { UmbId } from '@umbraco-cms/backoffice/id';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
@@ -16,11 +15,15 @@ import type {
ManifestDynamicRootQueryStep,
} from '@umbraco-cms/backoffice/extension-registry';
import type { UmbModalContext } from '@umbraco-cms/backoffice/modal';
import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation';
const elementName = 'umb-input-content-picker-document-root';
@customElement(elementName)
export class UmbInputContentPickerDocumentRootElement extends UUIFormControlMixin(UmbLitElement, '') {
protected getFormElement() {
export class UmbInputContentPickerDocumentRootElement extends UmbFormControlMixin<
string | undefined,
typeof UmbLitElement
>(UmbLitElement) {
protected override getFormElement() {
return undefined;
}

View File

@@ -11,6 +11,15 @@ export class UmbPropertyEditorUITextareaElement extends UmbLitElement implements
@property()
value = '';
/**
* 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 _maxChars?: number;
@@ -52,7 +61,8 @@ export class UmbPropertyEditorUITextareaElement extends UmbLitElement implements
.maxlength=${this._maxChars}
.rows=${this._rows}
.value=${this.value ?? ''}
@input=${this.#onInput}></uui-textarea>
@input=${this.#onInput}
?readonly=${this.readonly}></uui-textarea>
`;
}

View File

@@ -7,7 +7,7 @@ import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
export class UmbStaticFilePickerContext extends UmbPickerInputContext<
UmbStaticFileItemModel,
any,
UmbStaticFileItemModel,
UmbStaticFilePickerModalData,
UmbStaticFilePickerModalValue
> {

View File

@@ -3,11 +3,13 @@ import { UmbStaticFilePickerContext } from './input-static-file.context.js';
import { css, customElement, html, nothing, property, repeat, state } from '@umbraco-cms/backoffice/external/lit';
import { splitStringToArray } from '@umbraco-cms/backoffice/utils';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UUIFormControlMixin } from '@umbraco-cms/backoffice/external/uui';
import { UmbServerFilePathUniqueSerializer } from '@umbraco-cms/backoffice/server-file-system';
import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation';
@customElement('umb-input-static-file')
export class UmbInputStaticFileElement extends UUIFormControlMixin(UmbLitElement, '') {
export class UmbInputStaticFileElement extends UmbFormControlMixin<string | undefined, typeof UmbLitElement>(
UmbLitElement,
) {
#serializer = new UmbServerFilePathUniqueSerializer();
/**
@@ -63,14 +65,12 @@ export class UmbInputStaticFileElement extends UUIFormControlMixin(UmbLitElement
return this.#pickerContext.getSelection();
}
@property()
// get value is handled by super class.
public override set value(pathsString: string) {
// Its with full purpose we don't call super.value, as thats being handled by the observation of the context selection.
this.selection = splitStringToArray(pathsString);
@property({ type: String })
public override set value(selectionString: string | undefined) {
this.selection = splitStringToArray(selectionString);
}
public override get value(): string {
return this.selection.join(',');
public override get value(): string | undefined {
return this.selection.length > 0 ? this.selection.join(',') : undefined;
}
@property()
@@ -100,7 +100,7 @@ export class UmbInputStaticFileElement extends UUIFormControlMixin(UmbLitElement
this.observe(this.#pickerContext.selectedItems, (selectedItems) => (this._items = selectedItems));
}
protected getFormElement() {
protected override getFormElement() {
return undefined;
}

View File

@@ -1,7 +1,8 @@
import type { UmbInputStaticFileElement } from '../../components/index.js';
import { html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit';
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
import { customElement, html, property, state } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import type { UmbNumberRangeValueType } from '@umbraco-cms/backoffice/models';
import {
UmbPropertyValueChangeEvent,
type UmbPropertyEditorConfigCollection,
@@ -21,10 +22,10 @@ export class UmbPropertyEditorUIStaticFilePickerElement extends UmbLitElement im
}
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
const validationLimit = config?.find((x) => x.alias === 'validationLimit');
const validationLimit = config?.getValueByAlias<UmbNumberRangeValueType>('validationLimit');
this._limitMin = (validationLimit?.value as any)?.min;
this._limitMax = (validationLimit?.value as any)?.max;
this._limitMin = validationLimit?.min;
this._limitMax = validationLimit?.max;
}
@state()

View File

@@ -67,7 +67,7 @@ export class UmbTagsInputElement extends UUIFormControlMixin(UmbLitElement, '')
this._tagInput.focus();
}
protected getFormElement() {
protected override getFormElement() {
return undefined;
}

View File

@@ -94,7 +94,7 @@ export class UmbStylesheetInputElement extends UUIFormControlMixin(UmbLitElement
this.observe(this.#pickerContext.selectedItems, (selectedItems) => (this._items = selectedItems));
}
protected getFormElement() {
protected override getFormElement() {
return undefined;
}

Some files were not shown because too many files have changed in this diff Show More